The plan, this period's usage, payment state, add-ons and any pending change.
curl -X GET "https://api.rasket.com/billing" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/billing", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/billing",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "billing",
"plan": {
"code": "pro",
"name": "Pro",
"monthly_price_cents": 2000,
"included_emails": 50000,
"overage_per_1000_cents": 60
},
"effective_plan_code": "pro",
"subscription": {
"status": "active",
"current_period_start": "2026-09-01T00:00:00.000Z",
"current_period_end": "2026-10-01T00:00:00.000Z",
"invoicing": "automatic",
"latest_invoice_status": "paid"
},
"usage": {
"period_start": "2026-09-01T00:00:00.000Z",
"period_end": "2026-10-01T00:00:00.000Z",
"emails": 12840,
"included_emails": 50000
},
"pay_as_you_go": {
"enabled": false
},
"payment_method": {
"present": true,
"brand": "visa",
"last4": "4242"
},
"addons": [],
"pending_change": null,
"checkout_available": false
}
payment_method says whether a card is on file and shows its brand and last four digits. The card itself never leaves the payment provider.checkout_available is true when the team has no paid subscription yet, so POST /billing/checkout is the way to start one.
The team's invoices, newest first, with links to the hosted invoice and its PDF.
curl -X GET "https://api.rasket.com/billing/invoices" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/billing/invoices", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/billing/invoices",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": false,
"data": [
{
"id": "in_1Q2w3E4r5T6y7U8i",
"number": "ACME-0007",
"status": "paid",
"total_cents": 2000,
"currency": "usd",
"created_at": "2026-09-01T00:00:00.000Z",
"hosted_invoice_url": "https://invoices.example.com/in_1Q2w3E4r5T6y7U8i",
"invoice_pdf": "https://invoices.example.com/in_1Q2w3E4r5T6y7U8i.pdf"
}
]
}
- Read from the payment provider and cached for sixty seconds per team.
A hosted checkout page for a plan. Send the customer's browser to its `url`.
Body
Body| Field | Type | Description |
|---|
plan_code* | string | The plan to move to, such as pro or scale. |
return_url | string | Where the browser comes back to, with checkout=success or checkout=cancelled appended. Absolute https only. Defaults to the dashboard's plan page. |
curl -X POST "https://api.rasket.com/billing/checkout" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"plan_code": "pro",
"return_url": "https://app.example.com/settings/billing"
}'
const response = await fetch("https://api.rasket.com/billing/checkout", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
plan_code: "pro",
return_url: "https://app.example.com/settings/billing"
}),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/billing/checkout",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"plan_code": "pro",
"return_url": "https://app.example.com/settings/billing"
},
)
print(response.json())
Response 200
{
"object": "checkout_session",
"url": "https://checkout.example.com/c/pay/cs_live_a1B2c3D4",
"expires_at": "2026-09-13T10:00:00.000Z"
}
- The customer enters their card on the hosted page. Card details never pass through this API.
- A
return_url that is not absolute https is 422 validation_error. - Called with an API key, no email address is sent to the payment provider: the customer types one on the hosted page.
A hosted page for the payment method, address, tax ID, invoices and cancellation.
curl -X POST "https://api.rasket.com/billing/portal" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/billing/portal", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/billing/portal",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "portal_session",
"url": "https://billing.example.com/p/session/bps_a1B2c3D4"
}
- Takes no body. Send the customer's browser to
url.
Move an existing subscription to another paid plan.
Body
Body| Field | Type | Description |
|---|
plan_code* | string | The plan to move to, such as pro or scale. |
curl -X POST "https://api.rasket.com/billing/plan" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"plan_code": "scale"
}'
const response = await fetch("https://api.rasket.com/billing/plan", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
plan_code: "scale"
}),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/billing/plan",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"plan_code": "scale"
},
)
print(response.json())
Response 200
{
"object": "billing",
"plan": {
"code": "pro",
"name": "Pro",
"monthly_price_cents": 2000,
"included_emails": 50000,
"overage_per_1000_cents": 60
},
"effective_plan_code": "pro",
"subscription": {
"status": "active",
"current_period_start": "2026-09-01T00:00:00.000Z",
"current_period_end": "2026-10-01T00:00:00.000Z",
"invoicing": "automatic",
"latest_invoice_status": "paid"
},
"usage": {
"period_start": "2026-09-01T00:00:00.000Z",
"period_end": "2026-10-01T00:00:00.000Z",
"emails": 12840,
"included_emails": 50000
},
"pay_as_you_go": {
"enabled": false
},
"payment_method": {
"present": true,
"brand": "visa",
"last4": "4242"
},
"addons": [],
"pending_change": null,
"checkout_available": false
}
- An upgrade takes effect at once, with prorations. A downgrade is scheduled for the end of the period and shows in
pending_change. - Free to paid is a checkout, and paid to free is a cancellation in the portal, so both are refused here.
- A change that would turn off the team's single sign-on is refused for an API key: a signed-in admin makes it.
Keep sending beyond the plan's included emails, billed per thousand, or stop at them.
Body
Body| Field | Type | Description |
|---|
enabled* | boolean | true to continue beyond the quota, false to stop at it. |
curl -X POST "https://api.rasket.com/billing/payg" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'
const response = await fetch("https://api.rasket.com/billing/payg", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
enabled: true
}),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/billing/payg",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"enabled": True
},
)
print(response.json())
Response 200
{
"object": "billing_payg",
"enabled": true,
"overage_ceiling_emails": 500000
}
- Switching it on needs a plan with an overage rate and a payment method on file; otherwise
422 validation_error names what is missing. - It raises only the monthly quota — never the daily cap or a restricted team's limits.
Buy an add-on, or set how many units of it the team holds.
Body
Body| Field | Type | Description |
|---|
addon_code* | string | extra_domains_100, dedicated_ip or sso. |
quantity | integer | Units held after the call, 1–100. A set, not an increment. Defaults to 1. |
›2 more fields (region, expected_daily_volume)
Body, less common| Field | Type | Description |
|---|
region | string | dedicated_ip only: the region the pool should live in. |
expected_daily_volume | integer | dedicated_ip only: roughly how many emails a day the pool will carry. |
curl -X POST "https://api.rasket.com/billing/addons" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"addon_code": "extra_domains_100",
"quantity": 1
}'
const response = await fetch("https://api.rasket.com/billing/addons", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
addon_code: "extra_domains_100",
quantity: 1
}),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/billing/addons",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"addon_code": "extra_domains_100",
"quantity": 1
},
)
print(response.json())
Response 200
{
"object": "team_addon",
"addon_code": "extra_domains_100",
"name": "100 extra domains",
"monthly_price_cents": 2000,
"quantity": 1,
"status": "active",
"requested_at": "2026-09-12T10:00:00.000Z",
"provisioned_at": "2026-09-12T10:00:00.000Z"
}
- Every add-on is an item on the paid subscription, so a team without an active paid plan is
422 validation_error. dedicated_ip is a request: it is billed from now, and its status moves from requested to provisioning to active as an operator sets it up.sso needs the Scale plan or above.
Take an add-on off the subscription, with a proration.
Path parameters
Path parameters| Field | Type | Description |
|---|
addon_code* | string | extra_domains_100, dedicated_ip or sso. |
curl -X DELETE "https://api.rasket.com/billing/addons/extra_domains_100" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/billing/addons/extra_domains_100", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.delete(
"https://api.rasket.com/billing/addons/extra_domains_100",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "team_addon",
"addon_code": "extra_domains_100",
"name": "100 extra domains",
"monthly_price_cents": 2000,
"quantity": 1,
"status": "canceled",
"requested_at": "2026-09-12T10:00:00.000Z",
"provisioned_at": "2026-09-12T10:00:00.000Z"
}
- Removing
extra_domains_100 deletes no domain: the lower limit only refuses the next one you add. - Removing
sso turns single sign-on off, so an API key is refused it with 403: a signed-in admin removes it.