{
  "slug": "payment-receipt-email",
  "title": "Payment receipt email: template and code",
  "url": "https://www.courier.com/recipes/payment-receipt-email",
  "markdown": "https://www.courier.com/recipes/payment-receipt-email.md",
  "stage": "Account and security",
  "purpose": "Send a clean receipt after every payment, by email and in your app's Inbox.",
  "summary": "A payment receipt email confirms a successful payment with every line item, the subtotal, tax, and total, and a link to the full receipt. It sends by email and to your app's Inbox, which keeps a receipt history. If your payment webhook is retried within four days, the customer still gets one receipt.",
  "channels": [
    "email",
    "inbox"
  ],
  "shape": "send",
  "shows": [
    "A line-item list looped from a data array",
    "An Inbox copy tagged for your billing page",
    "An idempotency key held for four days, so a retried webhook sends one receipt"
  ],
  "data": [
    {
      "name": "receipt_number",
      "type": "string",
      "example": "R-20481",
      "note": "Also the idempotency key, held for four days, and the end of the receipt link"
    },
    {
      "name": "paid_at",
      "type": "string",
      "example": "2026-10-15T17:00:00Z",
      "note": "An ISO timestamp. The template formats it as a date in the recipient's timezone"
    },
    {
      "name": "payment_method",
      "type": "string",
      "example": "Visa ending in 4242"
    },
    {
      "name": "line_items",
      "type": "array",
      "example": "[{\"name\": \"Pro plan (monthly)\", \"amount\": 4900}, ...]",
      "note": "One object per item, amounts in cents"
    },
    {
      "name": "subtotal",
      "type": "integer",
      "example": "8600",
      "note": "In cents"
    },
    {
      "name": "tax",
      "type": "integer",
      "example": "731",
      "note": "In cents"
    },
    {
      "name": "total",
      "type": "integer",
      "example": "9331",
      "note": "In cents"
    }
  ],
  "steps": [
    {
      "step": "1",
      "when": "When a payment succeeds",
      "channels": "Email, Inbox",
      "templates": [
        "templates/receipt.json"
      ]
    }
  ],
  "files": {
    "templates": [
      "templates/receipt.json"
    ],
    "setup": [
      "setup.ts"
    ],
    "start": [
      "start.ts",
      "start.py"
    ]
  },
  "docs": [
    "https://www.courier.com/docs/design/elemental/control-flow",
    "https://www.courier.com/docs/in-app/send-to-the-inbox",
    "https://www.courier.com/docs/send/routing",
    "https://www.courier.com/docs/send/overview"
  ],
  "related_recipes": [
    "https://www.courier.com/recipes/dunning-email-sequence",
    "https://www.courier.com/recipes/expiring-card-reminder-email",
    "https://www.courier.com/recipes/subscription-renewal-reminder-email"
  ],
  "agent_prompt": "Add payment receipts to this app, sent through Courier: an email with every line item and the totals, plus an Inbox copy for the billing page. Follow the steps at https://www.courier.com/recipes/payment-receipt-email.md and use the Courier skill for SDK details.\n\n1. Create the template in my Courier workspace by running setup.ts from that page with COURIER_API_KEY from our environment. Save the template ID it prints as COURIER_RECEIPT_TEMPLATE_ID.\n2. Find where this codebase handles a successful payment (a payment webhook or the code right after a charge) and send the receipt there with the recipe's send code. Pass the fields in the Data fields table from our own data. Replace the placeholder product name (Acme) and receipt link (https://app.acme.com/billing/receipts/) in the template with ours.\n3. Keep the receipt number as the idempotency key, with the four-day expiration the send code sets, so a webhook retried within four days doesn't send a second receipt.\n4. Match this codebase's language, file layout, and error handling. Never hardcode the API key.\n5. When you're done, send one receipt with three line items to a test user and show me the rendered email.",
  "status": {
    "state": "passing",
    "last_tested": "2026-10-19"
  }
}
