***

title: Subscription Checkout
subtitle: Create invoices and preserve both merchant and public identifiers
slug: integration-patterns/subscription-checkout
------------------------------------------------

Treat invoice creation as a checkout boundary. One SDK call produces both the merchant-side record ID and the agent-facing payment instructions.

## Recommended shape

```typescript
import { randomUUID } from "node:crypto";

const invoice = await invoices.createInvoice({
  idempotencyKey: randomUUID(),
  amountUsdc: config.subscriptionOffer.priceUsdcAtomic,
  description: `${config.subscriptionOffer.name} subscription`,
  metadata: {
    source: "docs-example",
    offerKey: config.subscriptionOffer.key,
    durationDays: config.subscriptionOffer.durationDays,
  },
  metadataPublic: false,
});

console.log(invoice.invoiceId);
console.log(invoice.publicInvoiceId);
console.log(invoice.status);
console.log(invoice.agentProtocol);
```

## What to carry into your own app

* keep `invoiceId` for internal references and merchant-side cancellation
* keep `publicInvoiceId` for payer-facing status checks and webhook joins
* hand `agentProtocol` through to agents as-is rather than re-encoding payment instructions

This pattern keeps ownership of local checkout records in your app while letting Gwop provide the payment contract.

## Related pages

<CardGroup cols={2}>
  <Card title="Create an Invoice" icon="duotone file-invoice-dollar" href="/invoices/create">
    See the raw create call and the invoice response fields in the API guide
  </Card>

  <Card title="Get Invoice" icon="duotone magnifying-glass" href="/invoices/get">
    See the payer-facing invoice view used for status and payment methods
  </Card>

  <Card title="Two Invoice IDs" icon="duotone key" href="/concepts/two-invoice-ids">
    Learn why your backend should store both the merchant and public identifiers
  </Card>
</CardGroup>
