Guides

Errors and retries

Every refusal has the same shape and a stable code. Match on the code, never on the message.

The error body#

400 Bad Request
{
  "error": {
    "code": "invalid_request",
    "message": "Some fields are missing or not valid.",
    "fields": [
      {
        "field": "durationSeconds",
        "code": "out_of_range",
        "message": "durationSeconds must be at least 60."
      },
      {
        "field": "type",
        "code": "required",
        "message": "type is required."
      }
    ]
  },
  "requestId": "ec65f508-d907-4d78-a263-3dfd95794fa3"
}
  • code is stable. Build your handling on it.
  • message is for your logs. It can change at any time.
  • fields lists each field that failed, with its own code and message. It is empty when no single field is at fault.
  • requestId is the same as the X-Request-Id header. Send it to us with any question.

What to retry#

StatusRetry?
429Yes, after the seconds in Retry-After.
503Yes, after a few seconds (or Retry-After when sent), with the same externalId.
5xx, timeoutsYes, with the same externalId. Wait 1, 2, then 4 seconds and so on, up to a few minutes.
409 daily_limit_reachedNot before error.resetsAt. The workout was not stored.
Other 4xxNo. The same request will fail the same way. Fix it first.

Codes any call can get#

CodeMeaningWhat to do
400invalid_requestThe body is not valid JSON, or fields are missing or not valid. fields lists each one.Fix the fields listed. Retrying unchanged will not help.
400unknown_fieldThe body has a field we do not know, often a typo.Remove or rename the field named in fields.
401missing_api_keyThere is no Authorization: Bearer header.Send the key as Authorization: Bearer <key>.
401invalid_api_keyThe key is wrong, revoked, expired, or meant for the other environment.Check that you use the right key for the base URL.
403partner_api_disabledThe partner API is switched off on our side.Contact us. Nothing you send is processed until it is back on.
403https_requiredThe request was sent over plain HTTP.Call the base URL with https://.
403partner_pausedYour access is paused on our side.Contact us. Your keys keep working once access is resumed.
403team_not_startedYour team has not started yet.Wait for the start date, then send again.
403team_endedYour team has ended.Stop sending and contact us about a new campaign.
404not_foundThere is no such path in the partner API.Check the path against this reference.
405method_not_allowedThe path exists but not with this method, such as GET /activities.Use the method shown in this reference.
429rate_limitedMore than 60 requests in 60 seconds, or more than 2 at the same time.Wait for the seconds in Retry-After, then send again.
503service_unavailableWe are unavailable for a moment.Wait a few seconds, or for Retry-After when it is sent, and send the same request again. For a workout, keep the same externalId.

Codes from one call#

These come from one endpoint each. The reference lists them with the call.

CodeMeaning
409already_in_teamThe email belongs to someone in another team.
409team_fullYour team has reached its maximum number of members.
409person_unlinkedThe person's link to your team ended. It is final: they cannot be added again.
404user_not_foundNo person in your team matches the one you named.
409duplicate_external_idA workout with this externalId and different values was sent before.
409daily_limit_reachedThe person reached today's limit. error.resetsAt says when it resets.
409overlapping_activityThe person already has a workout at the same time.
422activity_not_availableYour team does not accept this type.
422started_at_out_of_rangestartedAt is before yesterday, or the workout ends more than 5 minutes from now.
404activity_not_foundYou sent no counted workout with this externalId.