API errors and endpoints
Every error is an RFC 7807 problem document with a stable code. Branch on the code, show detail to people. Examples and the request console are in the API reference.
Error catalog
Authentication
| Code | HTTP | Meaning and what to do |
|---|---|---|
authentication_failed | 401 | The API key, session or wallet signature is missing, invalid, expired or not allowed for this endpoint. The detail says which. Send a valid API key as "Authorization: Bearer sk_..." for store endpoints, or sign in again in the dashboard. Do not retry with the same credentials. |
unsupported_chain | 422 | Sign-in was requested for a chain id that Stablevoy does not support. Switch the wallet to one of the networks listed by GET /v1/networks and request a new challenge. |
Request validation
| Code | HTTP | Meaning and what to do |
|---|---|---|
validation_failed | 400 | The request body, query or path does not match the schema. The issues list names each field and the problem. Fix the fields named in issues. Unknown fields are rejected too, so send only the documented ones. |
bad_request | 400 | The request could not be read, for example malformed JSON. Send a well-formed JSON body with "Content-Type: application/json". |
payload_too_large | 413 | The request body is larger than the API accepts (64 KB). Send a smaller body; no endpoint needs more. |
unsupported_media_type | 415 | The body is not JSON. Send the body as JSON with "Content-Type: application/json". |
invalid_address | 422 | A value is not a valid EVM address (0x followed by 40 hex characters). Send the full address as your wallet shows it. |
Invoices and amounts
| Code | HTTP | Meaning and what to do |
|---|---|---|
invalid_amount | 422 | The amount is not a positive whole number of US cents. Send amountUsdCents as an integer, for example 1999 for $19.99. |
amount_below_minimum | 422 | The amount is below the store minimum or the platform minimum. limitUsdCents is the minimum that applies. Raise the amount to at least limitUsdCents, or lower the store minimum in the dashboard (not below the platform minimum). |
amount_above_store_limit | 422 | The amount is above the maximum set for this store. limitUsdCents is that maximum. Lower the amount, or raise the store maximum in the dashboard (up to the platform cap). |
amount_above_platform_cap | 422 | The amount is above the platform cap per invoice. limitUsdCents is the cap. Split the payment, or ask us for a higher cap through the contact form. |
invalid_external_reference | 422 | The external reference (your order id) is empty or too long. Send a reference of 1 to 200 characters, or leave it out. |
invalid_return_url | 422 | The return URL is not an absolute https URL without credentials, or is too long. Send a full https URL such as https://shop.example/order/123, at most 2048 characters. |
conflict | 409 | The Idempotency-Key was already used with different parameters. Reuse a key only to retry the exact same request; use a new key for a new invoice. |
store_disabled | 422 | The store is disabled and cannot create invoices. Enable the store in the dashboard. |
Stores, API keys and webhooks
| Code | HTTP | Meaning and what to do |
|---|---|---|
invalid_store_name | 422 | The store name is empty or too long. Use 1 to 100 characters. |
store_limit_reached | 422 | The account already has as many stores as it is allowed. Use an existing store, or ask us for more through the contact form. |
no_networks | 422 | A store must accept payments on at least one network. Enable at least one network for the store. |
invalid_limits | 422 | The store invoice limits are not valid: below the platform minimum, above the platform cap, or the minimum is above the maximum. Pick limits inside the platform range shown in the dashboard (GET /v1/limits), minimum not above maximum. |
invalid_website_url | 422 | The store website is not an absolute https URL without credentials, or is too long. Send the shop address as https://..., at most 2048 characters. |
invalid_webhook_url | 422 | The webhook URL is not https, contains credentials, uses an IP address or a local name, or is too long. Use a public https address with a domain name, such as https://shop.example/wp-json/stablevoy/v1/webhook. Deliveries to addresses that resolve to private networks are refused as well. |
webhook_not_configured | 422 | The action needs a webhook URL and the store has none. Set the webhook URL first, then send a test event or rotate the secret. |
invalid_key_name | 422 | The API key name is empty or too long. Use 1 to 60 characters. |
Payout address
| Code | HTTP | Meaning and what to do |
|---|---|---|
payout_address_not_set | 422 | The account has no payout address yet, so payments would have nowhere to go. Set the payout address in the dashboard, then create invoices. |
address_not_checksummed | 422 | The payout address is not in EIP-55 checksummed form (mixed case), so a typo could not be detected. Copy the address exactly as your wallet shows it. |
Networks and tokens
| Code | HTTP | Meaning and what to do |
|---|---|---|
unsupported_network | 422 | The network key is not one Stablevoy supports here. Use a key from GET /v1/networks that is enabled for the store. |
unsupported_token | 422 | The token is not accepted on that network. Use a token listed for the network in GET /v1/networks. |
networks_unavailable | 503 | Every network enabled for the store is degraded right now, so a payment could not be watched safely. Retry in a few minutes. GET /v1/health shows the state of each network. |
Contact form
| Code | HTTP | Meaning and what to do |
|---|---|---|
invalid_contact_topic | 422 | The topic is not one of the offered ones. Choose a topic from the form. |
invalid_contact_name | 422 | The name is empty or longer than 100 characters. Enter a name of 1 to 100 characters. |
invalid_contact_email | 422 | The email address is not valid, so we could not reply. Enter the address you want the reply at. |
invalid_contact_message | 422 | The message is shorter than 20 or longer than 5,000 characters. Write 20 to 5,000 characters. |
human_check_failed | 422 | The Cloudflare Turnstile check did not confirm a person, or its token was already used. Let the check finish on the page and send again. |
human_check_unavailable | 503 | The human check could not be verified right now, so the message was not accepted. Try again in a minute. |
General
| Code | HTTP | Meaning and what to do |
|---|---|---|
not_found | 404 | The resource or endpoint does not exist, or belongs to another account (we never reveal which). Check the id and the URL, and that the API key belongs to the right store. |
rate_limited | 429 | Too many requests from this client in a short time. Wait and retry with backoff. The Retry-After header says how long. |
internal_error | 500 | Something failed on our side. The error was logged and we are alerted. Retry later. For invoice creation, retry with the same Idempotency-Key so no duplicate is made. |
Endpoints
Invoices
Create invoices and read their status and payments. The main thing a shop integration does.
| POST | /v1/invoicesCreate an invoice | API key |
| GET | /v1/invoicesList invoices | API key |
| POST | /v1/stores/{storeId}/invoicesCreate an invoice for a store (dashboard) | Merchant session |
| GET | /v1/stores/{storeId}/invoicesList invoices of a store (dashboard) | Merchant session |
| GET | /v1/invoices/{invoiceId}Get an invoice | API key or Merchant session |
Checkout
Public data behind the hosted payment page.
| GET | /v1/checkout/invoices/{invoiceId}Payment page data | Public |
Stores
Stores with their networks, limits, website and webhook.
| GET | /v1/storesList stores | Merchant session |
| POST | /v1/storesCreate a store | Merchant session |
| GET | /v1/storeThe API key's store | API key |
| GET | /v1/stores/{storeId}Get a store | API key or Merchant session |
| PATCH | /v1/stores/{storeId}Update a store | Merchant session |
API keys
Keys for server-to-server calls, one store each.
| GET | /v1/stores/{storeId}/api-keysList API keys | Merchant session |
| POST | /v1/stores/{storeId}/api-keysCreate an API key | Merchant session |
| DELETE | /v1/stores/{storeId}/api-keys/{keyId}Revoke an API key | Merchant session |
Webhooks
Signing secret, test events, delivery history and redelivery.
| POST | /v1/stores/{storeId}/webhook-secret/rotateRotate the webhook secret | Merchant session |
| POST | /v1/stores/{storeId}/webhook/testSend a test webhook | Merchant session |
| GET | /v1/stores/{storeId}/webhook-eventsList webhook events | Merchant session |
| GET | /v1/stores/{storeId}/webhook-events/{eventId}Get a webhook event | Merchant session |
| POST | /v1/stores/{storeId}/webhook-events/{eventId}/redeliverRedeliver a webhook event | Merchant session |
Account
The signed-in merchant, setup progress and the payout wallet.
| GET | /v1/meCurrent account | Merchant session |
| GET | /v1/me/onboardingSetup progress | Merchant session |
| POST | /v1/me/payout-address/challengeStart a payout wallet change | Merchant session |
| POST | /v1/me/payout-address/confirmConfirm a payout wallet change | Merchant session |
Auth
Sign-In with Ethereum and sessions for the dashboard and apps.
| POST | /v1/auth/siwe/challengeStart sign-in | Public |
| POST | /v1/auth/siwe/verifyFinish sign-in | Public |
| POST | /v1/auth/refreshRefresh the session | Public |
| POST | /v1/auth/logoutSign out | Public |
System
Health, limits, pricing, networks, this document and the contact form.
| GET | /v1/healthService health | Public |
| GET | /v1/limitsPlatform invoice limits | Public |
| GET | /v1/pricingPricing | Public |
| GET | /v1/networksNetworks and tokens | Public |
| GET | /v1/errorsError catalog | Public |
| GET | /v1/openapi.jsonOpenAPI document | Public |
| POST | /v1/contactContact the team | Public |
Use it in other tools
In Postman: Import, then drop both files, or Import, Link and paste the OpenAPI URL. Put your API key into the apiKey variable. Insomnia, Bruno and Swagger UI import the same URL. Every error code is explained in the error catalog.