Flow Quick Start
Use this guide to complete a first DIRECT payment with the GOAT Flow SDKs.
For deeper details, see the Integration Guide and API Reference.
Choose the shortest path
| Goal | Start here |
|---|---|
| GOAT Flow-hosted wallet/transfer UI | Hosted Checkout |
| Custom merchant wallet/transfer UI | Server SDK + PaymentHelper |
| Agent or CLI payment | QuickPay |
| Paid API route | GOAT Flow MPP profile |
All merchant API credentials stay on your backend.
Prerequisites
- An approved Merchant Account
- Receiving chain/token configuration
- Sufficient merchant fee balance
- API key and secret for authenticated programmatic flows
- A payer wallet with the selected ERC-20 token and native gas
QuickPay product links and Hosted Checkout do not expose merchant credentials in the browser. Dynamic Hosted Checkout terms are still created by the merchant backend.
The runnable examples below use GOAT Testnet3. Move to Mainnet only after the same merchant, chain, token, receiving address, and service-fee configuration have been verified there; switch every origin and chain ID together.
Install
The TypeScript packages declare Node.js >= 18 where Node is used. The Go SDK module currently declares Go 1.25.
Path A: Hosted Checkout
Fixed product
Dynamic price
Create the session on your backend:
Open the opaque session in the browser:
This quick start covers the public DIRECT path. Operator-provisioned session variants are documented as compatibility reference in the Hosted Checkout guide and API Reference; do not select them unless the target merchant and environment have an explicit deployment contract.
Path B: Custom order and wallet UI
1. Configure the backend
Never ship these values in a browser bundle.
2. Create and map the order
The server and browser SDKs intentionally expose different Order shapes.
Map the object explicitly before returning it to the frontend.
Generate dappOrderId once for the cart or payment intent, persist it before
the request, and reuse the same value for a retry. Do not derive it from the
current timestamp inside createOrder().
Under the hood, successful order creation returns HTTP 402 Payment Required.
The server SDK treats it as success and normalizes the x402 body.
The server SDK accepts 402 as success only for order creation. An unexpected
402 from status, proof, checkout, signature, or cancellation fails closed.
3. Validate and pay in the browser
PaymentHelper.pay() does not classify TRANSACTION_REPLACED. If a wallet
speed-up is reported as failed, reconcile the original/replacement transaction
and backend order before considering another transfer.
Callback signing is an operator-provisioned compatibility path, not part of this DIRECT quick start. If the target deployment explicitly requires it, use the complete field, callback-chain, and signature-submission contract in the Integration Guide.
PaymentHelper.pay() checks token balance, submits the ERC-20 transfer, and
waits for a successful receipt. It returns failures in PaymentResult; it does
not check chain, payer, or expiration.
4. Confirm on the backend
Do not fulfill only because the wallet transaction returned successfully.
Current SDK status values are:
CHECKOUT_VERIFIEDPAYMENT_CONFIRMEDINVOICEDFAILEDEXPIREDCANCELLED
Server SDK order waiters treat PAYMENT_CONFIRMED and INVOICED as successful
terminal states. Core can advance a DIRECT order from PAYMENT_CONFIRMED to
INVOICED in one watcher transaction, so a poller may observe only
INVOICED. Before fulfillment, still validate the authenticated order's
merchant context, chain, token, amount, recipient, and transaction identity.
Cancel an abandoned order only while it remains CHECKOUT_VERIFIED:
Path C: QuickPay / agent
QuickPay accepts only canonical same-origin links:
The library derives the manifest and session endpoints from the trusted link
origin; it rejects remote http URLs and cross-origin endpoint substitution.
QuickPay sessions have their own terminal set: PAYMENT_CONFIRMED, EXPIRED,
FAILED, and CANCELLED. Polling is bounded by pollTimeoutMs, retains a
known transaction hash across transient failures, and performs five bounded
grace polls when a known transaction is reported EXPIRED. Reconcile by
session ID and transaction hash instead of rebroadcasting after an ambiguous
post-broadcast failure.
Library options are camelCase. For example, payX402() accepts amount,
chainId, tokenSymbol/tokenContract, memo, and idempotencyKey; it
derives the wire merchant_id and payer_addr. Do not pass raw API fields such
as amount_wei, merchant_id, or payer_addr to the library methods.
Path D: GOAT Flow MPP profile
MPP is an independent open protocol. The example below uses the current GOAT Flow adapter: deployment-specific JSON challenge/verify endpoints, a direct ERC-20 transfer, and a GOAT-specific signed receipt. It is not generic MPP client code, and no interoperability result with the official MPP SDKs is currently published.
This is the standalone GOAT Flow MPP adapter, so coreUrl is the Core/API
origin configured for that deployment. QuickPay pay-mpp instead derives
coreUrl from the trusted QuickPay link origin so discovery, challenge, and
verify remain same-origin.
For this profile's challenge endpoint, success is HTTP 402. Verify success is
HTTP 200 with its signed Payment-Receipt extension. A browser integration
works only when the Core origin
allows the DApp origin and exposes that response header, and the protected
resource allows the Payment-Receipt request header. Otherwise run the buyer
flow server-side. Once returned, the challenge is authoritative for payment
amount, chain, token, recipient, expiry, MAC, and pricing version.
Test environment
| Resource | GOAT Testnet3 | GOAT Mainnet |
|---|---|---|
| Chain ID | 48816 | 2345 |
| RPC | https://rpc.testnet3.goat.network | https://rpc.goat.network |
| Explorer | https://explorer.testnet3.goat.network | https://explorer.goat.network |
| Merchant Portal | https://flow-merchant.testnet3.goat.network | https://flow-merchant.goat.network |
| Admin Portal (operators only) | https://flow-admin.testnet3.goat.network | https://flow-admin.goat.network |
| Flow API / standalone MPP Core | https://flow-api.testnet3.goat.network | https://flow-api.goat.network |
| QuickPay / Checkout and same-origin public API | https://flow-quickpay.testnet3.goat.network | https://flow-quickpay.goat.network |
GOAT native gas is BTC. Testnet3 gas is available from the faucet. Token contracts and enabled transfer capabilities remain deployment/merchant-specific.
Troubleshooting
Order creation
- Confirm key, timestamp, nonce, and signature inputs.
- Confirm merchant fee balance.
- Confirm the chain/token is enabled for this merchant.
- Treat HTTP
402as success only on documented challenge endpoints. - If status/proof/checkout/signature/cancel returns
402, the Server SDK fails closed; treat it as an endpoint or deployment mismatch.
Wallet transfer
- Confirm
chainId,fromAddress, andexpiresAtbefore callingpay(). - Confirm the token balance is at least
amountWei. - Read
PaymentResult.error;pay()normally does not throw its payment error.
Status does not advance
- Confirm token contract, recipient, amount, chain, and payer match the order.
- Allow for the deployment's confirmation/finality requirement.
- For Server SDK order polling,
INVOICEDis a successful terminal state. - For QuickPay session polling, use its separate terminal set; it does not
include
INVOICED.
GOAT Flow MPP transfer broadcast but verify failed
- If
MPPError.recoverableexists, callverifyChallenge()with it. - Do not call
pay()again for the same already-broadcast payment. - Confirm Core CORS allows the DApp origin and exposes
Payment-Receipt, and the protected resource allows that origin and request header.