Base URL: https://api.cornerspot.net
Authentication: requests use a bearer token, for example Authorization: Bearer YOUR_API_KEY.
List invoices
GET /c/api/v1/invoices
Paginated, filterable invoices. Requires invoices_read + the Member Portal module.
Query parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
filter[status] | string | Comma-separated statuses (draft, open, paid, partially_paid, overdue, void, uncollectible). |
filter[account_id] | string | Comma-separated account ids. |
filter[subscription_id] | string | Comma-separated subscription ids. |
filter[due_before] | string | Only invoices due on or before this date. |
sort | string | One of invoice_number_seq,status,due_date,issued_at,total,amount_due,created_at,updated_at; - prefix descending. |
page | integer | |
per_page | integer |
Code samples
curl --request GET \
--url 'https://api.cornerspot.net/c/api/v1/invoices' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices', {
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/invoices', {
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/invoices"
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/invoices")
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/invoices',
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 invoices |
401 Unauthorized | missing or invalid API key |
402 Payment Required | the team's plan doesn't include the Member Portal module |
403 Forbidden | the key lacks the invoices_read scope |
Create a draft invoice
POST /c/api/v1/invoices
Creates a draft invoice. Line items reference catalog products (product_id) or are fully custom (description + unit_price). Taxes and discounts may be attached by id (tax_rate_ids, discount_definition_ids) or inline, at the invoice level or per line item. Requires invoices_write.
Request body
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
invoice | object | |
invoice.account_id | string · required | Required — billed account. |
invoice.currency_id | string | |
invoice.subscription_id | string | |
invoice.opportunity_id | string | |
invoice.due_date | string | |
invoice.notes | string | |
invoice.payment_terms | string | |
invoice.tax_rate_ids[] | array of string | Invoice-level taxes by id. |
invoice.discount_definition_ids[] | array of string | Invoice-level discounts by id. |
invoice.line_items[] | array of object | |
invoice.line_items[].product_id | string | Catalog product; supplies description/unit_price defaults. |
invoice.line_items[].description | string | |
invoice.line_items[].quantity | number | |
invoice.line_items[].unit_price | string | |
invoice.line_items[].tax_rate_ids[] | array of string | |
invoice.line_items[].discount_definition_ids[] | array of string |
Code samples
curl --request POST \
--url 'https://api.cornerspot.net/c/api/v1/invoices' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"invoice": {
"account_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"subscription_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"opportunity_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"due_date": "2026-01-15",
"notes": "string",
"payment_terms": "string",
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
],
"line_items": [
{}
]
}
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"invoice": {
"account_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"subscription_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"opportunity_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"due_date": "2026-01-15",
"notes": "string",
"payment_terms": "string",
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
],
"line_items": [
{}
]
}
})
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"invoice": {
"account_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"subscription_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"opportunity_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"due_date": "2026-01-15",
"notes": "string",
"payment_terms": "string",
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
],
"line_items": [
{}
]
}
})
});
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/invoices"
payload = json.dumps({
"invoice": {
"account_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"subscription_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"opportunity_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"due_date": "2026-01-15",
"notes": "string",
"payment_terms": "string",
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
],
"line_items": [
{}
]
}
}).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/invoices")
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
"invoice": {
"account_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"currency_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"subscription_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"opportunity_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
"due_date": "2026-01-15",
"notes": "string",
"payment_terms": "string",
"tax_rate_ids": [
"abc123"
],
"discount_definition_ids": [
"abc123"
],
"line_items": [
{}
]
}
})
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/invoices',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode([
'invoice' => [
'account_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'currency_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'subscription_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'opportunity_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
'due_date' => '2026-01-15',
'notes' => 'string',
'payment_terms' => 'string',
'tax_rate_ids' => [
'abc123',
],
'discount_definition_ids' => [
'abc123',
],
'line_items' => [
[],
],
],
]),
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
201 Created | created |
422 Unprocessable Content | validation errors |
Get an invoice
GET /c/api/v1/invoices/{id}
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Invoice id. |
Code samples
curl --request GET \
--url 'https://api.cornerspot.net/c/api/v1/invoices/abc123' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/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/invoices/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/invoices/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/invoices/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/invoices/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 invoice |
404 Not Found | no such invoice in this team |
Update a draft invoice
PATCH /c/api/v1/invoices/{id}
Only draft invoices may be updated; updating a finalized invoice returns 422 not_draft.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Invoice id. |
Request body
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
invoice | object | |
invoice.due_date | string | |
invoice.notes | string | |
invoice.line_items[] | array of object |
Code samples
curl --request PATCH \
--url 'https://api.cornerspot.net/c/api/v1/invoices/abc123' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"invoice": {
"due_date": "2026-01-15",
"notes": "string",
"line_items": [
{}
]
}
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/abc123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"invoice": {
"due_date": "2026-01-15",
"notes": "string",
"line_items": [
{}
]
}
})
});
const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/abc123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
"invoice": {
"due_date": "2026-01-15",
"notes": "string",
"line_items": [
{}
]
}
})
});
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/invoices/abc123"
payload = json.dumps({
"invoice": {
"due_date": "2026-01-15",
"notes": "string",
"line_items": [
{}
]
}
}).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/invoices/abc123")
request = Net::HTTP::Patch.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
"invoice": {
"due_date": "2026-01-15",
"notes": "string",
"line_items": [
{}
]
}
})
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/invoices/abc123',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer YOUR_API_KEY',
],
CURLOPT_POSTFIELDS => json_encode([
'invoice' => [
'due_date' => '2026-01-15',
'notes' => 'string',
'line_items' => [
[],
],
],
]),
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
print_r($data);
Responses
| STATUS | DESCRIPTION |
|---|---|
200 OK | updated |
Trash a draft invoice
DELETE /c/api/v1/invoices/{id}
Only draft invoices may be trashed; a finalized invoice returns 422 not_draft.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Invoice id. |
Code samples
curl --request DELETE \
--url 'https://api.cornerspot.net/c/api/v1/invoices/abc123' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/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/invoices/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/invoices/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/invoices/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/invoices/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 | trashed |
Finalize a draft invoice (draft → open)
POST /c/api/v1/invoices/{id}/finalize
Issues the invoice. Errors with 422 not_draft unless the invoice is currently a draft.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Invoice id. |
Code samples
curl --request POST \
--url 'https://api.cornerspot.net/c/api/v1/invoices/abc123/finalize' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/abc123/finalize', {
method: 'POST',
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/invoices/abc123/finalize', {
method: 'POST',
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/invoices/abc123/finalize"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, 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/invoices/abc123/finalize")
request = Net::HTTP::Post.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/invoices/abc123/finalize',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
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 | finalized |
422 Unprocessable Content | the invoice is not a draft |
Void a finalized invoice
POST /c/api/v1/invoices/{id}/void
Voids an open/partially_paid/overdue invoice. Errors with 422 not_finalized for drafts and paid invoices.
Path parameters
| FIELD | TYPE | DESCRIPTION |
|---|---|---|
id | string · required | Invoice id. |
Code samples
curl --request POST \
--url 'https://api.cornerspot.net/c/api/v1/invoices/abc123/void' \
--header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/invoices/abc123/void', {
method: 'POST',
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/invoices/abc123/void', {
method: 'POST',
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/invoices/abc123/void"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
request = urllib.request.Request(url, 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/invoices/abc123/void")
request = Net::HTTP::Post.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/invoices/abc123/void',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
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 | voided |
422 Unprocessable Content | the invoice cannot be voided in its current status |
