Initialize a Subscription
Initialize a subscription after you have created the customer and plan. The customer and plan must belong to your account and to the environment selected by your secret key.
Endpoint
POST https://backendapi.sayswitchgroup.com/api/v1/subscriptionIdempotency Key
Every initialization request requires an Idempotency-Key header:
Idempotency-Key: email-subscription-test-001Generate a unique value for the subscription operation and keep it when retrying the same request. Repeating a successful request with the same key returns the existing subscription instead of creating a duplicate.
An idempotency key can be up to 100 characters and is scoped to your account and test or live environment. Use a new key when you intend to create a different subscription.
Request
curl --request POST \
--url https://backendapi.sayswitchgroup.com/api/v1/subscription \
--header "Authorization: Bearer YOUR_SECRET_KEY" \
--header "Idempotency-Key: email-subscription-test-001" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{
"customer": "CUS_customer_code",
"plan_code": "PLN_plan_code",
"start_date": "2026-10-01T00:00:00+01:00",
"return_url": "https://merchant.example/subscription/complete",
"metadata": {
"merchant_order_id": "EMAIL-ORDER-001"
}
}'Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
customer | string | Yes | An existing customer code or customer email belonging to your account. |
plan_code | string | Yes | An active plan code belonging to your account. |
start_date | ISO 8601 date-time | No | When billing should begin. If omitted, billing begins immediately after authorization. |
return_url | URL | No | Your page to which the customer can be redirected after hosted authorization. |
metadata | object | No | Your own structured data, returned in subscription responses and lifecycle webhooks. |
Start Date
Use an ISO 8601 date and time with a timezone. For example, midnight in Lagos on October 1, 2026 is:
2026-10-01T00:00:00+01:00If start_date is omitted, the first charge is due immediately after successful card authorization. A future date delays the first charge until that date.
Return URL
return_url belongs to your website, not SaySwitch. When applicable, the hosted authorization flow redirects the customer back with subscription_code and status query parameters:
https://merchant.example/subscription/complete?subscription_code=SUB_example&status=activeLive subscriptions require an HTTPS return URL. Test subscriptions accept HTTP or HTTPS. A browser redirect is not final proof of activation or payment; retrieve the subscription and process webhooks before granting access or fulfilling an order.
Response
A newly initialized subscription returns HTTP 201.
{
"status": true,
"message": "Subscription initialized. Customer authorization is required.",
"data": {
"id": 84,
"business_id": 169,
"customer_id": 4512,
"recurring_plan_id": 42,
"recurring_payment_method_id": null,
"subscription_code": "SUB_7q2m9x4k1v8b5n3p6r0s",
"return_url": "https://merchant.example/subscription/complete",
"status": "pending_authorization",
"start_at": "2026-09-30T23:00:00.000000Z",
"next_charge_at": null,
"authorization_expires_at": "2026-09-26T10:30:00.000000Z",
"authorization_started_at": null,
"cancelled_at": null,
"successful_charge_count": 0,
"metadata": {
"merchant_order_id": "EMAIL-ORDER-001"
},
"domain": "test",
"created_at": "2026-09-25T10:30:00.000000Z",
"updated_at": "2026-09-25T10:30:00.000000Z",
"plan": {
"plan_code": "PLN_plan_code",
"name": "Email Monthly",
"amount": "15000.00",
"currency": "NGN",
"interval": "monthly",
"invoice_limit": 12,
"status": "active"
},
"customer": {
"id": 4512,
"email": "customer@example.com",
"first_name": "Ada",
"last_name": "Okafor",
"customer_code": "CUS_customer_code",
"domain": "test"
},
"payment_method": null,
"authorization_url": "https://checkout.sayswitchgroup.com/pay/subscription/SUBINIT_example"
}
}The related plan and customer objects may contain additional non-sensitive account fields. Redirect the customer to the exact URL in data.authorization_url; do not build this URL yourself.
Replaying the same initialized operation with the same idempotency key returns HTTP 200 with:
{
"status": true,
"message": "Existing subscription returned for this idempotency key.",
"data": {}
}The replayed data object contains the same subscription structure. If the subscription is still pending_authorization, authorization_url is returned; for other statuses it is null.
Common Errors
Missing Idempotency Key
HTTP 422:
{
"status": false,
"message": "Invalid subscription details.",
"errors": {
"idempotency_key": [
"The idempotency key field is required."
]
}
}Customer Not Found
HTTP 422:
{
"message": "The selected customer does not exist.",
"errors": {
"customer": [
"The selected customer does not exist."
]
}
}Plan Not Found or Inactive
HTTP 422:
{
"message": "The selected plan is invalid or inactive.",
"errors": {
"plan_code": [
"The selected plan is invalid or inactive."
]
}
}These responses are also used when the customer or plan belongs to a different merchant or test/live environment.
Invalid Start Date
HTTP 422:
{
"status": false,
"message": "Invalid subscription details.",
"errors": {
"start_date": [
"The start date is not a valid date."
]
}
}Invalid Return URL
HTTP 422 in live mode when the URL is not HTTPS:
{
"status": false,
"message": "Invalid subscription details.",
"errors": {
"return_url": [
"The return URL must use HTTPS for live subscriptions."
]
}
}Validation errors return HTTP 422, missing resources return HTTP 404, and missing or invalid secret-key authentication returns HTTP 401.