{
  "slug": "expiring-card-reminder-email",
  "title": "Expiring card reminder email: template and code",
  "url": "https://www.courier.com/recipes/expiring-card-reminder-email",
  "markdown": "https://www.courier.com/recipes/expiring-card-reminder-email.md",
  "stage": "Monetization",
  "purpose": "Get cards updated before they expire, so a payment never fails over a date.",
  "summary": "An expiring card reminder gets customers to update a credit card before it expires, so a renewal payment doesn't fail. It emails them 30 days before the expiry date, then sends a second email and an Inbox note a week before. Updating the card stops any reminder that hasn't gone out.",
  "channels": [
    "email",
    "inbox"
  ],
  "shape": "journey",
  "shows": [
    "Starting from a billing job that finds expiring cards",
    "A 23-day wait before the second reminder",
    "Cancel when the card is updated"
  ],
  "data": [
    {
      "name": "profile.first_name",
      "type": "string",
      "example": "Dana",
      "note": "From the profile. \"there\" is the fallback when it's missing"
    },
    {
      "name": "plan_name",
      "type": "string",
      "example": "Pro"
    },
    {
      "name": "card_brand",
      "type": "string",
      "example": "Visa"
    },
    {
      "name": "card_last4",
      "type": "string",
      "example": "4242"
    },
    {
      "name": "expires_at",
      "type": "string",
      "example": "2026-11-30T17:00:00Z",
      "note": "An ISO timestamp. The templates format it as a date in the recipient's timezone"
    }
  ],
  "steps": [
    {
      "step": "1",
      "when": "When the journey starts, 30 days before the card expires",
      "channels": "Email",
      "templates": [
        "templates/card-expiring-email.json"
      ]
    },
    {
      "step": "2",
      "when": "23 days after the first email, 7 days before the card expires",
      "channels": "Email, Inbox",
      "templates": [
        "templates/card-expiring-final-email.json",
        "templates/card-expiring-final-inbox.json"
      ]
    }
  ],
  "files": {
    "journey": "journey.json",
    "templates": [
      "templates/card-expiring-email.json",
      "templates/card-expiring-final-email.json",
      "templates/card-expiring-final-inbox.json"
    ],
    "setup": [
      "setup.ts"
    ],
    "start": [
      "start.ts",
      "start.py"
    ],
    "stop": [
      "stop.ts",
      "stop.py"
    ]
  },
  "docs": [
    "https://www.courier.com/docs/guides/notify-from-stripe",
    "https://www.courier.com/docs/journeys/nodes/delay",
    "https://www.courier.com/docs/journeys/nodes/cancel",
    "https://www.courier.com/docs/journeys/invoke"
  ],
  "related_recipes": [
    "https://www.courier.com/recipes/dunning-email-sequence",
    "https://www.courier.com/recipes/subscription-renewal-reminder-email",
    "https://www.courier.com/recipes/payment-receipt-email"
  ],
  "agent_prompt": "Add expiring card reminders to this app, sent through Courier: an email 30 days before a customer's card expires, then an email and in-app note 7 days before, stopped as soon as they update the card. Follow the steps at https://www.courier.com/recipes/expiring-card-reminder-email.md and use the Courier skill for SDK details.\n\n1. Create the journey and its three templates in my Courier workspace by running setup.ts from that page with COURIER_API_KEY from our environment. Save the journey ID it prints as COURIER_CARD_JOURNEY_ID. Replace the placeholder billing link (https://app.acme.com/billing/card) in the templates with ours.\n2. Find where this codebase checks payment methods (a daily billing job, or the payment provider's card-expiring webhook) and start the journey with the user's ID when a card is 30 days from expiring. Pass the fields in the Data fields table from our own data.\n3. Find where a customer saves a new card and cancel the journey with the token card-<user ID>.\n4. Match this codebase's language, file layout, and error handling. Never hardcode the API key.\n5. When you're done, start one run for a test user and show me the run's steps. The first email sends right away and the run then waits 23 days, so cancel the test run once you've checked it.",
  "status": {
    "state": "passing",
    "last_tested": "2026-10-19"
  }
}
