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.
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"
}
| Field | Type | Description |
|---|
type | string | A URI identifying the error type |
title | string | A short, human-readable summary |
status | integer | The HTTP status code |
detail | string | A human-readable explanation specific to this occurrence |
instance | string | The request path that generated the error |
error_code | string | A machine-readable error code in {DOMAIN}-{STATUS}-{SEQUENCE} format |
documentation | string | A URL to documentation for this error code |
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.
| Status | Error Code | Type | Description |
|---|
| 400 | PINT-400-001 | invalid_pint_payload | Malformed PINT payload or missing required fields |
| 400 | PINT-400-002 | invalid_audience | Audience is not a registered third-party identifier |
| 401 | PINT-401-001 | invalid_signature | EIP-712 signature verification failed (ECDSA) |
| 401 | PINT-401-002 | invalid_signature_eip1271 | EIP-1271 verification failed against Safe contract |
| 403 | PINT-403-001 | scope_not_permitted | Requested scopes are not authorised for this wallet or signer |
| 403 | PINT-403-002 | kyc_not_verified | User has not completed KYC verification |
| 409 | PINT-409-001 | nonce_already_used | Nonce has already been consumed for this wallet |
| 409 | PINT-409-002 | pint_revoked | PINT has been revoked; no new tokens can be issued |
| 410 | PINT-410-001 | pint_expired | PINT expiresAt timestamp has passed |
| 424 | PINT-424-001 | eip1271_unavailable | On-chain call to Safe contract failed during agent key verification |
| 429 | PINT-429-001 | rate_limited | API rate limit exceeded |
General API Errors
These errors can be returned by any SIS endpoint.
| Status | Description | When |
|---|
| 401 | Unauthorized | Missing or invalid API key in Authorization: Bearer header |
| 404 | Not Found | The requested resource does not exist |
| 429 | Too Many Requests | Rate limit exceeded — see rate limit headers |
| 500 | Internal Server Error | Unexpected server error — retry with exponential backoff |
Handling Errors
Retryable Errors
Some errors are transient and can be retried:
| Error Code | Retry Strategy |
|---|
PINT-424-001 | Retry with exponential backoff — the on-chain call may have timed out |
PINT-429-001 | Wait for the duration specified in the Retry-After header |
429 (general) | Wait for the duration specified in the Retry-After header |
500 | Retry with exponential backoff (max 3 attempts) |
Non-Retryable Errors
These errors indicate a problem with the request that won’t resolve on retry:
| Error Code | Resolution |
|---|
PINT-400-001 | Check the PINT payload structure against the EIP-712 schema |
PINT-400-002 | Verify the audience identifier matches your registered partner ID |
PINT-401-001 | The PINT signature is invalid — re-sign the PINT |
PINT-401-002 | The agent key is not a valid signer on the user’s Safe contract |
PINT-403-001 | The requested scopes exceed what’s authorised for this wallet |
PINT-403-002 | The user must complete KYC before PINTs can be exchanged |
PINT-409-001 | Increment the nonce and re-sign the PINT — see Nonce Management |
PINT-409-002 | The PINT has been revoked; a new PINT must be created |
PINT-410-001 | The 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()