Errors and refusals
Every answer from the Sotirea API has the same shape. A refusal is:
{ "success": false, "error": { "code": "forbidden", "message": "Your organisation has not paid this address before. Add it to your approved addresses; it can be paid 24 hours after it is added.", "fields": { "rule": "new_destination" } }, "meta": { "request_id": "9f1c2e4a7b3d5e6f8a0b1c2d3e4f5a6b" }}codeis the kind of refusal, with the HTTP status to match:invalid(400),unauthenticated(401),forbidden(403),not_found(404),conflict(409),rate_limited(429),unavailable(503), orinternal(500) for a fault on Sotirea’s side.messageis written for a person, and you may show it to one as it is. It can change, so never match on its words.fields.rule, when present, names exactly what refused the request, so your code can tell refusals apart: every one is listed below. Forinvalidwithout a rule,fieldsinstead names each field that was wrong, with what was wrong with it.meta.request_id, also in theX-Request-Idheader, identifies the request. Quote it when you ask Sotirea about one.
The Go client returns a refusal as an *sotirea.Error with Status, Code, Message, Rule()
and RequestID, and sotirea.IsCode(err, sotirea.CodeConflict) tests for a kind. The TypeScript
client throws a SotireaError with status, code, message, rule and requestId.
Handling them
Section titled “Handling them”- Retry
429and503, afterRetry-Afterseconds when it is given. A payment refused with these was not made, so sending it again with the same Idempotency-Key is safe. - Retry
500, with the same Idempotency-Key for a payment, after a short wait. - Do not retry
400,401,403,404or409unchanged. Something about the request, the key or your organisation’s rules has to change first. The rule says what. - When unsure whether a payment was made, for a timeout or a lost connection, send it again with the same Idempotency-Key: see references and idempotency.
A missing permission
Section titled “A missing permission”A key without the permission an operation needs is answered 403, code forbidden, with
fields.rule set to the permission it lacks, such as payments.request.
Authentication lists which operation needs which.
Someone who manages roles can give the key a role that has it.
Every rule
Section titled “Every rule”400: the request is not valid
code is invalid.
amountThe amount is not a whole number of the asset’s smallest unit, as a string of digits greater than zero.
Send "1500000000000000000" for 1.5 of an asset with 18 decimals.
idempotency_keyThe Idempotency-Key header is missing, or is not 1 to 64 letters, digits, dots, dashes, underscores or colons.
Name every payment with a key, such as your order id.
vault_idNo vault was named to pay from.
Set vault_id.
toThe address to pay is not a valid address.
Check it was copied in full.
chainThe vault is open on more than one network and the payment did not say which.
Set chain_id, such as eip155:8453.
networkThe network given is not one of your organisation’s.
Use an id from GET /v1/networks.
referenceThe reference is not 1 to 128 characters without spaces. Also 409 on a vault: see below.
Use your own id as it is, without spaces.
nameThe vault’s name is empty or too long. Also 409: see below.
Use at most 80 characters.
insufficient_balanceThe vault does not have that much free to send, or has never held the asset. The message says how much is free, reserved and held.
Send less, or wait for incoming money to become final.
insufficient_gasThe gas pool on that network cannot pay the network fee. The payment is failed and its money released.
Top up the pool, then send with a new Idempotency-Key.
destinationA sweep’s destination is not one of your vaults on that network, or is a vault it sweeps from.
Choose another vault.
assetA sweep’s asset is not native or a token’s contract address.
Use native or the token’s contract.
min_amountA sweep’s minimum is missing or nothing: a vault must hold more than nothing to be swept.
Set it as a string of the asset’s smallest units.
fee_ceilingA sweep has no fee ceiling: the most one sweep may cost in network fees.
Price one with GET /v1/sweeps/fee.
sourcesA sweep’s source vaults are not your vaults on that network, or include the vault it sweeps into.
Name your own vaults, or leave sources out for every vault opened with a reference.
urlA webhook’s address is not a full https address.
Use an https address your server answers on, reachable from the internet.
eventsA webhook names an event Sotirea does not send, or none.
Choose from GET /v1/webhook-events.
descriptionA webhook’s description is too long.
Shorten it.
graceA new webhook secret’s overlap is not now, 1h, 24h or 7d.
Choose one of those.
401: no valid key
code is unauthenticated.
api_key_missingThe request carried no API key.
Send Authorization: Bearer with your key.
api_keyThe key is not valid: mistyped, cut short, or revoked.
Check it was copied in full, or create a new one.
api_key_expiredThe key has passed the date it was made to work until.
Create a new key.
403: not allowed
code is forbidden.
api_key_addressThe key is limited to certain addresses, and this request came from another.
Call from an address on the key’s list, or add this one in the console.
environmentThe network belongs to the other environment: a Test organisation on a Live network, or the other way round. Also 503 when Live is not open yet.
Use the network’s counterpart, or the other key.
sanctioned_addressA sanctions list names the address. Nothing was sent.
Do not pay it. See sanctions screening.
blocked_destinationSotirea’s blocked list names the address. Nothing was sent.
Do not pay it.
lookalike_destinationThe address starts and ends like one you have paid or approved, and is not it: a common trick.
Check the address with the person who gave it to you.
allowlistYour rules allow only approved addresses, and this is not one.
Add it to your approved addresses, if it should be paid.
new_destinationYour organisation has never paid this address, and your rules make new addresses wait. Live starts with a 24-hour wait.
Add it to your approved addresses, then pay it once its wait is over.
destination_waitingThe address was approved recently and its wait is not over. The message says when it can be paid.
Send it then.
max_per_transferMore than one payment may move under your rules.
Send less, or split it, within your rules.
max_per_windowThe payment would take the period’s total past your rules’ limit.
Wait for the period to move on.
four_eyesA sweep a key proposes needs a person to confirm it, and your organisation has nobody else who could.
Give someone the permission to manage sweeps.
404: not found
code is not_found.
idNo vault or payment of yours has that id.
Check the id, and that the key is for the right organisation.
endpointNo webhook of yours has that id.
List them with GET /v1/webhooks.
deliveryThat delivery is not this webhook’s. Also 409: a delivery can be sent again only once it has given up.
Take the id from GET /v1/webhooks/{id}.
409: conflicts with what is there
code is conflict.
replaceThe payment cannot be sped up or cancelled: it is not stuck, or a cancel is already on its way. Also 503 when the network refuses the replacement; try again in a minute.
Follow the payment instead.
proposalA change to the sweep for this network and asset is already waiting, or the proposal was already decided.
Have the waiting one confirmed, declined or withdrawn first.
ruleOnly an active sweep can be stopped, or another sweep for the network and asset became active first.
List sweeps with GET /v1/sweeps.
endpointsYour organisation already has the most webhooks it can, 10.
Remove one, or send more events to one.
webhook_offThe webhook is turned off, so nothing can be sent to it again.
Turn it back on first.
429: too many requests
code is rate_limited.
rate_limitToo many requests from this key or address. Retry-After says how many seconds to wait.
Wait, then send again. Spread polling out, or use webhooks.
503: not available right now
code is unavailable.
chain_not_readySotirea cannot yet create vaults on that network, so a vault’s first payment there cannot go. Nothing was sent.
Try again later, or ask Sotirea’s support.
webhooks_offWebhooks are not set up on this deployment yet.
Follow payments with GET /v1/payments/{id} meanwhile.