Base URL: https://api.cornerspot.net
Authentication: requests use a bearer token, for example Authorization: Bearer YOUR_API_KEY.
List products
GET /c/api/v1/products
Returns a paginated, filterable page of the team's catalog products. Active products are returned by default; pass filter[include_inactive]=true to include inactive ones. Requires the products_read scope and the CRM module.
Query parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
query | string | Full-text search over name, code, description, category. |
filter[include_inactive] | string | Set to true to include inactive products. Default: only active products are returned. |
filter[category] | string | Comma-separated category values; returns products in any of them. |
filter[pricing_model] | string | Comma-separated pricing models: one_time, recurring. |
filter[product_category_ids] | string | Comma-separated ProductCategory ids; returns products belonging to any of them. |
filter[tags] | string | Comma-separated tag ids; returns products carrying any of them. |
sort | string | Sort column, - prefix for descending. One of name,code,category,default_price,active,pricing_model,billing_frequency,default_billing_term_months,created_at,updated_at. Default -updated_at. |
page | integer | 1-based page number. |
per_page | integer | Page size (1–100, default 25). |
Code samples
curl --request GET \
--url 'https://api.cornerspot.net/c/api/v1/products' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/products', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/products', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);
import json
import urllib.request
url = "https://api.cornerspot.net/c/api/v1/products"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, headers=headers, method="GET")
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
print(data)
require "json"
require "net/http"
uri = URI("https://api.cornerspot.net/c/api/v1/products")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/products',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
],
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
200 OK | a page of products |
401 Unauthorized | missing or invalid API key |
402 Payment Required | the team's plan doesn't include the CRM module |
403 Forbidden | the key lacks the products_read scope |
Create a product
POST /c/api/v1/products
Creates a catalog product. name and pricing_model are required. Requires products_write.
Request body
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
product | object | |
product.name | string · required | Required — product name. |
product.code | string | |
product.description | string | |
product.default_price | string | Decimal string (e.g. "99.00"). |
product.currency_id | string | |
product.active | boolean | |
product.category | string | |
product.unit | string | |
product.pricing_model | string · required one of one_time, recurring | Required. |
product.billing_frequency | string one of monthly, quarterly, semi_annual, annual | Required when pricing_model is recurring. |
product.default_billing_term_months | integer | Required when pricing_model is recurring. |
product.custom_fields | object | |
product.tag_ids[] | array of string | |
product.product_category_ids[] | array of string | |
product.tax_rate_ids[] | array of string | |
product.discount_definition_ids[] | array of string |
Code samples
curl --request POST \
--url 'https://api.cornerspot.net/c/api/v1/products' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/products', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/products', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);
import json
import urllib.request
url = "https://api.cornerspot.net/c/api/v1/products"
payload = json.dumps({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
}).encode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, data=payload, headers=headers, method="POST")
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
print(data)
require "json"
require "net/http"
uri = URI("https://api.cornerspot.net/c/api/v1/products")
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/products',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode([
'product' => [
'name' => 'string',
'code' => 'string',
'description' => 'string',
'default_price' => 'string',
'currency_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'active' => true,
'category' => 'string',
'unit' => 'string',
'pricing_model' => 'one_time',
'billing_frequency' => 'monthly',
'default_billing_term_months' => 1,
'custom_fields' => [],
'tag_ids' => [
'abc123',
],
'product_category_ids' => [
'abc123',
],
'tax_rate_ids' => [
'abc123',
],
'discount_definition_ids' => [
'abc123',
],
],
]),
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
201 Created | created |
401 Unauthorized | missing or invalid API key |
402 Payment Required | the team's plan doesn't include the CRM module |
403 Forbidden | the key lacks the products_write scope |
422 Unprocessable Content | validation errors (e.g. missing name) |
Get a product
GET /c/api/v1/products/{id}
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Product id. |
Code samples
curl --request GET \
--url 'https://api.cornerspot.net/c/api/v1/products/abc123' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);
import json
import urllib.request
url = "https://api.cornerspot.net/c/api/v1/products/abc123"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, headers=headers, method="GET")
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
print(data)
require "json"
require "net/http"
uri = URI("https://api.cornerspot.net/c/api/v1/products/abc123")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/products/abc123',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
],
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
200 OK | the product |
401 Unauthorized | missing or invalid API key |
404 Not Found | no such product in this team |
Update a product
PATCH /c/api/v1/products/{id}
Updates any field(s) on the product. Requires products_write.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Product id. |
Request body
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
product | object | |
product.name | string | |
product.code | string | |
product.description | string | |
product.default_price | string | |
product.currency_id | string | |
product.active | boolean | |
product.category | string | |
product.unit | string | |
product.pricing_model | string one of one_time, recurring | |
product.billing_frequency | string one of monthly, quarterly, semi_annual, annual | |
product.default_billing_term_months | integer | |
product.custom_fields | object | |
product.tag_ids[] | array of string | |
product.product_category_ids[] | array of string | |
product.tax_rate_ids[] | array of string | |
product.discount_definition_ids[] | array of string |
Code samples
curl --request PATCH \
--url 'https://api.cornerspot.net/c/api/v1/products/abc123' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);
import json
import urllib.request
url = "https://api.cornerspot.net/c/api/v1/products/abc123"
payload = json.dumps({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
}).encode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, data=payload, headers=headers, method="PATCH")
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
print(data)
require "json"
require "net/http"
uri = URI("https://api.cornerspot.net/c/api/v1/products/abc123")
request = Net::HTTP::Patch.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
"product": {
"name": "string",
"code": "string",
"description": "string",
"default_price": "string",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"active": true,
"category": "string",
"unit": "string",
"pricing_model": "one_time",
"billing_frequency": "monthly",
"default_billing_term_months": 1,
"custom_fields": {},
"tag_ids": [
"abc123"
],
"product_category_ids": [
"abc123"
],
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
]
}
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/products/abc123',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode([
'product' => [
'name' => 'string',
'code' => 'string',
'description' => 'string',
'default_price' => 'string',
'currency_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'active' => true,
'category' => 'string',
'unit' => 'string',
'pricing_model' => 'one_time',
'billing_frequency' => 'monthly',
'default_billing_term_months' => 1,
'custom_fields' => [],
'tag_ids' => [
'abc123',
],
'product_category_ids' => [
'abc123',
],
'tax_rate_ids' => [
'abc123',
],
'discount_definition_ids' => [
'abc123',
],
],
]),
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
200 OK | updated |
401 Unauthorized | missing or invalid API key |
403 Forbidden | the key lacks the products_write scope |
404 Not Found | no such product in this team |
422 Unprocessable Content | validation errors (e.g. blank name) |
Delete (soft) a product
DELETE /c/api/v1/products/{id}
Soft-deletes the product. Line items that reference it have their product_id nulled. Requires products_write.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Product id. |
Code samples
curl --request DELETE \
--url 'https://api.cornerspot.net/c/api/v1/products/abc123' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/products/abc123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const data = await response.json();
console.log(data);
import json
import urllib.request
url = "https://api.cornerspot.net/c/api/v1/products/abc123"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, headers=headers, method="DELETE")
with urllib.request.urlopen(request) as response:
data = json.loads(response.read().decode("utf-8"))
print(data)
require "json"
require "net/http"
uri = URI("https://api.cornerspot.net/c/api/v1/products/abc123")
request = Net::HTTP::Delete.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/products/abc123',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
],
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
204 No Content | deleted |
401 Unauthorized | missing or invalid API key |
403 Forbidden | the key lacks the products_write scope |
404 Not Found | no such product in this team |
