Pull API
The Pull API is the source of truth for partner data. All timestamps are UTC in ISO 8601. Authenticate with a static API key in the Authorization header.
Base URL and authentication
- Base URL:
https://api.dev-ai.coach/v1 - Production and test use this URL; the issued API key selects the environment.
- Authentication: Send your API key on every request:
Authorization: Api-Key <API KEY>You can obtain the API key from the Partner Portal. Keep it secret and do not expose it in client-side code.
Conventions
Pagination
List endpoints support cursor-based pagination:
limit(optional) — Max items per page (1–1000, default 100).cursor(optional) — Use thenext_cursorvalue from the previous response to fetch the next page. Omit for the first page.
Responses use this shape:
{
"data": [],
"meta": {
"limit": 100,
"next_cursor": null
}
}Use meta.next_cursor unchanged for the next page. A cursor is opaque and tied to the original endpoint and filters. When next_cursor is null, there are no more pages. There is no previous-page cursor.
Time filters
Where supported, use from and to as UTC ISO 8601 date-time query parameters. Items are filtered by the endpoint timestamp (completed_at for workouts, occurred_at for tests, body composition, and deliveries): from is inclusive and to is exclusive. Workouts, tests, and body composition are available for the 30 calendar days before the request date.
Response statuses
- 200 — Successful GET request, or member names stored (
PATCH/POSTname endpoints). - 202 — User removal accepted.
- 204 — No body composition measurement is available.
- 400 — Invalid query parameters, date range, limit, cursor, or request body.
- 401 — Missing, invalid, revoked, or expired API key; includes
WWW-Authenticate: Api-Key. - 403 — Authenticated API key is not permitted to perform the operation.
- 404 — Resource not found or unavailable in your partner scope.
- 405 — HTTP method is not supported.
- 429 — Rate limit exceeded. Use the
Retry-Afterresponse header (seconds) before retrying. - 500 — Internal server error.
Error responses are JSON with a detail string describing the issue.
Quick check
Verify connectivity and authentication:
curl -s -H "Authorization: Api-Key <API KEY>" https://api.dev-ai.coach/v1/statusExample response:
{
"status": "ok",
"partner_name": "Your Partner",
"timestamp": "2025-03-12T10:00:00.000Z"
}Endpoints by use case
Health and self-service
| Method | Path | Description |
|---|---|---|
| GET | /status | Health check; returns status, partner name, and timestamp. |
Webhook delivery audit
Use these to debug missed webhooks or reconcile with your system.
| Method | Path | Description |
|---|---|---|
| GET | /webhooks/deliveries | List webhook delivery records. Optional query: partner_user_id, status (pending, delivered, failed), from, to, limit, cursor. |
Users
| Method | Path | Description |
|---|---|---|
| GET | /users | Enumerate partner user IDs with first_name and last_name (paginated). |
| GET | /users/{partner_user_id} | Get user summary (names, latest workout, tests, body composition, and streak). |
| DELETE | /users/{partner_user_id} | Remove user from this partner’s API access. Clears the member’s names. Emits user.deleted; a repeated delete returns 404. |
| PATCH | /users/{partner_user_id}/name | Set the member’s first name, last name, or both. See Member Names. |
| POST | /users/names:batch | Set names for up to 500 members in one request. See Member Names. |
first_name and last_name are the names you set through Member Names. They are null until you set them, and they are separate from the name the member chose in the Zing app.
Workouts
| Method | Path | Description |
|---|---|---|
| GET | /users/{partner_user_id}/workouts | List workouts for a user. Optional: from, to, limit, cursor. |
| GET | /workouts/{workout_id} | Get full workout detail by ID (includes exercises with duration, weight, reps). |
Tests
| Method | Path | Description |
|---|---|---|
| GET | /users/{partner_user_id}/tests | List tests for a user. Optional: type (fitness | flexibility), from, to, limit, cursor. |
| GET | /tests/{test_id} | Get full test result by ID (includes metrics). |
Body composition
| Method | Path | Description |
|---|---|---|
| GET | /users/{partner_user_id}/body_composition | List body composition measurements. Optional: from, to, limit, cursor. |
| GET | /users/{partner_user_id}/body_composition/latest | Get latest measurement for the user. Returns 204 if none. |
Reporting (usage)
| Method | Path | Description |
|---|---|---|
| GET | /usage/daily | Daily usage for a date. Required query: date (YYYY-MM-DD). Returns active users, workouts, tests by type, body composition count. |
| GET | /usage/monthly | Monthly usage. Required query: date (YYYY-MM). Same metric shape as daily. |
Workout response
Completed workout list items have this shape:
{
"data": [
{
"workout_id": "0198f436-d258-7b42-a360-68b1cb923782",
"partner_user_id": "partner-usr-123",
"completed_at": "2025-03-12T09:00:00.000Z",
"updated_at": "2025-03-12T09:15:00.000Z",
"duration_seconds": 1800,
"category": "training"
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}Workout detail
When you receive a workout.completed webhook, fetch the full detail with the workout ID from the payload:
The response includes the same list fields plus a flat exercises array. Each exercise includes exercise_id, group_index, result_index, phase, name, target, duration_seconds, repetitions, and weight (value and unit).
Considerations
- Rate limits — If you receive 429, back off using
Retry-Afterand use exponential backoff for repeated failures. - Idempotency — GET and list endpoints are safe to retry. DELETE is idempotent: a second delete returns 404. The member name endpoints are safe to retry: sending the same names again stores the same values.
- Partner isolation — You only see data for users belonging to your partner account; user IDs are the same values you send to Zing when creating users.
Monthly usage is month-to-date: values cover the UTC month through the returned calculated_until date.
Request examples
Use the API key in the Authorization header. Replace <API KEY> with the key issued for your environment.
List users
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users"Example response:
{
"data": [
{
"partner_user_id": "partner-usr-123",
"first_name": "Jane",
"last_name": "Doe"
},
{
"partner_user_id": "partner-usr-456",
"first_name": null,
"last_name": null
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}Get user summary
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users/partner-usr-123"Example response:
{
"partner_user_id": "partner-usr-123",
"first_name": "Jane",
"last_name": "Doe",
"created_at": "2026-08-01T08:00:00.000Z",
"latest_workout": {
"workout_id": "0198f436-d258-7b42-a360-68b1cb923782",
"partner_user_id": "partner-usr-123",
"completed_at": "2026-08-20T10:15:32.120Z",
"updated_at": "2026-08-20T10:16:00.000Z",
"duration_seconds": 1800,
"category": "training"
},
"latest_tests": {
"fitness": null,
"flexibility": null
},
"latest_body_composition": null,
"streak": {
"date": "2026-08-20",
"streak_length": 5
}
}List workouts
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users/partner-usr-123/workouts"Example response:
{
"data": [
{
"workout_id": "0198f436-d258-7b42-a360-68b1cb923782",
"partner_user_id": "partner-usr-123",
"completed_at": "2026-08-20T10:15:32.120Z",
"updated_at": "2026-08-20T10:16:00.000Z",
"duration_seconds": 1800,
"category": "training"
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}Get workout detail
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/workouts/0198f436-d258-7b42-a360-68b1cb923782"Example response:
{
"workout_id": "0198f436-d258-7b42-a360-68b1cb923782",
"partner_user_id": "partner-usr-123",
"completed_at": "2026-08-20T10:15:32.120Z",
"updated_at": "2026-08-20T10:16:00.000Z",
"duration_seconds": 1800,
"category": "training",
"exercises": [
{
"exercise_id": "3dd31f8b-668d-4da4-a565-9dfcff5f5a13",
"group_index": 0,
"result_index": 0,
"phase": "main",
"name": "Squat",
"target": "lower_body",
"duration_seconds": null,
"repetitions": 12,
"weight": {
"value": 40,
"unit": "kg"
}
}
]
}List tests
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users/partner-usr-123/tests"Example response:
{
"data": [
{
"test_id": "0198f437-0101-70a6-b22f-3984cd49c9e2",
"partner_user_id": "partner-usr-123",
"test_type": "fitness",
"occurred_at": "2026-08-20T09:30:00.000Z",
"updated_at": "2026-08-20T09:31:00.000Z",
"score": 82.4
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}Get test detail
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/tests/0198f437-0101-70a6-b22f-3984cd49c9e2"Example response (fitness test):
{
"test_id": "0198f437-0101-70a6-b22f-3984cd49c9e2",
"test_type": "fitness",
"occurred_at": "2026-08-20T09:30:00.000Z",
"fitness_score": 82.4,
"fitness_level": 4.2,
"fitness_age": 31,
"fitness_score_lower_bound": 78,
"fitness_score_upper_bound": 86,
"sex": "male",
"exercises": [
{
"exercise_type": "push_ups",
"correct_reps": 18,
"total_reps": 20,
"score": 82.1,
"level": 4.2,
"movement_quality": 0.9,
"avg_speed": 1.4,
"max_speed": 2.1,
"time_seconds": 45.3,
"endurance": 0.8
}
]
}List body composition measurements
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users/partner-usr-123/body_composition"Example response:
{
"data": [
{
"measurement_id": "0198f438-0202-71b7-c33f-4095de50d3f3",
"partner_user_id": "partner-usr-123",
"occurred_at": "2026-08-20T08:00:00.000Z",
"total_body_fat_percentage": 19.5,
"weight": 80,
"weight_unit": "kg",
"fat_mass_index": {
"value": 4.7,
"category": "HEALTHY",
"unit": "kg/m2"
}
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}Get latest body composition measurement
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/users/partner-usr-123/body_composition/latest"Example response:
{
"measurement_id": "0198f438-0202-71b7-c33f-4095de50d3f3",
"partner_user_id": "partner-usr-123",
"occurred_at": "2026-08-20T08:00:00.000Z",
"total_body_fat_percentage": 19.5,
"weight": 80,
"weight_unit": "kg",
"fat_mass_index": {
"value": 4.7,
"category": "HEALTHY",
"unit": "kg/m2"
}
}Get daily usage
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/usage/daily?date=2026-08-20"Example response:
{
"date": "2026-08-20",
"active_users": 100,
"workouts_completed": 300,
"tests_completed_by_type": {
"fitness": 15,
"flexibility": 10
},
"body_composition_measurements": 7,
"calculated_at": "2026-08-21T01:00:00.000Z"
}Get monthly usage
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/usage/monthly?date=2026-08"Example response:
{
"month": "2026-08",
"active_users": 100,
"workouts_completed": 300,
"tests_completed_by_type": {
"fitness": 15,
"flexibility": 10
},
"body_composition_measurements": 7,
"calculated_until": "2026-08-20",
"calculated_at": "2026-08-21T02:09:00.000Z"
}List webhook deliveries
curl -sS \
-H "Authorization: Api-Key <API KEY>" \
"https://api.dev-ai.coach/v1/webhooks/deliveries"Example response:
{
"data": [
{
"delivery_id": "0198f439-0303-72c8-d44f-50a6ef61e4f4",
"destination_id": "0198f42f-580a-7856-bf69-d1f31ed2ef44",
"transport_type": "custom_webhook",
"event_id": "0198f435-e1f8-7e65-b8dc-00bc4bd91842",
"event_type": "workout.completed",
"occurred_at": "2026-08-20T10:15:32.120Z",
"partner_user_id": "partner-usr-123",
"status": "delivered",
"http_status": 200,
"attempt_count": 1,
"last_error": null,
"first_attempt_at": "2026-08-20T10:15:32.450Z",
"last_attempt_at": "2026-08-20T10:15:32.450Z",
"next_retry_at": null,
"delivered_at": "2026-08-20T10:15:32.710Z",
"created_at": "2026-08-20T10:15:32.200Z",
"event_timestamp_ns": 1787220932120000000
}
],
"meta": {
"limit": 100,
"next_cursor": null
}
}For receiving change notifications and implementing a webhook consumer, see Webhooks. For exhaustive endpoint details, parameters, and response schemas, see the Reference (opens in new window).