For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Apply for AccessDashboard
Guides
Guides
  • Get Started
    • Introduction
    • Quickstart
  • Agent Identity
    • Overview
    • Create Auth Intent
    • Exchange for JWT
    • Sessions
    • JWKS
  • Agent Checkout
    • Overview
    • Create an Invoice
    • List Invoices
    • Get Invoice
    • Cancel Invoice
  • Integration Patterns
    • Overview
    • Shared SDK Client
    • Wallet Auth
    • JWT Verification
    • Subscription Checkout
    • Webhook Verification
  • Concepts
    • Two Invoice IDs
    • Wallet Identity
    • Session vs Token
    • Webhook-Driven State
  • Webhooks
    • Overview
    • Verify Signatures
  • Reliability
    • Errors
    • SDK Reference
Apply for AccessDashboard
On this page
  • Create an invoice
  • Response
  • Parameters
  • Two IDs
  • Fees
  • Agent Protocol
  • Step 1: The protocol tells the agent where to look
  • Step 2: The agent fetches the public invoice and finds the x402 rails
  • Step 3: The agent pays
  • Idempotency
  • Custom Expiry
  • Public Metadata
  • Next step
Agent Checkout

Create an Invoice

Open an agent checkout with multi-chain x402 payment rails

||View as Markdown|
Was this page helpful?
Edit this page
Previous

Invoices

Next

List Invoices

Built with

Creating a Gwop invoice opens an agent checkout — a headless payment session with x402 rails for every supported chain. You define the amount and what you are selling. Gwop ties the payment URLs to the session and returns everything the agent needs to discover and pay the checkout.

The agent fetches the public invoice, picks a chain, and pays the session-scoped x402 URL — the same way it would pay any other x402 endpoint.

Create an invoice

1import { Gwop } from "@gwop/sdk";
2
3const gwop = new Gwop({
4 merchantApiKey: process.env.GWOP_MERCHANT_API_KEY,
5});
6
7const { result: invoice } = await gwop.invoices.create({
8 idempotencyKey: crypto.randomUUID(),
9 body: {
10 amountUsdc: 5_000_000, // $5.00 USDC (6 decimals)
11 description: "Starter plan — 300 credits",
12 },
13});
14
15console.log(invoice.publicInvoiceId); // inv_7dbeeaad... — hand this to the agent
16console.log(invoice.agentProtocol); // machine-readable checkout session
17console.log(invoice.status); // "OPEN"

Response

1{
2 "id": "ba7bc94a-5468-42f4-9f04-2502e50c7501",
3 "publicInvoiceId": "inv_7dbeeaad8ebf4f5298c380c90e4b3576",
4 "merchantId": "9e9c9ba5-3bab-4172-8a79-336f9ca0f163",
5 "amountUsdc": 1025000,
6 "currency": "USDC",
7 "status": "OPEN",
8 "description": "SDK test invoice",
9 "metadata": {
10 "test": "true",
11 "fee_usdc": 25000,
12 "base_amount_usdc": 1000000,
13 "fee_basis_points": 250,
14 "total_amount_usdc": 1025000
15 },
16 "metadataPublic": false,
17 "createdAt": "2026-03-25T01:42:45.287Z",
18 "expiresAt": "2026-03-25T01:57:45.232Z",
19 "agentProtocol": { "..." : "..." }
20}

Parameters

FieldTypeRequiredDefaultDescription
amountUsdcnumberYes—Amount in atomic USDC (6 decimals). 1_000_000 = $1.00
descriptionstringNo—Human-readable invoice description
metadataobjectNo—Arbitrary key-value pairs stored with the invoice
metadataPublicbooleanNofalseWhen true, metadata is visible to the payer via the public invoice endpoint
expiresInSecondsnumberNo900Invoice TTL in seconds. Minimum 60, default 15 minutes

The idempotencyKey is sent as a header. Always use crypto.randomUUID() for new invoices.

Two IDs

Every invoice has two identifiers:

FieldFormatWho uses itExample
idUUID v4Merchant (your backend)ba7bc94a-5468-42f4-9f04-2502e50c7501
publicInvoiceIdinv_*Payer / agentinv_7dbeeaad8ebf4f5298c380c90e4b3576

Your backend stores id for cancel and internal lookups. You hand publicInvoiceId to the agent.

Fees

amountUsdc in the create response is the source of truth for what the payer owes. If Gwop applies fees or other pricing adjustments, the returned amountUsdc can be higher than the base amount you sent. The response metadata may also include the pricing breakdown:

1{
2 "fee_usdc": 25000,
3 "base_amount_usdc": 1000000,
4 "fee_basis_points": 250,
5 "total_amount_usdc": 1025000
6}

Build your pricing around the base amount you send, but display or enforce the total using the response fields Gwop returns.

Agent Protocol

