A transfer hash is not a paid order. Accept agent payments with x402 by validating DIRECT transfers, interpreting order status, and recovering failed confirmations.
An AI agent says it has paid and sends your application a transaction hash. Should your server release the report, activate the license, or dispatch the item? Not from that message alone. The hash identifies something to investigate; it does not establish that the correct purchase was paid.
To accept payments from AI agents, expose machine-readable payment terms, use a compatible wallet payment client, and connect verified payment evidence to your merchant order. For GOAT Flow's current public DIRECT path, the payer transfers an ERC-20 token to the merchant's configured receiving address. Your backend then checks trusted order status and matches the payment against the expected terms before fulfilling once.
The critical integration is therefore the decision between payment execution and delivery. Direct transfers remove a custody intermediary from the customer-funds path, but they do not remove the merchant's responsibility for reconciliation, exceptions, or duplicate delivery.
A compatible payment client is only the beginning
x402 lets a service communicate payment requirements to a requesting client, which may be an AI agent. In the V2 HTTP exchange, PAYMENT-REQUIRED carries the requirements, PAYMENT-SIGNATURE carries the payer's payment payload, and PAYMENT-RESPONSE communicates settlement results. The client must understand the actual version, scheme, network, asset-transfer method, and relevant extensions. Receiving HTTP 402 Payment Required establishes none of that compatibility by itself.
There is also no universal rule that every x402 resource handler runs only after funds have moved. The current core specification distinguishes an authorization flow, where payment is verified before resource execution and settled afterward, from upfront and escrow flows with different ordering. Verification of an authorization is not itself an on-chain transfer. Choose the flow your resource server and payment implementation actually support, particularly when execution has irreversible side effects. The x402 V2 specification defines these distinctions; client budget management is outside its core scope.
GOAT Flow's public DIRECT order flow is a concrete commerce implementation, not a replacement definition of generic x402. Its challenge specifies a direct ERC-20 transfer, and Flow observes and records that transfer. An arbitrary x402 wallet client must not be assumed to understand Flow's order extensions merely because both use a 402 response. Validate the client/profile pairing rather than advertising untested universal compatibility.
Keep four names separate. x402 is the payment protocol. GOAT Flow is merchant commerce and transfer-verification software. The Machine Payments Protocol, or MPP, is an independent protocol; Flow's current MPP integration is a specific profile discussed below. GOAT Network's AgentKit is an agent SDK/runtime with actions and execution controls, not the merchant's payment ledger. AgentKit payment examples do not define what is enabled in a Flow merchant deployment.
On the buyer side, an agent needs an authorized signer, the accepted token balance, and whatever native gas or sponsorship its selected payment path requires. Do not assume a direct wallet transfer is gasless because another payment scheme supports sponsorship. The operator should enforce per-purchase and aggregate budgets, allowed merchants and assets, and an approval threshold outside the model's free-form instructions. These are recommended controls, not automatic guarantees from x402. A malicious or mistaken payment request should meet a constrained signer, not an unrestricted treasury wallet.
Bind the transfer to terms your backend owns
For public Flow DIRECT payments, configure a valid receiving address for each enabled chain/token pair. The payer's tokens go to that address, not into a Flow escrow awaiting merchant payout. Optional callback contracts and compatibility fields in a repository are not prerequisites for DIRECT acceptance. Legacy links under GOATNetwork/x402 now redirect to GOATNetwork/goat-flow; use the current documentation rather than reconstructing public behavior from old examples.
Your backend owns the price and expected order terms. It should derive the amount from trusted product or cart data, associate it with a stable business-order identifier, and create the payment order through the authenticated merchant interface. Keep merchant API credentials on that backend. They are not credentials the agent needs to pay, and they should never be embedded in browser JavaScript or handed to a buyer.
Flow documents HMAC-authenticated POST /api/v1/orders for order creation. A successful creation returns a documented 402 payment challenge, including the order identifier and payment requirements. Treat this as expected behavior for that endpoint, not as a general instruction to treat every 402 from an authenticated API as success. Status and proof reads have different response contracts.
The challenge's payment option identifies the network, token contract through asset, base-unit amount, and receiving address through payTo. The documented DIRECT flow is ERC20_DIRECT; its extensions also carry relevant order terms such as expiry. Store the returned Flow order ID alongside your business-order ID and the expected merchant, payer, chain, token, amount, recipient, and expiry. Preserve the association before asking the wallet to send funds.
SDK normalization makes fields easier to consume, but it does not prove they are valid. The current API reference explicitly warns that normalized fields can use fallbacks or remain empty when a challenge is incomplete. Validate required fields against your backend's expected terms and approved configuration before presenting a transfer. Reject a missing recipient, an unexpected token contract, an unrecognized flow, or an expired instruction instead of letting defaults silently authorize payment.
Trust the source of those instructions too. Configure the expected payment-service origin and merchant identity; do not accept a replacement endpoint or receiving address from arbitrary agent conversation text. A correctly executed transfer to an attacker's address is still a failed merchant purchase. Wallet-side allowlists complement, rather than replace, validation of the backend order terms.
Consider an illustrative purchase of a downloadable report priced at 10 units of an accepted token. If that particular token has six decimals, its amount is 10000000 base units. This is arithmetic, not a claim that every token named USDC has six decimals in every deployment. Resolve the actual contract and decimals from trusted configuration, and use integer-string arithmetic rather than floating-point conversion. A symbol alone cannot distinguish contracts on different chains.
Bind those terms to one report order and the intended buyer. The agent sends the exact ERC-20 amount to the returned receiving address on the selected chain; your application records the transaction identity as it becomes available. Receiving a wallet success signal still leaves the merchant confirmation step open. These endpoint and field semantics are documented in the current Flow API reference.
Turn paid status into one fulfillment decision
Read the order from your backend through the authenticated merchant interface, or process an authenticated webhook whose contract has been verified for your deployment. Do not let the buyer choose the merchant, payment amount, or status that your fulfillment worker trusts. A status object copied into a browser request is still buyer-controlled input, even when its fields resemble a legitimate API response.
The current Flow SDK order statuses require explicit classification:
Order status | Merchant interpretation | Delivery action |
|---|---|---|
| Pending payment | Keep the order unfulfilled |
| Successful payment terminal for the order waiter | Match expected payment fields before delivery |
| Successful DIRECT terminal that may be the first observed success | Apply the same matching and deduplication gate |
| Failed or closed order, not paid success | Do not fulfill automatically; reconcile exceptions |
Do not write if waiter returned, deliver. Order waiters can return on failure or closure too. Equally, do not require your polling loop to observe PAYMENT_CONFIRMED before accepting INVOICED. Core can advance between those states within one watcher transaction, so a poller may see only the latter. The successful state is meaningful, but the transition history you happened to observe is not a fulfillment prerequisite.
Before releasing value, compare the trusted Flow order ID and business-order ID with your stored purchase. Confirm merchant ownership, successful status, expected chain, token contract, integer amount, payer where required, receiving address, and transaction identity. Use the stored challenge together with trusted order/payment evidence for fields not present in the status response; never fill a missing verification field from the buyer's request. A paid order for another report, chain, merchant, or token is not payment for this purchase.
Fulfillment is a second state transition in your application. Recommended design: atomically record the verified payment association and enqueue a delivery job under a unique business-order key. A worker can then generate a report or activate a license using that same key. Persist the resulting delivery reference separately from the payment transaction. If the worker crashes after an external side effect, recovery needs a way to discover whether that side effect already happened.
This does not promise exactly-once behavior from a network. It makes repeated polls, webhook retries, and competing workers converge on one logical delivery. The same payment event must not be consumed for several business orders unless your application intentionally defines and verifies that allocation.
An ordinary ERC-20 transfer event does not contain your business-order ID. If one payer has two open orders for the same amount, token, and recipient, amount matching alone cannot identify the intended purchase. Use the trusted service's order association and preserve the transaction/log binding in your own ledger. If that association is missing or contradictory, hold delivery for reconciliation instead of assigning one transfer to both orders. Preventing indistinguishable concurrent payment attempts is a useful application control; do not assume undocumented matching behavior from a service.
For the illustrative report, INVOICED permits the payment check to proceed; it does not mean the download was delivered or opened. Maintain separate payment and fulfillment records so a paid-but-undelivered order is recoverable without asking the agent to pay again.
An order digest is not a signed receipt
Flow's getOrderProof() and Go GetOrderProof() return a server-issued payment record. Their historical field name signature is misleading: the documented value is an unsigned Keccak256 digest, not a cryptographic signature from an issuer.
The digest concatenates seven fields without separators, in this order: order_id, tx_hash, log_index, from_addr, to_addr, amount_wei, and from_chain_id. It does not cover status or a token-contract field. Anyone with the fields can recompute it. Checking that the digest matches those fields therefore cannot authenticate the issuer or establish that the supplied status is true.
The record is useful when retrieved through the trusted merchant API after a successful order check. It organizes payment data for reconciliation. It becomes unsafe when a merchant treats an agent-supplied copy as an independently signed receipt. Nor does it prove that a report was generated, an entitlement was granted, or a parcel was shipped.
When independent transfer verification is required, inspect the claimed transaction on the expected chain through a trusted node/provider. For an ERC-20 transfer, check execution success and the relevant transfer log from the expected token contract, including sender, recipient, base-unit amount, and log identity. Apply the confirmation/finality policy appropriate to that chain and purchase risk. A transaction receipt showing successful execution is not enough if the matching transfer went to a different recipient or used another token.
A separate artifact exists in the current GOAT Flow MPP profile for paid API resources: the signed Payment-Receipt. In that profile, the buyer obtains a challenge, transfers directly to the merchant recipient, submits transfer evidence to the verify endpoint, and uses the returned receipt on the protected route. The merchant resource server verifies the receipt's signature, merchant audience, canonical route binding, expiry, and applicable consumption policy before admitting the request.
For single-use receipts across several server replicas, consumption must be atomic in shared storage; otherwise simultaneous requests can each appear unused. Authentication of the receipt and successful resource delivery remain separate facts. If a paid handler fails, your retry or reissue policy must preserve the buyer's entitlement without unintentionally making a single purchase an unlimited reusable credential.
These are GOAT-specific JSON challenge/verify endpoints and a signed receipt extension, not the generic MPP HTTP wire exchange. The documentation reports no published interoperability result with official MPP SDKs. Do not substitute this receipt for getOrderProof, or advertise arbitrary MPP-client compatibility without an adapter and conformance checks. The Flow MPP integration guide defines that distinct access-control contract.
Recover uncertainty without paying again
The most expensive integration mistake can happen after a transfer has already been broadcast. An RPC timeout, failed status read, or lost response does not establish that no money moved. Retrying the whole purchase as a new transfer can create a second real payment while leaving the original order unresolved.
In an illustrative timeout scenario, the report-buying agent broadcasts its transfer and records the hash, but the application cannot obtain a final order result. Persist the business-order ID, Flow order ID, expected terms, payer, selected chain, and known transaction hash. The next action is to resume confirmation for that payment attempt, not to create a fresh purchase and send another 10 tokens.
Check the known transaction on its expected chain and reread trusted order status with bounded backoff. If the transfer is confirmed but Flow still shows a pending order, the disagreement belongs in reconciliation: retain evidence and investigate watcher or matching delays. Do not tell the buyer to pay again merely because the status service is unavailable. Where transaction replacement is possible, reconcile the actual canonical transaction rather than assuming the first hash is the only possible outcome.
If the transfer failed definitively, a new attempt may be appropriate after obtaining valid current terms. If the outcome remains unknown, keep it unknown and expose a resumable pending state. Define an escalation deadline for support rather than converting a local timeout into a fabricated payment failure. A generic x402 settlement response can also describe a pending transaction; its identifier enables investigation, not an unconditional retry or delivery decision.
Order-creation retries need their own protection. Use a stable business-order identifier and an explicit idempotency strategy before resubmitting a timed-out creation call. A stable identifier is not, on its own, proof that a particular API deduplicates every request. Confirm the behavior of the integration you use. Generic x402's optional payment-identifier extension likewise does not automatically deduplicate a merchant's shipping or license worker.
Late payments need a business rule. An expired order may still have a transfer arriving at the receiving wallet. Reconcile it against the original terms and inventory or entitlement state. You might fulfill after review, issue an agreed refund, or offer another resolution; do not automatically revive the order if its price or available stock changed. Cancellation of a software order cannot undo a token transfer already sent on-chain.
Wrong-chain, wrong-token, insufficient-amount, or wrong-recipient transfers are exceptions, not nearly successful purchases. Define how support investigates them before launch. Refunds, where offered, require controlled authorization, verified recipient instructions, and a separate outgoing transfer record. DIRECT acceptance gives the merchant control of received funds while placing this recovery responsibility with the merchant; it does not imply an automatic escrow reversal.
Operate confirmation as a separate service
Polling and webhooks solve different operational problems. Polling is straightforward to build from a known order ID and lets your backend fetch current state. It adds request load and a detection delay determined by your polling interval. Webhooks can reduce that delay, but introduce receiver authentication, duplicate delivery, outage recovery, and event-schema management.
For Flow, webhook events and signing rules are deployment-specific. Before enabling webhook-driven fulfillment, confirm the emitted event names, payload schema, signature input and headers, timestamp/replay rules, retry schedule, and delivery source. Do not invent an HMAC header or copy Testnet3 event names into a Mainnet assumption. If these details cannot be verified, keep authenticated status reads as the confirmation path.
A recommended receiver authenticates the request, durably records or queues the event, and acknowledges promptly. Preserve raw body bytes when the actual signing contract requires them. Let background processing match the order and claim delivery atomically. Reconciliation polling remains useful even with webhooks, because an event can be delayed or lost while an order is already paid. The Flow merchant guide documents these deployment checks, order reconciliation, and the distinction between direct customer funds and merchant fee credits.
Watch both payment observation and delivery. Useful operational records include the purchase and payment identifiers, expected terms, observed transaction/log identity, status-read results, verification time, and delivery reference. Protect access to those records: wallet addresses and transaction IDs do not need to be exposed alongside private purchase details in a public support endpoint. Merchant secrets and private keys should not enter logs.
Alerts should distinguish orders pending with no known broadcast, broadcast payments awaiting confirmation, confirmed transfers not yet matched by the service, and paid orders awaiting delivery. Those conditions require different responses. A single red payment indicator hides whether the team should inspect the chain, repair credentials, restore an observer, or retry a delivery job.
Fee balance is another separate ledger. Flow's merchant fee credits are not customer ERC-20 receipts and are not native network gas. Check active fees and credit requirements in the target environment; insufficient service credits can obstruct order operations without proving anything about an earlier buyer transfer. Do not assume cancellation or expiry always refunds a service fee, or that Testnet3 pricing applies on Mainnet.
Finally, plan for changes in SDKs and runtime configuration. Current branch documentation is not proof that a package candidate is published or that your installed version has identical retry behavior. TypeScript and Go order waiters have different documented error policies; choose explicit polling if consistent treatment is required. Pin verified dependencies, recheck enabled chain/token/recipient settings, and rerun your acceptance exercises after material changes. No public document establishes one universal confirmation time or asset list for every merchant.
Prove the fulfillment boundary before launch
Start in the intended test environment with separate credentials and wallets. These are recommended acceptance exercises, not tests reported as performed here. A happy-path transfer should produce a matched successful order and one delivery record. The evidence should show which chain, token, amount, recipient, and purchase were accepted, not merely display a green checkout banner.
Change one payment term at a time. An unexpected chain or token must be refused before sending where possible, and must not authorize delivery if it appears in reconciliation. Test an incomplete challenge, expired terms, a rejected wallet request, a reverted transfer, and an invalid merchant credential. Each should lead to an identifiable failure or resumable pending condition, with no fabricated paid status.
For webhook-enabled deployments, send a real event through the actual receiver and repeat it. Race it against a status poll and confirm that only one worker claims the delivery. Verify invalid authentication and replay handling against the active contract. Then interrupt the receiver long enough to exercise recovery from trusted order reads. Repeat environment-specific delivery checks before enabling production fulfillment.
Test a late payment against an expired order and route it through the exception policy. If you protect APIs with Flow's MPP profile, separately reject malformed, expired, wrong-merchant, wrong-route, and replayed receipts according to the configured consumption rule. An unsigned order digest must never substitute for that credential.
The final exercise should reproduce the uncertainty that started this integration: broadcast a transfer, interrupt confirmation, resume from the saved order and transaction, and then replay the successful notification. Inspect the records. There should be one reconciled payment association, no second buyer transfer initiated by recovery, and one logical delivery. That observable result is what makes the merchant ready to accept an agent's next purchase.



