Paid Inference with x402: When to Charge, Start Work, and Release Results
Consider a hypothetical document-extraction service. An agent accepts a fixed quote for one bounded inference job, authorizes payment, and waits. The HTTP wait ends before the model finishes. The agent has no output, but the provider may still be working and the payment may already be committed.
Should the agent submit again, retrieve a job, or ask for compensation? That depends on what the purchase promised and which operation actually ended.
Charging for inference requires more than a paid endpoint. The application needs to connect a price commitment, an external computation, and the buyer's entitlement to the result without treating their states as interchangeable.
Define the Purchased Work Before Quoting It
Start with a purchase record that identifies both the work and its owner. For the extraction example, a useful application contract binds:
An application purchase ID and authenticated customer.
The chosen model/version and saved input or content fingerprint.
Validated limits on the model-specific request and output.
The quoted amount, payment asset, units, recipient, and applicable expiry.
Completion criteria, partial-output policy, and result-retrieval terms.
These are application design choices, not standard x402 inference-job fields. The x402 V2 specification defines payment requirements; it does not define what constitutes a satisfactory extraction result. Similarly, inference inputs depend on the selected model's schema, as the Replicate HTTP reference explains.
The saved input matters. A URL whose content can change does not identify immutable work. Preserve the submitted document or otherwise bind the purchase to the exact content processed. Reject a retry that changes the model, document, output limits, or price while retaining the same purchase ID. A changed offer needs fresh validation and authorization.
Define completion before quoting. Does the buyer purchase a completed structured response, an attempt within a compute limit, or partial output if a deadline intervenes? Valid JSON alone does not establish that the extracted facts are correct. Any promised validation must have a corresponding application check.
Ownership belongs in this record even when the payer and customer differ. A delegated agent may pay for a customer's job, but the server still needs a defined relationship between that payer, the authenticated requester, and the account allowed to retrieve the document. Do not derive that relationship solely from an address supplied in the request.
Also distinguish model tokens from the token used for payment. An output-token cap limits one dimension of generation; it is not automatically a monetary cap covering every billable input, compute component, or service fee.
For the hypothetical service, suppose the offer is a fixed-price extraction of one saved document within declared limits, with authenticated retrieval of the completed result for a stated period. That is concrete enough to price and recover. “Pay for AI” is not.
Match the Quote to the Moment Funds Are Committed
A fixed quote and a usage ceiling solve different problems.
With a fixed bounded quote, the buyer agrees to a known amount. The seller absorbs variation in provider cost within the accepted job limits, subject to the cancellation and failure policy. The seller therefore needs enforceable limits rather than an optimistic estimate of typical output.
With usage-based billing, the buyer authorizes a maximum and the final charge depends on a trustworthy meter. The documented x402 upto scheme permits settlement for actual usage no greater than that maximum. Its mechanisms differ: the EVM implementation uses Permit2, while the Solana implementation uses a payment channel with a deposited ceiling. Support must match the scheme, network, client, server, and facilitator; it cannot be inferred from an endpoint returning HTTP 402.
The timing of commitment also matters. The currently documented exact payment flows distinguish authorization from optional upfront settlement:
Payment flow | Ordering relative to the resource handler | Consequence for inference |
|---|---|---|
| Verify payment, run the handler, then settle | The seller can incur compute cost before settlement succeeds. |
| Settle before the handler runs | A subsequent service failure needs an explicit delivery or compensation path. |
Escrow flow | Commit a deposit, perform work, then settle the final charge | Deposit commitment and final billing remain separate events. |
Those are payment-flow distinctions, not universal instructions for every API. Customer authentication, the agent's spending approval, and validation of a payment signature are also separate checks.
There is a particularly important boundary for asynchronous inference: returning a job ID does not measure future token usage. A handler-level metering example does not, by itself, provide durable capture after the handler has returned. A deferred-capture design needs explicit support for retaining authorization, measuring final usage, settling within its constraints, and recovering failures. Do not build that promise merely by placing upto around an enqueue response.
For the running extraction example, choose a fixed quote with the documented exact upfront flow. This design requires the chosen network mechanism, client/server implementation, and facilitator to explicitly support that flow; it is not a claim about an enabled deployment. Without that support, select another documented design rather than silently falling back to post-handler settlement. In this flow, /settle both validates and commits payment; a separate /verify call is not made.
The application's sequence is: saved purchase -> recorded successful settlement -> provider submission -> saved job ID and acknowledgement -> stored completed result and authorized retrieval. These are application milestones, not x402 status names:
Authenticate the buyer, validate the bounded request, and durably save the purchase and payment-attempt association before requesting settlement. Do not submit inference yet.
Only a successful server-side settlement result, durably associated with that purchase, permits provider submission. A signature, verification alone, or an unknown settlement response does not release that gate.
Claim the submission durably, then contact the provider. Save its accepted job ID before returning an accepted-job acknowledgement. This acknowledges the original job, not final output or another charge.
Release the result only when that settled purchase has a stored output meeting its completion policy and the requester owns an active retrieval entitlement. Status may be available earlier; output is not released merely because a job ID exists.
Job completion remains asynchronous, but settlement is not deferred until its token usage becomes known. The seller now owes delivery or the agreed compensation if work fails after payment.
For a usage-priced alternative, the quote should identify the rated quantities and their units, the applicable rates, rounding, and the maximum authorized total. Validate that the worst permitted request fits that ceiling. If input usage and output usage have different prices, limiting only output leaves part of the bill unspecified. Reject unsupported combinations before signing or execution rather than discovering after generation that the promised cap cannot be enforced.
GOAT Flow API Payments has a separate documented MPP Crypto prepayment profile: the client obtains a challenge, transfers the quoted funds, verifies through /mpp/v1/verify, and presents a signed Payment-Receipt to the protected route. Its challenge and receipt contract requires deployment-matched clients and verifiers, plus enabled merchant and route configuration. That profile is not interchangeable with an arbitrary MPP SDK, nor does it establish GOAT support for upto.
Give Waiting, Payment, and Execution Different Clocks
A timeout is actionable only when its clock is identified.
The quote expiry determines how long the offer remains available. Payment authorization has its own validity constraints, while x402's maxTimeoutSeconds concerns completing payment, not how long a model may run. Neither should be repurposed as the inference deadline.
The synchronous HTTP wait controls how long one connection remains open. Ending that wait can leave accepted work running. Queue delay is different again: the provider may have accepted the job without starting computation. An execution deadline or overall job-lifetime deadline determines when the provider should stop or abandon that work, according to its own API.
Replicate provides a concrete example. Its sync and async prediction modes allow an unfinished prediction to be retrieved after the synchronous wait ends. The HTTP reference permits Prefer: wait=n for a wait between one and sixty seconds. Cancel-After, by contrast, sets a lifetime measured from prediction creation, so time waiting to start counts toward it. These are Replicate controls, not generic x402 headers.
In the hypothetical extraction purchase, the application records the provider ID. When the wait ends, it can return the saved purchase/job reference and continue observing the original prediction. The agent requests status for that purchase instead of resubmitting the document as new work. A connection failure may prevent even that acknowledgement from arriving; the purchase record must still exist server-side.
Polling introduces another limit: the agent's willingness to keep checking. Exhausting a polling budget means stop polling or switch to a scheduled check; it does not cancel the job or prove payment failed. The application should retain the relationship so that a later status request can resume observation.
Finally, output retention limits how long the completed result remains available at the provider. That deadline can expire after successful computation, even though the buyer never downloaded anything.
For each clock, specify its owner and consequence: refuse a new offer, stop waiting, request cancellation, pause observation, or copy the output. If a transfer was already broadcast, an expired payment window calls for reconciliation, not an assumption that no funds moved.
Make Results Recoverable After the Handler Returns
An asynchronous response acknowledges accepted work. It should not be mistaken for a delivered result.
Persist the provider job ID against the purchase, then advance the application record from observed provider events. Polling and authenticated webhooks can both contribute observations, but the resulting transition must be safe when they race or repeat. Save the completed output and its association with the buyer before treating it as available for reliable retrieval.
Keep several facts separate: the provider accepted the job; output became available; the provider reached a terminal state; the application stored the result; the buyer retrieved it. They need not occur together. Replicate's creation documentation notes that file outputs can be available while a prediction is still processing. A file URL alone therefore should not stand in for whatever completion criteria the merchant promised.
Retention creates a practical storage obligation. For API predictions, Replicate's default data-retention policy removes inputs, outputs, files, and logs after an hour. An application promising longer access needs its own copies before removal. A provider URL is not permanent storage, and an application should not promise indefinite downloads unless it operates that service.
The retrieval path must authenticate the current customer and check ownership of the purchase. Knowing a job ID or possessing payment evidence should not unlock another customer's document or result. State whether repeat downloads are included and when that entitlement ends.
A single-use payment credential makes this distinction especially clear. In GOAT Flow's documented MPP middleware, the simple receipt store consumes authorization before the handler runs. A handler failure or lost response does not automatically restore the receipt. The documented boundary requires a shared durable consumption store and a trusted deployment-matched verification key; receipt validity does not authenticate the current customer or bind every body parameter.
For such a design, preserve consumption and recover through the application purchase record. After authenticating the buyer, return the saved result or current job state through an appropriate retrieval path. Do not delete a consumed key to make the paid request reusable, and do not interpret consumption as proof that the model finished.
Design the status and result operations separately from the operation that starts paid computation. A permitted repeat download should read the stored artifact, not invoke the model again. The response can identify the original purchase and its retention deadline so the agent knows whether to keep waiting or save its copy. Apply authorization on every retrieval, including requests made after the original payment credential expires.
The original extraction purchase now has a useful outcome: with successful settlement recorded, its provider job complete, and the result stored under the agreed completion policy, the authenticated owner can retrieve it within the active entitlement despite losing the initial response. If copying failed or provider retention elapsed first, record a delivery failure. Silently running another inference would create new cost and potentially a different answer, not restore the missing artifact.
Reconcile Unknown Outcomes Before Creating Anything Again
Retries are hardest when an external operation may have succeeded but its response was lost. The absence of a local ID is not evidence that the external operation failed.
Use a durable application creation claim before creating a payment order or submitting provider work. Bind it to the immutable purchase and serialize concurrent attempts. Once an attempt may have crossed an external boundary, retain that claim until its outcome is reconciled. These are application reliability recommendations, not an exactly-once guarantee supplied by a payment protocol.
Likewise, let polling and webhook workers contend for the same fulfillment transition rather than independently starting inference. Save the result reference and delivery outcome durably before acknowledging completion. If a worker crashes, its successor must inspect that record and the provider state. An elapsed local lease is a reason to investigate ownership of the attempt, not evidence that no external work exists.
The surviving evidence determines the next operation:
For the chosen upfront extraction path, known failed settlement leaves submission and output release blocked. Unknown settlement keeps the same purchase and payment attempt on hold until reconciled, without another automatic charge. If work is nevertheless found during recovery, retain its job/output evidence and reconcile payment before release; do not infer payment success from the work's existence.
Paid but not submitted is different. If settlement is recorded and no provider attempt began, resume submission under that same paid purchase. If the application cannot establish whether submission began, use the unknown-provider branch below, not a fresh submission. If the original service cannot be delivered, enter its compensation process without assuming a refund has executed. Losing an acknowledgement after provider acceptance likewise calls for recovering the saved job, not paying again.
A known payment order ID: inspect that original order's status and payment proof. Reuse saved payment requirements only while the order remains payable. If it is paid, advance the original purchase; if it has a genuine terminal failure, handle that outcome explicitly. Neither a polling exception nor a failure response should automatically create another order.
An unknown order-creation outcome: preserve the attempted merchant reference, payer, chain, asset, amount, and attempt time. Reconcile the original creation instead of guessing that a second create will return the same order. In GOAT Flow's Custom Integration example using Server SDK 0.4.0, createOrder() does not accept idempotencyKey, and an ordinary duplicate dappOrderId is rejected rather than returned as a lookup. Reconcile the original order through the saved identifiers in the Merchant Portal or with platform support. Do not substitute duplicate creation or assume a public lookup-by-dappOrderId SDK method.
An unknown provider-submission outcome: the provider may have accepted the job before the application saved its ID. Local locking prevents competing submissions, but cannot prove what happened remotely. Use the provider's available reconciliation process. Without evidence that resubmission is safe, hold that purchase rather than claim exactly-once execution.
A payment-ID cache cannot replace this durable record. The Payment-Identifier extension recommends binding an ID to a normalized request fingerprint and rejecting changed requests. Its cache examples also allow normal processing after cache expiry or failure. For costly inference, that behavior is insufficient as a purchase policy: losing deduplication state must not silently make an old paid job new again. Stop automatic re-execution and reconcile the purchase.
Now consider a second hypothetical purchase: the transfer was broadcast, its verification response was lost, and the challenge later expired. Keep the original challenge, order mapping, and transaction hash. Do not send another transfer merely to obtain fresh payment evidence.
In GOAT Flow's MPP Crypto retry rules, pending_inclusion or pending_finality means honor Retry-After and verify the original challenge and transaction. An expired challenge does not prove an unpaid purchase. Receipt recovery also has bounded windows; after replay-store eviction, payment may require platform reconciliation rather than another automatic payment. A consumed receipt with a lost merchant response instead points back to delivery recovery.
If payment is later confirmed, associate it with the original purchase and original terms. Inspect whether its job already exists or its output remains deliverable. Fulfill what is still owed or resolve compensation under the failure policy; do not treat late confirmation as a new authorization to change the work or price.
Replacement is a separate decision. Before authorizing it, establish what happened to the original payment and job and prevent both attempts from remaining independently fulfillable. If the original attempt genuinely failed, a new offer may require fresh approval. If its outcome is still unknown, a new purchase ID does not make the uncertainty disappear.
Separate Cancellation Cost From What the Buyer Is Owed
Cancellation has several stages: the customer requests it, the application sends the provider operation, the provider reports an outcome, and the merchant resolves the purchase. A cancellation request alone proves none of the later stages.
Replicate's prediction lifecycle illustrates why timing affects cost. A prediction whose deadline is reached before it starts becomes aborted and is not charged. If it has started, deadline cancellation produces canceled, and runtime already used is billed. Those are Replicate's deadline outcomes, not universal provider terms or the merchant's refund policy.
The merchant therefore needs to track three financial records separately: provider cost incurred, buyer payment outcome, and any compensation owed or completed. A seller can owe a buyer compensation even though the provider charged for work. Conversely, an attempt that never settled may need no buyer refund even if the seller incurred compute cost.
For fixed-price extraction, define in advance what happens when the buyer cancels while the job is queued, when execution has begun, and when output is already complete. State whether partial output satisfies any part of the offer. Do not retroactively convert an unsuccessful fixed-price result into a usage bill the buyer never authorized.
A useful failure policy also covers provider errors and paid-but-inaccessible output. If the model failed without a usable result, decide whether the contract permits a replacement attempt or calls for compensation. If partial output exists, make its treatment explicit rather than equating any generated text with successful delivery. If storage failed, reconcile the missing result instead of marking the purchase fulfilled merely because compute succeeded.
Be precise about reversals. Unsettled authorization is not a settled charge. An unused allowance is not automatically money returned. Releasing an escrow remainder, deciding refund eligibility, submitting a refund, and confirming that refund are different events. Record which one occurred and preserve the relationship to the original purchase.
GOAT Flow API Payments assigns delivery, refunds, and support to the merchant application. Its payment evidence does not supply an inference cancellation policy or automatic refund guarantee.
The policy should identify who can authorize compensation, what evidence they inspect, how the buyer learns the decision, and how completion is recorded. An “eligible for refund” status is not enough to tell an agent that its funds are available for another job.
Reserve the Task Budget Before Admitting More Work
Even a correctly bounded purchase can produce unbounded aggregate spending if an agent creates many copies in parallel.
Treat admission as a server-side decision. Validate the selected model, input, output limits, quoted amount, payment recipient, and asset against the saved purchase. The agent should approve terms before signing; the merchant should independently reject inconsistent requests. Neither side should rely on the other to repair an altered offer.
For an agent with a total task budget, reserve potential liability across admitted jobs rather than budgeting only average expected output. A fixed-price job consumes its quoted amount; a metered job needs room for the authorized ceiling and any separately applicable costs. Finalize the accounting when outcomes are known. Do not release a reservation merely because a client connection ended or the agent stopped polling.
The reservation must be atomic across concurrent admissions. Otherwise, several workers can each observe the same apparent remaining balance and individually approve work that exceeds the task's total allowance. Where the merchant and agent maintain separate budgets, each needs its own enforcement; a wallet signature does not implement the merchant's capacity policy.
Retain uncertain liability as well. A payment whose outcome is unresolved can still commit funds, and a provider submission with a lost response can still consume compute. Reconciliation may justify releasing the reservation, but a renamed purchase or expired cache should not.
Apply concurrency and queue limits before accepting more work where possible. Bound polling frequency and retries, authenticate webhook events, and enforce customer ownership on status, results, and cancellation. These are application controls: a paid route does not itself provide an inference queue or establish that capacity is available.
Protect the unpaid quote path too. Validate input size before expensive preprocessing, rate-limit repeated quote requests, and avoid launching model work just to discover its price. Charging at the final route does not bound resources consumed earlier. Those checks belong at admission, before a rejected or abandoned request has already created provider liability.
Admission failures after commitment still need the delivery and compensation policy. Checking capacity first reduces that exposure; it does not promise that later provider failures cannot happen. When either the task budget or the original purchase state cannot be established, pause automatic admission rather than make another paid attempt.
The hypothetical extraction buyer can finish by retrieving its original stored result. The buyer with a lost verification response must first reconcile the original payment, then receive the original service or the policy's compensation outcome. Neither needs a new charge merely because the first request ended. Before selling another inference job, the application should know which of those paths it can actually complete.



