Error codes

Every HTTP status a partner request can get, the messages behind it, what causes it, whether to retry, and which errors should pause or disconnect a customer.

Errors use the standard HTTP status and the same envelope as successes, with ok: false and a message.

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Your plan no longer includes API access"
}

The API has no machine-readable error code field. Branch on the HTTP status and, for 401 and 403, on message: it tells a revoked customer key apart from a problem on your side. Keep the X-Request-Id response header so we can trace a failure.

StatusMeaningRetry?
400The request was understood but a parameter is invalid.No
401The customer key or your partner secret is missing or invalid.No
403The key is valid but this access is not allowed.No
404The resource does not exist in the customer’s organization, or the route does not exist.No
405Partners only read: the request used a method other than `GET`.No
429A customer key exceeded 30 requests per minute, or authentication failed too often.After Retry-After
500Something failed on our side.With backoff
503The service is temporarily unable to serve requests.With backoff

Server errors never include stack traces, SQL or internals in message.

Is it the customer or you?

Some errors concern one customer, others your whole platform. Handle them at the right level:

AnswerConcernsAction
401 Invalid API keyOne customerMark them disconnected and stop calling the key: retrying spends your secret's failed-authentication budget.
401 Organization is not activeOne customerStop syncing and delete the key.
403 Your plan no longer includes API accessOne customerPause them and retry once a day.
401 Partner credentials required, 401 Invalid partner credentialsYour platformYour secret is missing, wrong or revoked.
403 Request origin not allowed for this integrationYour platformYou called from an address you did not register.
403 This integration is not availableYour platformYour integration is disabled. Contact Vitruve.
405 Method not allowedYour codeThe request is not a GET. Partners only read.
404 Route not foundYour codeThe path is not one of the partner endpoints.
429 Too many failed authentication attemptsYour platformYour secret, or your address, spent its failed-authentication budget. Stop retrying keys that answer 401.

A platform-level error with a valid customer key usually means every customer is affected: alert your team instead of disconnecting customers.

Handling errors

  1. Check response.ok before reading data.
  2. 4xx other than 429: do not retry the request unchanged. Act on the table above.
  3. 429: wait Retry-After seconds, then retry.
  4. 5xx: retry with exponential backoff and a cap, for example 1 s, 2 s, 4 s, 8 s up to five attempts. Do not move your sync checkpoint.
# curl has a built-in retry for 429, 500 and 503
curl --retry 5 --retry-all-errors \
  "https://api-integrations-next.vitruve.fit/v1/athletes" \
  -H "X-API-Key: CUSTOMER_INTEGRATION_KEY" -H "X-Partner-Secret: YOUR_PARTNER_SECRET"

Status reference

400

Bad request

Do not retry

The request was understood but a parameter is invalid.

Causes

  • A query parameter is out of range, has the wrong type or is not one of the allowed values.
  • A parameter name is misspelled or unknown. Unknown parameters are rejected rather than ignored, so a typo never returns unfiltered data.
  • A date is neither YYYY-MM-DD nor an ISO 8601 datetime.
  • A path id is not a UUID.
  • A cursor was edited or truncated, was served to another organization or for another list, or was issued before 2026-10.

What to do

Read message: it names each offending parameter. Fix the request, do not retry it unchanged.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Invalid query parameters: 'limit': Number must be less than or equal to 100"
}

Other messages

  • Invalid query parameters: 'status': Invalid enum value. Expected 'completed' | 'pending', received 'done'
  • Invalid query parameters: Unrecognized key(s) in object: 'userid'
  • Invalid query parameters: 'from': Invalid date: use YYYY-MM-DD or an ISO 8601 datetime
  • Invalid path parameters: 'id': Invalid uuid
  • Invalid query parameters: 'cursor': Invalid cursor
401

Unauthorized

Do not retry

The customer key or your partner secret is missing or invalid.

Causes

  • The X-API-Key header is absent or misspelled.
  • The key is not a valid key, or it was revoked.
  • The organization that owns the key is no longer active.
  • The request has no X-Partner-Secret, or a secret that is unknown, revoked or issued to another partner. A customer key only works with the secret of the platform it was created for.

What to do

Send the customer’s integration key and your partner secret on every request. If the key itself is invalid, stop using it and ask the customer to create a new one: repeated 401s throttle your address.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Missing X-API-Key header"
}

Other messages

  • Invalid API key
  • Organization is not active
  • Partner credentials required
  • Invalid partner credentials
403

Forbidden

Do not retry

The key is valid but this access is not allowed.

Causes

  • The customer's plan doesn't include export integrations anymore, or their subscription ended. Access follows the plan on every request.
  • The request came from an IP address you did not register with Vitruve.
  • Your platform’s integration is disabled.

What to do

Pause the customer and tell them when their plan is the cause. Otherwise call from a registered address.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Your plan no longer includes API access"
}

Other messages

  • Request origin not allowed for this integration
  • This integration is not available
404

Not found

Do not retry

The resource does not exist in the customer’s organization, or the route does not exist.

Causes

  • The id is well-formed but belongs to another organization, was deleted, or is of another kind (for example a template id sent to /workouts/{id}).
  • The workout is older than the history the customer’s plan includes.
  • The path is wrong, or it is not one of the partner endpoints.

What to do

Check the id with the matching list endpoint and the path against the reference.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Athlete not found"
}

Other messages

  • Workout not found
  • Route not found
405

Method not allowed

Do not retry

Partners only read: the request used a method other than `GET`.

Causes

  • The request is a POST, PATCH, PUT or DELETE. A partner never changes customer data.

What to do

Use GET. The Allow header lists the methods the API accepts.

Headers

  • Allow: `GET, HEAD`.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Method not allowed"
}
429

Too many requests

Retry after waiting

A customer key exceeded 30 requests per minute, or authentication failed too often.

Causes

  • More than 30 requests were sent with the same key in the current one-minute window, across every server. Requests answered 403 count too.
  • Requests with your partner secret, from your registered addresses, failed authentication 600 times in the current minute, across every customer key.
  • An address that is not registered, or that sent no valid secret, failed authentication 30 times in the current minute. IPv6 addresses count by their /64.

What to do

Wait Retry-After seconds, then continue. Page with limit=100 and cache the catalogs to need fewer requests.

Headers

  • Retry-After: Seconds until the window resets.
  • RateLimit-Reset: Same value, present on every response past the key check.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Rate limit of 30 requests per minute exceeded"
}

Other messages

  • Too many failed authentication attempts
500

Internal server error

Retry with backoff

Something failed on our side.

Causes

  • An unexpected error. Nothing in message reveals internals.
  • An analytics query failed while running.

What to do

Retry with backoff. If it persists, narrow the request (a shorter date range for analytics) or contact support with the X-Request-Id header value.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Internal server error"
}
503

Service unavailable

Retry with backoff

The service is temporarily unable to serve requests.

Causes

  • The database or the rate-limit store was unreachable or timed out.
  • A query ran past the 15-second limit.
  • A create sent with an Idempotency-Key could not reach the idempotency store. Nothing was written.

What to do

Retry with exponential backoff. If a query keeps running past the limit, narrow it, for example with a shorter date range.

Example

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Service temporarily unavailable"
}

Other messages

  • Rate limiter unavailable
  • Idempotency store unavailable

Reporting a problem

Write to support@vitruve.fit with the X-Request-Id of the failing request, the endpoint, the time, and the customer's organization id. Never include the customer key or your secret.

On this page