Skip to main content

Error Response Format

All APIs return errors in a JSON:API-style errors array:
{
  "errors": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": 400,
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "The request contains invalid parameters"
    }
  ]
}
FieldDescription
idUnique error instance identifier — useful for support requests
statusHTTP status code
codeMachine-readable error code
titleShort human-readable error category
detailSpecific description of what went wrong
The errors field is always an array — even for single errors. Always parse errors[0] rather than treating the response as a flat object.

HTTP Status Codes

StatusCodeDescription
OK200Request succeeded
Created201Resource created successfully
No Content204Request succeeded with no response body (e.g. revocation, webhook deletion)
Bad Request400Invalid or malformed parameters
Unauthorized401Authentication token is missing or expired
Not Found404The requested resource doesn’t exist
Internal Server Error500An unexpected server error — contact the YoID team

Common Errors

The most common error. Your access token expires after 300 seconds (5 minutes) with no refresh token support.Fix: Request a new token using the token caching pattern. If you see frequent 401s, your token caching isn’t refreshing proactively enough — refresh at least 30 seconds before expiry.
{
  "errors": [
    {
      "id": "...",
      "status": 401,
      "code": "UNAUTHORIZED",
      "title": "Unauthorized",
      "detail": "Access token is missing or expired"
    }
  ]
}
Common in the YOMA ecosystem where youth interact with multiple partners. If Thandi was already onboarded by another partner, POST /users returns 201 Created with an empty tempPassword — not an error code, not a different status. The only indicator is the empty string.What to do: Check tempPassword. If empty, the account already exists — skip onboarding emails and proceed directly to credential issuance.
{
  "email": "[email protected]",
  "tempPassword": ""
}
The request body contains invalid data.
{
  "errors": [
    {
      "id": "...",
      "status": 400,
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "Validation of attributes for credential template tpl_6421a8905c17830c188e2e2f failed"
    }
  ]
}
Attribute validation errors don’t specify which attribute failed. The detail message only references the template ID. To debug: compare your payload keys against the template’s attribute schema. Log the template definition (via GET /templates/credentials/{id}) and diff it against your request.
A template ID, presentation ID, or credential ID is incorrect or has been deleted.Fix: Verify the ID is correct and the resource hasn’t been archived.
{
  "errors": [
    {
      "id": "...",
      "status": 404,
      "code": "NOT_FOUND",
      "title": "Not Found",
      "detail": "Credential template not found"
    }
  ]
}
An unexpected server error. Not caused by your request. Retry after a short delay.Fix: If persistent, contact the YoID team at [email protected] and include the error id.
{
  "errors": [
    {
      "id": "...",
      "status": 500,
      "code": "INTERNAL_SERVER_ERROR",
      "title": "Internal Server Error",
      "detail": "An unexpected error occurred"
    }
  ]
}

Error Handling Pattern

async function yoidApiCall(url, options) {
  const token = await getAccessToken(); // Uses caching pattern

  const response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
  });

  if (response.status === 401) {
    // Token expired — clear cache and retry once
    clearTokenCache();
    const freshToken = await getAccessToken();
    return fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${freshToken}`,
        "Content-Type": "application/json",
      },
    });
  }

  if (!response.ok) {
    const body = await response.json();
    const err = body.errors?.[0];
    throw new Error(
      `YoID API error [${err?.code}]: ${err?.detail} (id: ${err?.id})`
    );
  }

  return response;
}