The agentProtocol field is the machine-readable checkout instruction set you hand to the agent. It tells the agent how to discover payment methods and complete the purchase — hand it through as-is.

Step 1: The protocol tells the agent where to look

1{
2 "version": "1.0",
3 "flow": "invoice_checkout",
4 "state": "invoice_created",
5 "goal": "Reach invoice payment completion deterministically.",
6 "steps": [
7 "Fetch invoice details to discover available payment_methods.",
8 "Choose a method+network option from payment_methods and execute its contract."
9 ],
10 "nextAction": {
11 "method": "GET",
12 "path": "/v1/invoices/inv_af95ad98fadb4599aab6373ac812842e",
13 "expectStatus": [200, 404],
14 "retry": { "strategy": "none" }
15 },
16 "completionCheck": {
17 "method": "GET",
18 "path": "/v1/invoices/inv_af95ad98fadb4599aab6373ac812842e",
19 "field": "status",
20 "successValue": "PAID"
21 },
22 "receiptPolicy": {
23 "mode": "hard_optional",
24 "optionalReceiptEmail": false,
25 "promptWhenAvailable": true,
26 "doNotBlockOnAbsent": true
27 }
28}

The protocol points the agent to the public invoice via nextAction. The agent follows that path and discovers the actual x402 payment URLs.

Step 2: The agent fetches the public invoice and finds the x402 rails

When the agent GETs the public invoice, it sees the full checkout session with one x402 payment method per chain:

1{
2 "paymentMethods": [
3 {
4 "id": "x402-base",
5 "kind": "x402",
6 "network": "eip155:8453",
7 "chain": "base",
8 "asset": {
9 "symbol": "USDC",
10 "decimals": 6,
11 "contract": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
12 },
13 "payTo": "0xcFf8Dcf2e9562Ec4D77E387902BB52Ea18539215",
14 "amount": 1025000,
15 "amountDisplay": "1.025 USDC",
16 "paymentUrl": "https://agents.gwop.io/v1/invoices/inv_.../x402/base",
17 "recoverUrl": "https://agents.gwop.io/v1/invoices/inv_.../x402/base/recover"
18 },
19 {
20 "id": "x402-solana",
21 "kind": "x402",
22 "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
23 "chain": "solana",
24 "asset": {
25 "symbol": "USDC",
26 "decimals": 6,
27 "contract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
28 },
29 "payTo": "BL24KoQbSate4NkfbGoyqK3ts8ck8fjiXrM3K3BJ9Hpr",
30 "amount": 1025000,
31 "amountDisplay": "1.025 USDC",
32 "paymentUrl": "https://agents.gwop.io/v1/invoices/inv_.../x402/solana",
33 "recoverUrl": "https://agents.gwop.io/v1/invoices/inv_.../x402/solana/recover"
34 }
35 ]
36}

Step 3: The agent pays

The agent picks a chain and pays the paymentUrl — the same way it would pay any x402 endpoint. The URL is scoped to this checkout session, not a permanent merchant endpoint. After payment settles, completionCheck confirms status === "PAID" and your backend receives a webhook.

Idempotency

Passing the same idempotencyKey returns the original response without creating a duplicate invoice. This makes retries safe:

1const key = crypto.randomUUID(); // generate once, retry with same key
2
3// First call creates the invoice
4const { result: first } = await gwop.invoices.create({
5 idempotencyKey: key,
6 body: { amountUsdc: 5_000_000 },
7});
8
9// Retry with same key returns the same invoice
10const { result: second } = await gwop.invoices.create({
11 idempotencyKey: key,
12 body: { amountUsdc: 5_000_000 },
13});
14
15first.id === second.id; // true

Always generate the idempotency key before the try/catch block so retries use the same key.

Custom Expiry

Invoices expire after 15 minutes by default. Set expiresInSeconds to customize:

1const { result } = await gwop.invoices.create({
2 idempotencyKey: crypto.randomUUID(),
3 body: {
4 amountUsdc: 1_000_000,
5 expiresInSeconds: 60, // 1 minute
6 },
7});
8
9// expiresAt will be ~60 seconds after createdAt

Public Metadata

By default, metadata is only visible to the merchant. Set metadataPublic: true to make it visible to the payer through the public invoice endpoint:

1const { result } = await gwop.invoices.create({
2 idempotencyKey: crypto.randomUUID(),
3 body: {
4 amountUsdc: 5_000_000,
5 description: "Starter plan",
6 metadata: { planName: "Starter", credits: 300 },
7 metadataPublic: true, // agent can see this
8 },
9});

This is useful when the agent needs context about what it’s paying for.

Next step

Get Invoice

Public checkout view the agent sees — payment methods, pricing, and status polling

Webhooks

Get notified when the agent pays — invoice.paid, expired, and canceled events