Reject a 0Pools quote
POST /pools/quotes/{quoteId}/reject - Decline a quote so it cannot be transacted.
0Pools API pages are for approved headless partners. They cover the partner-visible quote, transact, status, trade, and balance lifecycle only.
Endpoint
| Field | Value |
|---|---|
| Method | POST |
| Path | /pools/quotes/{quoteId}/reject |
| Area | Quotes |
| Operation id | rejectQuote |
| Auth boundary | Secret key from your server. |
Use it for
Explicitly decline a locked quote so it can never be transacted. Call this when the user dismisses the offer, lets your accept window lapse, or chooses a different route, and you want the quote put into a terminal rejected state rather than left to expire on its own.
Rejecting is money-free: nothing is reserved, debited, or delivered. It is a small piece of hygiene that makes reconciliation unambiguous, because the quote ends in a clear partner-visible state instead of an open lock that later silently expires.
Rejected is its own terminal state
A rejected quote is distinct from a consumed (transacted) quote. Reject sets the quote to rejected; transact moves it to a
consumed trade. When a quote's derived status is read back, rejected takes precedence over consumed, expired, and active.
Production rules
- Keep secret keys on your server.
- Reject from your backend only; never expose this call or the quote id to the browser.
- Reject is not idempotent: a second reject of an already consumed, rejected, or expired quote returns
409 conflict. Read state back before retrying. - Branch on machine-readable status, error code, object id, and request id.
- Treat examples and placeholder ids as fake data only.
Request
No request body is required. Authenticate with your secret key and address the quote by its id in the path. No Idempotency-Key is used: reject is a compare-and-swap that succeeds exactly once, so a repeat against a quote that is already consumed, rejected, or expired returns 409 conflict rather than re-confirming the prior state.
curl -X POST https://pools-api.0bit.app/v1/pools/quotes/quote_test_123/reject \
-H "Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"| Parameter | In | Required | Description |
|---|---|---|---|
quoteId | path | yes | The quote id returned by POST /pools/{id}/quote (firm only). |
Indicative quotes are price-only and are never persisted, so they have no quoteId and cannot be rejected. Only firm quotes can
be rejected.
Response
A successful call returns the full partner-visible quote object, identical to GET /pools/quotes/{quoteId}, with status now rejected and rejectedAt set to the time of the reject. Money and rate values are decimal strings; *Bps fields are integers. Store the status, the object id, and the X-Request-Id response header alongside your own reference for reconciliation.
{
"quoteId": "quote_test_123",
"poolId": "pool_test_123",
"pair": "EUR-USDT",
"side": "on_ramp",
"cryptoNetwork": "tron",
"fiatAmount": "100.00",
"cryptoAmount": "108.20",
"rate": "1.0820",
"spreadBps": 25,
"feeBps": 10,
"status": "rejected",
"expiresAt": "2026-06-28T12:00:15Z",
"consumedAt": null,
"rejectedAt": "2026-06-28T12:00:05Z",
"createdAt": "2026-06-28T12:00:00Z"
}Conflict on repeat
Reject is a one-shot compare-and-swap, not an idempotent operation. The first call sets the quote to rejected (and stamps rejectedAt); a second reject of a quote that is already consumed, rejected, or expired returns 409 conflict. Treat the conflict as authoritative: the quote already reached a terminal state, so refresh it with GET /pools/quotes/{quoteId} instead of retrying blindly.
Because rejected is terminal, a quote in this state cannot be transacted. A POST /pools/{id}/transact against a rejected quote also returns 409 conflict; refresh state instead of retrying blindly.
Status precedence
When you read a quote back with GET /pools/quotes/{quoteId}, its status is derived. If more than one terminal condition could apply, the resolved status follows this order:
| Precedence | Status | Meaning |
|---|---|---|
| 1 (highest) | rejected | The quote was explicitly declined. |
| 2 | consumed | The quote was transacted into a trade. |
| 3 | expired | The quote's short TTL elapsed without being used. |
| 4 (lowest) | active | The quote is still live and within its TTL. |
Errors
All errors use the unified envelope { type, code, message, request_id, doc_url, statusCode }, and every response carries an X-Request-Id header. Branch on type and code.
| Status | type | When it happens |
|---|---|---|
401 | unauthorized | Missing or invalid secret key. |
403 | forbidden | Wrong key mode. This route is secret-key only and runs no entitlement check, so the only code here is key_mode_mismatch (for example, a publishable key was used). The pool-access denial codes do not apply. |
404 | not_found | The quote id is unknown, or belongs to another partner. Cross-tenant access returns 404, never 403. |
409 | conflict | The quote is already terminal — consumed, rejected, or expired — so it cannot be rejected again. This is this endpoint's defining error. |
429 | rate_limited | Request throttle exceeded. |
{
"type": "conflict",
"code": "conflict",
"message": "Quote is no longer active and cannot be rejected.",
"request_id": "req_test_abc123",
"doc_url": null,
"statusCode": 409
}There is no quote.rejected webhook. Rejection is observed through this response and through
GET /pools/quotes/{quoteId}. Webhooks fire only for terminal trade events.
Public boundary
This reference covers partner-visible discovery, quote, transact, status, trade, and balance behavior. Liquidity operations, routing internals, provider details, reserve logic, and runbooks are outside the public API contract.
Related pages
Create a 0Pools quote
Lock the short-lived firm quote that this endpoint declines.
Retrieve a 0Pools quote
Read back the derived quote status, including rejected.
Execute a 0Pools quote
Transact an accepted quote instead of rejecting it.
Errors and rate limits
Handle conflicts, retries, and the unified error envelope.