A valid request URL is required to generate request examples{
"reserved": true
}Confirm a wallet reservation
This is a synchronous API endpoint you must expose, not a webhook.
DimeTrades calls it and blocks on the response, in the same
request/response cycle as order placement — it is not delivered by the
outbox/retry mechanism the wallet.debit/wallet.credit events use, and
DimeTrades never waits on anything from you asynchronously here.
{partnerApiBaseUrl} is your brand’s own configured base URL, not a
fixed DimeTrades host — there’s nothing to “try” against a shared server,
since every partner’s URL is different.
Called before accepting a BUY limit order or a cost-increasing modification, for any customer whose brand has external wallet integration enabled (REQ-01). Market orders never call this — they carry no limit price to size the check against, and DimeTrades no longer estimates one on your behalf (see “Reservation sizing” below).
Per your own integration flow, your backend already reserves funds
atomically against the customer’s balance before it ever calls
DimeTrades’s POST /orders — that atomicity can’t be delegated to a
callback. This endpoint is DimeTrades confirming that reservation
exists, not instructing you to create one.
Authenticating the request
POST {partnerApiBaseUrl}/v1/wallets/{externalCustomerId}/reserve HTTP/1.1
Authorization: Bearer {partnerApiKeyId}
X-DimeTrades-Signature: t=1786384403,v1=6ac323d7d75b7e9f6cbfce6acc19edc657798f1e30dcd00c933cba5a4000a58b
Content-Type: application/json
externalCustomerId is the id you supplied when the customer was
registered through the partner provisioning API — present both in the
URL and the body. X-DimeTrades-Signature uses the same
t=<unix seconds>,v1=<hex HMAC-SHA256> scheme as webhook deliveries,
but signed with your external wallet secret — a separate credential
from your webhook signing secret, issued and rotated independently —
and computed over this request’s own JSON body, the same way a webhook
delivery’s signature covers its body. Full verification steps are in
the Verifying a delivery section of the Partner webhooks guide (same
scheme, different secret). This signature is the actual proof the
call came from DimeTrades — verify it.
Authorization: Bearer {partnerApiKeyId} is also sent, but it is not a
credential and not part of authenticating the request: partnerApiKeyId
is a plain identifier your brand’s admin typed into DimeTrades’s own
settings, not issued, rotated, or cryptographically verified by
DimeTrades, and this field is optional on the brand’s side — a brand
with it unset still gets this header, just with an empty/placeholder
value. Treat it as an optional secondary hint at most, never as
something you need to check, and never as a substitute for verifying
the signature above.
Reservation sizing
amountCents already includes the worst-case fee: it’s the order’s
cost (price × quantity) plus the taker-rate fee, the higher of
the two rates DimeTrades ever charges. DimeTrades debits cost +
fee on fill (see wallet.debit), and the actual fee applied on fill
is always this taker rate or the lower maker rate — never higher. So
converting amountCents straight into a settled debit never
under-covers the fee; no additional buffer is needed on your side.
DimeTrades still has no visibility into your actual reservation and
can’t validate or enforce your sizing from its side — this section
just documents what amountCents itself already accounts for.
Timeout and retries
DimeTrades retries this check up to 3 times before giving up. The
partnerApiTimeoutMs configured for your brand (2000ms by default)
applies per attempt, not to the retry sequence as a whole — each of
the 3 attempts gets its own full timeout window. Between attempts,
DimeTrades waits a short backoff (100ms, then 500ms; no wait after the
final attempt).
Worst case, if every attempt times out, this adds up to roughly 6–7 seconds (3 × 2000ms timeout + 100ms + 500ms backoff), not the ~2.6s the backoff schedule alone might suggest — all of it within the lifetime of your customer’s order-placement request. Keep your actual response time well under your configured per-attempt timeout; if all retries fail, the order is rejected — a partner outage blocks that brand’s BUY flow rather than silently letting orders through unchecked.
Rejection mapping
| DimeTrades response to your user | When |
|---|---|
422 ExternalWalletInsufficientFunds | You responded reserved: false |
502 ExternalWalletUnavailable | Your reservation endpoint didn’t respond (or errored) after 3 attempts |
403 ExternalWalletManaged | Your user called DimeTrades’s own /wallet/deposit or /wallet/withdraw — not applicable while you hold the wallet |
Full context — setup, what happens if POST /orders itself fails or
times out, and how release works — is in the External wallet
integration guide.
A valid request URL is required to generate request examples{
"reserved": true
}Authorizations
HMAC request/delivery signature — not a bearer token or API key. The actual proof a call came from DimeTrades — verify it.
Used on webhook deliveries and on the external-wallet reservation check:
t=<unix seconds>,v1=<hex HMAC-SHA256>, where v1 is
HMAC-SHA256(secret, "{t}.{rawBody}") over the exact raw body sent.
Webhook deliveries are signed with your webhook signing secret; the
reservation check is signed with your separate external wallet secret.
Verify the signature and reject stale timestamps before trusting the
payload — full steps in the Partner webhooks guide's "Verifying a
delivery" section. Neither of these calls carries X-API-Key — that
identifies a platform calling DimeTrades; here DimeTrades is calling
you, with its own identity proven by this signature, not by any
header, alone.
The reservation check also carries Authorization: Bearer {partnerApiKeyId}, but that header is not part of authentication —
partnerApiKeyId is a plain identifier your brand's admin typed into
DimeTrades's settings, not issued or cryptographically verified by
DimeTrades, and it's optional on the brand's side. Treat this signature
as the only thing that actually proves the call is legitimate; see the
reservation check's own "Authenticating the request" section for that
header's details.
Path Parameters
The customer this check is for — the same id you supplied when registering them through the partner provisioning API.
Body
The idempotency key you supplied when calling POST /orders — the correlation key for this check, since it's generated by you and already known to you before this call happens.
The minimum amount, in integer cents, you must already have reserved — the order's cost (price × quantity) plus the worst-case (taker-rate) fee at placement. On a cost-increasing modification it is the order's remaining unfilled quantity × the new price, plus the same worst-case fee, and is only asked when that is larger than the order's current remaining cost. This already covers the maximum fee that order could ever be charged on fill, so no additional buffer is needed on top of it.
The customer this check is for — the same id you supplied when registering them through the partner provisioning API. Also present in the URL path; repeated here so it's directly in the payload you're matching against your own records.
Response
Respond with a boolean — never your customer's actual balance.
true when you're already holding at least amountCents in reserve for this clientOrderId. false rejects the order/modification — DimeTrades never instructs you to reserve; it only asks whether you already have.
