Let's get started and play with the TeamSnap API. This example will take you through setting up OAuth 2 and viewing information all the way to creating your own teams.
Storing and securing customer data is hard, and it's even harder when you have an API (or, in official OAuth 2 parlance, a "resource server"). Previously, the most common way to authenticate against an API was to pass in the user's username and password across the wire in exchange for an authentication token.
OAuth 2 solves this problem by moving the exchange of user credentials to an authorization server. Instead of having the user enter credentials directly in the client application, you now redirect the user to the authorization server. The authorization server then can redirect the user back to the client application with a token the client application can use.
OAuth 2 leaves a lot of details to the implementation, so instead of covering all the ways OAuth 2 could work, this guide will just cover how to authenticate with TeamSnap's services.
First things first: you need to get an OAuth2 client_id
and client_secret
from https://auth.teamsnap.com. If you don't have a TeamSnap account, you can create one for free here.
When you log in with your TeamSnap account details, you'll be presented with a screen like this:
Click on your name in the top-right corner, you'll be presented with a drop down menu:
Clicking Your Applications
will bring you to this page, where you can create an application:
Click on New Application
to create your application:
The redirect_uri
MUST be a URL you control, and secured via HTTPS. There is an exception for localhost
for testing purposes.
The "Name" for the application must be unique across the system.
Once you reach the final page, you can extract two very important pieces of information: the client id (shown as Application Id
) and the client secret (shown as Secret
).
Now that you have a client id and client secret, you need to redirect the user to the TeamSnap authentication service. To do this, you'll need to construct a url:
GET https://auth.teamsnap.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=RESPONSE_TYPE
Name | Type | Description |
---|---|---|
client_id | string | Required. The client_id is the application identifier you recieved from the TeamSnap Authorization Service when you registered your application. |
redirect_uri | string | The URL where you want users to be sent after authorization. This URI MUST be a subpath of a URI specified when you registered your application. Defaults to the first URI listed when registering your application. |
scope | string | A space-seperated list of scopes (permissions) your application requires. Defaults to read . |
response_type | string | code or token . Defaults to code . |
In this example, we're going to use 3-Leg OAuth 2, so we're going to use a response_type
of code
:
CLIENT_ID=your_client_id_here
REDIRECT_URI="https%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
RESPONSE_TYPE="code"
AUTHORIZATION_URL="https://auth.teamsnap.com/oauth/authorize"
# URL Assemble!
echo "$AUTHORIZATION_URL?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=$RESPONSE_TYPE"
Once we have this URL, you'll want to visit it in your web browser:
Since we didn't request any specific permissions, the authorization service prepares a default grant with just read permissions. This is fine for us right now, so authorize the application.
Woah! What? Don't panic - the first step of authorization actually completed successfully. Because there's no server running on https://localhost:3000/
, the browser, understandably, gives an error message. If you were building a real client application, the redirect would point to your (running) servers, and you'd have a custom screen here now that TeamSnap's authorization servers have redirect the user back to your application.
The important bit is in the URL that the authorization redirected to: https://localhost:3000/?code=AUTHORIZATION_CODE_HERE
This code is not enough to access the TeamSnap API as your application. If it were, any user could masquerade as your app. Instead, you need to exchange this authorization code for an authorization token:
POST https://auth.teamsnap.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&code=AUTHORIZATION_CODE&grant_type=authorization_code
Name | Type | Description |
---|---|---|
client_id | string | Required. The client_id is the application identifier you recieved from the TeamSnap Authorization Service when you registered your application. |
client_secret | string | Required. The client_secret is the application secret you recieved from the TeamSnap Authorization Service when you registered your application. |
redirect_uri | string | Required if you specified a redirect_uri in the authorization request. This redirect_uri MUST be the exact same as specified in the previous request. |
code | string | Required. The authorization code recieved in the previous step for token exchange. |
grant_type | string | Required. Should always be authorization_code . |
Let's put that together:
CODE=authorization_code_here
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here
REDIRECT_URI="http%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
GRANT_TYPE="authorization_code"
TOKEN_EXCHANGE_URL="https://auth.teamsnap.com/oauth/token"
curl -X POST "$TOKEN_EXCHANGE_URL?client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=$GRANT_TYPE"
This request should give you a response similar to the following:
{
"access_token": "e226c729934316851bcf568288c5573f60f190f5ee3900c1cc52e013ee313281",
"expires_in": 7200,
"scope": "read",
"token_type": "bearer"
}
Name | Description |
---|---|
access_token | This is the access token you will use to authorize your requests against the TeamSnap API. |
expires_in | Time, in seconds, until the token will expire. |
scope | The list of scopes (access) that this token provides. |
token_type | How to pass in the token to the Authorization header. Always bearer . |
Now that you have our access_token, it's time to start making requests against the API.
The root of the TeamSnap API is at https://api.teamsnap.com/v3/
. If we make a request:
curl -X GET -H "Content-Type: application/json" https://api.teamsnap.com/v3/
{
"collection": {
"error": {
"message": "You are not authorized to access this resource. Please ensure you've provided a valid access token."
}
}
}
All API requests must be authorized. Since you have a valid access token:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" https://api.teamsnap.com/v3/
{
"collection": {
"href": "https://api.teamsnap.com/v3/",
"links": [
{
"href": "https://api.teamsnap.com/v2",
"rel": "apiv2_root"
},
{
"href": "https://api.teamsnap.com/v3/assignments",
"rel": "assignments"
},
{
"href": "https://api.teamsnap.com/v3/availabilities",
"rel": "availabilities"
},
{
"href": "https://api.teamsnap.com/v3/contact_email_addresses",
"rel": "contact_email_addresses"
},
{
"href": "https://api.teamsnap.com/v3/contact_phone_numbers",
"rel": "contact_phone_numbers"
},
{
"href": "https://api.teamsnap.com/v3/contacts",
"rel": "contacts"
},
{
"href": "https://api.teamsnap.com/v3/custom_data",
"rel": "custom_data"
},
{
"href": "https://api.teamsnap.com/v3/custom_fields",
"rel": "custom_fields"
},
{
"href": "https://api.teamsnap.com/v3/events",
"rel": "events"
},
{
"href": "https://api.teamsnap.com/v3/forum_posts",
"rel": "forum_posts"
},
{
"href": "https://api.teamsnap.com/v3/forum_subscriptions",
"rel": "forum_subscriptions"
},
{
"href": "https://api.teamsnap.com/v3/forum_topics",
"rel": "forum_topics"
},
{
"href": "https://api.teamsnap.com/v3/locations",
"rel": "locations"
},
{
"href": "https://api.teamsnap.com/v3/me",
"rel": "me"
},
{
"href": "https://api.teamsnap.com/v3/member_email_addresses",
"rel": "member_email_addresses"
},
{
"href": "https://api.teamsnap.com/v3/member_files",
"rel": "member_files"
},
{
"href": "https://api.teamsnap.com/v3/member_links",
"rel": "member_links"
},
{
"href": "https://api.teamsnap.com/v3/member_phone_numbers",
"rel": "member_phone_numbers"
},
{
"href": "https://api.teamsnap.com/v3/members",
"rel": "members"
},
{
"href": "https://api.teamsnap.com/v3/members_preferences",
"rel": "members_preferences"
},
{
"href": "https://api.teamsnap.com/v3/opponents",
"rel": "opponents"
},
{
"href": "https://api.teamsnap.com/v3/opponents_results",
"rel": "opponents_results"
},
{
"href": "https://api.teamsnap.com/v3/plans",
"rel": "plans"
},
{
"href": "https://api.teamsnap.com/v3/sms_gateways",
"rel": "sms_gateways"
},
{
"href": "https://api.teamsnap.com/v3/sponsors",
"rel": "sponsors"
},
{
"href": "https://api.teamsnap.com/v3/sports",
"rel": "sports"
},
{
"href": "https://api.teamsnap.com/v3/team_files",
"rel": "team_files"
},
{
"href": "https://api.teamsnap.com/v3/team_public_sites",
"rel": "team_public_sites"
},
{
"href": "https://api.teamsnap.com/v3/teams",
"rel": "teams"
},
{
"href": "https://api.teamsnap.com/v3/teams_preferences",
"rel": "teams_preferences"
},
{
"href": "https://api.teamsnap.com/v3/teams_results",
"rel": "teams_results"
},
{
"href": "https://api.teamsnap.com/v3/time_zones",
"rel": "time_zones"
},
{
"href": "https://api.teamsnap.com/v3/tracked_item_statuses",
"rel": "tracked_item_statuses"
},
{
"href": "https://api.teamsnap.com/v3/tracked_items",
"rel": "tracked_items"
},
{
"href": "https://api.teamsnap.com/v3/tsl_metadata",
"rel": "tsl_metadata"
},
{
"href": "https://api.teamsnap.com/v3/users",
"rel": "users"
},
{
"href": "https://api.teamsnap.com/v3/",
"rel": "root"
},
{
"href": "https://api.teamsnap.com/v3/",
"rel": "self"
}
],
"queries": [
{
"data": [
{
"name": "team_id",
"value": null
},
{
"name": "types",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/bulk_load",
"rel": "bulk_load"
}
],
"version": "3.31.1"
}
}
That's a lot of data. Since this is a guided tour, our next step is to find out some more information about this user. Conveniently, there's a me
rel:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF="https://api.teamsnap.com/v3/me"
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/users",
"items": [
{
"data": [
{
"name": "id",
"value": 3745306
},
{
"name": "type",
"value": "user"
},
{
"name": "address_country",
"value": ""
},
{
"name": "address_state",
"value": ""
},
{
"name": "birthday",
"value": "1987-05-01"
},
{
"name": "email",
"value": "user@example.com"
},
{
"name": "facebook_access_token",
"value": null
},
{
"name": "facebook_id",
"value": null
},
{
"name": "first_name",
"value": "John"
},
{
"name": "last_name",
"value": "Doe"
},
{
"name": "receives_newsletter",
"value": false
},
{
"name": "teams_count",
"value": 1
},
{
"name": "created_at",
"type": "DateTime",
"value": "2012-11-12T17:05:51Z"
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-07T21:24:45Z"
}
],
"href": "https://api.teamsnap.com/v3/users/3745306",
"links": [
{
"href": "https://api.teamsnap.com/v3/members/search?user_id=3745306",
"rel": "members"
},
{
"href": "https://api.teamsnap.com/v3/teams/search?user_id=3745306",
"rel": "teams"
}
]
}
],
"links": [
{
"href": "https://api.teamsnap.com/v3/members",
"rel": "members"
},
{
"href": "https://api.teamsnap.com/v3/teams",
"rel": "teams"
},
{
"href": "https://api.teamsnap.com/v3/",
"rel": "root"
},
{
"href": "https://api.teamsnap.comv3/me",
"rel": "self"
}
],
"queries": [
{
"data": [
{
"name": "id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/users/search",
"rel": "search"
}
],
"template": {
"data": [
{
"name": "first_name",
"value": null
},
{
"name": "last_name",
"value": null
},
{
"name": "password",
"value": null
},
{
"name": "birthday",
"value": null
},
{
"name": "email",
"value": null
},
{
"name": "facebook_id",
"value": null
},
{
"name": "facebook_access_token",
"value": null
}
]
},
"version": "3.31.1"
}
}
In this response, we see that John Doe's collection response helpfully has a preconstructed teams
rel
under links
:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= # https://api.teamsnap.com/v3/teams/search?user_id=3745306
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"commands": [
{
"data": [
{
"name": "team_id",
"value": null
},
{
"name": "contact_id",
"value": null
},
{
"name": "member_id",
"value": null
},
{
"name": "introduction",
"value": null
},
{
"name": "notify_as_member_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/teams/invite",
"prompt": "invite team members or contacts to join TeamSnap.",
"rel": "invite"
}
],
"href": "https://api.teamsnap.com/v3/teams",
"items": [
{
"data": [
{
"name": "id",
"value": 890368
},
{
"name": "type",
"value": "team"
},
{
"name": "division_name",
"value": null
},
{
"name": "is_archived_season",
"value": false
},
{
"name": "league_name",
"value": null
},
{
"name": "league_url",
"value": null
},
{
"name": "location_country",
"value": "United States"
},
{
"name": "location_postal_code",
"value": "97229"
},
{
"name": "location_latitude",
"value": "45.546074"
},
{
"name": "location_longitude",
"value": "-122.812688"
},
{
"name": "name",
"value": "Test"
},
{
"name": "plan_id",
"value": 33
},
{
"name": "season_name",
"value": null
},
{
"name": "sport_id",
"value": 2
},
{
"name": "time_zone_description",
"value": "Pacific Time (US & Canada)"
},
{
"name": "time_zone_iana_name",
"value": "America/Los_Angeles"
},
{
"name": "time_zone_offset",
"value": "-08:00"
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-07T21:25:12Z"
},
{
"name": "created_at",
"type": "DateTime",
"value": "2015-02-07T21:24:12Z"
},
{
"name": "plan_id",
"value": 33
},
{
"name": "has_reached_roster_limit",
"value": false
},
{
"name": "roster_limit",
"value": 4000
}
],
"href": "https://api.teamsnap.com/v3/teams/890368",
"links": [
{
"href": "https://api.teamsnap.com/v3/assignments/search?team_id=890368",
"rel": "assignments"
},
{
"href": "https://api.teamsnap.com/v3/availabilities/search?team_id=890368",
"rel": "availabilities"
},
{
"href": "http://ical-cdn.teamsnap.com/team_schedule/95681c50-913d-0132-7e59-3c764e0552da.ics",
"rel": "calendar_http"
},
...
]
}
],
"links": [
...
],
"queries": [
{
"data": [
{
"name": "id",
"value": null
},
{
"name": "team_id",
"value": null
},
{
"name": "user_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/teams/search",
"rel": "search"
}
],
"template": {
"data": [
{
"name": "name",
"value": null
},
{
"name": "location_country",
"value": null
},
{
"name": "location_postal_code",
"value": null
},
{
"name": "time_zone",
"value": null
},
{
"name": "sport_id",
"value": null
},
{
"name": "division_name",
"value": null
},
{
"name": "season_name",
"value": null
},
{
"name": "league_name",
"value": null
},
{
"name": "league_url",
"value": null
}
]
},
"version": "3.31.1"
}
}
The teams output shows that John Doe only has one team at this time. Let's look at the members on his team.
Using the members
rel
in the links
section of the team
collection object, we can view the members of his team:
{
"href": "https://api.teamsnap.com/v3/members/search?team_id=890368",
"rel": "members"
}
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= # https://api.teamsnap.com/v3/members/search?team_id=890368
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"commands": [
{
"data": [
{
"name": "member_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/disable_member",
"rel": "disable_member"
},
{
"data": [
{
"name": "member_id",
"value": null
},
{
"name": "file",
"value": null
},
{
"name": "x",
"value": null
},
{
"name": "y",
"value": null
},
{
"name": "width",
"value": null
},
{
"name": "height",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/upload_member_photo",
"rel": "upload_member_photo"
},
{
"data": [
{
"name": "member_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/remove_member_photo",
"rel": "remove_member_photo"
},
{
"data": [
{
"name": "member_id",
"value": null
},
{
"name": "x",
"value": null
},
{
"name": "y",
"value": null
},
{
"name": "width",
"value": null
},
{
"name": "height",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/generate_member_thumbnail",
"rel": "generate_member_thumbnail"
}
],
"href": "https://api.teamsnap.com/v3/members",
"items": [
{
"data": [
{
"name": "id",
"value": 11068474
},
{
"name": "type",
"value": "member"
},
{
"name": "address_city",
"value": null
},
{
"name": "address_state",
"value": null
},
{
"name": "address_street1",
"value": null
},
{
"name": "address_street2",
"value": null
},
{
"name": "address_zip",
"value": null
},
{
"name": "birthday",
"value": ""
},
{
"name": "first_name",
"value": "John"
},
{
"name": "gender",
"value": null
},
{
"name": "hide_address",
"value": null
},
{
"name": "hide_age",
"value": null
},
{
"name": "invitation_code",
"value": null
},
{
"name": "invitation_declined",
"value": null
},
{
"name": "is_activated",
"value": true
},
{
"name": "is_invitable",
"value": false
},
{
"name": "is_manager",
"value": true
},
{
"name": "is_non_player",
"value": false
},
{
"name": "is_owner",
"value": true
},
{
"name": "is_ownership_pending",
"value": null
},
{
"name": "jersey_number",
"value": null
},
{
"name": "last_logged_in_at",
"type": "DateTime",
"value": "2015-02-07T21:24:13Z"
},
{
"name": "last_name",
"value": "Doe"
},
{
"name": "position",
"value": null
},
{
"name": "team_id",
"value": 890368
},
{
"name": "user_id",
"value": 3745306
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-07T21:24:13Z"
},
{
"name": "created_at",
"type": "DateTime",
"value": "2015-02-07T21:24:12Z"
}
],
"href": "https://api.teamsnap.com/v3/members/11068474",
"links": [
...
]
}
],
"links": [
...
],
"queries": [
{
"data": [
{
"name": "team_id",
"value": null
},
{
"name": "user_id",
"value": null
},
{
"name": "id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/search",
"rel": "search"
},
{
"data": [
{
"name": "team_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/managers",
"rel": "managers"
},
{
"data": [
{
"name": "team_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/members/owner",
"rel": "owner"
}
],
"template": {
"data": [
{
"name": "first_name",
"value": null
},
{
"name": "last_name",
"value": null
},
{
"name": "gender",
"value": null
},
{
"name": "position",
"value": null
},
{
"name": "is_manager",
"value": null
},
{
"name": "birthday",
"value": null
},
{
"name": "hide_age",
"value": null
},
{
"name": "hide_address",
"value": null
},
{
"name": "is_non_player",
"value": null
},
{
"name": "address_street1",
"value": null
},
{
"name": "address_street2",
"value": null
},
{
"name": "address_city",
"value": null
},
{
"name": "address_state",
"value": null
},
{
"name": "address_zip",
"value": null
},
{
"name": "jersey_number",
"value": null
},
{
"name": "team_id",
"value": null
}
]
},
"version": "3.31.1"
}
}
Looks like he's only got himself on the team right now. Since it's boring to play by yourself, let's change that for him.
In Collection+JSON, all updates are done via a PUT
request.
Let's try updating the team name from "Test" to "Super Dragons Unlimited Soccer Stars." A catchy name is always useful for recruiting players!
In order to do this, you'll need to grab the href
property of the team:
"href": "https://api.teamsnap.com/v3/teams/890368"
and use that as our API_HREF for your PUT request.
You'll also need to assemble the data according to the template:
"template": {
"data": [
{
"name": "name",
"value": null
},
{
"name": "location_country",
"value": null
},
{
"name": "location_postal_code",
"value": null
},
{
"name": "time_zone",
"value": null
},
{
"name": "sport_id",
"value": null
},
{
"name": "division_name",
"value": null
},
{
"name": "season_name",
"value": null
},
{
"name": "league_name",
"value": null
},
{
"name": "league_url",
"value": null
}
]
}
In this case, you're just updating the name attribute. In the examples below, it's a bit ugly because we're feeding the JSON body to curl, but you want to use the template JSON directly to update any attributes:
{
"template": {
"data": [
{
"name": "name",
"value": "Super Dragons Unlimited Soccer Stars"
}
]
}
}
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= # https://api.teamsnap.com/v3/teams/890368
curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{ "template": { "data": [{ "name": "name", "value": "Super Dragons Unlimited Soccer Stars"}] } }' $API_HREF
{
"collection": {
"error": {
"message": "You do not have the appropriate scopes to access this resource."
}
}
}
Oops, you'll need to get a token with appropriate scopes. To do this, you'll have to redirect the user to the authorization service again, but this time with the scope parameter set appropriately so you can get write access to their teams:
CLIENT_ID=your_client_id_here
REDIRECT_URI="http%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
RESPONSE_TYPE="code"
AUTHORIZATION_URL="https://auth.teamsnap.com/oauth/authorize"
SCOPE="read+write_teams" # read write_teams URL-encoded
echo "$AUTHORIZATION_URL?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=$RESPONSE_TYPE&scope=$SCOPE"
Perform token exchange on the new code:
CODE=authorization_code_here
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here
REDIRECT_URI="http%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
GRANT_TYPE="authorization_code"
TOKEN_EXCHANGE_URL="https://auth.teamsnap.com/oauth/token"
curl -X POST "$TOKEN_EXCHANGE_URL?client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=$GRANT_TYPE"
{
"access_token": "511597e33ba19a7520be3bc361e0fe50b49bfb396e3148b2fe699876e549ab0b",
"expires_in": 7200,
"scope": "read write_teams",
"token_type": "bearer"
}
And now you have the appropriate scopes to continue.
Let's try the request again:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= # https://api.teamsnap.com/v3/teams/890368
curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{ "template": { "data": [{ "name": "name", "value": "Super Dragons Unlimited Soccer Stars"}] } }' $API_HREF
{
"collection": {
"commands": [
{
...
}
],
"href": "https://api.teamsnap.com/v3/teams",
"items": [
{
"data": [
{
"name": "id",
"value": 890368
},
...
{
"name": "name",
"value": "Super Dragons Unlimited Soccer Stars"
},
],
"href": "https://api.teamsnap.com/v3/teams/890368",
"links": [
...
]
}
],
"links": [
...
],
"queries": [
...
],
"template": {
...
},
"version": "3.31.1"
}
}
Success! Now you should try adding a few teammates to the team.
With Collection+JSON, all creates are done via POST requests, and like updates, use the template provided in the collection.
If we go back to the root of the API, we can the members
rel
:
{
"href": "https://api.teamsnap.com/v3/members",
"rel": "members"
}
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/members
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"commands": [
...
],
"href": "https://api.teamsnap.com/v3/members",
"links": [
...
],
"queries": [
...
],
"template": {
"data": [
{
"name": "first_name",
"value": null
},
{
"name": "last_name",
"value": null
},
{
"name": "gender",
"value": null
},
{
"name": "position",
"value": null
},
{
"name": "is_manager",
"value": null
},
{
"name": "birthday",
"value": null
},
{
"name": "hide_age",
"value": null
},
{
"name": "hide_address",
"value": null
},
{
"name": "is_non_player",
"value": null
},
{
"name": "address_street1",
"value": null
},
{
"name": "address_street2",
"value": null
},
{
"name": "address_city",
"value": null
},
{
"name": "address_state",
"value": null
},
{
"name": "address_zip",
"value": null
},
{
"name": "jersey_number",
"value": null
},
{
"name": "team_id",
"value": null
}
]
},
"version": "3.31.1"
}
}
However, to write to this collection, you'll need to request additional scope permissions:
CLIENT_ID=your_client_id_here
REDIRECT_URI="http%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
RESPONSE_TYPE="code"
AUTHORIZATION_URL="https://auth.teamsnap.com/oauth/authorize"
SCOPE="read+write_teams+write_members" # read write_teams write_members URL-encoded
echo "$AUTHORIZATION_URL?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=$RESPONSE_TYPE&scope=$SCOPE"
CODE=authorization_code_here
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here
REDIRECT_URI="http%3A%2F%2Flocalhost%3A3000%2F" # https://localhost:3000/ URL-encoded
GRANT_TYPE="authorization_code"
TOKEN_EXCHANGE_URL="https://auth.teamsnap.com/oauth/token"
curl -X POST "$TOKEN_EXCHANGE_URL?client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=$GRANT_TYPE"
{
"access_token": "d47ecf8d047aa673d0b55e671f44ea794c3f8510289cdb0db95f470e8da45f64",
"expires_in": 7200,
"scope": "read write_teams write_members",
"token_type": "bearer"
}
The href
of the collection is https://api.teamsnap.com/v3/members
. The template is a bit large, though. What's actually required?
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/members
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"error": {
"message": "first_name can't be blank; team_id can't be blank"
}
}
}
Ok, simple enough. Let's add Jane Doe to the team as well:
{
"template": {
"data": [
{
"name": "first_name",
"value": "Jane"
},
{
"name": "last_name",
"value": "Doe"
},
{
"name": "team_id",
"value": 890368
}
]
}
}
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/members
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{ "template": { "data": [{ "name": "first_name", "value": "Jane" }, { "name": "last_name", "value": "Doe" }, { "name": "team_id", "value": 890368 }] } }' $API_HREF
{
"collection": {
"commands": [
...
],
"href": "https://api.teamsnap.com/v3/members",
"items": [
{
"data": [
{
"name": "id",
"value": 11074924
},
{
"name": "type",
"value": "member"
},
{
"name": "address_city",
"value": null
},
{
"name": "address_state",
"value": null
},
{
"name": "address_street1",
"value": null
},
{
"name": "address_street2",
"value": null
},
{
"name": "address_zip",
"value": null
},
{
"name": "birthday",
"value": ""
},
{
"name": "first_name",
"value": "Jane"
},
{
"name": "gender",
"value": null
},
{
"name": "hide_address",
"value": false
},
{
"name": "hide_age",
"value": false
},
{
"name": "invitation_code",
"value": null
},
{
"name": "invitation_declined",
"value": null
},
{
"name": "is_activated",
"value": false
},
{
"name": "is_invitable",
"value": false
},
{
"name": "is_manager",
"value": false
},
{
"name": "is_non_player",
"value": false
},
{
"name": "is_owner",
"value": false
},
{
"name": "is_ownership_pending",
"value": false
},
{
"name": "jersey_number",
"value": null
},
{
"name": "last_logged_in_at",
"type": "DateTime",
"value": null
},
{
"name": "last_name",
"value": "Doe"
},
{
"name": "position",
"value": null
},
{
"name": "team_id",
"value": 890368
},
{
"name": "user_id",
"value": null
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-08T08:06:13Z"
},
{
"name": "created_at",
"type": "DateTime",
"value": "2015-02-08T08:06:13Z"
}
],
"href": "https://api.teamsnap.com/v3/members/11074924",
"links": [
{
"href": "https://api.teamsnap.com/v3/member_email_addresses/search?member_id=11074924",
"rel": "member_email_addresses"
},
{
"href": "https://api.teamsnap.com/v3/member_phone_numbers/search?member_id=11074924",
"rel": "member_phone_numbers"
}
]
}
],
"links": [
...
],
"queries": [
...
],
"template": {
"data": [
...
]
},
"version": "3.31.1"
}
}
Great! Now Jane Doe is a member of the team. We didn't set up any contact information for Jane, though, so let's create that now.
Contact information in TeamSnap is split up into several items: member_email_addresses
, member_phone_numbers
, and then contacts
, which can have their own contact_email_addresses
and contact_phone_numbers
.
Let's start with setting an email address for Jane Doe.
In the Collection+JSON response returned when you created Jane's member record, the rel member_email_addresses
is present. Let's use that to dig further:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= #https://api.teamsnap.com/v3/member_email_addresses/search?member_id=11074924
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/member_email_addresses",
"links": [
{
"href": "https://api.teamsnap.com/v3/members",
"rel": "member"
},
{
"href": "https://api.teamsnap.com/v3/teams",
"rel": "team"
},
{
"href": "https://api.teamsnap.com/v3/",
"rel": "root"
},
{
"href": "https://api.teamsnap.comv3/member_email_addresses/search?member_id=11074924",
"rel": "self"
}
],
"queries": [
...
],
"template": {
"data": [
{
"name": "member_id",
"value": null
},
{
"name": "label",
"value": null
},
{
"name": "email",
"value": null
},
{
"name": "receives_team_emails",
"value": null
},
{
"name": "is_hidden",
"value": null
}
]
},
"version": "3.31.1"
}
}
Nothing here, which is to be expected. Jane's email address is jane@example.com
, so let's create that:
{
"template": {
"data": [
{
"name": "member_id",
"value": 11074924
},
{
"name": "label",
"value": "Work"
},
{
"name": "email",
"value": "jane@example.com"
},
{
"name": "receives_team_emails",
"value": true
},
{
"name": "is_hidden",
"value": true
}
]
}
}
receives_team_emails
means that Jane will get TeamSnap emails at this email address, and is_hidden
means that only Jane and Managers on the team can see this email address.
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/member_email_addresses
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{ "template": { "data": [{ "name": "member_id", "value": 11074924 }, { "name": "label", "value": "Work" }, { "name": "email", "value": "jane@example.com" }, { "name": "receives_team_emails","value": true }, { "name": "is_hidden", "value": true }] } }' $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/member_email_addresses",
"items": [
{
"data": [
{
"name": "id",
"value": 14314178
},
{
"name": "type",
"value": "member_email_address"
},
{
"name": "email",
"value": "jane@example.com"
},
{
"name": "is_hidden",
"value": true
},
{
"name": "label",
"value": "Work"
},
{
"name": "member_id",
"value": 11074924
},
{
"name": "team_id",
"value": 890368
},
{
"name": "receives_team_emails",
"value": true
},
{
"name": "created_at",
"type": "DateTime",
"value": "2015-02-08T08:28:14Z"
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-08T08:28:14Z"
}
],
"href": "https://api.teamsnap.com/v3/member_email_addresses/14314178",
"links": [
{
"href": "https://api.teamsnap.com/v3/members/11074924",
"rel": "member"
},
{
"href": "https://api.teamsnap.com/v3/teams/890368",
"rel": "team"
}
]
}
],
"links": [
...
],
"queries": [
...
],
"template": {
"data": [
...
]
},
"version": "3.31.1"
}
}
Great! Now let's do the same for her phone number.
As with email addresses, the rel member_phone_numbers
is available on the members collection:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF= #https://api.teamsnap.com/v3/member_phone_numbers/search?member_id=11074924
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/member_phone_numbers",
"links": [
{
"href": "https://api.teamsnap.com/v3/sms_gateways",
"rel": "sms_gateway"
}
],
"queries": [
...
],
"template": {
"data": [
{
"name": "label",
"value": null
},
{
"name": "phone_number",
"value": null
},
{
"name": "preferred",
"value": null
},
{
"name": "member_id",
"value": null
},
{
"name": "sms_enabled",
"value": null
},
{
"name": "sms_gateway_id",
"value": null
},
{
"name": "is_hidden",
"value": null
}
]
},
"version": "3.31.1"
}
}
It looks like there's a bit of a complication - if Jane wants to get SMS messages from TeamSnap, you'll need to present to her a list of sms_gateway
s and use her selection to push an id
up to the system:
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/sms_gateways
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/sms_gateways",
"items": [
{
"data": [
{
"name": "id",
"value": "acsalaska"
},
{
"name": "type",
"value": "SmsGateway"
},
{
"name": "domain",
"value": "@msg.acsalaska.com"
},
{
"name": "name",
"value": "ACS Alaska"
}
],
"href": "https://api.teamsnap.com/v3/sms_gateways/acsalaska"
},
...
],
"links": [
{
"href": "https://api.teamsnap.com/v3/",
"rel": "root"
},
{
"href": "https://api.teamsnap.comv3/sms_gateways",
"rel": "self"
}
],
"queries": [
{
"data": [
{
"name": "id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/sms_gateways/search",
"rel": "search"
}
],
"version": "3.31.1"
}
}
It looks like Jane is a subscriber of ACS Alaska (how convenient!). ACS Alaska has an id of acsalaska
, so let's use that to assemble the template:
{
"template": {
"data": [
{
"name": "label",
"value": "Cell"
},
{
"name": "phone_number",
"value": "555-867-5309"
},
{
"name": "preferred",
"value": true
},
{
"name": "member_id",
"value": 11074924
},
{
"name": "sms_enabled",
"value": true
},
{
"name": "sms_gateway_id",
"value": "acsalaska"
},
{
"name": "is_hidden",
"value": false
}
]
}
}
Here, Jane wants this to be her primary contact number (preferred
), and doesn't mind if everyone on the team knows what her cell number is (is_hidden
).
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/member_phone_numbers
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{ "template": { "data": [{ "name": "label", "value": "Cell" }, { "name": "phone_number", "value": "555-867-5309" }, { "name": "preferred", "value": true }, { "name": "member_id", "value": 11074924 }, { "name": "sms_enabled", "value": true }, { "name": "sms_gateway_id", "value": "acsalaska" }, { "name": "is_hidden", "value": false }] } }' $API_HREF
{
"collection": {
"href": "https://api.teamsnap.com/v3/member_phone_numbers",
"items": [
{
"data": [
{
"name": "id",
"value": 9706105
},
{
"name": "type",
"value": "member_phone_number"
},
{
"name": "is_hidden",
"value": false
},
{
"name": "label",
"value": "Cell"
},
{
"name": "member_id",
"value": 11074924
},
{
"name": "phone_number",
"value": "555-867-5309"
},
{
"name": "preferred",
"value": true
},
{
"name": "sms_email_address",
"value": "5558675309@msg.acsalaska.com"
},
{
"name": "sms_enabled",
"value": true
},
{
"name": "sms_gateway_id",
"value": "acsalaska"
},
{
"name": "team_id",
"value": 890368
}
],
"href": "https://api.teamsnap.com/v3/member_phone_numbers/9706105",
"links": [
{
"href": "https://api.teamsnap.com/v3/members/11074924",
"rel": "member"
},
{
"href": "https://api.teamsnap.com/v3/sms_gateways/acsalaska",
"rel": "sms_gateway"
},
{
"href": "https://api.teamsnap.com/v3/teams/890368",
"rel": "team"
}
]
}
],
"links": [
...
],
"queries": [
...
],
"template": {
"data": [
...
]
},
"version": "3.31.1"
}
}
And now Jane has a phone number set up in TeamSnap. Now that Jane has an email address, we can invite her to join TeamSnap with her own user account.
To invite a member to TeamSnap, they must have an email address set up that is set to receive team emails.
Back on the Team collection, you might have noticed a command
:
"commands": [
{
"data": [
{
"name": "team_id",
"value": null
},
{
"name": "contact_id",
"value": null
},
{
"name": "member_id",
"value": null
},
{
"name": "introduction",
"value": null
},
{
"name": "notify_as_member_id",
"value": null
}
],
"href": "https://api.teamsnap.com/v3/teams/invite",
"prompt": "invite team members or contacts to join TeamSnap.",
"rel": "invite"
}
]
Let's give it a shot!
{
"team_id": 890368,
"member_id": 11074924,
"introduction": "Hey Jane, you should join TeamSnap!",
"notify_as_member_id": 11068474
}
OAUTH_ACCESS_TOKEN=your_oauth_access_token
API_HREF=https://api.teamsnap.com/v3/teams/invite
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" -d '{"team_id": 890368, "member_id": 11074924, "introduction": "Hey Jane, you should join TeamSnap!", "notify_as_member_id": 11068474 }' $API_HREF | python -m json.tool
{
"collection": {
"commands": [
...
],
"href": "https://api.teamsnap.com/v3/teams",
"items": [
{
"data": [
{
"name": "id",
"value": 11074924
},
{
"name": "type",
"value": "member"
},
{
"name": "address_city",
"value": ""
},
{
"name": "address_state",
"value": ""
},
{
"name": "address_street1",
"value": ""
},
{
"name": "address_street2",
"value": null
},
{
"name": "address_zip",
"value": ""
},
{
"name": "birthday",
"value": ""
},
{
"name": "first_name",
"value": "Jane"
},
{
"name": "gender",
"value": ""
},
{
"name": "hide_address",
"value": false
},
{
"name": "hide_age",
"value": false
},
{
"name": "invitation_code",
"value": null
},
{
"name": "invitation_declined",
"value": null
},
{
"name": "is_activated",
"value": false
},
{
"name": "is_invitable",
"value": true
},
{
"name": "is_manager",
"value": false
},
{
"name": "is_non_player",
"value": false
},
{
"name": "is_owner",
"value": false
},
{
"name": "is_ownership_pending",
"value": false
},
{
"name": "jersey_number",
"value": ""
},
{
"name": "last_logged_in_at",
"type": "DateTime",
"value": null
},
{
"name": "last_name",
"value": "Doe"
},
{
"name": "position",
"value": ""
},
{
"name": "team_id",
"value": 890368
},
{
"name": "user_id",
"value": null
},
{
"name": "updated_at",
"type": "DateTime",
"value": "2015-02-08T08:56:18Z"
},
{
"name": "created_at",
"type": "DateTime",
"value": "2015-02-08T08:06:13Z"
}
],
"href": "https://api.teamsnap.com/v3/members/11074924",
"links": [
...
]
}
],
"links": [
...
],
"queries": [
...
],
"template": {
"data": [
...
]
},
"version": "3.31.1"
}
}
Success! Jane has been invited to John's team and should receive an email shortly.
Now that you've successfully authorized requests via OAuth 2, read Collection+JSON data, updated and created new records, and utilized a command template, the API should be pretty straightforward to explore. On the next page of the API documentation is a listing of objects you will encounter in the TeamSnap API.