API reference
Endpoints
https://dyb5ahy4siv91.cloudfront.net/partner/v1 on staging. Codes that any call can get are on Errors and retries./usersAdd a personPOST/activitiesLog a workoutGET/users/{userId}Get a personGET/usersFind a person by your IDGET/activities/{externalId}Get a workoutGET/teamGet your team/usersCreates an Active Giving account (or finds the existing one), adds the person to your team and sends them a welcome email.
Body
Unique across Active Giving. The person signs into the app with it later.
Up to 100 characters. Shown to the team and in the welcome email.
Your own ID for this person, up to 128 characters: letters, numbers and - _ . :. Lets you log workouts and look them up without storing ours. If you first add someone without it, a later retry can set it once; after that it does not change.
The language of the welcome email and the app, in capitals. Defaults to EN.
Request
curl -X POST "https://dyb5ahy4siv91.cloudfront.net/partner/v1/users" \
-H "Authorization: Bearer $AG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maria.lopez@example.com",
"name": "Maria Lopez",
"partnerUserId": "emp-1042",
"language": "DE"
}'Response
{
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93",
"partnerUserId": "emp-1042",
"email": "maria.lopez@example.com",
"name": "Maria Lopez",
"language": "DE",
"teamId": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"linkedAt": "2026-10-14T08:20:11Z"
}Responses
| Status | When |
|---|---|
201 + the person | New email. The welcome email goes out. |
200 + the person | The email is already in your team. Safe to retry: nothing changes and no second email goes out. |
409already_in_team | The email belongs to someone in another team. |
409team_full | Your team has reached its maximum number of members. |
409person_unlinked | The person's link to your team ended. It is final: they cannot be added again. |
/activitiesRecords one finished workout and turns it into impact in a single call. The response says straight away whether it counted. Nothing is left pending.
Body
Our user ID, the userId from Add a person. Send exactly one of userId, userEmail and partnerUserId.
The email you added the person with.
Your own ID for the person, as you sent it in Add a person.
Your ID for this workout, up to 128 characters: letters, numbers and - _ . :. It never changes and is also the retry key: the same workout sent twice counts once.
A key from activityTypes in Get your team.
From the start of yesterday, in your team's time zone, until now. The workout must end no more than 5 minutes in the future.
60 to 86,400.
Required when the type has earnsBy: "DISTANCE". Above 0, up to 1,000,000.
Required, above 0, when the type has earnsBy: "CALORIES". Up to 20,000.
Request
curl -X POST "https://dyb5ahy4siv91.cloudfront.net/partner/v1/activities" \
-H "Authorization: Bearer $AG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"partnerUserId": "emp-1042",
"externalId": "wk-20261014-0007",
"type": "RUNNING",
"startedAt": "2026-10-14T05:30:00Z",
"durationSeconds": 2700,
"distanceMeters": 8200
}'Response
200 with the same body when the same workout was already received.
{
"id": "2b4eb032-c972-4360-a140-b46ad7a08805",
"externalId": "wk-20261014-0007",
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93",
"type": "RUNNING",
"startedAt": "2026-10-14T05:30:00Z",
"durationSeconds": 2700,
"distanceMeters": 8200,
"kilocalories": null,
"status": "COUNTED",
"impact": {
"unit": "TREE",
"amount": 0.4,
"reducedBy": null
},
"teamId": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"createdAt": "2026-10-14T06:16:02Z"
}Responses
| Status | When |
|---|---|
404user_not_found | No person in your team matches the one you named. |
409person_unlinked | The person's link to your team ended. Stop sending workouts for them. |
409duplicate_external_id | A workout with this externalId and different values was sent before. |
409daily_limit_reached | The person reached today's limit. error.resetsAt says when it resets. |
409overlapping_activity | The person already has a workout at the same time. |
422activity_not_available | Your team does not accept this type. |
422started_at_out_of_range | startedAt is before yesterday, or the workout ends more than 5 minutes from now. |
/users/{userId}Checks whether someone you added is still linked to your team, by the userId that Add a person answered.
Path
The userId from Add a person, in its full 36-character form.
Request
curl "https://dyb5ahy4siv91.cloudfront.net/partner/v1/users/3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93" \
-H "Authorization: Bearer $AG_API_KEY"Response
status is LINKED or ENDED. ENDED is final and covers every way a link ends; who ended it and why is not shared. LINKED only means the link exists, not that the person opened the app or got the welcome email. endedAt is null while the person is linked, and partnerUserId is null if you never sent one. There is no name, email or workout data.
{
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93",
"partnerUserId": "emp-1042",
"status": "LINKED",
"teamId": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"linkedAt": "2026-10-14T08:20:11Z",
"endedAt": null
}Responses
| Status | When |
|---|---|
404user_not_found | You did not add this person. That includes ids that do not exist and other partners' people, so the answer never tells whether an account exists. |
400invalid_request | userId is not in the full 36-character form we gave out. fields names it. |
/usersThe same lookup, by the partnerUserId you sent when you added the person.
Query
Your own ID for the person, up to 128 characters: letters, numbers and - _ . :. It must match exactly, case included.
Request
curl "https://dyb5ahy4siv91.cloudfront.net/partner/v1/users?partnerUserId=emp-1042" \
-H "Authorization: Bearer $AG_API_KEY"Response
status is LINKED or ENDED. ENDED is final and covers every way a link ends; who ended it and why is not shared. LINKED only means the link exists, not that the person opened the app or got the welcome email. endedAt is null while the person is linked, and partnerUserId is null if you never sent one. There is no name, email or workout data.
{
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93",
"partnerUserId": "emp-1042",
"status": "LINKED",
"teamId": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"linkedAt": "2026-10-14T08:20:11Z",
"endedAt": null
}Responses
| Status | When |
|---|---|
404user_not_found | You did not add this person. That includes ids that do not exist and other partners' people, so the answer never tells whether an account exists. |
400invalid_request | partnerUserId is missing, or not up to 128 characters: letters, numbers and - _ . :. fields names it. |
/activities/{externalId}Reads one workout you sent, with its outcome and impact.
Path
The externalId you sent the workout with.
Request
curl "https://dyb5ahy4siv91.cloudfront.net/partner/v1/activities/wk-20261014-0007" \
-H "Authorization: Bearer $AG_API_KEY"Response
{
"id": "2b4eb032-c972-4360-a140-b46ad7a08805",
"externalId": "wk-20261014-0007",
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d8e6f0a7b93",
"type": "RUNNING",
"startedAt": "2026-10-14T05:30:00Z",
"durationSeconds": 2700,
"distanceMeters": 8200,
"kilocalories": null,
"status": "COUNTED",
"impact": {
"unit": "TREE",
"amount": 0.4,
"reducedBy": null
},
"teamId": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"createdAt": "2026-10-14T06:16:02Z"
}Responses
| Status | When |
|---|---|
404activity_not_found | You sent no counted workout with this externalId. |
/teamEverything about your team in one call: whether it is running, places and budget left, the workout types it accepts, the daily limit and the totals. Cache it for a few minutes.
Request
curl "https://dyb5ahy4siv91.cloudfront.net/partner/v1/team" \
-H "Authorization: Bearer $AG_API_KEY"Response
{
"id": "7a1d9e40-5c2b-4f8e-a6d3-1b0c9e8f2a57",
"name": "Acme Move Challenge",
"state": "RUNNING",
"startsAt": "2026-10-01T00:00:00Z",
"endsAt": "2026-12-31T23:59:59Z",
"placesLeft": 412,
"budgetLeft": true,
"impactUnit": "TREE",
"activityTypes": [
{
"key": "RUNNING",
"label": "Running",
"earnsBy": "DISTANCE"
},
{
"key": "CYCLING",
"label": "Cycling",
"earnsBy": "DISTANCE"
},
{
"key": "YOGA",
"label": "Yoga",
"earnsBy": "CALORIES"
}
],
"totals": {
"members": 88,
"activities": 1204,
"kilometers": 6311.2,
"kilocalories": 512400,
"impact": 214.5
},
"dailyLimit": {
"mode": "COUNT",
"max": 5,
"unit": null,
"resetsAt": "2026-10-14T22:00:00Z"
}
}