Skip to main content
All SIS API errors follow the RFC 7807 Problem Details format. This page documents the error structure and the complete list of error codes you may encounter.

Error Format

Every error response is a JSON object with these fields:
{
  "type": "https://docs.sumvin.com/errors/pint_revoked",
  "title": "PINT Revoked",
  "status": 409,
  "detail": "PINT sr:us:pint:abc123 was revoked at 2026-02-13T11:30:00Z. No new tokens can be issued.",
  "instance": "/v0/sis/token/pint",
  "error_code": "PINT-409-002",
  "documentation": "https://docs.sumvin.com/errors/PINT-409-002"
}
FieldTypeDescription
typestringA URI identifying the error type
titlestringA short, human-readable summary
statusintegerThe HTTP status code
detailstringA human-readable explanation specific to this occurrence
instancestringThe request path that generated the error
error_codestringA machine-readable error code in {DOMAIN}-{STATUS}-{SEQUENCE} format
documentationstringA URL to documentation for this error code

Error Code Format

Error codes follow the pattern {DOMAIN}-{STATUS}-{SEQUENCE}:
  • DOMAIN identifies the API surface (e.g., PINT for token exchange endpoints)
  • STATUS is the HTTP status code
  • SEQUENCE is a zero-padded sequence number for disambiguation
For example, PINT-409-001 means the first 409 Conflict error type in the PINT token exchange domain.

Token Exchange Errors

These errors are returned by the token exchange endpoint. POST /v0/sis/token/pint — Exchange a signed PINT for a JWT. See Token Exchange for the flow.
Token exchange is in early access, and the error codes below are the contract it will ship with. Partners wiring in now can harden their error handling against the real launch shape — contact your account manager for sandbox credentials.
StatusError CodeTypeDescription
400PINT-400-001invalid_pint_payloadMalformed PINT payload or missing required fields
400PINT-400-002invalid_audienceAudience is not a registered third-party identifier
401PINT-401-001invalid_signatureEIP-712 signature verification failed (ECDSA)
401PINT-401-002invalid_signature_eip1271EIP-1271 verification failed against Safe contract
403PINT-403-001scope_not_permittedRequested scopes are not authorised for this wallet or signer
403PINT-403-002kyc_not_verifiedUser has not completed KYC verification
409PINT-409-001nonce_already_usedNonce has already been consumed for this wallet
409PINT-409-002pint_revokedPINT has been revoked; no new tokens can be issued
410PINT-410-001pint_expiredPINT expiresAt timestamp has passed
424PINT-424-001eip1271_unavailableOn-chain call to Safe contract failed during agent key verification
429PINT-429-001rate_limitedAPI rate limit exceeded

General API Errors

These errors can be returned by any SIS endpoint.
StatusDescriptionWhen
401UnauthorizedMissing or invalid API key in Authorization: Bearer header
404Not FoundThe requested resource does not exist
429Too Many RequestsRate limit exceeded — see rate limit headers
500Internal Server ErrorUnexpected server error — retry with exponential backoff

Handling Errors

Retryable Errors

Some errors are transient and can be retried:
Error CodeRetry Strategy
PINT-424-001Retry with exponential backoff — the on-chain call may have timed out
PINT-429-001Wait for the duration specified in the Retry-After header
429 (general)Wait for the duration specified in the Retry-After header
500Retry with exponential backoff (max 3 attempts)

Non-Retryable Errors

These errors indicate a problem with the request that won’t resolve on retry:
Error CodeResolution
PINT-400-001Check the PINT payload structure against the EIP-712 schema
PINT-400-002Verify the audience identifier matches your registered partner ID
PINT-401-001The PINT signature is invalid — re-sign the PINT
PINT-401-002The agent key is not a valid signer on the user’s Safe contract
PINT-403-001The requested scopes exceed what’s authorised for this wallet
PINT-403-002The user must complete KYC before PINTs can be exchanged
PINT-409-001Increment the nonce and re-sign the PINT — see Nonce Management
PINT-409-002The PINT has been revoked; a new PINT must be created
PINT-410-001The PINT has expired; create a new PINT with a future expiresAt

TypeScript Example

interface ProblemDetail {
  type: string;
  title: string;
  status: number;
  detail: string;
  instance: string;
  error_code: string;
  documentation: string;
}

async function exchangePint(payload: unknown): Promise<Response> {
  const response = await fetch("https://sis.sumvin.com/v0/sis/token/pint", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.SIS_API_KEY}`,
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const error: ProblemDetail = await response.json();

    switch (error.error_code) {
      case "PINT-409-001":
        // Nonce conflict — increment and retry
        throw new RetryableError("Nonce already used", error);
      case "PINT-429-001":
        // Rate limited — wait and retry
        const retryAfter = response.headers.get("Retry-After");
        throw new RateLimitError(retryAfter, error);
      case "PINT-424-001":
        // On-chain call failed — retry with backoff
        throw new RetryableError("EIP-1271 check failed", error);
      default:
        throw new PintExchangeError(error);
    }
  }

  return response;
}

Python Example

import requests

def exchange_pint(payload: dict, api_key: str) -> dict:
    response = requests.post(
        "https://sis.sumvin.com/v0/sis/token/pint",
        json=payload,
        headers={"Authorization": f"Bearer {api_key}"},
    )

    if not response.ok:
        error = response.json()
        error_code = error.get("error_code", "")

        if error_code == "PINT-409-001":
            raise NonceConflictError(error["detail"])
        elif error_code in ("PINT-429-001",):
            retry_after = response.headers.get("Retry-After", "30")
            raise RateLimitError(error["detail"], int(retry_after))
        elif error_code == "PINT-424-001":
            raise RetryableError(error["detail"])
        else:
            raise PintExchangeError(error["detail"], error_code)

    return response.json()