202 Accepted before
anything reaches the chain, and the outcome arrives seconds later by polling or webhook.
That gap is where integrations go wrong. This page covers the three things that make an
integration correct: idempotency, knowing which states are terminal, and knowing
what is safe to retry.
Idempotency keys
Every money-moving endpoint takes a caller-supplied key. It is the single most important field in the request.
The key is yours to choose and should be derived from something stable in your own
system — an order id, a payout row id, a ticket reference. Never generate it fresh on retry;
that defeats the entire mechanism.
Keys are scoped to your business
Your idempotency keys live in your own namespace.invoice-1001 used by another Rach
partner does not collide with yours, and never blocks you from using that value.
This is a change from earlier behaviour, where keys were unique platform-wide and one
partner could inadvertently reserve a common string like
order-1 for everyone. If you
previously worked around that by prefixing keys, the workaround is harmless but no longer
necessary.What a duplicate returns
CaaS distinguishes “still running” from “already done”:202 duplicate returns the original resource and its current status — not a new one.
That makes the safe retry pattern simple: resend the identical request, and use whatever
comes back.
A 409 means an identical request is being processed right now. Wait briefly and poll the
resource rather than resending immediately.
Settlement states
Only two states are terminal. Everything else means “keep waiting”.SUBMISSION_UNKNOWN
This is the state most integrations get wrong. It means a submission was sent but Rach could not confirm whether the network received it. The operation may be live on-chain, or may not exist at all — and from outside, those look identical. Resending the same idempotency key is always safe, and is the correct move if you are unsure whether your original request was even accepted.Failure returns your money
FAILED is clean. For funding and transfers, the value is returned to your ledger as part
of the same failure — you are never left short, and there is no reconciliation step on your
side. The error_reason field explains what happened.
Polling vs webhooks
Prefer webhooks: Rach pushes the terminal state and you do no work while waiting. Poll when you need a synchronous answer for a user staring at a screen. If you poll:- Back off. These settle in seconds, not milliseconds — every 2–3 seconds is plenty.
- Stop at a terminal state. Polling a
SETTLEDresource forever costs you rate limit for nothing. - Do not treat a slow settlement as a failure. There is no timeout after which an operation
becomes safe to re-send; only
FAILEDmeans it did not happen.
Webhooks and polling agree, but webhooks can arrive before your own
202 handler has
finished writing to your database. Make your webhook handler tolerant of an unknown id
rather than treating it as an error — retry it, or reconcile on the next poll.Withdrawals settle in two stages
An off-ramp has a crypto leg and a cash leg, and they complete at different times.COMPLETED is deliberately strict: it requires durable, operator-attributed evidence that
the local-currency payout actually reached the recipient. A customer asking “where is my
money?” is answered by CRYPTO_RECEIVED — the crypto has moved, the cash is on its way.
Do not tell a customer they have been paid until the withdrawal reaches COMPLETED.
Sandbox does not exercise any of this
Arach_sk_test_ key returns SANDBOX_SIMULATED immediately, without touching a chain.
It validates your request shape, authentication and idempotency handling — and nothing else.
Sandbox will never give you SUBMITTING, SUBMISSION_UNKNOWN, or FAILED. Write and test
that handling deliberately, because sandbox will not force you to discover it.
A correct integration, end to end
1
Derive a stable key
Use your own order or payout id. Store it before you call CaaS, so a crash mid-request
still leaves you able to retry with the same key.
2
Call and record the 202
Store the returned resource id against your order immediately.
3
On any network error, resend the identical request
Same key, same body. You will get either the original resource (
202) or a 409.
Neither is a double-spend.4
Wait for a terminal state
Take
SETTLED/COMPLETED or FAILED from a webhook, or poll until you see one. Never
infer an outcome from elapsed time.5
Act only on the terminal state
Release goods, notify the customer, or return the failure. A non-terminal state is not a
result.

