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

# Recurring Payments (Subscriptions)

> Set up plans and charge customers on a recurring schedule.

Recurring payments or subscriptions are scheduled payments to pay for products or services that occurs frequently. For example, a cardholder paying for an on-demand internet service provider's monthly subscription fee without having to manually pay every month.

After first successful payment from the customers card, the card is stored as a token which will be used for subsequent transactions.

> Note that recurrent transaction works only for cards

**Ideal for**: Charging a customer on a schedule — monthly software, membership dues, instalment plans. The customer authorises once, and SeerBit charges the stored card thereafter.

> **Note**: Recurring transactions work with cards only. After the first successful payment the card is stored as a token, and subsequent charges use that token.

## Subscriptions or card tokenisation?

Both charge a card the customer has already authorised, but they differ in **who decides when the charge happens**.

| | Subscriptions | [Card tokenisation](/online-payments/payment-features/card-tokenisation) |
| - | - | - |
| **What triggers a charge** | A schedule you define in a plan | You do, by calling the charge endpoint |
| **Timing** | Fixed cycle — daily, weekly, monthly, annually | Whenever you decide |
| **The amount** | Set by the plan | Different every time, if you want |
| **You manage** | Plans and subscribers | Tokens |
| **Best for** | Software subscriptions, memberships, instalments | Usage-based billing, one-click repeat purchases, top-ups |

Use a subscription when the billing is regular and predictable. Use tokenisation when you need to charge a saved card at unpredictable times or for varying amounts.

## How it works

<Steps>
  <Step title="Create a plan">
    Define the amount, currency and billing cycle once. A plan is the template every subscriber is billed against.
  </Step>

  <Step title="Subscribe a customer">
    The customer makes a first payment against the plan. That payment authorises the card and returns an `authorizationCode`.
  </Step>

  <Step title="SeerBit charges on schedule">
    Subsequent charges happen automatically on the plan's cycle, using the stored token.
  </Step>

  <Step title="Manage the subscription">
    Look subscriptions up by customer, update them, or charge the stored card yourself with the `authorizationCode`.
  </Step>
</Steps>

You can also create plans without code on the SeerBit merchant dashboard.

## Authentication

Subscription calls are authenticated with a **bearer token**, generated from your public and secret keys — the same as every other collection API.

```bash theme={null}
POST https://seerbitapi.com/api/v2/encrypt/keys
```

<Card title="Authentication" icon="key" href="/authentication#bearer-token">
  How to generate the token, and which credential every other SeerBit API expects.
</Card>

## Create Plan

For the full specification, see our [API Reference](/api-reference)

<Badge color="blue">POST</Badge>

```bash theme={null}
https://merchants.seerbitapi.com/api/v1/recurrent/plan/create
```

#### Request Sample

The code snippet below shows an example request for creating a subscription

