Client API: Services
Order and manage provisioned services (lifecycle, actions, cancel, plan changes) and the add-ons on each one.
Order and manage provisioned services (lifecycle, actions, cancel, plan changes) and the add-ons on each one.
Base URL: https://api.coritan.com/api/v1. Paths below are complete.
To try these requests in the browser, open the interactive Client API reference.
Operations
Section titled Operations| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/services/ |
List services |
| POST | /api/v1/services/order |
Order a platform service, and any add-ons bought with it |
| GET | /api/v1/services/{service_ref} |
Fetch a service by numeric id OR underlying resource UUID (instance/server/IP) |
| POST | /api/v1/services/{service_ref}/actions |
Execute action |
| GET | /api/v1/services/{service_ref}/addons |
The add-ons on one of your services, and the ones you can add |
| POST | /api/v1/services/{service_ref}/addons |
Add a capacity add-on to one of your active services |
| POST | /api/v1/services/{service_ref}/addons/preview |
What adding an add-on to one of your services would charge |
| DELETE | /api/v1/services/{service_ref}/addons/{addon_ref} |
Remove a capacity add-on from one of your services |
| POST | /api/v1/services/{service_ref}/cancel |
Cancel the service now or at the end of its term |
| POST | /api/v1/services/{service_ref}/change-plan |
Change the service to another price, prorated |
| GET | /api/v1/services/{service_ref}/events |
Get events |
| POST | /api/v1/services/{service_ref}/keep |
Withdraw a cancellation set for the end of the term, so the service keeps renewing |
| GET | /api/v1/services/{service_ref}/upgrade-preview |
What changing the service to another price would cost now |
List services
Section titled List servicesGET /api/v1/services/
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
status |
query | string | no | |
tag |
query | string | no | Filter by resource tag |
resource_type |
query | string | no | Filter by product: vps (or cloud_compute), container (or container_apps), ip (or floating_ip), mail, smtp_relay or storage (Snapshot Storage). Another word answers 422 with the words it accepts. |
limit |
query | integer | no | Default: 100. |
offset |
query | integer | no | Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
A 200 response is a list; each item has these fields:
| Field | Type | Description |
|---|---|---|
[].id |
integer | |
[].user_id |
integer | |
[].product_id |
integer | |
[].pricing_id |
integer | |
[].hostname |
string or null | |
[].status |
string | |
[].billing_cycle |
string | |
[].amount |
number | |
[].next_due_date |
string (date-time) or null | |
[].config |
object or null | |
[].module_data |
object or null | |
[].suspension_reason |
string or null | |
[].provisioned_at |
string (date-time) or null | |
[].created_at |
string (date-time) | |
[].updated_at |
string (date-time) | |
[].product_name |
string or null | |
[].product_slug |
string or null | |
[].module_name |
string or null | |
[].pricing_name |
string or null | |
[].termination_date |
string (date-time) or null | |
[].billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
[].monthly_cap |
number or null | |
[].hourly_usage_this_month |
number or null | |
[].hourly_cap_reached |
boolean or null | |
[].tags |
array of string | |
[].resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
[].resource.type |
string | Module resource type: vps | container | ip | external_server |
[].resource.label |
string or null | Human label: hostname, server name, or IP/CIDR |
[].resource.status |
string or null | Resource-level status (not billing status) |
[].resource.address |
string or null | Primary reachability address (IP, IP:port, or CIDR) |
[].resource.detail |
Detail | Module-specific fields (uuids, node, plan, attach state, …) |
Order a platform service, and any add-ons bought with it
Section titled Order a platform service, and any add-ons bought with itPOST /api/v1/services/order
Order a platform service, and any add-ons bought with it.
The handler checks every add-on before it writes anything. One that the
order cannot take refuses the whole order with 422 and
{"errors": [<sentence>]}, and the handler creates nothing:
- the parent decides which add-ons it takes. An instance takes Floating IP, DDoS Shield, Mail Hosting and SMTP Relay; a server takes those and Snapshot Storage; a floating IP takes DDoS Shield; a mail plan takes SMTP Relay. A server and an instance also take the capacity add-ons that fit them (more ports, databases or backup slots, automatic backups). Any other product takes none;
- the add-on product exists and is active. It is not the free plan, and it is not a product that goes on a service the customer already has, such as an SMTP Relay dedicated IP;
- its price belongs to it, is active and costs more than $0. Without a
pricing_idthe order takes the price with the parent's billing cycle, else the monthly price, else the first active price. An hourly price needs the same deposit as an hourly service; - an order takes one each of DDoS Shield, Mail Hosting, SMTP Relay and Snapshot Storage, up to 4 floating IPs for an instance and one /32 for a server. A floating IP with a quantity above 1 becomes one service per unit. A capacity add-on sold per unit becomes one service that holds its quantity, up to 20 units; one sold as a switch, and every other add-on, takes a quantity of 1;
- an instance takes floating IPs only with its included IPv4
(
order_ipv4), which stays its free primary address; - DDoS Shield needs an address in the order: the instance's included
IPv4, a floating IP add-on on a server, or the floating IP being
ordered. The order names those addresses itself, so its config may not
set
ip_service_ids; - each add-on's config passes the checks an order of that product on its own passes, and its config options change its price the same way. A floating IP comes from the parent's location unless it names a pool.
Each add-on becomes a pending service of the parent's owner, with
addon_of_service_id in its config, and the parent's config lists them
in addon_service_ids. When any of them needs a first payment, the
parent, its included IP and the add-ons share one first invoice, and
credit pays it once. Every service then provisions on its own job, queued
when that invoice is paid, or at once when nothing is owed. Once the
services are up, the floating IPs attach to the parent and the Shield
profile protects the addresses. A replayed order answers with the add-ons
it created the first time and creates nothing.
promo_code takes the code's discount off the product ordered, as a
credit line on the first invoice; add-ons bought with it are charged in
full. A code that repeats discounts the renewals after that. A code the
order cannot use refuses the whole order with 422,
{"errors": [<sentence>], "promo": <reason>}, before anything is
written. A first invoice the code brings to zero is paid at once.
DDoS Shield ordered on its own may name in ip_service_ids only the
customer's own floating IPs that are not terminated or cancelled.
A server's name (config.name, else hostname) follows the rule a
rename follows: 2–48 characters once its spaces are collapsed, letters,
digits, spaces and - _ . ' ! & ( ) [ ] , : +. Any other answers 422.
A game server order may set config.start_on_install to true. We
then start the server once its first install finishes. Without it, or
with false, the server stays stopped until you start it. A server
that waits to be restored from a snapshot stays stopped either way.
A product we no longer sell, one sold only through our sales team and one a plan includes answer 422 with a sentence that names the product. Services already on such a product renew and change plan as before. A product sold before the account plans stays on sale to an account the plans do not apply to yet. A capacity add-on that goes on a service answers 422 when ordered on its own.
An account plan answers 403, {"code": "plans_not_open"}, while plans
are not open on the account, and 409 when the account already has a plan
or an unpaid order for one.
Mail Hosting, SMTP Relay, Object Storage and a floating IP answer 422,
{"code": "out_of_stock", "message", "errors"}, when we cannot set
the order up right now: mail is not open for orders or has no capacity,
the region has no storage, or no address is in stock. Nothing is charged
and no invoice is made. GET /api/v1/availability lists what is
available now.
org_slug orders an App Deployment for that organization
(:mod:app.deployments.order_account): the caller is its owner or an
admin, the service goes on the owner's account and pays from it, and the
deployment is the organization's. Any other product answers 422 with
"field": "org_slug"; an organization that does not exist 404; a caller
who is not its owner or admin 403. Each order for it goes to its audit log
as deployment.ordered, as the member who placed it.
The size is the plan's. A virtual machine or a game server gets the
vCPUs, memory and disk of the plan the order names, and config may not
set them: a cpu_cores, vcpu, cpu_percent, memory_mb,
ram_mb, ram_gb, disk_gb or disk_mb that is not the plan's
own answers 422, {"field": "<the name sent>", "errors": [...]}. Naming
the plan's own figure is the same as leaving it out. Choose a larger plan
for a larger size. An order staff place for a customer may size a one-off
server.
Billed by use. A virtual machine (Cloud Compute), a game server or a
database ordered on your own account is billed by what it uses, whichever
price you name. Its service costs 0 to order, has no
renewal and no monthly cap, and provisions at once: there is no first
invoice. It needs Server access, which comes with its add-on, Pro,
Business and Enterprise: without it the order answers 402,
{"code": "paid_plan_required", "upgrade": {"addon", "plan"}}. A prepaid
account must also have made the first deposit (billing.hourly_minimum_deposit)
before it starts anything that runs, or the order answers 403. An account
billed by invoice needs no deposit. An organization's order and an order
staff place for a customer keep the flat price of the plan.
Server access with the order. A Free account can send
include_paid_plan: true to buy Server access (the addon-compute-paid
add-on, billed monthly at its price in the catalogue) with its first
virtual machine or game server instead of meeting the 402. The add-on is
an account service of its own and goes on the order's first invoice, so
the invoice is the add-on's first month. The server waits for that invoice
as a flat order waits for its first payment: credit pays it at once, and
otherwise both services start when it is paid. An account billed by
invoice gets both at once, and the add-on renews with its other services.
The answer lists the add-on in addons. It answers 422 with
{"code": "included_by_plan"} while the plan already includes Server
access, with {"code": "already_ordered"} while the account holds it,
and with a sentence for an order that is not a virtual machine or a game
server billed by use.
An App Deployment of kind git, image, hybrid or static, ordered on your
own account, is billed by use too and needs no plan. Leave product_id
and pricing_id out (or send 0) to order it on App Deployment's own
product. Naming a CX plan instead sets the memory the deployment starts
with. config.billing.mode and config.billing.overage are accepted
and ignored; config.billing.spend_limit still caps the month. A static
deployment needs no deposit, because it runs no instance. A service billed
by use refuses POST /services/{ref}/change-plan with 409,
{"code": "usage_billed"}.
Authentication: an access token, sent as Authorization: Bearer <token>.
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
product_id |
integer or null | no | The product to order. An App Deployment of kind git, image, hybrid or static, ordered on your own account, may leave it out or send 0: it is then ordered on App Deployment's usage terms. Naming a CX plan on such an order sets the memory the deployment starts with. Every other order names the product. |
pricing_id |
integer or null | no | The price of the product. Leave it out only when product_id is also left out, or names App Deployment's own product, which has one price. Virtual machines and game servers are billed by use whichever price you name. |
hostname |
string or null | no | The service's name. A Cloud Compute order uses it as the guest hostname: one name of up to 63 letters, digits and hyphens, with no dots and no hyphen at either end. Any other hostname answers 422. |
config |
object or null | no | |
idempotency_key |
string or null | no | Replay key for IP orders (double-submit / multi-tab) |
turnstile_token |
string or null | no | |
addons |
array of ServiceOrderAddon | no | Up to 8 products bought with this one. Cloud Compute takes Floating IP, DDoS Shield, Mail Hosting and SMTP Relay. App Deployment takes Floating IP, DDoS Shield, Snapshot Storage, Mail Hosting and SMTP Relay. Floating IP takes DDoS Shield. Mail Hosting takes SMTP Relay. App Deployment also takes extra backup slots, extra ports, extra databases, extra CPU, automatic backups and Server Management. Cloud Compute also takes automatic backups. Floating IP, DDoS Shield and Snapshot Storage go on a server, so of the App Deployment kinds only a template takes them. When the API cannot take one add-on, it refuses the whole order and creates nothing. |
addons[].product_id |
integer | yes | The add-on product. |
addons[].pricing_id |
integer or null | no | One of the add-on's active prices. Leave it out to take the price with the parent's billing cycle, else the monthly price, else the first active price. |
addons[].quantity |
integer | no | How many to order. Each floating IP becomes its own service. A capacity add-on sold per unit, such as Extra Port, becomes one service that holds its quantity, up to 20 units. Every other add-on takes 1. |
addons[].config |
object or null | no | The add-on's own config, as an order for that product on its own takes it. A floating IP comes from the parent's location unless config.pool_id names a pool. A DDoS Shield add-on takes profile_name (up to 40 characters), protection_mode, default_action, per_source_pps and aggregate_pps. The order sets the addresses it protects, so the API refuses ip_service_ids. |
promo_code |
string or null | no | A promo code. Its discount comes off the product ordered on the first invoice, and off later invoices when the code repeats. A code the order cannot use refuses the order with 422. |
include_paid_plan |
boolean | no | Buy Server access with this order. A virtual machine or a game server needs it, and a Free account has none, so without this the order answers 402 paid_plan_required. With true the order adds Server access (the addon-compute-paid add-on, billed monthly at its current price) to the same first invoice. The server starts when that invoice is paid, at once when your credit covers it. The order answers 422 with included_by_plan when your plan already includes Server access, with already_ordered when your account already holds it, and with a sentence when the order is not a virtual machine or a game server billed by use. |
org_slug |
string or null | no | Order an App Deployment for this organization instead of your own account. You must be the organization's owner or an admin. The deployment belongs to the organization, and the service goes on the owner's account, which pays for it. Only an App Deployment can be ordered this way. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 201 response:
| Field | Type | Description |
|---|---|---|
service |
ServiceResponse | |
service.id |
integer | |
service.user_id |
integer | |
service.product_id |
integer | |
service.pricing_id |
integer | |
service.hostname |
string or null | |
service.status |
string | |
service.billing_cycle |
string | |
service.amount |
number | |
service.next_due_date |
string (date-time) or null | |
service.config |
object or null | |
service.module_data |
object or null | |
service.suspension_reason |
string or null | |
service.provisioned_at |
string (date-time) or null | |
service.created_at |
string (date-time) | |
service.updated_at |
string (date-time) | |
service.product_name |
string or null | |
service.product_slug |
string or null | |
service.module_name |
string or null | |
service.pricing_name |
string or null | |
service.termination_date |
string (date-time) or null | |
service.billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
service.monthly_cap |
number or null | |
service.hourly_usage_this_month |
number or null | |
service.hourly_cap_reached |
boolean or null | |
service.tags |
array of string | |
service.resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
invoice_id |
integer or null | |
requires_payment |
boolean | |
checkout_available |
boolean | |
amount_due |
string or null | |
message |
string or null | |
addons |
array of ServiceResponse | The services created for the order's add-ons, in the order the client listed them: one per floating IP, and one for each other add-on, which holds its quantity. A replayed order lists the add-ons it created the first time. |
addons[].id |
integer | |
addons[].user_id |
integer | |
addons[].product_id |
integer | |
addons[].pricing_id |
integer | |
addons[].hostname |
string or null | |
addons[].status |
string | |
addons[].billing_cycle |
string | |
addons[].amount |
number | |
addons[].next_due_date |
string (date-time) or null | |
addons[].config |
object or null | |
addons[].module_data |
object or null | |
addons[].suspension_reason |
string or null | |
addons[].provisioned_at |
string (date-time) or null | |
addons[].created_at |
string (date-time) | |
addons[].updated_at |
string (date-time) | |
addons[].product_name |
string or null | |
addons[].product_slug |
string or null | |
addons[].module_name |
string or null | |
addons[].pricing_name |
string or null | |
addons[].termination_date |
string (date-time) or null | |
addons[].billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
addons[].monthly_cap |
number or null | |
addons[].hourly_usage_this_month |
number or null | |
addons[].hourly_cap_reached |
boolean or null | |
addons[].tags |
array of string | |
addons[].resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
Fetch a service by numeric id OR underlying resource UUID (instance/server/IP)
Section titled Fetch a service by numeric id OR underlying resource UUID (instance/server/IP)GET /api/v1/services/{service_ref}
Fetch a service by numeric id OR underlying resource UUID (instance/server/IP).
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
id |
integer | |
user_id |
integer | |
product_id |
integer | |
pricing_id |
integer | |
hostname |
string or null | |
status |
string | |
billing_cycle |
string | |
amount |
number | |
next_due_date |
string (date-time) or null | |
config |
object or null | |
module_data |
object or null | |
suspension_reason |
string or null | |
provisioned_at |
string (date-time) or null | |
created_at |
string (date-time) | |
updated_at |
string (date-time) | |
product_name |
string or null | |
product_slug |
string or null | |
module_name |
string or null | |
pricing_name |
string or null | |
termination_date |
string (date-time) or null | |
billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
monthly_cap |
number or null | |
hourly_usage_this_month |
number or null | |
hourly_cap_reached |
boolean or null | |
tags |
array of string | |
resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
resource.type |
string | Module resource type: vps | container | ip | external_server |
resource.label |
string or null | Human label: hostname, server name, or IP/CIDR |
resource.status |
string or null | Resource-level status (not billing status) |
resource.address |
string or null | Primary reachability address (IP, IP:port, or CIDR) |
resource.detail |
Detail | Module-specific fields (uuids, node, plan, attach state, …) |
Execute action
Section titled Execute actionPOST /api/v1/services/{service_ref}/actions
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required |
|---|---|---|
action |
string | yes |
params |
object or null | no |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
The add-ons on one of your services, and the ones you can add
Section titled The add-ons on one of your services, and the ones you can addGET /api/v1/services/{service_ref}/addons
The add-ons on one of your services, and the ones you can add.
attached lists every add-on that has not ended: the products bought
with the service (a floating IP, DDoS Shield, Snapshot Storage), the
capacity add-ons added since and an SMTP Relay's dedicated IPs. Each
carries addon, which says what it adds and whether DELETE takes
it. available lists every capacity add-on for this kind of service,
with its price on the service's billing cycle. When one cannot be added
now, addable is false and reason_unavailable says why. Answers
404 for a service that does not exist and 403 for one that is not yours.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
parent |
AddonParent | |
parent.id |
integer | |
parent.product_name |
string or null | |
parent.module_name |
string | |
parent.status |
string | |
parent.billing_cycle |
string | The cycle the service renews on. Its add-ons renew with it. A service billed by use is hourly: each add-on then renews every month on its own, from the day you add it. |
parent.amount |
string | The service's own price each cycle. A service billed by use has none. |
parent.next_due_date |
string or null | The service's next renewal. An add-on bought now is charged up to this date. |
attached |
array of AttachedAddon | |
attached[].id |
integer | |
attached[].user_id |
integer | |
attached[].product_id |
integer | |
attached[].pricing_id |
integer | |
attached[].hostname |
string or null | |
attached[].status |
string | |
attached[].billing_cycle |
string | |
attached[].amount |
number | |
attached[].next_due_date |
string (date-time) or null | |
attached[].config |
object or null | |
attached[].module_data |
object or null | |
attached[].suspension_reason |
string or null | |
attached[].provisioned_at |
string (date-time) or null | |
attached[].created_at |
string (date-time) | |
attached[].updated_at |
string (date-time) | |
attached[].product_name |
string or null | |
attached[].product_slug |
string or null | |
attached[].module_name |
string or null | |
attached[].pricing_name |
string or null | |
attached[].termination_date |
string (date-time) or null | |
attached[].billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
attached[].monthly_cap |
number or null | |
attached[].hourly_usage_this_month |
number or null | |
attached[].hourly_cap_reached |
boolean or null | |
attached[].tags |
array of string | |
attached[].resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
attached[].addon |
AddonBlock | |
available |
array of AvailableAddon | |
available[].product |
AddonProduct | |
available[].kind |
string | |
available[].label |
string | |
available[].adds |
string | What one unit adds. |
available[].unit |
integer | How many of the limit one unit adds. |
available[].unit_label |
string | |
available[].fits |
array of string | |
available[].price |
AddonPrice | |
available[].max_quantity |
integer | The largest quantity POST takes now. 0 when it cannot be added. |
available[].addable |
boolean | |
available[].included_by_plan |
boolean | |
available[].reason_unavailable |
string or null | Why it cannot be added now, in a sentence. |
Add a capacity add-on to one of your active services
Section titled Add a capacity add-on to one of your active servicesPOST /api/v1/services/{service_ref}/addons
Add a capacity add-on to one of your active services.
The add-on renews with the service, on its billing cycle and date. The
first invoice charges the rest of the current period, plus any setup
fee, and we take it from your credit balance when that covers it. The
add-on applies once the invoice is paid: until then requires_payment
is true and invoice_id names the invoice to pay. A service billed
by the hour pays a full hour.
Answers 422 with {"errors": [<sentence>]} when the add-on cannot go
on this service, such as a product that is not an add-on for it, a
quantity above what the service still takes, or automatic backups on a
plan that already includes them. A promo code it cannot use also answers
422, with promo naming the reason. Answers 429, with
Retry-After, when the account changes add-ons too often.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
product_id |
integer | yes | An add-on from this service's available list. |
quantity |
integer or null | no | How many units, for an add-on sold per unit. Leave it out for 1. The most a service takes of one kind, across its add-ons, is 20. |
billing_cycle |
string or null | no | An add-on renews with its service. Leave it out, or send the service's own cycle. A service billed by use has none, so its add-ons renew monthly: send monthly or leave it out. |
promo_code |
string or null | no | A promo code for the add-on. A code it cannot use refuses the request with 422. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 201 response:
| Field | Type | Description |
|---|---|---|
service |
AttachedAddon | |
service.id |
integer | |
service.user_id |
integer | |
service.product_id |
integer | |
service.pricing_id |
integer | |
service.hostname |
string or null | |
service.status |
string | |
service.billing_cycle |
string | |
service.amount |
number | |
service.next_due_date |
string (date-time) or null | |
service.config |
object or null | |
service.module_data |
object or null | |
service.suspension_reason |
string or null | |
service.provisioned_at |
string (date-time) or null | |
service.created_at |
string (date-time) | |
service.updated_at |
string (date-time) | |
service.product_name |
string or null | |
service.product_slug |
string or null | |
service.module_name |
string or null | |
service.pricing_name |
string or null | |
service.termination_date |
string (date-time) or null | |
service.billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
service.monthly_cap |
number or null | |
service.hourly_usage_this_month |
number or null | |
service.hourly_cap_reached |
boolean or null | |
service.tags |
array of string | |
service.resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
service.addon |
AddonBlock | |
invoice_id |
integer or null | |
requires_payment |
boolean | |
charge |
string | The first charge: the rest of this period, plus any setup fee. |
discount |
string | |
amount_due |
string | What is left to pay on the invoice. |
renews_at |
string or null | |
renewal_amount |
string | What the add-on costs each cycle from its first renewal. |
billing_cycle |
string | |
message |
string |
What adding an add-on to one of your services would charge
Section titled What adding an add-on to one of your services would chargePOST /api/v1/services/{service_ref}/addons/preview
What adding an add-on to one of your services would charge. Nothing is added or charged.
The body is the one POST /api/v1/services/{service_ref}/addons takes.
The answer is {due_now, currency, lines, renews, promo}: due_now
is what the first invoice charges, lines are its parts (the add-on,
any setup fee and a promo code as a negative amount), and renews is
{amount, cycle, date} for the next renewal. An add-on bought after
its service is charged up to the service's next renewal and renews with
it. A service billed by use has no renewal, so its add-on charges a full
month and renews every month from today.
promo is {valid, message} when you send promo_code and null
otherwise. A code the add-on cannot use does not refuse the preview: it
answers valid false with the reason, and a refused code counts against
the budget POST /api/v1/billing/promo/validate keeps. Refuses what
adding the add-on would refuse, with the same answer: 403 for a service
that is not yours, 404 for a service or product that does not exist and
422 for an add-on the service cannot take, a quantity it cannot take or
another billing cycle.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
product_id |
integer | yes | An add-on from this service's available list. |
quantity |
integer or null | no | How many units, for an add-on sold per unit. Leave it out for 1. The most a service takes of one kind, across its add-ons, is 20. |
billing_cycle |
string or null | no | An add-on renews with its service. Leave it out, or send the service's own cycle. A service billed by use has none, so its add-ons renew monthly: send monthly or leave it out. |
promo_code |
string or null | no | A promo code for the add-on. A code it cannot use refuses the request with 422. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
due_now |
string | What the first invoice charges, after a promo code. |
currency |
string | |
lines |
array of PreviewLine | |
lines[].label |
string | |
lines[].amount |
string | What the line costs now. A promo code is a line with a negative amount. |
renews |
PreviewRenewal | |
renews.amount |
string | What the add-on costs at each renewal, after a promo code that repeats. |
renews.cycle |
string | |
renews.date |
string | When it renews next, as an ISO 8601 time in UTC. |
promo |
PreviewPromo or null | Null when the request names no promo code. |
promo.valid |
boolean | |
promo.message |
string |
Remove a capacity add-on from one of your services
Section titled Remove a capacity add-on from one of your servicesDELETE /api/v1/services/{service_ref}/addons/{addon_ref}
Remove a capacity add-on from one of your services.
addon_ref is the add-on's service id, from the list. The limit it
added comes off when it ends. Nothing you already have is deleted, but
you cannot add more until you are under the limit again. An add-on whose
first invoice was never paid ends at once and its invoice is cancelled.
Extra mailboxes or storage in use cannot be removed: delete what is over
the limit first (409). An add-on that is being applied cannot be removed
until it is on (409). A product bought with the service, such as a
floating IP, is cancelled from its own page (422). Answers 429, with
Retry-After, when the account changes add-ons too often.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
service_ref |
path | string | yes | |
addon_ref |
path | string | yes | |
when |
query | string | no | end_of_term keeps the add-on until the service renews, and nothing more is charged for it. now removes it at once and refunds nothing. Default: end_of_term. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
service_id |
integer | |
when |
string | now or end_of_term, as it was applied. |
status |
string | |
termination_date |
string or null | |
message |
string |
Cancel the service now or at the end of its term
Section titled Cancel the service now or at the end of its termPOST /api/v1/services/{service_ref}/cancel
Cancel the service now or at the end of its term.
immediate queues the terminate job, and a service that was never
built ends at once. Otherwise it stays active until its next due date,
when the daily sweep ends it. Its unpaid invoices are voided either way.
The capacity add-ons on it end with it, on the same day; a failure there
is logged and never stops the cancellation. Answers 400 when the service
has already ended or is already set to end.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required |
|---|---|---|
reason |
string or null | no |
immediate |
boolean | no |
keep_snapshot |
boolean | no |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Change the service to another price, prorated
Section titled Change the service to another price, proratedPOST /api/v1/services/{service_ref}/change-plan
Change the service to another price, prorated.
new_pricing_id must be a price of the service's own product, except
that an account plan may move between the Pro and Business plans, and
Object Storage on a plan we no longer sell may move to pay as you go;
the service moves with it. An upgrade creates an invoice for the rest of the
cycle and applies once it is paid, at once when your credit covers it.
When no whole day is left to prorate, or the new plan costs less per day,
that invoice is for a whole period of the new plan instead: the period
runs from the renewal date (from now when a period from that date would
already be over), the renewal date moves to its end, and the open renewal
invoice for that period is voided. A downgrade applies now and credits the
unused remainder less the holdback days. The service is then resized.
Refuses a service that is not active or already on that price (400), an
add-on (422), a price of another product (400), a plan we no longer sell
or sell only through our sales team (422), a price that is no longer on
sale (422, {"code": "price_not_on_sale"}), a plan whose terms our
sales team set (409), a floating IP or DDoS Shield profile the account
plan pays for (409), and a whole period while the renewal invoice it would
replace is part paid (409). A capacity add-on changes with its service,
and an account add-on is cancelled and ordered again. An included service
follows the account plan and is not changed on its own. A service billed by
what it uses has no price to change and answers 409,
{"code": "usage_billed"}. An account plan changes its billing period
on the Plan page, or with POST /api/v1/account/plan,
and a price on another billing period answers 409.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required |
|---|---|---|
new_pricing_id |
integer | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type |
|---|---|
change_type |
string |
net_amount |
number |
credit_amount |
number |
charge_amount |
number |
credit_issued |
number |
days_remaining |
integer |
invoice_id |
integer or null |
status |
string or null |
message |
string or null |
Get events
Section titled Get eventsGET /api/v1/services/{service_ref}/events
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
service_ref |
path | string | yes | |
page |
query | integer | no | Default: 1. |
limit |
query | integer | no | Default: 50. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
A 200 response is a list; each item has these fields:
| Field | Type |
|---|---|
[].id |
integer |
[].event_type |
string |
[].actor_type |
string |
[].actor_id |
integer or null |
[].description |
string or null |
[].metadata |
object or null |
[].created_at |
string (date-time) |
Withdraw a cancellation set for the end of the term, so the service keeps renewing
Section titled Withdraw a cancellation set for the end of the term, so the service keeps renewingPOST /api/v1/services/{service_ref}/keep
Withdraw a cancellation set for the end of the term, so the service keeps renewing.
Send no body. It works on your own service while it is active and has an
end date in the future: the end date goes back to empty, and the capacity
add-ons that were set to end with the service stay too. The answer is the
service, as GET /api/v1/services/{service_ref} returns it. The event
goes to the service's history and to your account's activity log.
What the cancellation already did is not undone. An unpaid invoice it voided stays void, and a plan change it cleared stays cleared. The next renewal is invoiced as usual, on the plan the service is on now.
Answers 409 with {"code", "message"} when it cannot keep the service:
not_cancelled when nothing is scheduled, already_ended when the
service has ended or its end date has passed, not_active for a service
that is suspended or not running, and scheduled_by_support for an end
date our team set. Another account's service answers 403. Organization
portals keep their own route for their customers' services.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
id |
integer | |
user_id |
integer | |
product_id |
integer | |
pricing_id |
integer | |
hostname |
string or null | |
status |
string | |
billing_cycle |
string | |
amount |
number | |
next_due_date |
string (date-time) or null | |
config |
object or null | |
module_data |
object or null | |
suspension_reason |
string or null | |
provisioned_at |
string (date-time) or null | |
created_at |
string (date-time) | |
updated_at |
string (date-time) | |
product_name |
string or null | |
product_slug |
string or null | |
module_name |
string or null | |
pricing_name |
string or null | |
termination_date |
string (date-time) or null | |
billing_model |
string or null | usage for a service billed by what it uses, with no plan price and no renewal. Empty for a service billed at a flat price. |
monthly_cap |
number or null | |
hourly_usage_this_month |
number or null | |
hourly_cap_reached |
boolean or null | |
tags |
array of string | |
resource |
ServiceResourceSummary or null | Underlying VPS / Container App / Floating IP summary (DB-backed) |
resource.type |
string | Module resource type: vps | container | ip | external_server |
resource.label |
string or null | Human label: hostname, server name, or IP/CIDR |
resource.status |
string or null | Resource-level status (not billing status) |
resource.address |
string or null | Primary reachability address (IP, IP:port, or CIDR) |
resource.detail |
Detail | Module-specific fields (uuids, node, plan, attach state, …) |
What changing the service to another price would cost now
Section titled What changing the service to another price would cost nowGET /api/v1/services/{service_ref}/upgrade-preview
What changing the service to another price would cost now.
new_pricing_id must be a price of the service's own product, with
two exceptions: an account plan may move between the Pro and Business
plans, and Object Storage on a plan we no longer sell may move to pay as
you go. The answer is the prorated charge or credit for the rest
of the current cycle; credit_estimate is what a downgrade returns
after the holdback days. Refuses a service that is not active (400), an
add-on (422), a price of another product (400), a plan we no longer sell
or sell only through our sales team (422), a price that is no longer on
sale (422, {"code": "price_not_on_sale"}), a plan whose terms our
sales team set (409), a floating IP or DDoS Shield profile the account
plan pays for (409), and a service billed by what it uses (409,
{"code": "usage_billed"}). A capacity add-on changes with its service,
and an account add-on is cancelled and ordered again. An account plan
changes its billing period on the Plan page, or with
POST /api/v1/account/plan, and a price on another billing period
answers 409.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
service_ref |
path | string | yes |
new_pricing_id |
query | integer | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type |
|---|---|
credit_amount |
number |
charge_amount |
number |
net_amount |
number |
credit_estimate |
number |
creditable_days |
integer |
days_remaining |
integer |
days_in_cycle |
integer |
change_type |
string |