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

# Subscriptions

> Create and manage webhook subscriptions to receive real-time event notifications.

Webhook subscriptions let you register HTTPS endpoints that TagPay calls whenever specific events occur in your account. Each subscription can listen to one or more event types, and you can manage them independently without changing your existing callback URL configuration.

<Info>
  Before subscriptions take effect, make sure your webhook mode is set to `SUBSCRIPTIONS` or `BOTH`. See [Get webhook settings](#get-webhook-settings) below.
</Info>

***

## Create a subscription

Register a new webhook endpoint.

```
POST https://api.tagpay.ng/v1/merchant/webhook/subscribe
```

### Request body

<ParamField body="url" type="string" required>
  The HTTPS URL TagPay will POST events to. Must be a publicly reachable endpoint. HTTP URLs are not accepted in production.
</ParamField>

<ParamField body="events" type="string[]" required>
  Array of event type strings to subscribe to. At least one event is required. Use `["*"]` to subscribe to all events. See [Event Types](/api/webhooks/events) for the full list.
</ParamField>

<ParamField body="description" type="string">
  Optional human-readable label for the subscription, useful when managing multiple endpoints.
</ParamField>

### Response

<ResponseField name="status" type="boolean">
  `true` when the subscription was created.
</ResponseField>

<ResponseField name="message" type="string">
  `"Webhook subscription created successfully"`.
</ResponseField>

<ResponseField name="data" type="object">
  The created subscription.

  <Expandable title="Subscription object">
    <ResponseField name="id" type="string">
      Unique subscription ID (UUID).
    </ResponseField>

    <ResponseField name="url" type="string">
      The registered endpoint URL.
    </ResponseField>

    <ResponseField name="events" type="string[]">
      Event types this subscription listens to.
    </ResponseField>

    <ResponseField name="active" type="boolean">
      Whether the subscription is currently active.
    </ResponseField>

    <ResponseField name="description" type="string">
      Human-readable description, if provided.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO 8601 creation timestamp.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url "https://api.tagpay.ng/v1/merchant/webhook/subscribe" \
    --header "Authorization: Bearer <token>" \
    --header "Content-Type: application/json" \
    --data '{
      "url": "https://example.com/webhooks/tagpay",
      "events": ["transaction.success", "wallet.credit", "wallet.debit"],
      "description": "Production webhook endpoint"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "status": true,
    "message": "Webhook subscription created successfully",
    "data": {
      "id": "sub_e5f6a7b8-c9d0-1234-efab-567890123456",
      "url": "https://example.com/webhooks/tagpay",
      "events": ["transaction.success", "wallet.credit", "wallet.debit"],
      "active": true,
      "description": "Production webhook endpoint",
      "createdAt": "2024-04-01T10:00:00.000Z"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "status": false,
    "message": "Webhook URL is required"
  }
  ```

  ```json 400 theme={null}
  {
    "status": false,
    "message": "At least one event type is required",
    "availableEvents": ["transaction.success", "transaction.failed", "wallet.credit", "..."]
  }
  ```
</ResponseExample>

***

## List subscriptions

Retrieve all webhook subscriptions for your merchant account.

```
GET https://api.tagpay.ng/v1/merchant/webhook/subscriptions
```

### Query parameters

<ParamField query="page" type="number" default="1">
  Page number for pagination.
</ParamField>

<ParamField query="limit" type="number" default="10">
  Number of records per page.
</ParamField>

<ParamField query="activeOnly" type="boolean" default="false">
  When `true`, only returns active subscriptions.
</ParamField>

### Response

<ResponseField name="status" type="boolean">
  `true` when the request succeeded.
</ResponseField>

<ResponseField name="data" type="object[]">
  Array of subscription objects.
</ResponseField>

<ResponseField name="metadata" type="object">
  Pagination metadata.

  <Expandable title="Pagination">
    <ResponseField name="page" type="number">Current page.</ResponseField>
    <ResponseField name="limit" type="number">Records per page.</ResponseField>
    <ResponseField name="total" type="number">Total number of matching subscriptions.</ResponseField>
    <ResponseField name="totalPages" type="number">Total pages.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="availableEvents" type="string[]">
  Complete list of available event types for reference.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET \
    --url "https://api.tagpay.ng/v1/merchant/webhook/subscriptions?page=1&limit=10" \
    --header "Authorization: Bearer <token>"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Subscriptions retrieved successfully",
    "data": [
      {
        "id": "sub_e5f6a7b8-c9d0-1234-efab-567890123456",
        "url": "https://example.com/webhooks/tagpay",
        "events": ["transaction.success", "wallet.credit"],
        "active": true,
        "description": "Production webhook endpoint",
        "createdAt": "2024-04-01T10:00:00.000Z"
      }
    ],
    "metadata": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    },
    "availableEvents": ["transaction.success", "transaction.failed", "wallet.credit", "wallet.debit", "..."]
  }
  ```
</ResponseExample>

***

## Get a subscription

Retrieve a single subscription by its ID.

```
GET https://api.tagpay.ng/v1/merchant/webhook/subscription/:id
```

### Path parameters

<ParamField path="id" type="string" required>
  The UUID of the subscription.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET \
    --url "https://api.tagpay.ng/v1/merchant/webhook/subscription/sub_e5f6a7b8-c9d0-1234-efab-567890123456" \
    --header "Authorization: Bearer <token>"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Subscription retrieved successfully",
    "data": {
      "id": "sub_e5f6a7b8-c9d0-1234-efab-567890123456",
      "url": "https://example.com/webhooks/tagpay",
      "events": ["transaction.success", "wallet.credit"],
      "active": true,
      "description": "Production webhook endpoint",
      "createdAt": "2024-04-01T10:00:00.000Z"
    }
  }
  ```

  ```json 404 theme={null}
  {
    "status": false,
    "message": "Subscription not found"
  }
  ```
</ResponseExample>

***

## Update a subscription

Modify an existing subscription's URL, events, description, or active status.

```
PUT https://api.tagpay.ng/v1/merchant/webhook/subscription/:id
```

### Path parameters

<ParamField path="id" type="string" required>
  The UUID of the subscription to update.
</ParamField>

### Request body

<ParamField body="url" type="string">
  New HTTPS endpoint URL.
</ParamField>

<ParamField body="events" type="string[]">
  Updated list of event types to subscribe to.
</ParamField>

<ParamField body="description" type="string">
  Updated description.
</ParamField>

<ParamField body="active" type="boolean">
  Set to `false` to pause deliveries to this subscription without deleting it.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request PUT \
    --url "https://api.tagpay.ng/v1/merchant/webhook/subscription/sub_e5f6a7b8-c9d0-1234-efab-567890123456" \
    --header "Authorization: Bearer <token>" \
    --header "Content-Type: application/json" \
    --data '{
      "events": ["transaction.success", "transaction.failed", "wallet.credit", "wallet.debit"],
      "active": true
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Subscription updated successfully",
    "data": {
      "id": "sub_e5f6a7b8-c9d0-1234-efab-567890123456",
      "url": "https://example.com/webhooks/tagpay",
      "events": ["transaction.success", "transaction.failed", "wallet.credit", "wallet.debit"],
      "active": true,
      "description": "Production webhook endpoint",
      "updatedAt": "2024-04-02T09:00:00.000Z"
    }
  }
  ```
