Skip to content
YutaiDocs
GET /v1/statusGet API key

Resources / Errors and limits

Errors and limits

The refusals every keyed call shares, in the interface description's own words: one row per status code, the calls that answer it, and the count each scope allows per key in one fixed minute. The one error shape a refusal carries stands on the API reference.

View as .md

The status codes

Every refusal the document's calls answer, one row per status code. Each sentence is the document's own, and the calls named under it answer with exactly that sentence.

Every refusal status the distributor API's interface description declares
StatusWhat it answers
400

The reference is missing or is not an opaque id.

Answered byGET /v1/connect/outcomes.

401
403

The key does not carry the scope, or the wallets name no chain the distributor serves. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byGET /v1/eligibility.

The key does not carry the scope. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byGET /v1/availability,GET /v1/registry/companies,GET /v1/registry/instruments,GET /v1/claims/{id},POST /v1/claims/{id}/link,GET /v1/fulfilments,GET /v1/connect/sessions/{id},GET /v1/connect/outcomes,DELETE /v1/connect/links/{external_ref}.

The key does not carry the scope, or the challenge itself was refused: the venue is paused or not a self-custody venue, the benefit is not a claimable offer, or a wallet sits on a chain the venue does not serve. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byPOST /v1/claims/challenge.

The key does not carry the scope, or the claim itself was refused: the challenge was never verified, was issued for another distributor or another benefit, or the holder's own world refused the claim, and the attested subject's statement the same - unsigned or unverifiable, expired, naming an instrument the distributor does not list or the registry no longer keeps active, naming another tenant, or for a benefit the account's holder already claimed once. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byPOST /v1/claims.

The key does not carry the scope, or the fulfilment was already confirmed: the confirm that stands is the one that landed first. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byPOST /v1/fulfilments/{id}/confirm.

The key does not carry the scope, or the return address is not one the distributor's profile allows. The call is also refused with 403, nothing read, when the distributor is paused, suspended or closed, when the key is paused, or when the key presents from an origin it does not allow.

Answered byPOST /v1/connect/sessions.

404

No claim answers this id under this distributor's key: an unknown id, or one another distributor's key recorded. The answer is the same for both, so no claim id can be probed.

Answered byGET /v1/claims/{id},POST /v1/claims/{id}/link.

No fulfilment answers this id under this distributor's key: an unknown id, or one another distributor's key recorded. The answer is the same for both, so no fulfilment id can be probed.

Answered byPOST /v1/fulfilments/{id}/confirm.

No Connect session answers this id under this distributor's key: an unknown id, a malformed id, or one another distributor's key created. The answer is the same for both, so no session id can be probed.

Answered byGET /v1/connect/sessions/{id}.

No standing link answers this reference under this distributor's key. Nothing was read.

Answered byDELETE /v1/connect/links/{external_ref}.

409

The claim the id names stands rejected or taken back, so it carries no redemption link to reissue.

Answered byPOST /v1/claims/{id}/link.

429

The key made too many calls this minute, or the platform has used today's live wallet reads; the Retry-After header names the seconds until the next window opens, or until the reads open again. Nothing was read.

Answered byGET /v1/eligibility.

500

The redemption link was not reissued, so the previous link still stands. Nothing was changed.

Answered byPOST /v1/claims/{id}/link.

The challenge was not issued, so nothing is ready to sign. Nothing was changed.

Answered byPOST /v1/claims/challenge.

The claim was not recorded, so no benefit was claimed. Nothing was changed.

Answered byPOST /v1/claims.

The fulfilment was not confirmed, so the credit still waits. Nothing was changed.

Answered byPOST /v1/fulfilments/{id}/confirm.

The Connect session was not created, so no hosted page was started. Nothing was changed.

Answered byPOST /v1/connect/sessions.

The person's link was not ended, so the person stays linked. Nothing was changed.

Answered byDELETE /v1/connect/links/{external_ref}.

503

