curl --request PATCH \
--url https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Pro Monthly (v2)",
"description": "Updated description.",
"metadata": {},
"isVisible": true,
"license": {
"enabled": true,
"activationLimit": 3,
"activationLimitEnabled": true,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": true
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"fileKeys": [
"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf"
]
}
'import requests
url = "https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/"
payload = {
"name": "Pro Monthly (v2)",
"description": "Updated description.",
"metadata": {},
"isVisible": True,
"license": {
"enabled": True,
"activationLimit": 3,
"activationLimitEnabled": True,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": True
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"fileKeys": ["tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Pro Monthly (v2)',
description: 'Updated description.',
metadata: {},
isVisible: true,
license: {
enabled: true,
activationLimit: 3,
activationLimitEnabled: true,
durationUnit: 'YEAR',
durationValue: 1,
hasExpiry: true
},
links: [{name: 'Product page', url: 'https://example.com/product'}],
fileKeys: ['tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf']
})
};
fetch('https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/', 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://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Pro Monthly (v2)',
'description' => 'Updated description.',
'metadata' => [
],
'isVisible' => true,
'license' => [
'enabled' => true,
'activationLimit' => 3,
'activationLimitEnabled' => true,
'durationUnit' => 'YEAR',
'durationValue' => 1,
'hasExpiry' => true
],
'links' => [
[
'name' => 'Product page',
'url' => 'https://example.com/product'
]
],
'fileKeys' => [
'tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf'
]
]),
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://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/"
payload := strings.NewReader("{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"identifier": "pro-monthly",
"name": "Pro Monthly",
"description": "Pro tier billed monthly.",
"product": "0d65f7c0-7e91-4f56-9b32-13a9a6a7c1de",
"metadata": {},
"version": 3,
"isLatest": true,
"modifiedOn": "2025-04-12T08:21:14.910Z",
"createdOn": "2025-03-01T08:21:14.910Z",
"details": {
"stripeProductId": "prod_ABC123"
},
"isVisible": true,
"isImported": false,
"countries": [
"US",
"IN"
],
"license": {
"enabled": true,
"activationLimit": 3,
"activationLimitEnabled": true,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": true
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"files": [
{
"id": "bf9f0fe0-c9c0-436d-8811-e412d0365470",
"name": "custom-pricinig.png",
"file": "https://cdn.kelviq.com/media/organizations/8/plan/1ad723d2-40eb-4bf0-b924-557e6697e788/53c28d460fed421a81f6c6e90114ff4f/custom-pricinig.png",
"ordering": 0,
"enabled": true,
"downloadUrl": "https://api.kelviq.com/api/v1/catalog/plans/10-july/file/bf9f0fe0-c9c0-436d-8811-e412d0365470/download/"
}
],
"ordering": 1
}Update a plan
Partial update. If the latest version is already published (isLatest=true), a new draft version is created automatically; otherwise the existing draft is mutated.
curl --request PATCH \
--url https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Pro Monthly (v2)",
"description": "Updated description.",
"metadata": {},
"isVisible": true,
"license": {
"enabled": true,
"activationLimit": 3,
"activationLimitEnabled": true,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": true
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"fileKeys": [
"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf"
]
}
'import requests
url = "https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/"
payload = {
"name": "Pro Monthly (v2)",
"description": "Updated description.",
"metadata": {},
"isVisible": True,
"license": {
"enabled": True,
"activationLimit": 3,
"activationLimitEnabled": True,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": True
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"fileKeys": ["tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Pro Monthly (v2)',
description: 'Updated description.',
metadata: {},
isVisible: true,
license: {
enabled: true,
activationLimit: 3,
activationLimitEnabled: true,
durationUnit: 'YEAR',
durationValue: 1,
hasExpiry: true
},
links: [{name: 'Product page', url: 'https://example.com/product'}],
fileKeys: ['tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf']
})
};
fetch('https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/', 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://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Pro Monthly (v2)',
'description' => 'Updated description.',
'metadata' => [
],
'isVisible' => true,
'license' => [
'enabled' => true,
'activationLimit' => 3,
'activationLimitEnabled' => true,
'durationUnit' => 'YEAR',
'durationValue' => 1,
'hasExpiry' => true
],
'links' => [
[
'name' => 'Product page',
'url' => 'https://example.com/product'
]
],
'fileKeys' => [
'tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf'
]
]),
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://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/"
payload := strings.NewReader("{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandboxapi.kelviq.com/api/v1/catalog/plans/{identifier}/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Pro Monthly (v2)\",\n \"description\": \"Updated description.\",\n \"metadata\": {},\n \"isVisible\": true,\n \"license\": {\n \"enabled\": true,\n \"activationLimit\": 3,\n \"activationLimitEnabled\": true,\n \"durationUnit\": \"YEAR\",\n \"durationValue\": 1,\n \"hasExpiry\": true\n },\n \"links\": [\n {\n \"name\": \"Product page\",\n \"url\": \"https://example.com/product\"\n }\n ],\n \"fileKeys\": [\n \"tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"identifier": "pro-monthly",
"name": "Pro Monthly",
"description": "Pro tier billed monthly.",
"product": "0d65f7c0-7e91-4f56-9b32-13a9a6a7c1de",
"metadata": {},
"version": 3,
"isLatest": true,
"modifiedOn": "2025-04-12T08:21:14.910Z",
"createdOn": "2025-03-01T08:21:14.910Z",
"details": {
"stripeProductId": "prod_ABC123"
},
"isVisible": true,
"isImported": false,
"countries": [
"US",
"IN"
],
"license": {
"enabled": true,
"activationLimit": 3,
"activationLimitEnabled": true,
"durationUnit": "YEAR",
"durationValue": 1,
"hasExpiry": true
},
"links": [
{
"name": "Product page",
"url": "https://example.com/product"
}
],
"files": [
{
"id": "bf9f0fe0-c9c0-436d-8811-e412d0365470",
"name": "custom-pricinig.png",
"file": "https://cdn.kelviq.com/media/organizations/8/plan/1ad723d2-40eb-4bf0-b924-557e6697e788/53c28d460fed421a81f6c6e90114ff4f/custom-pricinig.png",
"ordering": 0,
"enabled": true,
"downloadUrl": "https://api.kelviq.com/api/v1/catalog/plans/10-july/file/bf9f0fe0-c9c0-436d-8811-e412d0365470/download/"
}
],
"ordering": 1
}Authorizations
The Server API Key obtained from the kelviq application. Pass as a Bearer token in the Authorization header. Example: 'Authorization: Bearer YOUR_API_KEY'
Path Parameters
Plan identifier (slug). Stable across versions.
Query Parameters
Specific version number to fetch / update. Defaults to the latest version.
Body
Patch payload for a plan. If applied to a published (is_latest) plan, a new version is created automatically.
"Pro Monthly (v2)"
"Updated description."
{}
true
License configuration for a plan (used when issuing license keys).
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Additional temporary S3 keys (from POST /media/) to append to the plan's files. Existing files are left untouched.
[ "tmp/9b1c8af2-3d4e-4f9a-8b2c-1f3e5a7b9d12/plan-terms.pdf" ]
Response
Updated plan.
A versioned plan attached to a product. Updates create new versions; only the published version is is_latest=true.
URL-safe slug. Stable across versions.
"pro-monthly"
"Pro Monthly"
"Pro tier billed monthly."
UUID of the parent product.
"0d65f7c0-7e91-4f56-9b32-13a9a6a7c1de"
{}
3
True only for the currently published version.
true
"2025-04-12T08:21:14.910Z"
"2025-03-01T08:21:14.910Z"
Provider-side identifiers (e.g. stripeProductId).
{ "stripeProductId": "prod_ABC123" }
true
false
["US", "IN"]
License configuration for a plan (used when issuing license keys).
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
1