curl --request PATCH \
--url https://api.zode.dev/v1/billing \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"daily_cap_micros": 50000000000,
"sandbox_default_cap_micros": 50000000000,
"auto_top_up": {
"enabled": true,
"threshold_micros": 123,
"amount_micros": 123
},
"billing_email": "<string>",
"plan": "<string>"
}
'import requests
url = "https://api.zode.dev/v1/billing"
payload = {
"daily_cap_micros": 50000000000,
"sandbox_default_cap_micros": 50000000000,
"auto_top_up": {
"enabled": True,
"threshold_micros": 123,
"amount_micros": 123
},
"billing_email": "<string>",
"plan": "<string>"
}
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({
daily_cap_micros: 50000000000,
sandbox_default_cap_micros: 50000000000,
auto_top_up: {enabled: true, threshold_micros: 123, amount_micros: 123},
billing_email: '<string>',
plan: '<string>'
})
};
fetch('https://api.zode.dev/v1/billing', 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.zode.dev/v1/billing",
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([
'daily_cap_micros' => 50000000000,
'sandbox_default_cap_micros' => 50000000000,
'auto_top_up' => [
'enabled' => true,
'threshold_micros' => 123,
'amount_micros' => 123
],
'billing_email' => '<string>',
'plan' => '<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://api.zode.dev/v1/billing"
payload := strings.NewReader("{\n \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\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://api.zode.dev/v1/billing")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zode.dev/v1/billing")
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 \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"plan": {
"name": "free",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
},
"limits": {
"name": "free",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
},
"trial": {
"days": 123,
"available": true,
"active": true,
"plan": "<string>",
"started_at": "2023-11-07T05:31:56Z",
"ends_at": "2023-11-07T05:31:56Z",
"source": "self"
},
"period": {
"start": "2023-12-25",
"end": "2023-12-25",
"as_of": "2023-11-07T05:31:56Z"
},
"usage": {
"compute_micros": 123,
"storage_micros": 123,
"static_ip_micros": 123,
"billable_micros": 123,
"ai_micros": 123,
"ai_billed": true,
"ai_known": true
},
"estimate": {
"lines": [
{
"description": "<string>",
"kind": "<string>",
"micros": 123,
"cents": 123
}
],
"informational": [
{
"description": "<string>",
"kind": "<string>",
"micros": 123,
"cents": 123
}
],
"total_micros": 123,
"total_cents": 123
},
"credit": {
"balance_micros": 123,
"auto_top_up": {
"enabled": true,
"threshold_micros": 123,
"amount_micros": 123
}
},
"caps": {
"daily_micros": 123,
"sandbox_default_micros": 123,
"today_micros": 123
},
"billing_email": "<string>",
"provider": {
"configured": true,
"name": "<string>",
"plans": [
"<string>"
],
"offers": [
{
"name": "<string>",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
}
]
},
"can_manage": true
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}Change caps and billing
Change caps, auto top-up, billing email or plan (owner, billing).
Absent fields are unchanged; a cap set to null is removed. Auto
top-up and plan changes need a payment provider: without one they
answer 409 billing_not_open. Auto top-up adds 5to1,000 in
whole cents. plan moves an existing Stripe subscription (or
cancels it for free); the org’s plan changes only when Stripe’s
customer.subscription.* webhook confirms it. A paid plan without
a subscription answers 409 checkout_required: use
POST /v1/billing/checkout. Audited as billing.update.
curl --request PATCH \
--url https://api.zode.dev/v1/billing \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"daily_cap_micros": 50000000000,
"sandbox_default_cap_micros": 50000000000,
"auto_top_up": {
"enabled": true,
"threshold_micros": 123,
"amount_micros": 123
},
"billing_email": "<string>",
"plan": "<string>"
}
'import requests
url = "https://api.zode.dev/v1/billing"
payload = {
"daily_cap_micros": 50000000000,
"sandbox_default_cap_micros": 50000000000,
"auto_top_up": {
"enabled": True,
"threshold_micros": 123,
"amount_micros": 123
},
"billing_email": "<string>",
"plan": "<string>"
}
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({
daily_cap_micros: 50000000000,
sandbox_default_cap_micros: 50000000000,
auto_top_up: {enabled: true, threshold_micros: 123, amount_micros: 123},
billing_email: '<string>',
plan: '<string>'
})
};
fetch('https://api.zode.dev/v1/billing', 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.zode.dev/v1/billing",
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([
'daily_cap_micros' => 50000000000,
'sandbox_default_cap_micros' => 50000000000,
'auto_top_up' => [
'enabled' => true,
'threshold_micros' => 123,
'amount_micros' => 123
],
'billing_email' => '<string>',
'plan' => '<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://api.zode.dev/v1/billing"
payload := strings.NewReader("{\n \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\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://api.zode.dev/v1/billing")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zode.dev/v1/billing")
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 \"daily_cap_micros\": 50000000000,\n \"sandbox_default_cap_micros\": 50000000000,\n \"auto_top_up\": {\n \"enabled\": true,\n \"threshold_micros\": 123,\n \"amount_micros\": 123\n },\n \"billing_email\": \"<string>\",\n \"plan\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"plan": {
"name": "free",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
},
"limits": {
"name": "free",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
},
"trial": {
"days": 123,
"available": true,
"active": true,
"plan": "<string>",
"started_at": "2023-11-07T05:31:56Z",
"ends_at": "2023-11-07T05:31:56Z",
"source": "self"
},
"period": {
"start": "2023-12-25",
"end": "2023-12-25",
"as_of": "2023-11-07T05:31:56Z"
},
"usage": {
"compute_micros": 123,
"storage_micros": 123,
"static_ip_micros": 123,
"billable_micros": 123,
"ai_micros": 123,
"ai_billed": true,
"ai_known": true
},
"estimate": {
"lines": [
{
"description": "<string>",
"kind": "<string>",
"micros": 123,
"cents": 123
}
],
"informational": [
{
"description": "<string>",
"kind": "<string>",
"micros": 123,
"cents": 123
}
],
"total_micros": 123,
"total_cents": 123
},
"credit": {
"balance_micros": 123,
"auto_top_up": {
"enabled": true,
"threshold_micros": 123,
"amount_micros": 123
}
},
"caps": {
"daily_micros": 123,
"sandbox_default_micros": 123,
"today_micros": 123
},
"billing_email": "<string>",
"provider": {
"configured": true,
"name": "<string>",
"plans": [
"<string>"
],
"offers": [
{
"name": "<string>",
"monthly_fee_micros": 123,
"included_usage_micros": 123,
"signup_credit_micros": 123,
"max_concurrent": 123,
"recorder_days": 123
}
]
},
"can_manage": true
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}Authorizations
An API key (zode_tok_...). Create one in the console under API keys (https://console.zode.dev/tokens), or with zode login.
Body
Response
Billing after the change
Plan, this calendar month (UTC) of usage and the invoice the ledger
would build from it today, credit, caps and the billing email. AI
spend is shown, not billed (ai_billed), and unknown when the
flight recorder is off (ai_known). provider.configured is false
until billing opens: no cards, invoices or plan changes then.