Subscribe Pay
The Subscribe Pay capability enables recurring subscription billing. A payer agent subscribes to a service plan, and the subscription automatically renews at each billing interval, generating new PaymentIntents and QR codes for each renewal.
Swimlane Diagrams
The following swimlane diagrams trace the full subscription lifecycle across the four parties: Human (Payer), Agent (Buyer), ItPay Protocol, and Channel (Alipay).
1. Subscription Creation & Authorization
The human requests a subscription, the agent creates it, and the human authorizes the first payment via QR.
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ "Subscribe to │ │ │
│ Pro for $29.99"│ │ │
│─────────────────>│ │ │
│ │ │ │
│ │ POST /v1/subscriptions │
│ │──────────────────> │
│ │ │ │
│ │ 201 Created │ │
│ │ { │ │
│ │ status: │ │
│ │ "pending", │ │
│ │ first_payment:│ │
│ │ {qr: {...}} │ │
│ │ } │ │
│ │<──────────────────│ │
│ │ │ │
│ Show QR code │ │ │
│ "Scan to pay │ │ │
│ $29.99" │ │ │
│<─────────────────│ │ │
│ │ │ │
│ Scans QR with │ │ │
│ phone & auths │ │ │
│──────────────────────────────────────────────> │
│ │ │ │
│ │ │ Payment │
│ │ │ confirmed │
│ │ │<────────────────│
│ │ │ │
│ "Payment sent!" │ │ │
│<────────────────────────────────────────────── │
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ activated │ │
│ │<──────────────────│ │
│ │ │ │
│ "Pro plan is │ │ │
│ active!" │ │ │
│<─────────────────│ │ │
Interaction Trace — Subscription Creation:
// Step 1 — Agent creates subscription
// REQUEST
POST /v1/subscriptions
Content-Type: application/json
Authorization: Bearer ***
{
"service_id": "01J7XYKZ1A2B3C4D5E6F7G8H9I",
"plan_id": "plan_pro",
"channel": "alipay",
"payer_info": {
"agent_id": "agent_cli_a1b2c3d4",
"human_id": "user_abc_789"
},
"auto_renew": true,
"return_url": "https://summarybot.ai/welcome"
}
// RESPONSE
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "pending",
"plan": {
"plan_id": "plan_pro",
"name": "Pro",
"amount": 2999,
"currency": "USD",
"interval": "monthly"
},
"first_payment": {
"payment_intent_id": "pi_01J7Y6A7B8C9D0E1F2G3H4I5K",
"qr": {
"charge_id": "qr_01J7Y6B7C8D9E0F1G2H3I4J5L",
"scan_url": "https://pay.summarybot.ai/qr/qr_01J7Y6B7C8D9E0F1G2H3I4J5L"
},
"status": "pending",
"expires_at": "2026-05-27T09:30:00Z"
},
"current_period": {
"start": "2026-05-27T09:15:00Z",
"end": "2026-06-27T09:15:00Z"
}
}
// Step 2 — Human scans QR, authorizes in Alipay
// (No direct API call — human action in Alipay app)
// Step 3 — Alipay confirms payment to ItPay
// (Internal callback from payment channel)
// Step 4 — ItPay sends activation webhook
// WEBHOOK (sent to agent's webhook endpoint)
{
"id": "evt_01J7Y7A8B9C0D1E2F3G4H5I6J",
"type": "subscription.activated",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "active",
"current_period": {
"start": "2026-05-27T09:15:00Z",
"end": "2026-06-27T09:15:00Z"
},
"payment_intent_id": "pi_01J7Y6A7B8C9D0E1F2G3H4I5K"
},
"created_at": "2026-05-27T09:16:00Z"
}
2. Auto-Renewal Cycle
When the billing period ends, ItPay automatically creates a new PaymentIntent. The agent auto-pays (if under auto_pay_limit) or shows a new QR code.
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ [Billing period │ │ │
│ ends] │ │ │
│ │ │ Creates new │
│ │ │ PaymentIntent │
│ │ │ for $29.99 │
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ renewed │ │
│ │<──────────────────│ │
│ │ │ │
│ │ Checks amount: │ │
│ │ $29.99 <= │ │
│ │ auto_pay_limit │ │
│ │ ($100.00) ✓ │ │
│ │ │ │
│ │ Auto-pay via │ │
│ │ saved channel │ │
│ │──────────────────> │
│ │ │ │
│ │ │ Process payment │
│ │ │────────────────>│
│ │ │ │
│ │ │ Settlement │
│ │ │ confirmed │
│ │ │<────────────────│
│ │ │ │
│ "Auto-renewed: │ │ │
│ $29.99 charged │ │ │
│ — Pro plan │ │ │
│ continues" │ │ │
│<─────────────────│ │ │
│ │ │ │
│ [Service │ │ │
│ delivery │ │ │
│ continues] │ │ │
Interaction Trace — Auto-Renewal:
// Step 1 — ItPay creates renewal PaymentIntent (automatic)
// No explicit API call — ItPay handles internally at period end
// Step 2 — ItPay sends renewal webhook
// WEBHOOK
{
"id": "evt_01J7Y8C9D0E1F2G3H4I5J6K7L",
"type": "subscription.renewed",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"new_period": {
"start": "2026-06-27T09:15:00Z",
"end": "2026-07-27T09:15:00Z"
},
"payment_intent_id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"amount": {
"currency": "USD",
"value": 2999
}
},
"created_at": "2026-06-27T09:15:05Z"
}
// Step 3 — Agent fetches payment intent details
// REQUEST
GET /v1/payment_intents/pi_01J7Y8C9D0E1F2G3H4I5J6K7M
Authorization: Bearer ***
// RESPONSE
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"amount": { "currency": "USD", "value": 2999 },
"status": "pending",
"qr": {
"charge_id": "qr_01J7Y8D9E0F1G2H3I4J5K6L7N",
"scan_url": "https://pay.summarybot.ai/qr/qr_01J7Y8D9E0F1G2H3I4J5K6L7N"
}
}
// Step 4 — Agent auto-pays (automatically processes payment
// using saved channel credentials, no human QR needed)
// REQUEST (internal — agent sends payment instruction)
POST /v1/payment_intents/pi_01J7Y8C9D0E1F2G3H4I5J6K7M/pay
Authorization: Bearer ***
Content-Type: application/json
{
"channel": "alipay",
"auto": true
}
// RESPONSE
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"status": "processing",
"amount": { "currency": "USD", "value": 2999 }
}
3. Failed Renewal with Retries
When a renewal payment fails, the subscription enters past_due with retry attempts and new QR codes.
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ [Current period │ │ │
│ ends] │ │ │
│ │ │ Creates new │
│ │ │ PaymentIntent │
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ renewed │ │
│ │<──────────────────│ │
│ │ │ │
│ │ Auto-pay │ │
│ │ attempt fails │ │
│ │──────────────────> │
│ │ │ │
│ │ │ Insufficient │
│ │ │ funds / decline│
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ past_due │ │
│ │<──────────────────│ │
│ │ │ │
│ "Payment issue: │ │ │
│ scan to retry │ │ │
│ $29.99" │ │ │
│<─────────────────│ │ │
│ │ │ │
│ ── Retry #1 ── │ │ │
│ │ │ │
│ Scans new QR │ │ │
│──────────────────────────────────────────────> │
│ │ │ │
│ │ │ Payment fails │
│ │ │ again │
│ │ │ │
│ ── Retry #2 ── │ │ │
│ │ │ │
│ Scans new QR │ │ │
│──────────────────────────────────────────────> │
│ │ │ │
│ │ │ Payment │
│ │ │ confirmed! │
│ │ │<────────────────│
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ renewed (paid) │ │
│ │<──────────────────│ │
│ │ │ │
│ "Payment │ │ │
│ successful! │ │ │
│ Pro plan │ │ │
│ restored" │ │ │
│<─────────────────│ │ │
Interaction Trace — Failed Renewal:
// Step 1 — ItPay detects auto-pay failure, sends past_due webhook
// WEBHOOK
{
"id": "evt_01J7Y9A0B1C2D3E4F5G6H7I8J",
"type": "subscription.past_due",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "past_due",
"retry_count": 1,
"max_retries": 3,
"next_retry_at": "2026-06-28T09:15:00Z",
"payment_intent_id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"amount": { "currency": "USD", "value": 2999 }
},
"created_at": "2026-06-27T09:15:30Z"
}
// Step 2 — Agent shows new QR to human
// (Agent fetches PaymentIntent which returns a fresh QR)
// Step 3 — Human scans QR, retries payment
// (Human action in Alipay app — may succeed or fail)
// Step 4 — On success, ItPay sends renewed webhook
// WEBHOOK
{
"id": "evt_01J7Y9B1C2D3E4F5G6H7I8J9K",
"type": "subscription.renewed",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "active",
"new_period": {
"start": "2026-06-27T09:30:00Z",
"end": "2026-07-27T09:30:00Z"
},
"payment_intent_id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"amount": { "currency": "USD", "value": 2999 }
},
"created_at": "2026-06-27T09:30:05Z"
}
4. Cancellation Flow
The human or agent can cancel a subscription at any time. The subscription stops renewing and enters the cancelled state.
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ "Cancel my │ │ │
│ subscription" │ │ │
│─────────────────>│ │ │
│ │ │ │
│ │ POST │ │
│ │ /v1/subscriptions│ │
│ │ /:id/cancel │ │
│ │──────────────────> │
│ │ │ │
│ │ 200 OK │ │
│ │ { │ │
│ │ status: │ │
│ │ "cancelled", │ │
│ │ cancelled_at: │ │
│ │ "2026-07-15..."│ │
│ │ } │ │
│ │<──────────────────│ │
│ │ │ │
│ │ Webhook: │ │
│ │ subscription. │ │
│ │ cancelled │ │
│ │<──────────────────│ │
│ │ │ │
│ "Subscription │ │ │
│ cancelled. │ │ │
│ Access ends │ │ │
│ Jul 27" │ │ │
│<─────────────────│ │ │
│ │ │ │
│ [If cancelled │ │ │
│ mid-period: │ │ │
│ service valid │ │ │
│ until period │ │ │
│ end, no refund]│ │ │
Interaction Trace — Cancellation:
// Step 1 — Agent cancels the subscription
// REQUEST
POST /v1/subscriptions/sub_01J7Y6A7B8C9D0E1F2G3H4I5J/cancel
Authorization: Bearer ***
Content-Type: application/json
{}
// RESPONSE
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "cancelled",
"cancelled_at": "2026-07-15T10:00:00Z",
"current_period": {
"start": "2026-06-27T09:15:00Z",
"end": "2026-07-27T09:15:00Z"
},
"note": "Service continues until end of current billing period"
}
// Step 2 — ItPay sends cancellation webhook
// WEBHOOK
{
"id": "evt_01J7Y9C2D3E4F5G6H7I8J9K0L",
"type": "subscription.cancelled",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"status": "cancelled",
"cancelled_at": "2026-07-15T10:00:00Z",
"effective_end": "2026-07-27T09:15:00Z"
},
"created_at": "2026-07-15T10:00:05Z"
}
Endpoint
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/subscriptions | Create a new subscription |
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
service_id | string (UUIDv7) | yes | The ServiceManifest id |
plan_id | string | yes | Plan identifier from the manifest's pricing.subscription array |
channel | string | yes | Default payment channel for recurring charges |
payer_info | object | yes | Payer identification |
payer_info.agent_id | string | yes | Paying agent identifier |
payer_info.human_id | string | no | Human user identifier |
auto_renew | boolean | no | Whether to auto-renew at the end of each billing period (default: true) |
return_url | string (URL) | no | Redirect URL for the initial payment checkout |
metadata | object | no | Arbitrary key-value data (max 4 KB) |
Request Example
POST /v1/subscriptions
Content-Type: application/json
Authorization: Bearer sk_inst_a1b2c3d4
{
"service_id": "01J7XYKZ1A2B3C4D5E6F7G8H9I",
"plan_id": "plan_pro",
"channel": "alipay",
"payer_info": {
"agent_id": "agent_cli_a1b2c3d4",
"human_id": "user_abc_789"
},
"auto_renew": true,
"return_url": "https://summarybot.ai/welcome",
"metadata": {
"referral": "campaign_q2_2026",
"onboarding_session": "sess_onboard_001"
}
}
Response Example
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"service_id": "01J7XYKZ1A2B3C4D5E6F7G8H9I",
"plan_id": "plan_pro",
"status": "pending",
"plan": {
"plan_id": "plan_pro",
"name": "Pro",
"amount": 2999,
"currency": "USD",
"interval": "monthly",
"features": [
"500 summaries/mo",
"Priority support",
"API access"
]
},
"current_period": {
"start": "2026-05-27T09:15:00Z",
"end": "2026-06-27T09:15:00Z"
},
"auto_renew": true,
"first_payment": {
"payment_intent_id": "pi_01J7Y6A7B8C9D0E1F2G3H4I5K",
"amount": {
"currency": "USD",
"value": 2999
},
"qr": {
"charge_id": "qr_01J7Y6B7C8D9E0F1G2H3I4J5L",
"scan_url": "https://pay.summarybot.ai/qr/qr_01J7Y6B7C8D9E0F1G2H3I4J5L"
},
"status": "pending",
"expires_at": "2026-05-27T09:30:00Z"
},
"metadata": {
"referral": "campaign_q2_2026",
"onboarding_session": "sess_onboard_001"
},
"created_at": "2026-05-27T09:15:00Z",
"updated_at": "2026-05-27T09:15:00Z"
}
State Machine
┌───────────┐
│ pending │
└─────┬─────┘
│ initial payment confirmed
▼
┌───────────┐
│ active │
└─────┬─────┘
┌────┴────┐
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ past_due│ │cancelled │
└────┬────┘ └──────────┘
│
▼
┌──────────┐
│ expired │
└──────────┘
Transitions
| From | To | Trigger |
|---|---|---|
pending | active | Initial payment is confirmed |
active | past_due | Renewal payment fails or is pending beyond grace period |
past_due | active | Retried renewal payment succeeds |
active | cancelled | Payer or service owner cancels the subscription |
past_due | cancelled | Payer cancels while past due |
past_due | expired | Grace period ends without payment |
active | expired | End of term without auto-renew |
Renewal Flow
When a subscription renews:
- A new
PaymentIntentis created for the renewal amount. - A new
QRChargeis generated (if the channel requires QR). - A
subscription.renewedwebhook event is sent. - If
auto_renewisfalse, the subscription expires at the end of the current period.
// Webhook: subscription.renewed
{
"id": "evt_01J7Y8C9D0E1F2G3H4I5J6K7L",
"type": "subscription.renewed",
"data": {
"subscription_id": "sub_01J7Y6A7B8C9D0E1F2G3H4I5J",
"new_period": {
"start": "2026-06-27T09:15:00Z",
"end": "2026-07-27T09:15:00Z"
},
"payment_intent_id": "pi_01J7Y8C9D0E1F2G3H4I5J6K7M",
"amount": {
"currency": "USD",
"value": 2999
}
},
"created_at": "2026-06-27T09:15:05Z"
}
Key Behaviors
- First payment QR: The response includes a
first_paymentobject with a QR code for the initial payment. The subscription transitions toactiveonly after this payment is confirmed. - Auto-renew: When
auto_renewistrue, a new PaymentIntent is automatically created shortly before the current period ends. The agent can choose to auto-pay (if underauto_pay_limit) or show a new QR code. - Past due handling: If a renewal payment fails, the subscription enters
past_due. The service retries payment after a configurable interval (default: 3 retries over 7 days). After the grace period, the subscription expires. - Plan changes: To change plans, cancel the existing subscription and create a new one with the desired
plan_id. Proration is not handled at the protocol level.
Webhook Events
| Event | Description |
|---|---|
subscription.created | Subscription was created and is pending initial payment |
subscription.activated | Initial payment confirmed, subscription is active |
subscription.renewed | Subscription has been renewed for a new period |
subscription.past_due | Renewal payment failed, subscription is past due |
subscription.cancelled | Subscription was cancelled |
subscription.expired | Subscription expired (end of term without renewal) |
Next Steps
- Void Service — Cancel a subscription before the next renewal
- Refund — Refund a subscription payment
- Request Payment — One-time QR payments