</ResponseExample>

***

## Delete a subscription

Permanently remove a webhook subscription. In-flight deliveries for this subscription will not be retried.

```
DELETE https://api.tagpay.ng/v1/merchant/webhook/subscription/:id
```

### Path parameters

<ParamField path="id" type="string" required>
  The UUID of the subscription to delete.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request DELETE \
    --url "https://api.tagpay.ng/v1/merchant/webhook/subscription/sub_e5f6a7b8-c9d0-1234-efab-567890123456" \
    --header "Authorization: Bearer <token>"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Subscription deleted successfully"
  }
  ```
</ResponseExample>

***

## Get webhook settings

Retrieve your current webhook delivery mode and configured callback URLs.

```
GET https://api.tagpay.ng/v1/merchant/webhook/settings
```

### Response

<ResponseField name="data" type="object">
  <Expandable title="Settings object" defaultOpen>
    <ResponseField name="webhookMode" type="string">
      Current delivery mode. One of `LEGACY`, `SUBSCRIPTIONS`, or `BOTH`.
    </ResponseField>

    <ResponseField name="callbackURL" type="string">
      Production callback URL configured in your merchant profile. `null` if not set.
    </ResponseField>

    <ResponseField name="sandboxCallbackURL" type="string">
      Sandbox callback URL. `null` if not set.
    </ResponseField>

    <ResponseField name="availableModes" type="object[]">
      Descriptions of each available mode.

      <Expandable title="Mode object">
        <ResponseField name="value" type="string">Mode identifier: `LEGACY`, `SUBSCRIPTIONS`, or `BOTH`.</ResponseField>
        <ResponseField name="label" type="string">Human-readable label.</ResponseField>
        <ResponseField name="description" type="string">Explanation of what this mode does.</ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET \
    --url "https://api.tagpay.ng/v1/merchant/webhook/settings" \
    --header "Authorization: Bearer <token>"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Webhook settings retrieved successfully",
    "data": {
      "webhookMode": "LEGACY",
      "callbackURL": "https://example.com/legacy-webhook",
      "sandboxCallbackURL": "https://sandbox.example.com/legacy-webhook",
      "availableModes": [
        {
          "value": "LEGACY",
          "label": "Legacy Only",
          "description": "Send webhooks only to the callback URL configured in your profile"
        },
        {
          "value": "SUBSCRIPTIONS",
          "label": "Subscriptions Only",
          "description": "Send webhooks only to your webhook subscriptions (ignore callback URL)"
        },
        {
          "value": "BOTH",
          "label": "Both (Recommended for Migration)",
          "description": "Send webhooks to both callback URL and matching subscriptions"
        }
      ]
    }
  }
  ```
