Plans
Create Plan
Create a new pricing plan
POST
/
v1
/
plans
Create a plan
curl --request POST \
--url https://billing.example.com/v1/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"code": "<string>",
"interval_count": 2,
"amount": 123,
"currency": "<string>",
"hsn_code": "<string>"
}
'import requests
url = "https://billing.example.com/v1/plans"
payload = {
"name": "<string>",
"code": "<string>",
"interval_count": 2,
"amount": 123,
"currency": "<string>",
"hsn_code": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
code: '<string>',
interval_count: 2,
amount: 123,
currency: '<string>',
hsn_code: '<string>'
})
};
fetch('https://billing.example.com/v1/plans', 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://billing.example.com/v1/plans",
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([
'name' => '<string>',
'code' => '<string>',
'interval_count' => 2,
'amount' => 123,
'currency' => '<string>',
'hsn_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://billing.example.com/v1/plans"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://billing.example.com/v1/plans")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"code": "<string>",
"interval_unit": "day",
"interval_count": 123,
"active": true,
"hsn_code": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"prices": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"amount": 123,
"type": "recurring",
"created_at": "2023-11-07T05:31:56Z"
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the plan |
description | string | No | Plan description |
interval | string | Yes | Billing interval: day, week, month, year |
interval_count | integer | No | Number of intervals (default: 1) |
trial_days | integer | No | Free trial period in days |
prices | array | Yes | Price configurations |
features | array | No | List of included features |
metadata | object | No | Custom key-value data |
Price Object
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Price in smallest currency unit |
currency | string | Yes | Three-letter ISO currency code |
billing_scheme | string | No | per_unit, tiered, or metered |
Example Request
curl -X POST https://api.recurso.dev/v1/plans \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro Plan",
"description": "For growing teams",
"interval": "month",
"trial_days": 14,
"prices": [
{ "amount": 4999, "currency": "INR" },
{ "amount": 999, "currency": "USD" }
],
"features": ["Unlimited users", "Priority support"]
}'
Response
{
"id": "plan_pro_01",
"object": "plan",
"name": "Pro Plan",
"description": "For growing teams",
"interval": "month",
"interval_count": 1,
"trial_days": 14,
"active": true,
"prices": [
{ "amount": 4999, "currency": "INR" },
{ "amount": 999, "currency": "USD" }
],
"features": ["Unlimited users", "Priority support"],
"created_at": "2024-01-15T10:30:00Z"
}
Errors
| Status | Code | When | Fix |
|---|---|---|---|
| 400 | validation_failed | The request body is not valid JSON or fails binding. | Send a well-formed JSON body with the required fields. |
| 400 | validation_failed | amount is zero or negative (amount must be positive). | Set amount to a positive integer in minor units (e.g. cents). |
| 401 | unauthorized | API key missing or invalid (invalid_api_key), or a live/test mode mismatch (key_mode_mismatch). | Send Authorization: Bearer <api_key> with a key for the right mode. |
| 500 | internal_error | The plan could not be persisted. | Retry; if it persists, contact support with the request timestamp. |
Authorizations
Tenant API key obtained from POST /auth/register or POST /v1/developer/keys.
Body
application/json
Unique plan code (e.g. gold-monthly).
Available options:
day, week, month, year Required range:
x >= 1Price in the lowest currency unit (e.g. cents/paise).
ISO 4217 code.
Required string length:
3Optional HSN/SAC code for this plan. Each invoice line for the plan is taxed at this code's GST rate. Empty falls back to the tenant SAC (then the 998314 default).
Response
Plan created.
Available options:
day, week, month, year HSN/SAC code the plan's invoice lines are taxed at (empty = tenant SAC default).
Show child attributes
Show child attributes
⌘I
Create a plan
curl --request POST \
--url https://billing.example.com/v1/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"code": "<string>",
"interval_count": 2,
"amount": 123,
"currency": "<string>",
"hsn_code": "<string>"
}
'import requests
url = "https://billing.example.com/v1/plans"
payload = {
"name": "<string>",
"code": "<string>",
"interval_count": 2,
"amount": 123,
"currency": "<string>",
"hsn_code": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
code: '<string>',
interval_count: 2,
amount: 123,
currency: '<string>',
hsn_code: '<string>'
})
};
fetch('https://billing.example.com/v1/plans', 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://billing.example.com/v1/plans",
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([
'name' => '<string>',
'code' => '<string>',
'interval_count' => 2,
'amount' => 123,
'currency' => '<string>',
'hsn_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://billing.example.com/v1/plans"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://billing.example.com/v1/plans")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"code\": \"<string>\",\n \"interval_count\": 2,\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"hsn_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"code": "<string>",
"interval_unit": "day",
"interval_count": 123,
"active": true,
"hsn_code": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"prices": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"amount": 123,
"type": "recurring",
"created_at": "2023-11-07T05:31:56Z"
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}