Skip to main content
Subscriptions tie a customer to a product and automatically track billing periods. Each renewal can be collected via virtual account bank transfer, card, or a manual confirmation. Hyparrow records every payment in a full payment history you can query at any time.
Subscriptions are linked to a product (which carries the price and currency) and a customer record. Create both before creating a subscription.

Create a subscription

POST /api/v1/subscriptions/
customerId
string
required
UUID of the customer to subscribe.
productId
string
required
UUID of the product. The subscription amount and currency are taken from the product.
interval
string
required
Billing frequency. One of: daily, every_3_days, weekly, biweekly, monthly, quarterly, biannual, yearly.
paymentMethod
string
required
How each renewal is collected. One of: card, manual, va.
graceDays
number
default:"3"
Number of days after a missed payment before the subscription is auto-canceled.
metadata
object
Arbitrary key-value pairs stored on the subscription.
checkoutCallbackUrl
string
URL that Hyparrow POSTs to when a checkout-link payment for this subscription changes status (completed, pending, or failed).
curl --request POST \
  --url https://api.hyparrow.com/api/v1/subscriptions/ \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret" \
  --header "Content-Type: application/json" \
  --data '{
    "customerId": "cust-uuid-...",
    "productId": "prod-uuid-...",
    "interval": "monthly",
    "paymentMethod": "va",
    "graceDays": 5,
    "checkoutCallbackUrl": "https://yourapp.com/webhooks/subscription"
  }'
Response
{
  "success": true,
  "message": "Subscription created",
  "data": {
    "id": "sub-uuid-...",
    "status": "pending_payment",
    "interval": "monthly",
    "amount": 5000.00,
    "currency": "NGN",
    "paymentMethod": "va",
    "graceDays": 5,
    "nextBillingAt": null,
    "createdAt": "2025-06-01T10:00:00Z"
  }
}
A new subscription starts with status: pending_payment. It becomes active once the first payment is recorded.

Subscription statuses

StatusMeaning
pending_paymentCreated, waiting for first payment
activeBilling is running normally
canceledManually canceled
expiredGrace period elapsed without payment

Generate a virtual account

For subscriptions with paymentMethod: va, generate a short-lived virtual account for the current billing period. POST /api/v1/subscriptions/:subscriptionId/generate-va
expiryMinutes
number
required
VA lifetime in minutes. Must be exactly 10, 15, or 30.
cURL
curl --request POST \
  --url https://api.hyparrow.com/api/v1/subscriptions/sub-uuid-.../generate-va \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret" \
  --header "Content-Type: application/json" \
  --data '{ "expiryMinutes": 15 }'
Response
{
  "success": true,
  "message": "Virtual account generated — pay the exact amount before it expires",
  "data": {
    "accountNumber": "0123456789",
    "accountName": "Hyparrow / Jane Doe",
    "bankName": "Wema Bank",
    "bankCode": "035",
    "expiresAt": "2025-06-01T10:15:00Z"
  }
}
The customer must pay the exact subscription amount before the VA expires.

Mark as paid (manual)

For subscriptions with paymentMethod: manual, record a payment confirmation after collecting it through your own system. POST /api/v1/subscriptions/:subscriptionId/pay
reference
string
Your own payment reference.
payerName
string
Name of the payer as known by your system.
cURL
curl --request POST \
  --url https://api.hyparrow.com/api/v1/subscriptions/sub-uuid-.../pay \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret" \
  --header "Content-Type: application/json" \
  --data '{
    "reference": "TXN-20250601-001",
    "payerName": "Jane Doe"
  }'

Cancel a subscription

POST /api/v1/subscriptions/:subscriptionId/cancel Cancels the subscription immediately. No further payments are collected. The canceledAt timestamp is set on the record.
cURL
curl --request POST \
  --url https://api.hyparrow.com/api/v1/subscriptions/sub-uuid-.../cancel \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret"
Response
{
  "success": true,
  "message": "Subscription canceled",
  "data": {
    "id": "sub-uuid-...",
    "status": "canceled",
    "canceledAt": "2025-06-01T11:00:00Z"
  }
}

Get subscription status

GET /api/v1/subscriptions/:subscriptionId
cURL
curl --request GET \
  --url https://api.hyparrow.com/api/v1/subscriptions/sub-uuid-... \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret"
The response includes the full subscription object with currentPeriodStart, currentPeriodEnd, nextBillingAt, and nested customer and product objects.

Payment history

GET /api/v1/subscriptions/:subscriptionId/payments Returns a paginated list of SubscriptionPayment records, each covering a single billing cycle.
cURL
curl --request GET \
  --url "https://api.hyparrow.com/api/v1/subscriptions/sub-uuid-.../payments?page=1&limit=20" \
  --header "x-api-key: your_api_key" \
  --header "x-api-secret: your_api_secret"
Response
{
  "success": true,
  "data": [
    {
      "id": "pay-uuid-...",
      "subscriptionId": "sub-uuid-...",
      "amount": 5000.00,
      "currency": "NGN",
      "paidAt": "2025-06-01T10:05:00Z",
      "reference": "TXN-20250601-001",
      "payerName": "Jane Doe",
      "periodStart": "2025-06-01T00:00:00Z",
      "periodEnd": "2025-07-01T00:00:00Z",
      "paymentSource": "va"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1
  }
}

List subscriptions

GET /api/v1/subscriptions/
Query parameterTypeDefaultDescription
pagenumber1Page number
limitnumber20Results per page
statusstringFilter by subscription status

Public checkout

Share a hosted checkout page with the subscriber. No authentication is needed on their side.
GET https://api.hyparrow.com/api/v1/checkout/subscription/:subscriptionId
Hyparrow renders the payment options and, on completion, POSTs a status update to the checkoutCallbackUrl configured on the subscription.