Payments and Refunds
This page covers what's specific to paying for a job with x402: how a quote is priced, the time windows that apply, what a declined payment looks like, how to recover a pending purchase, and when the service refunds you. A quote uses the pay-as-you-go rates on pricing. Subscription prices and discounts don't apply.
Quotes
An unpaid request creates a quote and returns 402. The quote's resource.url carries a purchase_id. The paid request must repeat the same request fields and the quote's resource and accepted values, or the service answers 409.
- A quote is valid for 300 seconds. The service removes an expired, unpaid quote about an hour later.
- Unpaid quote requests are limited to about 20 per minute from one IP address. Over the limit, the service answers
429withRetry-After: 60. Paid requests, replays, and cancellations are never limited.
How the Price Is Computed
The quote freezes the rates, your options, and the purchased allowance. The service rounds the duration up to whole minutes, adds the per-minute rate of the core transcription and of each add-on you selected, and rounds the total up to whole cents once. The quote takes its rates from the pay-as-you-go rates on pricing. The smallest quote is one cent, and add-ons have no separate minimum.
For a combined rate R in integer millionths of a dollar per minute:
M = ceil(input_duration / 60)
paid_cents = ceil(M * R / 10_000)
USDC_atomic_amount = paid_cents * 10_000
max_input_duration = min(86_400, 60 * floor(paid_cents * 10_000 / R))
max_input_duration is the purchased allowance. It's the longest file, in seconds, that your payment covers at the frozen rate. The service sets it, and you can't send it.
A 200-second claim with no add-ons is four billable minutes. The quote is one cent (amount is 10000), and the allowance is 300 seconds. A 250-second file succeeds, and so does one of exactly 300 seconds. The same claim with can_parse_words costs two cents (20000) and allows up to 360 seconds, because the allowance depends on the combined rate.
The service measures the actual duration while it processes the file. A shorter file succeeds. A file longer than the allowance fails, and the service refunds you in full. It never truncates the file or charges you again.
Time Windows
| Window | Length | If it passes |
|---|---|---|
| Quote | 300 seconds from the unpaid request | The paid request gets 410. After the service removes the quote, it gets 404. The service took no payment. |
validBefore | 6 to 360 seconds after the service's clock when the paid request arrives. Standard clients set it 300 seconds ahead. | 402 with a fresh PAYMENT-REQUIRED and an error. The service took no payment. |
| Upload start | 300 seconds from payment confirmation | The purchase expires and the service refunds it in full. See Upload a File. |
Send the paid request right after you sign it, from a machine with an accurate clock.
Declined Payments
A paid request can also return 402. Its payment header tells you what happened.
Fresh PAYMENT-REQUIRED
A fresh PAYMENT-REQUIRED header with an error means the service rejected that proof and took no payment. Causes include a facilitator rejection such as insufficient_funds, an invalid authorization, an authorization that doesn't match the quote, and a validBefore outside the allowed window. The quote stays payable until it expires. Fix the cause, then sign the returned requirement again or request a new quote.
PAYMENT-RESPONSE with success: false
A PAYMENT-RESPONSE header with success: false and an errorReason means the facilitator declined the first settlement before it broadcast a transfer. The body still reports status: "PENDING" and payment_status: "settlement_unknown", but the decline is final. The service took no payment and never submits that proof again.
- Replaying the proof returns the same
402, then410after itsvalidBeforepasses. - The quote stays bound to that proof, so a new signature for the same quote returns
409. - Fix the cause, then request a new quote and pay it.
If Base later shows that transfer anyway, for example because you submitted the authorization yourself, the service treats the purchase as paid. A URL job starts, and an upload purchase expires unused with a full refund.
Recover a Pending Purchase
A timeout or a lost response doesn't mean the payment failed. Save the exact request and the signed proof before you send the paid request, and keep both private. To recover, send the same request with the same PAYMENT-SIGNATURE header again. The service returns the purchase's current state and never charges you again. Changing any request field returns 409.
A replay returns one of these:
- A
202with onlypurchase_id,status: "PENDING", and apayment_status. The payment isn't confirmed yet. Replay again in a few seconds. The values are in States. - A
202with a jobid, or withREADYfor an upload. The purchase is confirmed. - A
402with a freshPAYMENT-REQUIREDor aPAYMENT-RESPONSEwithsuccess: false. The service took no payment. See Declined Payments. - A
404or410. The service took no payment. Request a new quote.
Reuse the proof. Don't pay again to resolve a pending answer.
A URL purchase also starts its job without a replay, but the service checks pending payments only every few minutes, so a replay gets you the job id sooner. Replay a pending upload purchase at least once a minute, and more often if you can. Its 300-second upload window starts when the payment is confirmed, even if that happens in the background.
A job id with admission_status: "dispatch_pending" means the job exists but the service hasn't confirmed that it started. Keep polling Get a Job, and don't pay or submit again. The service never submits a job twice, and uncertainty alone doesn't trigger a refund.
If a purchase or job stays pending, email support@speechischeap.com with its purchase or job ID.
Refunds
Refunds return USDC to the paying wallet. The service pays the processing and settlement fees, so they don't reduce a refund.
Excess Refunds
After a job succeeds, the service recomputes the price from the actual duration with the frozen rate and the same rounding. If you paid more, it refunds the difference. The price you keep rounds up to whole cents, so the refund is always a whole number of cents:
| You paid | Price of the actual duration, before cent rounding | Refund |
|---|---|---|
| $0.12 | $0.022 | $0.09 |
| $0.12 | $0.010 | $0.11 |
| $0.01 | $0.006 | None |
The service makes no adjustment before a job succeeds, and it never sends a zero-amount refund.
Full Refunds
The service refunds the whole payment when:
- The transcription fails, including a file that is longer than the purchased allowance.
- The service can't fetch the file after you pay.
- An upload fails, or an upload purchase isn't used within its start window.
- You cancel the job and the cancellation is confirmed. See Cancel a Job.
Tracking a Refund
If you set a webhook_url, the service sends a refund update when a refund is pending, succeeded, or failed. See Webhooks. A succeeded refund means the service issued it, not that your wallet already received it. Allow up to an hour for a refund to arrive. A failed refund remains owed. If a refund hasn't arrived after an hour, email support@speechischeap.com with the purchase or job ID.