> For the complete documentation index, see [llms.txt](https://pingpay.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pingpay.gitbook.io/docs/pingpay-api/subscriptions/api-reference.md).

# API Reference

Base URL: `https://pay.pingpay.io/api/rpc`

All request and response bodies are JSON. Amounts are strings in the smallest unit of the asset (e.g. `"5000000"` = 5 USDC, since USDC has 6 decimals).

***

### Create Subscription Session

Creates a new subscription session that a subscriber can activate.

**Requires API key authentication.**

```
POST /subscriptions/sessions
```

#### Headers

| Header         | Required | Description        |
| -------------- | -------- | ------------------ |
| `Content-Type` | Yes      | `application/json` |
| `x-api-key`    | Yes      | Your Ping API key  |

#### Request Body

| Field          | Type             | Required | Description                                                              |
| -------------- | ---------------- | -------- | ------------------------------------------------------------------------ |
| `name`         | string           | Yes      | Plan name displayed to subscriber (1-100 chars)                          |
| `amount`       | string           | Yes      | Payment amount per period in smallest units (e.g. `"5000000"` = 5 USDC)  |
| `asset`        | object           | Yes      | `{ "chain": "near", "symbol": "USDC" }`                                  |
| `interval`     | string or object | Yes      | `"WEEKLY"`, `"MONTHLY"`, `"YEARLY"`, or `{ "customSecs": 120 }` (min 60) |
| `totalPeriods` | number           | Yes      | Number of payments (1-12)                                                |
| `successUrl`   | string           | No       | Redirect URL after successful activation                                 |
| `cancelUrl`    | string           | No       | Redirect URL if subscriber cancels                                       |
| `metadata`     | object           | No       | Arbitrary key-value data attached to the session                         |

#### Example

```bash
curl -s -X POST https://pay.pingpay.io/api/rpc/subscriptions/sessions \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_abc123" \
  -d '{
    "name": "Pro Plan",
    "amount": "5000000",
    "asset": { "chain": "near", "symbol": "USDC" },
    "interval": "MONTHLY",
    "totalPeriods": 12,
    "successUrl": "https://yourapp.com/success?session={SESSION_ID}",
    "cancelUrl": "https://yourapp.com/cancel"
  }' | python3 -m json.tool
```

#### Response

```json
{
  "sessionId": "ss_a1b2c3d4e5f6",
  "name": "Pro Plan",
  "amount": "5000000",
  "assetSymbol": "USDC",
  "assetChain": "near",
  "intervalLabel": "MONTHLY",
  "intervalSecs": 2592000,
  "totalPeriods": 12,
  "recipientAddress": "merchant.near",
  "status": "CREATED",
  "successUrl": "https://yourapp.com/success?session={SESSION_ID}",
  "createdAt": "2026-04-21T12:00:00.000Z",
  "expiresAt": "2026-04-21T13:00:00.000Z",
  "sessionUrl": "https://pay.pingpay.io/subscribe/ss_a1b2c3d4e5f6"
}
```

> **Note:** Sessions expire 1 hour after creation. Redirect the subscriber to `sessionUrl` promptly.

***

### Get Subscription Session

Retrieve details of a subscription session.

**No authentication required.**

```
GET /subscriptions/sessions/{sessionId}
```

#### Example

```bash
curl -s https://pay.pingpay.io/api/rpc/subscriptions/sessions/ss_a1b2c3d4e5f6 \
  | python3 -m json.tool
```

#### Response

Same schema as the create response. If the session has been activated, includes a `subscriptionId` field.

```json
{
  "sessionId": "ss_a1b2c3d4e5f6",
  "name": "Pro Plan",
  "amount": "5000000",
  "assetSymbol": "USDC",
  "assetChain": "near",
  "intervalLabel": "MONTHLY",
  "intervalSecs": 2592000,
  "totalPeriods": 12,
  "recipientAddress": "merchant.near",
  "status": "ACTIVE",
  "subscriptionId": "sub_x7y8z9",
  "createdAt": "2026-04-21T12:00:00.000Z",
  "expiresAt": "2026-04-21T13:00:00.000Z"
}
```

***

### Get Subscription

Retrieve a subscription by ID.

**No authentication required.**

```
GET /subscriptions/{subscriptionId}
```

#### Example

```bash
curl -s https://pay.pingpay.io/api/rpc/subscriptions/sub_x7y8z9 \
  | python3 -m json.tool
```

#### Response

```json
{
  "subscriptionId": "sub_x7y8z9",
  "sessionId": "ss_a1b2c3d4e5f6",
  "subscriber": "alice.near",
  "merchant": "merchant.near",
  "status": "ACTIVE",
  "amount": "5000000",
  "assetSymbol": "USDC",
  "assetChain": "near",
  "intervalSecs": 2592000,
  "intervalLabel": "MONTHLY",
  "totalPeriods": 12,
  "releasedCount": 3,
  "startTime": 1713700800,
  "nextReleaseTime": 1721476800,
  "createdAt": "2026-04-21T12:00:00.000Z",
  "releaseHistory": [
    { "period": 1, "timestamp": 1713700800, "intentHash": "Abc123..." },
    { "period": 2, "timestamp": 1716292800, "intentHash": "Def456..." },
    { "period": 3, "timestamp": 1718884800, "intentHash": "Ghi789..." }
  ]
}
```

***

### Cancel Subscription

Cancel an active subscription. Can be called by either the merchant (via API key) or the subscriber (via their NEAR address).

```
POST /subscriptions/{subscriptionId}/cancel
```

#### Merchant Cancel (API Key)

```bash
curl -s -X POST https://pay.pingpay.io/api/rpc/subscriptions/sub_x7y8z9/cancel \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_abc123" \
  | python3 -m json.tool
```

#### Subscriber Cancel

```bash
curl -s -X POST https://pay.pingpay.io/api/rpc/subscriptions/sub_x7y8z9/cancel \
  -H "Content-Type: application/json" \
  -d '{ "subscriberAddress": "alice.near" }' \
  | python3 -m json.tool
```

#### Response

Returns the updated subscription with `status: "CANCELLED"` and `cancelledAt` timestamp.

***

### List Subscriptions

List all subscriptions for your organization.

**Requires API key authentication.**

```
GET /subscriptions
```

#### Example

```bash
curl -s https://pay.pingpay.io/api/rpc/subscriptions \
  -H "x-api-key: pk_live_abc123" \
  | python3 -m json.tool
```

#### Response

```json
[
  {
    "subscriptionId": "sub_x7y8z9",
    "subscriber": "alice.near",
    "status": "ACTIVE",
    "amount": "5000000",
    "assetSymbol": "USDC",
    "intervalLabel": "MONTHLY",
    "totalPeriods": 12,
    "releasedCount": 3,
    "createdAt": "2026-04-21T12:00:00.000Z"
  }
]
```

***

### Activate Subscription

> **Note:** This endpoint is called automatically by the Ping subscription UI. You typically don't need to call it directly.

Activates a subscription session by submitting signed NEAR intents.

```
POST /subscriptions/activate
```

#### Request Body

| Field           | Type   | Required | Description                                  |
| --------------- | ------ | -------- | -------------------------------------------- |
| `sessionId`     | string | Yes      | The session to activate                      |
| `subscriber`    | string | Yes      | NEAR account address of the subscriber       |
| `signedIntents` | array  | Yes      | One signed NEP-413 intent per payment period |

Each signed intent:

```json
{
  "standard": "nep413",
  "payload": {
    "message": "{\"signer_id\":\"alice.near\",\"deadline\":\"...\",\"intents\":[...]}",
    "nonce": "base64_nonce",
    "recipient": "intents.near"
  },
  "signature": "ed25519:base58_signature",
  "publicKey": "ed25519:base58_public_key"
}
```

***

### Subscription Statuses

| Status           | Description                                                        |
| ---------------- | ------------------------------------------------------------------ |
| `ACTIVE`         | Subscription is active and payments are being released on schedule |
| `CANCELLED`      | Cancelled by merchant or subscriber. No further payments.          |
| `COMPLETED`      | All periods have been successfully released                        |
| `PAYMENT_FAILED` | 3+ consecutive payment failures. Requires manual intervention.     |

***

### Error Responses

All errors follow this format:

```json
{
  "error": {
    "code": "SESSION_EXPIRED",
    "message": "Subscription session has expired"
  }
}
```

Common error codes:

| Code                     | HTTP Status | Description                                |
| ------------------------ | ----------- | ------------------------------------------ |
| `SESSION_NOT_FOUND`      | 404         | Session ID does not exist                  |
| `SESSION_EXPIRED`        | 400         | Session expired (1 hour TTL)               |
| `SESSION_ALREADY_ACTIVE` | 400         | Session already has an active subscription |
| `SUBSCRIPTION_NOT_FOUND` | 404         | Subscription ID does not exist             |
| `UNAUTHORIZED`           | 401         | Missing or invalid API key                 |
| `INVALID_INPUT`          | 400         | Request body validation failed             |