> Billing Cycle should be set to : ***DAILY***, ***WEEKLY***, ***MONTHLY*** or ***ANNUALLY***

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://merchants.seerbitapi.com/api/v1/recurrent/plan/create' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_ENCRYPTED_KEY' \
  --data '{
      "productId": "<Plan name>",
      "productDescription": "<Description of Plan>",
      "amount": "100",
      "billingCycle": "MONTHLY",
      "limit": 5,
      "publicKey": "<public key>",
      "country": "NG",
      "currency": "NGN",
      "allowPartialDebit": false
  }'
  ```

  ```javascript NODE theme={null}
  var request = require('request');
  var options = {
    method: 'POST',
    url: 'https://merchants.seerbitapi.com/api/v1/recurrent/plan/create',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer Token',
    },
    body: JSON.stringify({
      productId: '<Plan Name>',
      productDescription: '<Description of Plan>',
      amount: '100',
      billingCycle: 'MONTHLY',
      limit: 5,
      publicKey: '<Public key>',
      country: 'NG',
      currency: 'NGN',
      allowPartialDebit: false,
    }),
  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
  });
  ```

  ```php PHP theme={null}
  ?php
  $curl = curl_init();
  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://merchants.seerbitapi.com/api/v1/recurrent/plan/create',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS =>'{
      "productId": "<Plan Name>",
      "productDescription": "<Description of Plan>",
      "amount": "100",
      "billingCycle": "MONTHLY",
      "limit": 5,
      "publicKey": "<Public Key>",
      "country": "NG",
      "currency": "NGN",
      "allowPartialDebit": false
  }',
    CURLOPT_HTTPHEADER => array(
      'Content-Type: application/json',
      'Authorization: Bearer Token'
    ),
  ));
  $response = curl_exec($curl);
  curl_close($curl);
  echo $response;
  ```
</CodeGroup>

##### Response Sample

The code snippet below shows an example response for creating a subscription

<CodeGroup>
  ```json 200:OK theme={null}
  {
    "payload": {
      "country": "NG",
      "createdAt": 1715607343498,
      "amount": 100,
      "productId": "<Plan name>",
      "billingCycle": "MONTHLY",
      "currency": "NGN",
      "payUrl": "https://pay.seerbitapi.com/db1ea861993689a57dac",
      "details": {
        "country": "NG",
        "amount": 100,
        "productId": "<Plan name>",
        "allowPartialDebit": false,
        "payLinkUrl": "https://pay.seerbitapi.com/db1ea861993689a57dac",
        "publicKey": "<public key>",
        "createdAt": 1715607343498,
        "trialDuration": 0,
        "trialPeriod": false,
        "billingCycle": "MONTHLY",
        "limit": 5,
        "planId": "db1ea861993689a57dac",
        "currency": "NGN",
        "id": 20031,
        "productDescription": "<description of plan>",
        "updatedAt": null,
        "status": "ACTIVE"
      },
      "publicKey": "<public key>",
      "plan": "db1ea861993689a57dac",
      "productDescription": "<description of plan>"
    },
    "message": "Successful",
    "status": "SUCCESS",
    "responseCode": "00"
  }
  ```

  ```json 400:Bad Request theme={null}
  {
    "message": "Bad Request",
    "error": "There has been a problem with reading or understanding the request."
  }
  ```

  ```json 401:Unauthourized theme={null}
  {
    "message": "Invalid Authentication Token",
    "error": "INPUT"
  }
  ```
</CodeGroup>

#### Parameter description

| Name | Type | Description |
| - | - | - |
| publicKey | `string` | Your SeerBit public key, from **Settings > API Keys**. |
| productId | `string` | The plan name, as the customer will see it. |
| productDescription | `string` | Longer description of what the plan covers. |
| amount | `string` | Amount charged each cycle. |
| currency | `string` | Currency of the plan, e.g. `NGN`. See [currency codes](/development-resources/currency-codes/overview). |
| country | `string` | Country the plan bills from. |
| billingCycle | `string` | How often the customer is charged: `DAILY`, `WEEKLY`, `MONTHLY` or `ANNUALLY`. |
| limit | `number` | How many times to charge before the subscription ends. |
| allowPartialDebit | `boolean` | If `true`, a charge may take less than `amount` when the card has insufficient funds. |

## Get Merchant Subscription

The Get Merchant Subscription returns all customer subscriptions. Included in the response is authorizationCode which can be used for separate charges to the customer

For the full specification, see our [API Reference](/api-reference)

<Badge color="green">GET</Badge>

```bash theme={null}
https://seerbitapi.com/api/v2/recurring/publicKey/{publicKey}
```

#### Request Sample

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://seerbitapi.com/api/v2/recurring/publicKey/{publicKey}' \
  --header 'Authorization: Bearer YOUR_ENCRYPTED_KEY' \
  ```

  ```javascript NODE theme={null}
  var request = require('request');
  var options = {
    method: 'GET',
    url: 'https://seerbitapi.com/api/v2/recurring/publicKey/{publicKey}',
    headers: {
      Authorization: 'Bearer YOUR_ENCRYPTED_KEY',
    },
  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
  });
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://seerbitapi.com/api/v2/recurring/publicKey/{publicKey}',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => array(
      'Authorization: Bearer YOUR_ENCRYPTED_KEY'
    ),
  ));

  $response = curl_exec($curl);

  curl_close($curl);
  echo $response;
  ```
