1. Core Concepts
Kobaru
  • Kobaru.io Gateway API
    • Introduction
      • What is Kobaru?
      • Quick start
      • How x402 works
    • Integration
      • Standard x402 SDK
      • Advanced SDK
      • Transparent proxy integration
      • Direct API integration
    • Core Concepts
      • Available Chains and Assets
      • Payment schemes
      • Security
      • Usage models
      • Access tiers
      • Idempotency
    • Guides
      • Pricing your API
      • Going to Production
      • Testing with devnet
      • Bazaar discovery
      • BITE encryption for SKALE
    • API Reference
      • Error Handling
      • Get Supported Payment Kinds
      • Verify Payment Authorization
      • Settle Payment
    • Discovery
      • List Discovery Resources
    • Transparent Proxy
      • Overview - Transparent Proxy
      • Upstream authentication
      • Troubleshooting
      • Constraints and security
      • Capabilities and routes
      • Domain verification
      • Service setup
    • Effortless MCP
      • Kobaru MCP Overview
      • Wallets
      • CLI reference
      • Setup Template
    • Schemas
      • SupportedResponse
      • ErrorResponse
      • UnauthorizedResponse
      • RateLimitResponse
      • VerifySuccessResponse
      • VerifyErrorResponse
      • SettleSuccessResponse
      • SettleErrorResponse
      • DiscoveryResourceItem
      • ListDiscoveryResourcesResponse
  1. Core Concepts

Idempotency

You can always safely retry a Kobaru payment call. A retry never charges the payer twice, and you never lose the answer to a payment that went through. You don't generate, send or store idempotency keys: Kobaru derives the payment's identity from the payment itself.
This page explains how that works, what each response means, what Kobaru guarantees, where the limits are, and how the approach compares to the alternatives you will meet.

Key points#

A payment is identified by its on-chain authorization, not by a key you invent.
Protection doesn't expire. The same payment gets the same answer next week as it does in the next second.
Concurrent requests for one payment are serialized. Only one of them can reach the chain.
A settlement whose outcome is unknown is reported as settlement_pending, never as a failure. In the console's authorizations list it shows as UNKNOWN, with its transaction hash, and the dashboard leaves it out of the success rate and the failure reasons until it resolves.

How Kobaru identifies a payment#

Kobaru identifies a payment by what the chain itself accepts only once:
NetworkPayment identity
EVM (EIP-3009)Network, scheme, token, authorization.from and authorization.nonce
SolanaNetwork, scheme and the transaction message (signatures excluded)
The identity is always scoped to your merchant account, so two merchants never share a payment record. The network in the payment requirements decides which fields count: an EVM payment is read only from signature and authorization, a Solana payment only from transaction, and fields meant for the other network are ignored. Payloads whose fields can't be decoded fall back to the exact payload together with the payment requirements.
Because the identity comes from the authorization and not from the signature string:
Re-encoded signatures map to the same payment. An ECDSA signature can be written in more than one valid form, and Solana signatures can be re-serialized. None of that creates a second payment.
The identity is permanent. It lasts as long as the payment record, not for a 24-hour window. A payment presented again after a day, or a month, still meets its stored outcome.
There is nothing to lose. A client that crashed and retries with the same payload hits the same record, even if it kept no state.

What each response means#

SDK mode (/verify and /settle)#

ResponseHTTPRetry-AfterWhat it meansWhat to do
Fresh result (no replayed)200 or 400noneThe first evaluation of this paymentAct on it. On a /settle success, record the fulfilment against the payment
replayed: true and header Idempotent-Replayed: true200 or 400noneThe stored result of an earlier request for the same payment. A replayed /settle success carries the original transaction: no new transfer happenedTreat it as confirming an existing charge. Look the payment up in your own order or fulfilment record and don't deliver twice
duplicate_request4095Another request for the same payment is running right nowRetry the same payload after Retry-After
settlement_pending40930A transaction was (or may have been) broadcast and its outcome isn't known yet. On /verify, a settle of this payment is unresolved. transaction is included when knownCheck transaction on chain. Retry the same payload after Retry-After: a /settle retry checks the chain first. Don't deliver, and don't ask for a new payment meanwhile
idempotency_conflict409noneThe payment already has a binding outcome with a different payTo or amountDon't retry automatically. Resend with the original requirements, or have the payer sign a new authorization
payment_already_settled400none/verify of a payment that is already settled (same signature). Includes transaction, and payer when knownTreat the payment as used and check your fulfilment record
payment_settlement_failed400none/verify of a payment whose settlement failed for good: reverted on chain, or expired without landingDon't deliver. The payer needs a new payment
payment_proof_mismatch400noneThe payment is known, but this signature isn't the one it was settled, verified or first broadcast with. Nothing is recordedTreat the request as invalid. Only the original payload gets the stored answer
claim_unavailable5035Kobaru couldn't claim the payment (temporary database problem). Nothing was recorded or broadcastRetry the same payload after Retry-After
rpc_unavailable, bite_unavailable5035, 10The network's RPC (EVM) or the SKALE BITE encryption service couldn't be reached. Nothing was broadcast; the attempt isn't stored as a resultRetry the same payload after Retry-After
A replayed /settle success looks like this:
{
  "success": true,
  "transaction": "0x5b0e8f1c7a3d4e2b9f6a1c8d0e7b3a5f2c4d6e8a0b1c3d5e7f9a2b4c6d8e0f1a",
  "network": "eip155:8453",
  "payer": "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23",
  "replayed": true
}
A stored final failure also comes back with replayed: true, so always read success or isValid first.

