Skip to content

Recurring and repeat payments

Bill subscriptions and invoices with one payment per period, sent to the customer on your schedule.

402pay has no subscription object and never charges anyone on its own: crypto can't be pulled from a customer's wallet, and cards aren't kept on file. Bill each period with a payment of its own, created by your server on your schedule, and send the customer its url.

One payment per period

Make the reference name the subscription and the period, such as sub_42-2026-10. A retried run of your billing job then gets the same payment back, and each period gets its own.

Bill a period
curl -X POST "https://dash.402pay.co/api/v1/payments" \  -H "Authorization: Bearer $PAY402_SECRET_KEY" \  -H "Content-Type: application/json" \  -d '{    "amount": 4900,    "currency": "USD",    "reference": "sub_42-2026-10",    "description": "Pro plan, October 2026",    "customer_email": "harper.wilson@example.com",    "success_url": "https://example.com/billing",    "metadata": {      "subscription_id": "sub_42",      "period": "2026-10"    }  }'
  • customer_email links the payment to the customer, adding one if they're new, and checkout doesn't ask them for it again.
  • Put the subscription and period in metadata too, so you can list and filter them later.
  • The amount is fixed per payment. For a plan change mid-period, bill the new price on the next period's payment, or cancel this one and create it again.

Send it to the customer

402pay doesn't email customers. Send the payment's url yourself, in your billing email or in your app, with the amount and the period it covers. The same link works until the payment is paid, expires or is canceled.

Due dates and reminders

  • Set expires_at to the end of your grace period, up to 30 days out. Without it, a payment expires after 24 hours, which is short for an invoice.
  • A payment never expires while the customer has a checkout open for it. When it does, you receive payment.expired.
  • An expired payment frees its reference. To give a late customer another chance, create the payment again with the same reference and send the new url.

Track what's paid

Mark the period paid on payment.succeeded, whose payment carries your reference and metadata. To see a subscription's history, filter payments by its metadata.

A subscription's payments
curl -g "https://dash.402pay.co/api/v1/payments?metadata[subscription_id]=sub_42&status=succeeded" \  -H "Authorization: Bearer $PAY402_SECRET_KEY"

GET /payments?customer_id=… lists every payment of one customer, across subscriptions.

Good to know

  • A blocked customer can't pay: checkout refuses their email with 403 customer_blocked. Block or unblock someone in the dashboard or with PATCH /customers/{id}.
  • A payment link can take the same price again and again, but its payments have no reference, so you match them to customers by email rather than to periods. For billing, a payment per period is easier to reconcile.
  • Amounts are in your currency, and checkout quotes the coin amount when the customer pays, so a period costs the same whatever a coin's price does.