</CodeGroup>

#### Response Sample

The code snippet below shows an example response to get merchant subscription

```json theme={null}
{
  "status": "SUCCESS",
  "data": {
    "subscriptions": [
      {
        "publicKey": "SBTEST**************************viTF",
        "amount": "20",
        "country": "NG",
        "customerId": "651d33a62ad69c9f37c4",
        "cardName": "Jane Smith",
        "cardNumber": "2223-00xx-xxxx-0007",
        "plan": "ae702f51220000722dca",
        "status": "ACTIVE",
        "billingId": "WQ6676yPOpr12348o",
        "authorizationCode": "2beb0ccdd347e604552a",
        "startDate": "2019-01-11 00:00:00",
        "createdAt": 1578648329000
      },
      {
        "publicKey": "SBTEST**************************viTF",
        "amount": "100",
        "country": "NG",
        "customerId": "ba981a0b7ed1c68ad245",
        "cardName": "Jane Smith",
        "cardNumber": "5123-45xx-xxxx-0008",
        "plan": "ead5e697f42c1cd60813",
        "status": "ACTIVE",
        "billingId": "PUBK_PjQ5d1578649732262",
        "authorizationCode": "145a3bb3418824c14d65",
        "startDate": "2020-10-01 10:47:49",
        "createdAt": 1578649752000
      }
    ],
    "code": "00",
    "message": "successful"
  }
}
```

## Charge Subscription

For the full specification, see our [API Reference](/api-reference)

<Badge color="blue">POST</Badge>

```bash theme={null}
https://seerbitapi.com/api/v2/recurring/charge
```

#### Request Sample

The code snippet below shows an example request for charging a customer with an authorizationCode

