upcoach API endpoint reference
upcoach API endpoint reference
Every endpoint of the upcoach API, grouped by what it works on. Paths are relative to the base URL, https://v3.upcoach.com/s/api/v1, and every request sends Authorization: Bearer <your token>. The basics (errors, pages, rate limits) are in Use the upcoach API and webhooks.
The examples are real responses from a demo workspace, shortened to one or two items.
| Endpoint | What it does | Scope |
|---|---|---|
GET /me | The token’s person and workspace | any |
GET /programs | List programs | api:read |
GET /programs/{id} | One program | api:read |
GET /programs/{id}/members | List a program’s members | api:read |
POST /programs/{id}/invitations | Invite people to a program | api:write |
DELETE /programs/{id}/members/{user_id} | Remove someone from a program | api:write |
GET /members | List the workspace’s people | api:read |
GET /events | List events across the workspace | api:read |
GET /programs/{id}/events | List a program’s events | api:read |
GET /completions | List activity completions | api:read |
GET /enrollments | List offer enrollments | api:read |
GET /webhooks, POST /webhooks, GET /webhooks/{id}, DELETE /webhooks/{id}, GET /webhooks/samples/{event} | Webhook subscriptions | webhooks:manage |
Your token
GET /me
The token’s person, its workspace and the scopes it holds. Use it to check a token works.
{
"data": {
"user": { "id": "4704aa8c-30dd-4cf6-9b3c-0104bf275f44", "name": "Maya Chen", "email": "[email protected]" },
"workspace": { "id": "org-1b547af4-c0cb-4f48-8d4e-d7a1fef601b2", "name": "Brightpath Coaching", "url": "https://brightpath.upcoach.com/" },
"scopes": ["api:read", "api:write", "webhooks:manage"]
}
}
Programs
GET /programs
Your programs, newest first.
| Parameter | What it does |
|---|---|
search | Part of the program’s name, in any letter case |
status | published or draft |
limit, cursor | Page size and the next page |
curl "https://v3.upcoach.com/s/api/v1/programs?limit=2" \
-H "Authorization: Bearer <your token>"
{
"data": [
{
"id": "ef6e8b2e-7e21-4b84-af23-453203c0444e",
"name": "12-Week Leadership Program",
"url": "https://brightpath.upcoach.com/s/spaces/coaching-cohort",
"status": "draft",
"type": null,
"starts_at": null,
"member_count": 2,
"created_at": "2026-11-11T05:52:28Z"
},
{
"id": "97173975-aa90-4c20-b5ad-83cb7d4b94ae",
"name": "Wellness Program",
"url": "https://brightpath.upcoach.com/s/spaces/wellness-program",
"status": "published",
"type": null,
"starts_at": null,
"member_count": 2,
"created_at": "2026-11-11T05:52:28Z"
}
],
"next_cursor": null
}
type is the program type it was made from, if any. member_count counts active participants. url opens the program; its address contains /spaces/, an older name for programs.
GET /programs/{id}
One program, with the same fields, as { "data": {...} }. A program of another workspace is not found (404).
Members and invitations
GET /programs/{id}/members
A program’s members, newest membership first.
| Parameter | What it does |
|---|---|
role | participant, coach, program_admin, program_sponsor or reporting_sponsor |
search | Part of the name or email |
email | An exact email address, in any letter case |
limit, cursor | Page size and the next page |
{
"data": [
{
"id": "7770c4ed-c615-4cab-a103-3de4cc7958d7",
"name": "Priya Nair",
"email": "[email protected]",
"timezone": "UTC",
"role": "participant",
"status": "pending",
"joined_at": "2026-11-11T05:52:28Z"
}
],
"next_cursor": "eyJpdiI6IkcrMHBmYzc0MHVRYk5Ndkd1TE45UUE9PSIs..."
}
status is active, pending (invited but never joined) or deactivated. joined_at is when they were added to the program. coach is the program’s Program Facilitator.
POST /programs/{id}/invitations
Emails each address the same invite the Users page sends, as a participant or a coach.
- Someone already in your workspace is in the program at once (
in_program: true). Anyone else joins it when they accept. - Someone already in the program is left out, under
not_invitedwith a reason. If they never joined, their invite is still pending and you invite them with the same role, they get it again (invite: "resent", or"new"if the old invite had expired). - Participants count toward your plan’s client limit and coaches toward its admin seats (seats and billing). A batch that would go over is refused with a 409. If some invites went out before the limit was reached,
messagenames them. - Invite emails count toward the workspace’s invite email caps. Over them, you get a 429.
| Field | What it is |
|---|---|
emails | 1 to 20 addresses, each listed once |
role | participant or coach |
curl -X POST "https://v3.upcoach.com/s/api/v1/programs/ef6e8b2e-7e21-4b84-af23-453203c0444e/invitations" \
-H "Authorization: Bearer <your token>" \
-H "Content-Type: application/json" \
-d '{"emails":["[email protected]","[email protected]"],"role":"participant"}'
{
"data": {
"program": { "id": "ef6e8b2e-7e21-4b84-af23-453203c0444e", "name": "12-Week Leadership Program", "url": "https://brightpath.upcoach.com/s/spaces/coaching-cohort" },
"role": "participant",
"invited": [
{ "email": "[email protected]", "status": "invited", "invite": "new", "in_program": false },
{ "email": "[email protected]", "status": "invited", "invite": "new", "in_program": false }
],
"not_invited": []
}
}
Inviting Sam again, this time as a coach:
{
"data": {
"program": { "id": "ef6e8b2e-7e21-4b84-af23-453203c0444e", "name": "12-Week Leadership Program", "url": "https://brightpath.upcoach.com/s/spaces/coaching-cohort" },
"role": "coach",
"invited": [],
"not_invited": [
{
"email": "[email protected]",
"status": "not_invited",
"reason": "other_role",
"message": "Already in this program as Participant; nothing was sent and their role is unchanged."
}
]
}
}
reason is already_member (in the program with this role), other_role (in it with another role, which stays) or cannot_invite (an address that can’t be invited).
DELETE /programs/{id}/members/{user_id}
Removes the member from the program and notifies them. Their account and their place in the workspace stay. Owners and Admins of the workspace, and a program’s only Program Admin, can only be removed on the program’s Members page (403). Someone who isn’t in the program is not found (404).
curl -X DELETE "https://v3.upcoach.com/s/api/v1/programs/ef6e8b2e-7e21-4b84-af23-453203c0444e/members/6548f98c-5eb0-458c-80e9-441bf5116cae" \
-H "Authorization: Bearer <your token>"
{ "data": { "program_id": "ef6e8b2e-7e21-4b84-af23-453203c0444e", "member_id": "6548f98c-5eb0-458c-80e9-441bf5116cae", "removed": true } }
GET /members
Everyone in your workspace, deactivated people included, newest first, as Admin Area > Users lists them. Filter with email (an exact address).
{
"data": [
{
"id": "698fffed-b97e-4711-808d-d3cce8817363",
"name": "Sam Rivera",
"email": "[email protected]",
"timezone": "UTC",
"org_role": null,
"status": "pending",
"joined_at": null
}
],
"next_cursor": null
}
org_role is owner, admin, implementation_admin or null. joined_at is when they joined the workspace.
Events
GET /events and GET /programs/{id}/events
Events that start between from and to, earliest first: across the workspace (the ones the token’s person may see), or in one program.
| Parameter | What it does |
|---|---|
from | An ISO 8601 date or date-time, UTC unless it carries an offset. Defaults to the start of today (UTC) |
to | Defaults to 30 days after from, at most 366 days after it |
limit, cursor | Page size and the next page |
curl "https://v3.upcoach.com/s/api/v1/programs/97173975-aa90-4c20-b5ad-83cb7d4b94ae/events?from=2026-11-12&to=2026-12-31" \
-H "Authorization: Bearer <your token>"
{
"data": [
{
"id": "b238aee2-9243-4457-955f-eb42a7ad347c",
"title": "Group coaching call",
"starts_at": "2026-11-18T14:00:00Z",
"ends_at": "2026-11-18T15:00:00Z",
"timezone": "UTC",
"duration_minutes": 60,
"status": "upcoming",
"location_type": "link",
"location_detail": "https://example.com/meet",
"series_id": null,
"is_one_to_one_session": false,
"hosts": [
{ "id": "38289adf-a43e-4d34-bf11-7034afea768b", "name": "Jordan Lee", "email": "[email protected]", "timezone": "UTC" }
],
"program": { "id": "97173975-aa90-4c20-b5ad-83cb7d4b94ae", "name": "Wellness Program", "url": "https://brightpath.upcoach.com/s/spaces/wellness-program" },
"going_count": 0
}
],
"next_cursor": null
}
status is upcoming, in_progress or past. location_type is link, in_person or null, and location_detail the meeting link or address. Events of one recurring series share a series_id. going_count counts active members who said they’re going.
Completions
GET /completions
Activities members completed, newest first. Filter with program_id and since (an ISO 8601 time). Each item has the same fields as the activity.completed webhook, plus an id that is the same every time for one person and one activity.
{
"data": [
{
"id": "e81ff51d-1bc7-5595-bec1-507b2b1bccc2",
"member": { "id": "698fffed-b97e-4711-808d-d3cce8817363", "name": "Sam Rivera", "email": "[email protected]", "timezone": "UTC" },
"activity": { "id": "10172d34-76eb-4c46-b99f-277d5375872f", "title": "Reflection Worksheet", "type": "worksheet" },
"module": { "id": "8a05598d-ed54-41cd-a89d-f76264556eb4", "title": "Module 1" },
"section": { "id": "1de23536-c393-47a1-af84-d849c20ae39c", "title": "Foundation Week" },
"program": { "id": "97173975-aa90-4c20-b5ad-83cb7d4b94ae", "name": "Wellness Program", "url": "https://brightpath.upcoach.com/s/spaces/wellness-program" },
"completed_at": "2026-11-11T05:55:11Z"
}
],
"next_cursor": null
}
Enrollments
GET /enrollments
Offer purchases and free joins, newest first, as { "data": [...], "next_cursor": ... }. Filter with offer_id. Each item has the enrollment’s id plus the same fields as the enrollment.created webhook. Those fields, as in the data of the example GET /webhooks/samples/enrollment.created returns:
{
"member": { "id": "0b9d2f4e-1c3a-4e5b-8d7f-6a2c9e1b3d40", "name": "Sam Rivera", "email": "[email protected]", "timezone": "Europe/London" },
"offer": { "id": "8d2f6b4a-1e3c-4a7d-9b5f-2c0e7a1d4b36", "name": "Leadership Program" },
"programs": [
{ "id": "7c4e1a9b-2d3f-4b6a-8e5c-1f0d9a7b3c21", "name": "12-Week Leadership Program", "url": "https://brightpath.upcoach.com/s/spaces/12-week-leadership-program" }
],
"amount": 49900,
"currency": "usd",
"coupon": null,
"is_free": false,
"enrolled_at": "2026-11-12T09:30:00Z"
}
amount is in the currency’s smallest unit (cents), and null for a free offer. coupon has the coupon’s code and name when one was used.
Webhooks
Subscribe a URL to events, list and delete subscriptions, and get example payloads. The events, payloads and signature are in Send events to your tools with webhooks.
POST /webhooks
| Field | What it is |
|---|---|
url | An https URL on port 443 that resolves to public internet addresses only |
events | One or more event types, such as program.member_joined |
program_id | Optional: send only this program’s events |
curl -X POST "https://v3.upcoach.com/s/api/v1/webhooks" \
-H "Authorization: Bearer <your token>" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.example.com/upcoach","events":["program.member_joined","activity.completed"]}'
The answer is a 201 with the subscription and its signing secret. The secret is shown only here:
{
"data": {
"id": "4333cd09-bc03-4ec3-908e-17caea2cb6c7",
"url": "https://hooks.example.com/upcoach",
"events": ["program.member_joined", "activity.completed"],
"program_id": null,
"status": "active",
"disabled_reason": null,
"created_at": "2026-11-11T05:55:04Z",
"secret": "whsec_…"
}
}
A URL that isn’t public is refused:
{ "error": { "code": "validation_failed", "message": "The request is not valid.", "fields": { "url": ["Webhooks can only be sent to public internet addresses."] } } }
Creating subscriptions counts toward the rate limits.
GET /webhooks and GET /webhooks/{id}
The workspace’s subscriptions, newest first, whoever made them, on the Webhooks page or over the API. The same fields, without the secret. status is active or disabled, and disabled_reason says why: failing or access_revoked.
DELETE /webhooks/{id}
Deletes the subscription and its delivery log. Answers 204 with no body.
GET /webhooks/samples/{event}
Up to 3 payloads of the event that your workspace sent in the last 7 days, exactly as delivered, newest first. With none yet, one fixed example.