The data source this read needs is not live yet, or the owners' blockchain switch does not allow the read, so the read is refused. Nothing was read.

Answered byGET /v1/eligibility.

The data source this read needs is not live yet, so the read is refused. Nothing was read.

Answered byGET /v1/availability,GET /v1/registry/companies,GET /v1/registry/instruments.

The limits

Once the key a call presents stands, the call is counted, per key and per scope, in one fixed window of 60 seconds that starts on the minute. A call past the scope's own count is refused without being counted: the refusal answers the one error shape the Errors section carries, and its Retry-After header names the seconds to wait until the next window opens.

eligibility.read
At most 120 calls per key and scope in the window.
availability.read
At most 600 calls per key and scope in the window.
claims.write
At most 60 calls per key and scope in the window.
connect.write
At most 60 calls per key and scope in the window.
connect.read
At most 60 calls per key and scope in the window.
claims.read
At most 60 calls per key and scope in the window.
How long an answer stands
Every other read's answer is private to the distributor that asked and may stand for 60 seconds. The GET /v1/connect/sessions/{id} and GET /v1/connect/outcomes reads are never held.

A call past its scope's count answers the 429 row above: nothing was read, and the Retry-After header names when the next window opens.

When a call is limited

A limited call answers the status line, the Retry-After header and the error body below, with the interface description's own sentence for the refusal most calls share.

A refused limit or cursor answers in that same error shape. The Pagination page says what each one carries and how to walk past one page.

A limited answer
HTTP/1.1 429 Too Many Requests
Retry-After: 23

{
  "message": "The key made too many calls this minute. The Retry-After header names the seconds until the next window opens. Nothing was read.",
  "code": "rate_limited",
  "requestId": "req_01K4V9QG000000000000000001"
}

The loop reads that header, waits the seconds it names and tries the same call again at most three times. The wait is capped at one hour, the longest wait the SDK itself holds, so a header naming a day never freezes the caller for a day.

Wait and try again
async function callWithWait(url, options) {
  for (let attempt = 0; attempt < 3; attempt += 1) {
    const response = await fetch(url, options);
    if (response.status !== 429) return response;
    const seconds = Math.min(3600, Math.max(1, Number(response.headers.get("Retry-After")) || 1));
    if (attempt < 2) {
      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
    }
  }
  throw new Error("the call was limited after three tries");
}

When an element refuses

An element that refuses, whether a value it cannot draw or a read it cannot make, keeps its last good paint and throws nothing into your page: the element sets data-yutai-state="refused" on itself and fires one yutai-error event that bubbles and is composed, so a listener on your document hears it from inside the element's shadow root. The attribute comes off the next time the element draws, except a refusal a Connect press told, which stands until the next press.

detail.tag
The tag of the element that refused, like yutai-tier-badge, so the page can tell which one it was.
detail.sentence
The plain sentence saying what to fix, written for the page's developer.
Listen for a refusal
document.addEventListener("yutai-error", (event) => {
  console.warn(event.detail.tag, event.detail.sentence);
});

// The last good paint stays, and the attribute stands until the element draws again.
const refused = document.querySelectorAll('[data-yutai-state="refused"]');

Each element page lists the sentences its own element tells: the credential card, the benefits list, the benefits module and the tier badge. A page built with React hears the same refusals through the wrapper's onError prop.

The status word

The status call needs no key. It answers one word for how the service stands, then one row for every data domain, each carrying the sentence for its SIMULATED, SANDBOX or LIVE mode, so no public read stands without its flag.

ok
The service answers: every check behind the status read passed.
degraded
The service answers only partly: part of it is unavailable.
down
A check failed, so the answer names no data domains at all; the word stands for up to thirty seconds, so a service that has recovered can answer down briefly.
SIMULATED
This is simulated sample data for trying Yutai, not real records.
SANDBOX
This data comes from a provider's test system, not real records.
LIVE
This data is live, read from real records.

Check the API status to read the answer itself, with the fields it carries.