> **Authorise Charge** - Authorisation Code is gotten when a subscription has been successfully completed

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://seerbitapi.com/api/v2/recurring/charge' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_ENCRYPTED_KEY' \
  --data-raw '{
  	"amount":"200", 
  	"publicKey":"YOUR_PUBLIC_KEY", 
  	"email":"js@emaildomain.com", 
    	"allowPartialDebit":"true",
  	"authorizationCode":"1234567898765325", 
  	"paymentReference":"2938765582R37065687631",
  	"currency":"NGN"
  }'
  ```

  ```javascript NODE theme={null}
  var request = require('request');
  var options = {
    method: 'POST',
    url: 'https://seerbitapi.com/api/v2/recurring/charge',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer YOUR_ENCRYPTED_KEY',
    },
    body: JSON.stringify({
      amount: '200',
      publicKey: 'YOUR_PUBLIC_KEY',
      email: 'js@emaildomain.com',
      allowPartialDebit: 'true',
      authorizationCode: '1234567898765325',
      paymentReference: '2938765582R37065687631',
      currency: 'NGN',
    }),
  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
  });
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://seerbitapi.com/api/v2/recurring/charge',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS =>'{
  	"amount":"200",
  	"publicKey":"YOUR_PUBLIC_KEY",
  	"email":"js@emaildomain.com",
    "allowPartialDebit":"true",
  	"authorizationCode":"1234567898765325",
  	"paymentReference":"2938765582R37065687631",
  	"currency":"NGN"
  }',
    CURLOPT_HTTPHEADER => array(
      'Content-Type: application/json',
      'Authorization: Bearer YOUR_ENCRYPTED_KEY'
    ),
  ));

  $response = curl_exec($curl);

  curl_close($curl);
  echo $response;
  ```
</CodeGroup>

##### Response Sample

The code snippet below shows an example response for charging a subscription

<CodeGroup>
  ```json 200:OK theme={null}
  {
    "status": "SUCCESS",
    "data": {
       "code": "00",
       "payments": {
           "code": "00",
           "message": "Successful",
           "paymentReference": "2938765582R37065687631",
           "publicKey": "SBTEST**************************viTF",
           "amount": "200",
           "currency": "NGN",
           "country": "NG",
           "email": "js@emaildomain.com", 
           "productDescription": "Authorised charge"
        },
        "message": "Successful"
  	}
  }
  ```

  ```json 400:Bad Request theme={null}
  {
    "message": "Bad Request",
    "error": "There has been a problem with reading or understanding the request."
  }
  ```

  ```json 401:Unauthorized theme={null}
  {
    "message": "Invalid Authentication Token",
    "error": "INPUT"
  }
  ```
</CodeGroup>

#### Parameter description

| Name | Type | Description |
| - | - | - |
| publicKey | `string` | Your SeerBit public key. |
| authorizationCode | `string` | Returned once a subscription's first payment succeeds. It stands in for the stored card. |
| amount | `string` | Amount to charge on this call. |
| currency | `string` | Currency of the charge. |
| email | `string` | Email of the customer being charged. |
| paymentReference | `string` | Unique reference you generate for this charge. See [payment references](/online-payments/integrations/standard-checkout#payment-references-and-retries). |
| allowPartialDebit | `string` | `"true"` permits a partial debit when funds are short. |

## Get Customer Subscription

For the full specification, see our [API Reference](/api-reference)

<Badge color="green">GET</Badge>

```bash theme={null}
https://seerbitapi.com/api/v2/recurring/{publicKey}/customerId/{customerId}
```

#### Request Sample

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://seerbitapi.com/api/v2/recurring/{publicKey}/customerId/{customerId}' \
  --header 'Authorization: Bearer YOUR_ENCRYPTED_KEY' \
  ```

  ```javascript NODE theme={null}
  var request = require('request');
  var options = {
    method: 'GET',
    url: 'https://seerbitapi.com/api/v2/recurring/{publicKey}/customerId/{customerId}',
    headers: {
      Authorization: 'Bearer YOUR_ENCRYPTED_KEY',
    },
  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
  });
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://seerbitapi.com/api/v2/recurring/publicKey/{publicKey}',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => array(
      'Authorization: Bearer YOUR_ENCRYPTED_KEY'
    ),
  ));

  $response = curl_exec($curl);

  curl_close($curl);
  echo $response;
  ```
</CodeGroup>

##### Response Sample

The code snippet below shows an example response to get customer subscription by customerId

```json theme={null}
{
	"status": "SUCCESS",
	"data": {
    "subscriptions": [
      {
        "publicKey": "SBTEST**************************viTF",
        "amount": "100",
        "country": "NG",
        "customerId": "ba981a0b7ed1c68ad245",
        "cardName": "Jane Smith",
        "cardNumber": "5123-45xx-xxxx-0008",
        "plan": "ead5e697f42c1cd60813",
        "status": "ACTIVE",
        "billingId": "PUBK_PjQ5d1578649732262",
        "authorizationCode": "145a3bb3418824c14d65",
        "startDate": "2020-10-01 10:47:49",
        "createdAt": 1578649752000
      },
      {
        "publicKey": "SBTEST**************************viTF",
        "amount": "20000",
        "country": "NG",
        "customerId": "ba981a0b7ed1c68ad245",
        "cardName": "John Smith",
        "cardNumber": "5123-45xx-xxxx-0008",
        "plan": "80b0854b35a0e279efc3",
        "status": "INACTIVE",
        "billingId": "PUBK_PjQ5d1578650322483",
        "authorizationCode": "ddfce36aa4f3abc7cf72",
        "startDate": "2020-10-01 10:58:25",
        "createdAt": 1578650353000
      }
    ],
    "code": "00",
 }
```