Proxy mode#

When Kobaru sits in front of your API, the agent calling it sees these outcomes:
reasonHTTPRetry-AfterWhat it means
duplicate_request, claim_unavailable5035The payment is busy or couldn't be claimed. Answered before your API is called
rpc_unavailable, bite_unavailable5035, 10The network's RPC or the SKALE BITE encryption service is down. Nothing was broadcast; if your API already answered, the use is refunded
settlement_pending50330The settlement outcome isn't known yet (transaction when known). The use isn't refunded, and it isn't charged again later
payment_settlement_failed402noneThe settlement failed for good. The agent must pay again
payment_expired402noneThe payment is settled, but its quota has lapsed or was never created
payment_already_used402noneA single-use payment was already used
payment_bound_to_other_route402noneThe payment's quota belongs to the first route that used it
A 503 from the proxy is never a payment failure. The agent retries after Retry-After and never pays again for it.
A retry after a settlement_pending 503 is resolved before your API is called again. The proxy settles first: if the payment settled, the request is served without consuming a new use; if the outcome is still unknown, the agent gets another 503 and your API isn't called; if the settlement failed for good, the agent gets 402 payment_settlement_failed.

Guarantees#

Kobaru backs each of these promises in code:
One on-chain charge per authorization. Only the request that holds the claim can broadcast. The chain enforces it too: an EIP-3009 authorization is single-use, and Solana rejects a signed transaction it has already processed, so a retry of a payment that already landed can't pay twice.
The same answer for the same payment. Once a payment has a binding outcome, every later request for it with the same signature gets that outcome. Answers served from history write nothing, so retries can't grow the record.
Concurrent requests are serialized. Kobaru claims a payment inside a database transaction that locks its record. A concurrent request waits for the lock, sees the claim and gets duplicate_request. The chain is only called after the claim is committed.
An unknown outcome is never reported as a failure. A confirmation timeout, a transport error while sending, or an authorization found already used on chain (for example after a front-run) all become settlement_pending. A retry records a failure only when the chain proves a revert or an expiry.
A stored success is only returned to the same proof. Anyone who has seen a payment knows its from and nonce, so Kobaru also stores a digest of the signature. A copied from+nonce with a forged signature never gets a stored success: /settle rejects the bad signature before anything is recorded, a settled payment answers payment_proof_mismatch, and /verify of an unsettled payment checks the new signature from scratch.
Rejected attempts don't lock the payment. A bad signature, or a failure before anything was broadcast (such as insufficient_funds or a failed simulation), isn't replayed. A corrected request is evaluated again. The exception is an expiry on the first attempt: that payment can never execute, so its failure is final.
Proxy quota is bound to the payment and its first route. Every encoding of one payment shares one quota, the first route (service and route) that uses it owns that quota, and a payment that is already settled can never create new quota.

Limits#

Kobaru is honest about what isn't covered yet:
No background reconciliation job yet. An uncertain settlement is resolved on the next retry, when Kobaru checks the chain. Until someone retries, it stays settlement_pending. One rare EVM case stays pending even on retry: an authorization used by a transaction Kobaru doesn't know (for example after a transport error during the send). That case waits for the reconciliation job; contact support with the transaction and time if it persists.
Uses served during an in-flight settle (proxy mode). While the first settlement of a payment is still running, concurrent requests with the same payment are served with a PAYMENT-RESPONSE marked pending: true instead of waiting. They never broadcast, so there is no double charge. If that settlement then fails for good, those uses were served unpaid. The exposure is bounded: at most limit − 1 extra uses for pay-per-request, or about 65 seconds of a pay-per-time window.
The x402 payment-identifier extension isn't supported yet. A client that loses a response and signs a new authorization creates a new payment. Retrying with the original payload is always safe; signing again is not.
Payments settled before the September 2026 idempotency release aren't found by the new records. Sending one again while its authorization is still valid answers settlement_pending (the chain says it was already used) until Kobaru reconciles it; it was paid once and is never charged twice. Don't retry it; contact support with the original transaction if you need it confirmed.

