Subscriptions
This page describes the complete lifecycle of a Subscription: its status flow, what each status means, the notifications you receive, the structure of the callback payload, and how to query updates.
A Subscription emits two distinct kinds of status update. Keep them separate when building your integration:
- Subscription status update — a change in the state of the recurring agreement itself (e.g.
PENDING → ACTIVE,ACTIVE → SUSPENDED,→ CANCELED). Covered by the Status Map below. - Payment status update (of a Subscription charge) — a change in the state of an individual payment generated by the subscription's billing cycle (e.g.
PROCESSING → PAID). These follow the Payments status flow, not the subscription status flow.
Status Map
The Subscription entity functions as a state machine. Its status transitions are driven by three primary factors:
- Enrollment Events: The authorization process with the Financial Institution (PSP).
- Billing Results: Success or failure of recurring charges (including retries).
- Manual Interventions: Actions triggered by the merchant (e.g., suspension, cancellation) or the payer (e.g., revocation).
The following flowchart illustrates all valid transitions within the subscription lifecycle.
Status Description
Onboarding & Enrollment Phase
Statuses related to the setup of the subscription and the initial authorization with the PSP.
| Status | Description |
|---|---|
| CREATED | The subscription object has been initialized in our system but the enrollment request has not yet been sent to the PSP. |
| PENDING | The enrollment request has been sent and is awaiting Payer authorization (e.g., via Bank App) or PSP confirmation. |
| ACTIVE | The Goal State. The enrollment is authorized, and the subscription is healthy, valid, and ready to process charges according to the schedule. |
| DECLINED | The enrollment request was immediately declined by the PSP (e.g., invalid data or business rules). |
| REJECTED | The payer actively rejected the enrollment request in their banking app, or the PSP rejected it after analysis. |
| EXPIRED | The time window for the payer to authorize the enrollment (QR Code) has elapsed without action. |
| ERROR | A technical error occurred during the setup process preventing the enrollment. |
Operational & Billing Phase
Statuses indicating the ongoing health of an active subscription based on payment performance.
| Status | Description |
|---|---|
| PAST_DUE | A scheduled payment failed, but the Retry Policy is still active. The system will attempt to charge again within the defined window. |
| UNPAID | All retry attempts defined in the policy have failed. The subscription remains valid but is in default. |
| SUSPENDED | The merchant has manually paused the subscription. No new charges will be generated until it is reactivated. |
Terminal States
Final states from which a subscription typically cannot return to ACTIVE (unless a new enrollment is created).
| Status | Description |
|---|---|
| FINISHED | The subscription has reached its natural endDate as defined in the schedule. |
| CANCELED | The subscription was manually terminated by the merchant or the system (e.g., due to long-term default). |
| REVOKED | Critical State. The underlying authorization was revoked by the Payer directly at their bank or by the Financial Institution. No further charges are possible. |
Notification
A subscription integration receives two kinds of notification — keep them separate:
| Kind | What changed | Where the status flow is documented |
|---|---|---|
| Subscription status notification | The recurring agreement itself changed state (e.g. PENDING → ACTIVE, ACTIVE → SUSPENDED, → CANCELED). | The Status Map on this page. |
| Subscription payment notification | An individual charge generated by a billing cycle changed state (e.g. PROCESSING → PAID). | Payments - Status Maps & Updates. |
Configure where each notification is delivered when creating the subscription: subscription-notification-url receives subscription-lifecycle events, while notification-url receives the payment-lifecycle events of each generated charge.
A subscription status notification carries the subscription identifiers:
{
"subscription_id": "SUBSCRIPTION_ID",
"reference_id": "SUBSCRIPTION_REFERENCE_ID"
}
The identifiers returned differ depending on what you query or receive:
| Context | Identifiers returned |
|---|---|
Calling the Subscription endpoint (GET /subscriptions/{id}) | The Subscription id and the Subscription reference_id. |
| Receiving a Subscription payment notification | The Payment reference_id and the Subscription reference_id, so the individual charge can be reconciled against its parent agreement. |
This dual-reference behavior is what lets you tie a single charge to both the payment and the subscription that generated it. See Payments → Notification for the payment-side view.
All notifications are sent from a fixed set of source IP addresses. Add them to the allowlist of your notification endpoint, and always query the Update Endpoint again after each notification you receive, since the notification is only a trigger and does not carry the final status of the transaction. See Validating Notifications on the Payments page for the source IP list and the full procedure.
Update Endpoint
Retrieve the current state of a subscription on demand. Identify the subscription by its id; the response returns the subscription object including its id, reference_id, and status.
GET https://api-sandbox.letpay.io/subscriptions/SUBSCRIPTION_ID
| AUTHORIZATION | API Key |
|---|---|
| Key | X-Auth-Token |
| Value | MY_ACCESS_TOKEN |
- 200 - Success
Example Request
curl --location 'https://api-sandbox.letpay.io/subscriptions/SUBSCRIPTION_ID' \
--header 'X-Auth-Token: MY_ACCESS_TOKEN'
Example Response
Content-Type: application/json
{
"id": "cc6effd7-2100-47ee-b483-5b4ac719f97d",
"reference_id": "MY_REFERENCE_ID",
"status": "ACTIVE",
"created_at": "2025-10-01T12:34:56.123",
"error_code": null,
"error_description": null,
"due_date": "2025-10-05",
"end_date": null,
"periodicity": "WEEKLY",
"force_work_day": true,
"merchant_initiation": false,
"order_amount": "100.00",
"order_currency": "BRL",
"payment_country": "BR",
"payment_currency": "BRL",
"amount_type": "FIXED",
"scheme": "PIX_AUTOMATICO",
"retry_policy": "NOT_ALLOW",
"minimum_amount": 1
}
To query an individual payment generated by the subscription, use the Payments Update Endpoint.