UnifiWallet Payments

Errors

A code to branch on, a message to act on, and a request id to quote.

Every error carries a code your program can branch on, a message a person can act on, and a request_id to quote if you need to ask us about it.

{
  "error": {
    "type": "invalid_request_error",
    "code": "below_minimum_payment",
    "message": "Order total 1.00 is below this account's minimum of 5.00.",
    "param": "amount",
    "request_id": "req_9f3aKd2mQx7b",
    "doc_url": "https://payment.unifiwallet.com/docs/errors#below_minimum_payment"
  }
}

Branch on code, never on message — messages are written for humans and get clearer over time.

Status codes

StatusMeans
400The request is wrong. Fix it; retrying will not help.
401We could not authenticate you. Usually the signature.
403We know who you are and this is not allowed. Scope, role or step-up.
404No such thing, or it belongs to another account. We do not distinguish.
409The thing exists but not in a state this works on.
422Well-formed and refused on its content.
429Too many. Read Retry-After.
5xxOurs. Retry with the same idempotency key.

Authentication

CodeWhat to do
missing_signatureSend all three signing headers.
timestamp_out_of_rangeYour clock has drifted. Fix NTP.
nonce_reusedGenerate a fresh nonce per request.
invalid_signatureAlmost always the body: hash the exact bytes you send.
insufficient_scopeThe message names what is missing. Create a key that has it.
signature_requiredA bearer token was used where money moves. Sign the request.
panel_onlyCredentials and destinations need a person in the panel.

Creating a payment

CodeWhat to do
no_settlement_destinationRegister and verify a wallet first.
settlement_destination_not_verifiedSign the verification message with that wallet.
destination_in_cooling_periodWait. The response says until when.
below_minimum_paymentUnder your floor. Network fees would cost more than the sale.
domain_not_verifiedYour return URL is on a domain you have not proved you own — or the DNS challenge does not match yet.
live_not_enabledAdd your business details to take live payments.
manual_capture_unavailableHolds are not switched on for this deployment, or no escrow contract is deployed on your settlement chain. Use automatic.
merchant_unavailableCheckout: the merchant account is suspended. Nothing was charged.
escrow_operation_in_flightA capture or void is still confirming. Wait — do not retry, or the buyer could be charged twice.
authorization_expiredThe hold lapsed and the buyer may take the funds back. Ask them to pay again.
capture_failed / void_failedThe transaction could not be submitted. Nothing moved.
invalid_capture_amountMore than is still held. Check amount_capturable.
deposit_address_unavailableCheckout: no deposit address for a native coin. Pay from a wallet.

Idempotency

CodeWhat to do
idempotency_key_requiredEvery POST needs one.
request_in_progressThe first attempt is still running. Wait and retry the same key.
idempotency_key_reuseSame key, different body. Use a new key for a different request.

Refunds and subscriptions

CodeWhat to do
payment_not_finalThe payment is settled but not yet completed. Refund it once it is.
refund_exceeds_settlementMore than arrived. The message says what remains.
transfer_already_usedThat transfer settled another refund. Send a separate one.
allowance_below_cycleThe buyer's cap is under one cycle. Every renewal would decline.
auto_charge_unavailableNo spend permission contract on that chain. Use a payment link.
cycle_in_flightAlready being charged. Do not retry, or the buyer pays twice. A cycle a crash left behind is recovered within the hour.

Compliance

These are refusals, not holds. Nothing has moved and nothing is stranded — the checks run before the buyer signs, because non-custodially that is the only moment we have.

CodeMeans
payer_screening_failedThe paying address did not pass. The buyer can pay from another.
destination_flaggedThe settlement address cannot be used.
screening_unavailableWe could not check. A temporary block, not a decision about you.

When to retry

  • Retry 5xx, 429 and network timeouts — same idempotency key, backing off.
  • Do not retry 4xx. Nothing about sending it again changes the answer.
  • Wait, then retry request_in_progress with the same key.