x402 Giftcard Purchase
The giftcard plugin is a real consumer flow built on x402: agents pay cross-chain in stablecoins, and the GOAT giftcard backend fulfills the order off-chain (delivers a digital giftcard code by email or hands off to a brand integration). It's a turnkey reference for "Agent pays → user receives off-chain good".
End users buy via the agentkit-giftcard CLI; programmatic consumers use the plugin's 8 actions directly.
Quick Start (CLI)
The CLI bundles the full create-order → pay-order → poll-until-fulfilled sequence into a single buy subcommand. Brand catalogs are region-scoped (the upstream API silently defaults to US if you don't pick one), so the very first step is to discover which regions you can purchase from:
Region matters: the upstream giftcard API silently defaults to US if --country is omitted, which hides catalogs for other regions (e.g. CA). The CLI forces you to pick — either interactively (TTY prompt with US as the default), or via --country <iso2> in non-interactive contexts. Run regions first to see what's available.
Use --reveal-secrets on status / list-orders to print the delivered card_code / card_pin / card_link in the clear (redacted by default).
Actions
| Action | Name | Risk | Description |
|---|---|---|---|
listBrandsAction | goat.giftcard.listBrands | read | List supported giftcard brands (filter by country / category / language) |
getBrandAction | goat.giftcard.getBrand | read | Details for one brand including products + denominations |
listCategoriesAction | goat.giftcard.listCategories | read | Brand category taxonomy |
listSupportedTokensAction | goat.giftcard.listSupportedTokens | read | Per-chain supported ERC-20 payment tokens |
createOrderAction | goat.giftcard.createOrder | medium | Create a giftcard order. Requires product_id (UUID), face_value, pay_chain_id, pay_token_symbol, and an idempotency_key matching ExecutionOptions.idempotencyKey |
payOrderAction | goat.giftcard.payOrder | high | Broadcast the source-chain ERC-20 transfer that funds the order |
getOrderAction | goat.giftcard.getOrder | read | Status snapshot (lifecycle below) |
listOrdersAction | goat.giftcard.listOrders | read | List the agent's past orders |
Supported Source Chains
The giftcard backend accepts cross-chain payments from:
| Chain | Chain ID | Common Stablecoins |
|---|---|---|
| GOAT mainnet | 2345 | USDC, USDT (default — no PAYMENT_CHAIN_* env vars needed) |
| Polygon | 137 | USDC, USDT |
| Base | 8453 | USDC |
| Arbitrum | 42161 | USDC, USDT |
| Optimism | 10 | USDC, USDT |
| BSC | 56 | USDT (18 decimals — different from the 6-decimal USDC/USDT on other chains) |
| Metis | 1088 | USDC, USDT |
Use goat.giftcard.listSupportedTokens for the authoritative per-chain token addresses + decimals at runtime.
Order Lifecycle
The full GiftcardOrderStatus enum:
The giftcard lifecycle includes PAYMENT_PENDING as a real state — distinct from the GNS x402 lifecycle, which never emits PAYMENT_PENDING. The two flows hit different backend services with different state machines; do not conflate them.
Architecture
EIP-712 auth + Redis single-flight
Eip712AuthSigner obtains a session token from the giftcard backend by signing an EIP-712 typed message with the agent's wallet. Under concurrent load (e.g. two agents from the same wallet starting at the same time), it uses single-flight to ensure only one token request goes to the backend per (wallet, expiry-bucket) — duplicate concurrent callers wait for the in-flight request and share the result. Single-process callers (the default — including the CLI) use an in-memory single-flight; multi-process / multi-instance deployments can inject a GiftcardRedisClient into HttpGiftcardGatewayAdapter via the redis option for distributed deduplication.
The auth-signer constructor takes a WalletProvider (the wallet that signs the auth message) plus an optional Eip712AuthSignerOptions for domain override.
Safety posture (payOrder / CLI buy)
payOrder is a money path with multiple defenses:
- Lifecycle gate: explicit
status === 'PAYMENT_PENDING'. Refuses to double-pay any non-pending order (FAIL-CLOSED on missing / empty status to avoid truthy-gate bypass). - Chain binding:
wallet.getChainId() === order.pay_chain_id(elseINVALID_INPUT('chain_mismatch')); refuses to broadcast on the wrong chain. - Expiry safety margin: refuses to pay inside the last 30 seconds before
expire_at(else the transfer could land after expiry). NoopWalletProviderrefusal: the CLI hard-refuses to runbuyagainst aNoopWalletProvideroutsideDEMO_MOCK=true. A real signer is mandatory for any production purchase.- Per-orderId single-flight: module-scope Map dedupes concurrent
payOrdercalls for the sameorder_id(double-pay TOCTOU defense). - Idempotency-key contract:
createOrder.idempotency_keyMUST equal theExecutionOptions.idempotencyKeypassed toruntime.run(...); the action rejects withINVALID_INPUTbefore any HTTP traffic on mismatch, so the runtime cache short-circuit and the backend dedup both line up.
Programmatic Usage
Environment Variables
| Variable | Required | Description |
|---|---|---|
GOAT_PRIVATE_KEY | Yes | Wallet key that signs EIP-712 auth and (when paying on GOAT) broadcasts the source-chain transfer |
PAYMENT_CHAIN_RPC_URL | When --pay-chain is non-GOAT | RPC URL of the source chain you're paying from |
PAYMENT_CHAIN_ID | When --pay-chain is non-GOAT | Numeric chain id of the source chain (sanity check) |
PAYMENT_CHAIN_PRIVATE_KEY | Optional | Source-chain signer key; falls back to GOAT_PRIVATE_KEY when omitted |
GIFTCARD_API_BASE_URL | Optional | Override default https://giftcard-api.goat.network |
GIFTCARD_AUTH_DOMAIN_NAME / _VERSION / _CHAIN_ID | Optional | EIP-712 auth domain override |
DEMO_MOCK | Optional | true allows the CLI to run buy --dry-run with a NoopWalletProvider for shape demos only |
Redis-backed single-flight for the auth signer is enabled by injecting a GiftcardRedisClient into HttpGiftcardGatewayAdapter (the redis option), not via an environment variable. The CLI runs with the in-process fallback; production deployments that need cross-process dedup pass a Redis client to the adapter constructor directly.
Examples
examples/giftcard-purchase— full end-to-end demobin/_lib/cli-giftcard.ts— the reference implementation of theagentkit-giftcardCLI
Related
- CLIs —
agentkit-giftcardflags and env vars - Plugins Reference — full inventory of all 15 plugins
- x402 Payments — the underlying agent payment protocol
- GNS — the other consumer flow (
.goatname registration paid cross-chain via x402)