Error Codes Reference
Every Urblock API error returns a Stripe-style JSON envelope:
{
"error": {
"type": "invalid_request_error",
"code": "missing_field",
"message": "The 'name' field is required.",
"param": "name",
"status": 400
}
}
Error Types
| Type | Description |
|---|---|
invalid_request_error | The request was malformed, missing required fields, or has invalid parameter values. |
authentication_error | Missing, expired, or invalid authentication credentials. |
authorization_error | The API key or token lacks the required scope or permission. |
not_found_error | The requested resource does not exist or is not accessible to this tenant. |
rate_limit_error | The request was rate-limited. Retry after the indicated delay. |
conflict_error | The request conflicts with the current state (e.g., duplicate idempotency key). |
blockchain_error | An on-chain operation failed (reverted, insufficient gas, nonce collision). |
api_error | An internal server error occurred. Contact support if this persists. |
Error Codes by Category
Authentication (authentication_error)
| Code | Status | Description |
|---|---|---|
missing_credentials | 401 | Authorization header with Bearer token or API key is required. |
missing_token | 401 | Authorization header with Bearer token is required. |
invalid_token | 401 | The provided JWT or API key is invalid. |
token_expired | 401 | The JWT has expired. Refresh using /auth/refresh. |
invalid_credentials | 401 | Invalid email or password. |
invalid_refresh_token | 401 | Refresh token is invalid, expired, or has been revoked. |
invalid_api_key | 401 | The API key does not exist or has been revoked. |
session_ip_mismatch | 401 | JWT originated from a different IP (when IP binding is enforced). |
account_locked | 423 | Account temporarily locked due to too many failed login attempts. |
Authorization (authorization_error)
| Code | Status | Description |
|---|---|---|
insufficient_scope | 403 | The API key does not have the required scope for this operation. |
secret_key_required | 403 | This endpoint requires a secret key (sk_), not a publishable key. |
admin_required | 403 | This endpoint requires admin role. |
tenant_mismatch | 403 | The resource belongs to a different tenant. |
Validation (invalid_request_error)
| Code | Status | Description |
|---|---|---|
missing_field | 400 | A required field is missing from the request body. |
invalid_field | 400 | A field value is invalid (wrong type, format, or range). |
invalid_id_format | 400 | The provided ID does not match the expected format (tok_, wal_, etc.). |
invalid_address | 400 | The provided Ethereum address is not a valid checksummed address. |
chain_id_required | 400 | The chain_id query parameter is required for this endpoint. |
invalid_chain_id | 400 | chain_id must be a positive integer. |
invalid_network | 400 | The specified network is not supported or not active. |
invalid_pagination | 400 | Invalid pagination parameters (limit/offset out of range). |
Resource Not Found (not_found_error)
| Code | Status | Description |
|---|---|---|
token_not_found | 404 | Token with the given ID does not exist for this tenant. |
wallet_not_found | 404 | Wallet with the given ID does not exist for this tenant. |
transaction_not_found | 404 | Transaction with the given ID does not exist for this tenant. |
nft_not_found | 404 | NFT with the given ID does not exist for this tenant. |
identity_not_found | 404 | Identity with the given ID does not exist for this tenant. |
governance_not_found | 404 | Governance contract not found for this tenant. |
vesting_not_found | 404 | Vesting schedule not found for this tenant. |
vault_not_found | 404 | Vault not found for this tenant. |
webhook_not_found | 404 | Webhook endpoint not found for this tenant. |
network_not_found | 404 | The specified network does not exist. |
user_not_found | 404 | User not found. |
connect_account_not_found | 404 | Connect smart account not found. |
Conflict (conflict_error)
| Code | Status | Description |
|---|---|---|
email_already_exists | 409 | An account with this email already exists. |
idempotency_conflict | 409 | A request with this idempotency key was already processed with different parameters. |
token_already_deployed | 409 | This token has already been deployed on the specified network. |
duplicate_webhook | 409 | A webhook with this URL already exists for this tenant. |
Rate Limiting (rate_limit_error)
| Code | Status | Description |
|---|---|---|
rate_limited | 429 | Too many requests. Check Retry-After and X-RateLimit-* headers. |
usage_limit_exceeded | 429 | Monthly usage limit exceeded for your plan. Upgrade to continue. |
Blockchain (blockchain_error)
| Code | Status | Description |
|---|---|---|
contract_reverted | 422 | The smart contract call reverted. Check the message for the revert reason. |
insufficient_gas | 422 | Transaction ran out of gas. The gas limit was insufficient. |
nonce_collision | 422 | Nonce has already been used. The transaction may have been submitted twice. |
rpc_error | 502 | The blockchain RPC node returned an error. Retry after a short delay. |
chain_not_supported | 400 | The specified chain ID is not configured. |
deployment_failed | 422 | Contract deployment failed on-chain. |
Internal (api_error)
| Code | Status | Description |
|---|---|---|
internal_error | 500 | An unexpected internal error occurred. |
service_unavailable | 503 | The service is temporarily unavailable. Retry with exponential backoff. |
request_timeout | 408 | The request timed out. |
HTTP Status Code Summary
| Status | Meaning | Retryable? |
|---|---|---|
| 400 | Bad Request — fix the request | No |
| 401 | Unauthorized — check credentials | No |
| 403 | Forbidden — insufficient permissions | No |
| 404 | Not Found — resource doesn't exist | No |
| 408 | Timeout — request took too long | Yes |
| 409 | Conflict — already exists | No |
| 422 | Unprocessable — blockchain/business rule failure | Sometimes |
| 423 | Locked — account locked | No (wait) |
| 429 | Rate Limited | Yes (after delay) |
| 500 | Internal Error | Yes |
| 502 | Bad Gateway (RPC) | Yes |
| 503 | Service Unavailable | Yes |
SDK Error Handling
import { Urblock, UrblockApiError } from "@urblock/sdk";
const client = new Urblock("sk_live_...");
try {
const token = await client.tokens.create({ /* ... */ });
} catch (err) {
if (err instanceof UrblockApiError) {
console.error(`[${err.type}] ${err.code}: ${err.message}`);
console.error(`Status: ${err.status}`);
if (err.param) console.error(`Param: ${err.param}`);
if (err.rateLimit) {
console.error(`Rate limit: ${err.rateLimit.remaining}/${err.rateLimit.limit}`);
}
}
}