## Update Customer Subscription

For the full specification, see our [API Reference](/api-reference)

<Badge color="yellow">PUT</Badge>

```bash theme={null}
https://seerbitapi.com/api/v2/recurring/updates
```

#### Request Sample

The code snippet below shows an example request for updating a subscription

> For credit cards you can update the previously stored payment details, this may be required when the card expiry date or the billing/delivery address changes.

<CodeGroup>
  ```bash cURL theme={null}
  curl --location --request PUT 'https://seerbitapi.com/api/v2/recurring/updates' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_ENCRYPTED_KEY' \
  --data '{
  	"amount":"20000",
  	"currency":"NGN",
  	"country":"NG",
  	"mobileNumber":"08033456500", 
  	"billingId":"PUBK_PjQ5d1578650322483", 
  	"publicKey":"YOUR_PULIC_KEY", 
  	"status":"INACTIVE"
  }'
  ```

  ```javascRipt NODE theme={null}
  var request = require('request');
  var options = {
    'method': 'PUT',
    'url': 'https://seerbitapi.com/api/v2/recurring/updates',
    'headers': {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_ENCRYPTED_KEY'
    },
    body: JSON.stringify({
      "amount": "20000",
      "currency": "NGN",
      "country": "NG",
      "mobileNumber": "08033456500",
      "billingId": "PUBK_PjQ5d1578650322483",
      "publicKey": "YOUR_PULIC_KEY",
      "status": "INACTIVE"
    })

  };
  request(options, function (error, response) {
    if (error) throw new Error(error);
    console.log(response.body);
  });
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://seerbitapi.com/api/v2/recurring/updates',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_POSTFIELDS =>'{
  "amount":"20000",
  "currency":"NGN",
  "country":"NG",
  "mobileNumber":"08033456500",
  "billingId":"PUBK_PjQ5d1578650322483",
  "publicKey":"YOUR_PULIC_KEY",
  "status":"INACTIVE"
  }',
    CURLOPT_HTTPHEADER => array(
      'Content-Type: application/json',
      'Authorization: Bearer YOUR_ENCRYPTED_KEY'
    ),
  ));

  $response = curl_exec($curl);

  curl_close($curl);
  echo $response;
  ```
</CodeGroup>

##### Response Sample

The code snippet below shows an example response for updating a subscription

```json theme={null}
"status": "SUCCESS",
    "data": {
      "subscriptions": {
        "publicKey": "SBTEST**************************viTF",
        "amount": "20000",
        "country": "NG",
        "customerId": "ba981a0b7ed1c68ad245",
        "cardName": "Jane Smith",
        "cardNumber": "5123-45xx-xxxx-0008",
        "plan": "80b0854b35a0e279efc3",
        "status": "INACTIVE",
        "billingId": "PUBK_PjQ5d1578650322483",
        "authorizationCode": "ddfce36aa4f3abc7cf72",
        "startDate": "2020-10-01 10:58:25",
        "createdAt": 1578650353000
      },
      "code": "00",
      "message": "Successful"
  }
```

## Notes

* **Store the `authorizationCode`.** It is what lets you charge the saved card again — without it you must ask the customer to authorise afresh.
* **`limit` ends the subscription.** Set it to the number of cycles you intend to bill; leaving it open means charging until the subscription is cancelled.
* **Cards only.** Bank transfer, USSD and mobile money cannot be used for recurring charges, so offer a card at sign-up even if your checkout supports other methods.
* **A failed cycle is not a cancelled subscription.** Watch for the recurring-debit [webhook events](/online-payments/after-payments/webhook-events) and handle a decline in your own dunning logic.
* Confirm every charge server-side before granting access — see [Verify a payment](/online-payments/after-payments/verify-payment).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.