> ## Documentation Index
> Fetch the complete documentation index at: https://docs.subscribd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# REST API

> Bearer-token authenticated REST API for headless and mobile integrations

# REST API

Subscribd ships a public REST API for headless or mobile integrations. It is **disabled by default** — enable it in `config/subscribd.php`:

```php theme={null}
'api' => [
    'enabled'          => true,
    'prefix'           => 'subscribd/v1',
    'token_middleware' => ['auth'],
],
```

## Authentication

The API uses stateless Bearer tokens issued per-billable. The token issuance and revocation endpoints are protected by your own session auth (the `token_middleware` config key).

### Issue a token

```http theme={null}
POST /subscribd/v1/tokens
```

No request body required. The authenticated user receives a token scoped to their account.

**Response:**

```json theme={null}
{
  "token": "sbst_abc123...",
  "createdAt": "2026-04-19T10:00:00Z"
}
```

### Revoke a token

```http theme={null}
DELETE /subscribd/v1/tokens/{token}
```

Use the Bearer token on all other endpoints:

```http theme={null}
Authorization: Bearer sbst_abc123...
```

***

## Plans

Plans are read-only via the API. Write operations (create/update/delete) are admin-only.

### List plans

```http theme={null}
GET /subscribd/v1/plans
```

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": 1,
      "key": "pro",
      "name": "Pro",
      "price": 4900,
      "currency": "USD",
      "interval": "month",
      "intervalCount": 1,
      "trialDays": 14,
      "isRecurring": true,
      "features": {
        "exports": true
      },
      "items": [
        {
          "key": "projects",
          "name": "Projects",
          "includedQuantity": 3,
          "unitPrice": 1000,
          "capBehavior": "charge_until_ceiling",
          "ceiling": 50
        }
      ]
    }
  ]
}
```

### Get a plan

```http theme={null}
GET /subscribd/v1/plans/{plan}
```

***

## Subscriptions

All subscription endpoints are scoped to the token owner — a billable cannot access another billable's subscriptions.

### List subscriptions

```http theme={null}
GET /subscribd/v1/subscriptions
```

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": 42,
      "name": "default",
      "status": "active",
      "plan": { "key": "pro", "name": "Pro" },
      "currentPeriodStart": "2026-04-01T00:00:00Z",
      "currentPeriodEnd":   "2026-05-01T00:00:00Z",
      "trialEndsAt": null,
      "canceledAt": null,
      "endsAt": null,
      "createdAt": "2026-03-01T00:00:00Z"
    }
  ]
}
```

### Get a subscription

```http theme={null}
GET /subscribd/v1/subscriptions/{subscription}
```

### Cancel a subscription

```http theme={null}
POST /subscribd/v1/subscriptions/{subscription}/cancel
```

**Request body (optional):**

```json theme={null}
{ "immediately": false }
```

`immediately: false` (default) cancels at period end (grace period). `immediately: true` revokes access immediately.

### Resume a subscription

```http theme={null}
POST /subscribd/v1/subscriptions/{subscription}/resume
```

Resumes a paused or grace-period subscription.

### Tally metered usage

```http theme={null}
POST /subscribd/v1/subscriptions/{subscription}/tally-usage
```

**Request body:**

```json theme={null}
{
  "feature": "api_calls",
  "quantity": 150,
  "idempotencyKey": "req_abc123"
}
```

`idempotencyKey` is optional. When provided, duplicate requests with the same key are silently ignored.

### Upgrade from free

```http theme={null}
POST /subscribd/v1/subscriptions/{subscription}/upgrade-from-free
```

**Request body:**

```json theme={null}
{ "planKey": "pro" }
```

Upgrades a community/free subscription to a paid plan. Assumes payment has already been collected.

***

## Invoices

### List invoices

```http theme={null}
GET /subscribd/v1/invoices
```

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": 17,
      "status": "paid",
      "total": 4900,
      "currency": "USD",
      "paidAt": "2026-04-01T00:00:00Z",
      "periodStart": "2026-04-01T00:00:00Z",
      "periodEnd": "2026-05-01T00:00:00Z",
      "pdfUrl": "/subscribd/invoices/17/pdf"
    }
  ]
}
```

### Get an invoice

```http theme={null}
GET /subscribd/v1/invoices/{invoice}
```

***

## Payment methods

### List payment methods

```http theme={null}
GET /subscribd/v1/payment-methods
```

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": 5,
      "brand": "visa",
      "last4": "4242",
      "expMonth": 12,
      "expYear": 2028,
      "isDefault": true
    }
  ]
}
```

### Delete a payment method

```http theme={null}
DELETE /subscribd/v1/payment-methods/{paymentMethod}
```

### Set as default

```http theme={null}
POST /subscribd/v1/payment-methods/{paymentMethod}/default
```

***

## Error responses

All errors return a JSON body with `message` and an appropriate HTTP status code.

| Status | Meaning                                                       |
| ------ | ------------------------------------------------------------- |
| 401    | Invalid or missing Bearer token                               |
| 403    | Token owner does not own the resource                         |
| 404    | Resource not found                                            |
| 422    | Validation error — `errors` key contains field-level messages |
| 500    | Gateway or server error — check your logs                     |

```json theme={null}
{
  "message": "The subscription does not belong to this token owner.",
  "errors": {}
}
```

***

## Rate limiting

Rate limiting is not applied by default. Add it via your `token_middleware` stack:

```php theme={null}
'token_middleware' => ['auth', 'throttle:60,1'],
```

***

## Next steps

* **[Testing](/advanced/testing)** — How to test API integrations with the FakeGateway
* **[Hooks and Events](/advanced/hooks-and-events)** — Events fired during API operations