How Kobaru compares#

As of September 2026, based on each provider's public documentation. "Not documented" means the source doesn't say.
KobaruCoinbase CDP x402 /settlex402 payment-identifierClient-supplied keys (Stripe Idempotency-Key, CDP X-Idempotency-Key)
Who supplies the keyNobody: derived from the on-chain authorizationNo idempotency header documented for /settleThe client: an id of 16–128 characters (letters, digits, -, _); optional or required, per serverThe client. Stripe: up to 255 characters, V4 UUID suggested. CDP: must be a UUID v4
How long protection lastsNo expiryNot documentedA server-chosen cache TTL (examples range from 5 minutes to 24 hours; one sample uses 1 hour). After it, the same id is processed againStripe: keys can be pruned once at least 24 hours old, and a reused key is then a new request. CDP: unique within a rolling 24 hours
Retry of a settled paymentStored success, same transaction, replayed: true and Idempotent-Replayed: trueNot documented. The error list includes duplicate_settlement and invalid_exact_evm_nonce_already_used without saying when they applyCached response, payment skipped (within the TTL)The stored status and body. Stripe replays even a 500
Same identity, different terms409 idempotency_conflict once the payment is boundNot documented409 Conflict on a different fingerprint (scheme, network, asset, amount, payTo, and optionally path, method or order id)Error on different parameters (Stripe) or a different payload (CDP)
In-flight duplicate409 duplicate_request with Retry-After; a database lock lets only one request broadcastNot documentedNot documentedStripe: treated as a conflict and safe to retry. CDP: an error saying the key is still processing
Unknown on-chain outcome409 settlement_pending with transaction when known; your retry checks the chain and returns the real outcome when it cansettlement_pending with the tx hash, "for the caller to reconcile before retrying"Not documentedNot chain-aware: the first response is replayed as-is
Signature re-encoding and forged proofsRe-encodings map to the same payment; a stored success is only returned to the same signatureNot documentedNot documentedNot addressed: the key the client sends, not the payload, identifies the request
Proxy quota bindingQuota bound to the payment and to the first route that uses itN/AN/AN/A
What sets Kobaru apart, against this table:
It's the only one of these that ties idempotency to the on-chain authorization itself, so there is no key to generate, store or lose.
Its protection doesn't expire. The key-based options expire after 24 hours or a server-chosen TTL, and CDP doesn't document a window for /settle.
Both Kobaru and CDP report an unknown outcome as settlement_pending with the hash instead of a failure. Kobaru also resolves it against the chain on your retry; CDP's documentation leaves reconciliation to the caller.
It's the only one that documents binding a stored success to the original proof, so a copied from+nonce with a forged signature never receives a stored success.
Where an alternative covers something Kobaru doesn't: payment-identifier can recognize a client that signs a fresh authorization after losing a response. Kobaru plans to support it.

Integration checklist#

Keep your own order or fulfilment record, keyed by the payment: token, from and nonce on EVM, or the transaction returned by /settle (it's the same on every replay).
Deliver once per record. On replayed: true, look the payment up before delivering.
Honour Retry-After on duplicate_request, settlement_pending, claim_unavailable, rpc_unavailable and bite_unavailable, and retry with the same payload.
Treat 409 and 503 as "not final yet", not as failures.
Don't auto-retry idempotency_conflict or payment_proof_mismatch.
On settlement_pending, check transaction on chain. Don't deliver and don't ask the payer to pay again until you know the outcome.
Proxy mode: make sure your agents treat a 503 as "retry later", never as "pay again".

Related documentation#

Security - Replay protection and TOCTOU prevention
POST /verify - Idempotency behaviour on /verify
POST /settle - Idempotency behaviour and settlement pending
Error codes - Every reason with status, Retry-After and advice
Usage models - How proxy quota is consumed and refunded
Modified at 2026-10-21 21:04:55
Previous
Access tiers
Next
Pricing your API
Built with