curl --request POST \
--url https://api.example.com/subscription-links \
--header 'ApiKey: <apikey>' \
--header 'Content-Type: application/json' \
--header 'Environment: <environment>' \
--header 'MerchantId: <merchantid>' \
--data '
{
"amount": 5000,
"currency": "XOF",
"purchaseReference": "SUB_2024_001",
"frequency": "monthly",
"startDate": "2026-08-01",
"country": "CI",
"description": "<string>",
"expirationDate": "2026-12-31T23:59:59.000Z",
"successUrl": "https://merchant.com/success",
"failureUrl": "https://merchant.com/failure"
}
'import requests
url = "https://api.example.com/subscription-links"
payload = {
"amount": 5000,
"currency": "XOF",
"purchaseReference": "SUB_2024_001",
"frequency": "monthly",
"startDate": "2026-08-01",
"country": "CI",
"description": "<string>",
"expirationDate": "2026-12-31T23:59:59.000Z",
"successUrl": "https://merchant.com/success",
"failureUrl": "https://merchant.com/failure"
}
headers = {
"ApiKey": "<apikey>",
"MerchantId": "<merchantid>",
"Environment": "<environment>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
ApiKey: '<apikey>',
MerchantId: '<merchantid>',
Environment: '<environment>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 5000,
currency: 'XOF',
purchaseReference: 'SUB_2024_001',
frequency: 'monthly',
startDate: '2026-08-01',
country: 'CI',
description: '<string>',
expirationDate: '2026-12-31T23:59:59.000Z',
successUrl: 'https://merchant.com/success',
failureUrl: 'https://merchant.com/failure'
})
};
fetch('https://api.example.com/subscription-links', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/subscription-links",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 5000,
'currency' => 'XOF',
'purchaseReference' => 'SUB_2024_001',
'frequency' => 'monthly',
'startDate' => '2026-08-01',
'country' => 'CI',
'description' => '<string>',
'expirationDate' => '2026-12-31T23:59:59.000Z',
'successUrl' => 'https://merchant.com/success',
'failureUrl' => 'https://merchant.com/failure'
]),
CURLOPT_HTTPHEADER => [
"ApiKey: <apikey>",
"Content-Type: application/json",
"Environment: <environment>",
"MerchantId: <merchantid>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/subscription-links"
payload := strings.NewReader("{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("ApiKey", "<apikey>")
req.Header.Add("MerchantId", "<merchantid>")
req.Header.Add("Environment", "<environment>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/subscription-links")
.header("ApiKey", "<apikey>")
.header("MerchantId", "<merchantid>")
.header("Environment", "<environment>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/subscription-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["ApiKey"] = '<apikey>'
request["MerchantId"] = '<merchantid>'
request["Environment"] = '<environment>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}"
response = http.request(request)
puts response.read_body{
"id": "pl_z1urYtVFgEebtcj8fxp4v",
"url": "https://pay.hub2.com/pl_z1urYtVFgEebtcj8fxp4v",
"status": "active",
"purchaseReference": "ORDER-12345",
"amount": 1000,
"currency": "XOF",
"currentSuccessCount": 0,
"maximumAttempts": 3,
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:30:00.000Z",
"expirationDate": "2024-01-15T14:30:00.000Z",
"customerPhoneNumber": "123456789",
"type": "single_use",
"openAmount": false,
"minAmount": 500,
"maxAmount": 100000,
"maximumPayments": 50,
"customerFields": [
{
"fieldName": "national_id",
"fieldLabel": "National ID",
"fieldType": "text",
"isRequired": true,
"fieldPlaceholder": "<string>"
}
]
}{
"status": 400,
"error": {
"statusCode": 400,
"message": [
"destination.provider must be a string"
],
"error": "Bad Request"
}
}{
"status": 401,
"error": {
"type": "authorization_error",
"code": "wrong_credentials",
"message": "L'ID marchand et/ou la clé d'API sont incorrects."
}
}{
"status": 403,
"error": {
"statusCode": 403,
"message": "Forbidden",
"error": "<string>"
}
}{
"httpStatus": 409,
"type": "invalid_request",
"code": "unsupported_action",
"message": "This action is not supported"
}{
"status": 429,
"error": "ThrottlerException: Too Many Requests"
}{
"type": "internal_error",
"code": [
"internal_error",
"wrong_credentials",
"not_granted",
"live_mode_not_granted"
],
"message": "An error occurred on our system. Please try again later."
}{
"status": 503,
"code": "merchant_group_unavailable",
"message": "Your merchant group could not be verified. Please retry in a few moments.",
"request_id": "<string>"
}Create Subscription Link
Create a new card-on-file subscription enrollment link
curl --request POST \
--url https://api.example.com/subscription-links \
--header 'ApiKey: <apikey>' \
--header 'Content-Type: application/json' \
--header 'Environment: <environment>' \
--header 'MerchantId: <merchantid>' \
--data '
{
"amount": 5000,
"currency": "XOF",
"purchaseReference": "SUB_2024_001",
"frequency": "monthly",
"startDate": "2026-08-01",
"country": "CI",
"description": "<string>",
"expirationDate": "2026-12-31T23:59:59.000Z",
"successUrl": "https://merchant.com/success",
"failureUrl": "https://merchant.com/failure"
}
'import requests
url = "https://api.example.com/subscription-links"
payload = {
"amount": 5000,
"currency": "XOF",
"purchaseReference": "SUB_2024_001",
"frequency": "monthly",
"startDate": "2026-08-01",
"country": "CI",
"description": "<string>",
"expirationDate": "2026-12-31T23:59:59.000Z",
"successUrl": "https://merchant.com/success",
"failureUrl": "https://merchant.com/failure"
}
headers = {
"ApiKey": "<apikey>",
"MerchantId": "<merchantid>",
"Environment": "<environment>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
ApiKey: '<apikey>',
MerchantId: '<merchantid>',
Environment: '<environment>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 5000,
currency: 'XOF',
purchaseReference: 'SUB_2024_001',
frequency: 'monthly',
startDate: '2026-08-01',
country: 'CI',
description: '<string>',
expirationDate: '2026-12-31T23:59:59.000Z',
successUrl: 'https://merchant.com/success',
failureUrl: 'https://merchant.com/failure'
})
};
fetch('https://api.example.com/subscription-links', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/subscription-links",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 5000,
'currency' => 'XOF',
'purchaseReference' => 'SUB_2024_001',
'frequency' => 'monthly',
'startDate' => '2026-08-01',
'country' => 'CI',
'description' => '<string>',
'expirationDate' => '2026-12-31T23:59:59.000Z',
'successUrl' => 'https://merchant.com/success',
'failureUrl' => 'https://merchant.com/failure'
]),
CURLOPT_HTTPHEADER => [
"ApiKey: <apikey>",
"Content-Type: application/json",
"Environment: <environment>",
"MerchantId: <merchantid>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/subscription-links"
payload := strings.NewReader("{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("ApiKey", "<apikey>")
req.Header.Add("MerchantId", "<merchantid>")
req.Header.Add("Environment", "<environment>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/subscription-links")
.header("ApiKey", "<apikey>")
.header("MerchantId", "<merchantid>")
.header("Environment", "<environment>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/subscription-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["ApiKey"] = '<apikey>'
request["MerchantId"] = '<merchantid>'
request["Environment"] = '<environment>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 5000,\n \"currency\": \"XOF\",\n \"purchaseReference\": \"SUB_2024_001\",\n \"frequency\": \"monthly\",\n \"startDate\": \"2026-08-01\",\n \"country\": \"CI\",\n \"description\": \"<string>\",\n \"expirationDate\": \"2026-12-31T23:59:59.000Z\",\n \"successUrl\": \"https://merchant.com/success\",\n \"failureUrl\": \"https://merchant.com/failure\"\n}"
response = http.request(request)
puts response.read_body{
"id": "pl_z1urYtVFgEebtcj8fxp4v",
"url": "https://pay.hub2.com/pl_z1urYtVFgEebtcj8fxp4v",
"status": "active",
"purchaseReference": "ORDER-12345",
"amount": 1000,
"currency": "XOF",
"currentSuccessCount": 0,
"maximumAttempts": 3,
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:30:00.000Z",
"expirationDate": "2024-01-15T14:30:00.000Z",
"customerPhoneNumber": "123456789",
"type": "single_use",
"openAmount": false,
"minAmount": 500,
"maxAmount": 100000,
"maximumPayments": 50,
"customerFields": [
{
"fieldName": "national_id",
"fieldLabel": "National ID",
"fieldType": "text",
"isRequired": true,
"fieldPlaceholder": "<string>"
}
]
}{
"status": 400,
"error": {
"statusCode": 400,
"message": [
"destination.provider must be a string"
],
"error": "Bad Request"
}
}{
"status": 401,
"error": {
"type": "authorization_error",
"code": "wrong_credentials",
"message": "L'ID marchand et/ou la clé d'API sont incorrects."
}
}{
"status": 403,
"error": {
"statusCode": 403,
"message": "Forbidden",
"error": "<string>"
}
}{
"httpStatus": 409,
"type": "invalid_request",
"code": "unsupported_action",
"message": "This action is not supported"
}{
"status": 429,
"error": "ThrottlerException: Too Many Requests"
}{
"type": "internal_error",
"code": [
"internal_error",
"wrong_credentials",
"not_granted",
"live_mode_not_granted"
],
"message": "An error occurred on our system. Please try again later."
}{
"status": 503,
"code": "merchant_group_unavailable",
"message": "Your merchant group could not be verified. Please retry in a few moments.",
"request_id": "<string>"
}Headers
Your api key. To create a key, please get into our dashboard. If you don't have access to it, please reach the Support team.
Your merchant ID. This information is available in our dashboard. If you don't have access to it, please reach the Support team.
Allow you to choose between the sandbox mode to perform some tests or the live mode for real world transactions.
live, sandbox Body
Recurring debit amount charged on each occurrence.
x >= 15000
Three-letter ISO 4217 currency code
"XOF"
Unique reference for this subscription
100"SUB_2024_001"
Recurring debit frequency.
weekly, monthly "monthly"
ISO-8601 date of the first recurring debit.
"2026-08-01"
Two-letter ISO 3166-1 alpha-2 country code where the enrollment will be processed
"CI"
Description of the subscription link
300Expiration date for the enrollment link (ISO 8601 format)
"2026-12-31T23:59:59.000Z"
URL to redirect to after successful enrollment
"https://merchant.com/success"
URL to redirect to after failed enrollment
"https://merchant.com/failure"
Response
Subscription link created successfully
Unique identifier for the payment link
"pl_z1urYtVFgEebtcj8fxp4v"
URL for the payment link
"https://pay.hub2.com/pl_z1urYtVFgEebtcj8fxp4v"
Current status of the payment link
active, expired, closed, completed "active"
Merchant reference for the payment
"ORDER-12345"
Amount intended to be charged in the smallest currency unit. Null when openAmount is true.
1000
Three-letter ISO 4217 currency code
"XOF"
Number of successful payments recorded for this link
0
Maximum number of failed payments allowed per user
3
Creation date in ISO 8601 format
"2024-01-15T12:00:00.000Z"
Last update date in ISO 8601 format
"2024-01-15T12:30:00.000Z"
Expiration date in ISO 8601 format
"2024-01-15T14:30:00.000Z"
Restricted MSISDN
"123456789"
Type of the payment link
single_use, multi_use, bill_payment "single_use"
When true, the payer decides the amount at payment time.
false
Minimum amount the payer can enter (only when openAmount is true).
500
Maximum amount the payer can enter (only when openAmount is true).
100000
Maximum successful payments allowed (omitted when unlimited multi_use)
50
Custom form fields defined on this payment link. Absent when the link has no customer fields.
Show child attributes
Show child attributes