</ResponseExample>

***

## Update webhook settings

Change the webhook delivery mode for your merchant account.

```
PUT https://api.tagpay.ng/v1/merchant/webhook/settings
```

### Request body

<ParamField body="webhookMode" type="string" required>
  The delivery mode to activate. Must be one of:

  * `LEGACY` — deliver only to your profile's callback URL.
  * `SUBSCRIPTIONS` — deliver only to matching webhook subscriptions.
  * `BOTH` — deliver to both the callback URL and matching subscriptions. Use this during migration.
</ParamField>

<Tip>
  If you are migrating from the legacy callback URL to subscriptions, set the mode to `BOTH` first. Once you have verified your subscription endpoint is receiving events correctly, switch to `SUBSCRIPTIONS`.
</Tip>

<RequestExample>
  ```bash cURL theme={null}
  curl --request PUT \
    --url "https://api.tagpay.ng/v1/merchant/webhook/settings" \
    --header "Authorization: Bearer <token>" \
    --header "Content-Type: application/json" \
    --data '{
      "webhookMode": "SUBSCRIPTIONS"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Webhook mode updated to SUBSCRIPTIONS",
    "data": {
      "webhookMode": "SUBSCRIPTIONS"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "status": false,
    "message": "Invalid webhook mode. Valid options: LEGACY, SUBSCRIPTIONS, BOTH",
    "validModes": ["LEGACY", "SUBSCRIPTIONS", "BOTH"]
  }
  ```
</ResponseExample>

***

## Send a test event

Immediately deliver a test payload to a subscription endpoint to verify your integration without waiting for a real event.

```
POST https://api.tagpay.ng/v1/merchant/webhook/test/:id
```

### Path parameters

<ParamField path="id" type="string" required>
  The UUID of the subscription to test.
</ParamField>

### Request body

<ParamField body="eventType" type="string">
  The event type to simulate, e.g. `transaction.success`. Defaults to `test.webhook` when omitted.
</ParamField>

### Response

<ResponseField name="success" type="boolean">
  `true` when your endpoint returned a `2xx` HTTP status.
</ResponseField>

<ResponseField name="statusCode" type="number">
  The HTTP status code your endpoint returned.
</ResponseField>

<ResponseField name="responseTime" type="number">
  Round-trip response time in milliseconds.
</ResponseField>

<ResponseField name="message" type="string">
  Result description.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url "https://api.tagpay.ng/v1/merchant/webhook/test/sub_e5f6a7b8-c9d0-1234-efab-567890123456" \
    --header "Authorization: Bearer <token>" \
    --header "Content-Type: application/json" \
    --data '{
      "eventType": "transaction.success"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "data": {
      "success": true,
      "statusCode": 200,
      "responseTime": 142,
      "message": "Test webhook delivered successfully"
    }
  }
  ```

  ```json 200 theme={null}
  {
    "status": true,
    "data": {
      "success": false,
      "statusCode": 404,
      "responseTime": 98,
      "message": "Request failed with status code 404",
      "error": null
    }
  }
  ```
</ResponseExample>

***

## Replay a failed delivery

Create a new delivery attempt for a previously failed webhook delivery.

```
POST https://api.tagpay.ng/v1/merchant/webhook/replay/:id
```

### Path parameters

<ParamField path="id" type="string" required>
  The UUID of the delivery record to replay. Retrieve delivery IDs from [Delivery History](/api/webhooks/deliveries).
</ParamField>

### Response

Returns the newly created delivery record. The new delivery has a reference prefixed with `replay-`.

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url "https://api.tagpay.ng/v1/merchant/webhook/replay/del_f6a7b8c9-d0e1-2345-fabc-678901234567" \
    --header "Authorization: Bearer <token>"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": true,
    "message": "Delivery replayed successfully",
    "data": {
      "id": "del_new1234-d0e1-2345-fabc-678901234999",
      "subscriptionId": "sub_e5f6a7b8-c9d0-1234-efab-567890123456",
      "eventType": "transaction.success",
      "status": "pending",
      "attempts": 0,
      "reference": "replay-del_f6a7b8c9-d0e1-2345-fabc-678901234567",
      "createdAt": "2024-04-03T11:00:00.000Z"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "status": false,
    "message": "Delivery not found"
  }
  ```

  ```json 400 theme={null}
  {
    "status": false,
    "message": "Subscription is not active"
  }
  ```
</ResponseExample>
