Supported boundary
- x402 v2
exact, Base mainneteip155:8453. - Native USDC
0x833589fcd6edb6e08f4c7c32d4f71b54bda02913, six decimals. - EOA wallets signing EIP-3009
TransferWithAuthorization, domainUSD Coin, version2. - Existing Grantex assignment/layered policies, DPoP-bound OAuth, approvals and blocks.
- Other chains, assets, Permit2 and contract wallets remain unsupported.
/v1/x402/verify and /v1/x402/settle remain for grantex:prepaid. Grantex
independently reconciles chain evidence; a merchant HTTP 200 is not evidence
for updating the Base wallet ledger.
Provision custody
Use a dedicated address for each wallet. Do not spend it through another app or share it across Grantex deployments: independent ledgers cannot coordinate the same balance. A unique database index prevents duplicate Base custody addresses within one deployment. Apply the complete migration set, including094_base_usdc_custody.sql.
Configure these secrets on the authorization service, never in an agent,
browser, repository or command-line log:
Mapping shape, with placeholders only:
Create and fund
Using an authenticated principal-session client:walletAddress; its provisioned owner must match the
caller. Transfer native USDC through the operator’s approved funding process.
Grantex does not charge a card or convert fiat. Once the transfer is finalized,
credit it using the lowercase transaction hash and decimal transfer log index:
fundReload.
Assign recipients, resource origins, scopes, per-transaction and cumulative
limits through the usual principal API. Layered amount/count budgets and exact
approval policies also apply. Hex address letter case cannot evade policy.
Authorize and pay
Build the updated SDK and x402 package from this checkout:agent.fetch, not the exposed low-level agent.client, for request-bound
Base handling. The server encrypts and commits the signature with its balance
hold before returning it. The merchant gets no internal Grantex JWT or policy
metadata. Timeouts are 10-300 seconds, further bounded by grant, token and
assignment expiry.
Retries and blocks
Reuse the same idempotency key for the same logical request after response loss. Retries recover the same stored signature and nonce, including after a service restart. Changed terms conflict. After settlement/expiry, inspect reconciliation and the merchant’s stored result instead of automatically paying with a new key. Blocking stops new signatures, but cannot recall an existing one. Previously signed payments may still settle before their on-chain expiry. Revocation, policy changes, blocks and manual release cannot return that exposure to the available balance. Outstanding holds count against budgets across window edges. The service sweeps pending Base reservations every 30 seconds in bounded batches and log ranges. You can also reconcile explicitly:reconcileReservation in TypeScript,
reconcile_reservation in Python and ReconcileReservation in Go. Python
preserves evmPayment as a dictionary; TypeScript/Go have typed response fields.
Automatic x402 HTTP retries are provided by the TypeScript adapter, not newly
claimed as a Python/Go feature.
Settlement requires a finalized matching nonce event and transfer receipt.
Unused expiry requires a finalized block past expiry and an unused nonce.
RPC failure, stale chain time or missing evidence leaves funds reserved. A
consumed nonce without matching settlement evidence also remains reserved.
Finality can take longer than the payment timeout. Monitor old pending holds
and provider incidents; never manually credit them just to unblock spending.
Deployment and recovery runbook
- Back up PostgreSQL and the stable vault/signing keys. Deploy the reviewed server and complete migration set with Base custody still unconfigured.
- Confirm
/healthand the existing OAuth/prepaid regression suite. Deploying code alone does not activate a wallet or transfer funds. - After custody review, inject the protected RPC and exact owner-to-wallet mapping from your secret manager. Never use the Docker fixture keys or token contract in production. Fund and reconcile a dedicated limited-float wallet.
- Run one approved low-value compatibility payment, retaining the HTTP status, finalized transaction hash and matching ledger entry, not the signature/key.
- Operate reconciliation continuously. On request-throttled or scale-to-zero runtimes such as Cloud Run, the in-process timer is not a guaranteed scheduler. Use an always-allocated CPU instance with a minimum instance count, or an authenticated external worker calling the reconciliation API for pending IDs. Alert on stale pending holds and provider failures.
External responsibilities
Provision and protect a funded wallet, trusted RPC and custody process. Confirm facilitator support with the merchant. Merchant result recovery requires its HTTPIdempotency-Key result store; Grantex cannot add that to an unrelated API.
Notification delivery, KYC/AML, refunds, disputes and legal/provider approval
remain operator responsibilities.
The local tests use PostgreSQL, Redis, the auth-service, official x402 facilitator
code and an isolated Anvil chain with a test-only USDC contract. This verifies
real signatures and transfers locally, not Base-mainnet/PayAI availability. The
repository’s tests/base-usdc/README.md contains repeatable test commands.