API-overzicht
Authenticatie
Alle /api/*-verzoeken authenticeren met een HTTP-token in de Authorization-
header. Zowel het Token- als het Bearer-schema wordt geaccepteerd:
Authorization: Token {{ CloudPress API Token }}
Authorization: Bearer {{ CloudPress API Token }}
Er zijn drie soorten credentials, die allemaal op dezelfde manier worden aangeboden. De server bepaalt om welk type het gaat (eerst sessie / API-sleutel, daarna OAuth):
| Credential | Identiteit | Admin‑rechten? | Gelden OAuth-scopes? | Opmerkingen |
|---|---|---|---|---|
| User API key | Een gebruiker (heeft toegang tot de accounts waartoe die gebruiker behoort) | Als de sleutel als admin is gemarkeerd | Nee (omzeilt scopecontroles) | Optionele IP-toegangslijst. |
| System API key | Een account (alleen systeembeheerd) | Als als admin gemarkeerd | Nee | Het account komt van de drager van de sleutel — vereist geen X-Auth-Account; het IP moet op de systeemtoegangslijst staan. |
| OAuth 2.1 access token | Een gebruiker, gebonden aan één (account, brand) |
Nooit | Ja — fail-closed | Uitgegeven via de OAuth 2.1 autorisatieserver. |
Trial-accounts kunnen de API niet gebruiken
Een OAuth-token wordt altijd geweigerd wanneer het gekoppelde account een
trial-account is. Een user API key wordt alleen geweigerd wanneer
X-Auth-Account naar een trial-account verwijst — zonder die header is er
geen account om te controleren en gaat het verzoek door. Een system API
key wordt afgehandeld vóórdat de trial-controle plaatsvindt en wordt op
deze grond nooit geweigerd.
IP-beperking
Je kunt de toegang per IP beperken tot een specifieke API-sleutel in de CloudPress API Key Manager. Let op: wanneer je probeert verbinding te maken vanaf een niet-geautoriseerd IP, krijg je dezelfde reactie als wanneer je een ongeldige API-sleutel had opgegeven.
Standaard is er geen IP-beperking ingesteld.
Accountscope instellen
Sommige API-endpoints vereisen een accountscope. Om aan te geven onder welk account
je wilt werken, voeg je de header X-Auth-Account toe met je Account-ID:
X-Auth-Account: {{ CloudPress Account ID }}
Gedrag:
- Voor een user API key scope't
X-Auth-Accounthet verzoek naar één account en stelt het de accountcontext in. Zonder deze header geven list-endpoints resources terug over alle accounts waartoe de gebruiker van de sleutel toegang heeft. - Twee lijsten negeren de header volledig.
GET /api/domainsenGET /api/dns_zonesgeven altijd elk domein / elke zone terug waar de gebruiker van de sleutel bij kan, of jeX-Auth-Accountnu meestuurt of niet. Filter aan de clientzijde als je de subset van één account nodig hebt. - Sommige endpoints vereisen de header en geven
400{"errors":["Missing X-Auth-Account"],"code":"missing_account"}terug wanneer hij ontbreekt — Orders, Carts, Subscriptions, Users, SSO, cPanel-accounts, en alle endpoints voor domeinregistratie. Het aanmaken van een DNS-zone hanteert dezelfde regel, maar rendert een eigen body zondercode-sleutel —400{"errors":["Missing X-Auth-Account"]}— vertrouw daar dus niet opmissing_account. Mailspacecreateheeft ook een accountcontext nodig en antwoordt met400account_required. - OAuth-tokens dragen altijd een account, dus voor die tokens wordt de header genegeerd.
Authenticatiefouten
Een mislukte authenticatie geeft 401 terug met de header
WWW-Authenticate: Token realm="Application" en een lege body. Mogelijke oorzaken
zijn: geen/ongeldig token, een IP dat niet op de toegangslijst van de sleutel staat,
een trial-account, of een X-Auth-Account-waarde die niet overeenkomt met een
account waartoe het token toegang heeft.
OAuth audience binding (RFC 8707)
Een OAuth-token dat is aangemaakt met een resource-indicator (bijvoorbeeld een
token uitgegeven voor de MCP-server op /mcp) wordt op /api/* geweigerd
met HTTP 401 en een JSON-body — niet de bovenstaande vorm met lege body en
WWW-Authenticate:
{ "error": "invalid_token", "error_description": "token audience is not valid for /api" }
/api geeft nooit resource-gebonden tokens uit, dus elk token dat een
resource draagt is aangemaakt voor een andere audience en kan /api niet
bereiken.
Conventies
- Alle API-routes vallen onder
/api/. Alle reacties zijn JSON. - Resource-ID's zijn GUID's, behalve numerieke task-ID's, integer volume-ID's,
integer DNS-recordtype-codes, en numerieke
domain_contact-ID's. - Tijdstempels zijn ISO 8601, UTC.
- Asynchrone bewerkingen geven
202 Acceptedterug — poll een task, registrar-proces of cart om de voltooiing te controleren (zie Asynchrone bewerkingen).
Paginering
Paginering is geen conventie die overal geldt. Precies vijf index-endpoints
accepteren page en per_page:
GET /api/ordersGET /api/subscriptionsGET /api/domainsGET /api/dns_zonesGET /api/cpanel_accounts
| Param | Type | Standaard | Opmerkingen |
|---|---|---|---|
page |
Integer | 1 |
Paginanummer |
per_page |
Integer | 50 |
Records per pagina, begrensd tot een maximum van 100 |
Elke andere index-actie — sites, tasks, users, accounts, API-sleutels, DNS-records, domeinregistraties, domeincontacten, Mailspace, de domeinen van een cPanel account, en alle sub-resources van een site — negeert beide parameters en geeft de volledige set in één reactie terug.
Rate limiting
Verzoeken zijn beperkt tot 600 per 10 minuten, geteld per client-IP-adres en per controller — niet per credential. Daaruit volgen twee dingen:
- Eén credential krijgt een apart budget van 600 verzoeken tegen elke groep endpoints (sites, domeinen, DNS-zones, orders, …), dus werk dat over meerdere resources verdeeld is, valt niet onder één gedeeld maximum van 600.
- Twee credentials die vanaf hetzelfde bron-IP verzoeken sturen — achter één NAT of egress-gateway — delen één bucket en kunnen elkaars budget opmaken.
Bij overschrijding van de limiet wordt 429 met een lege body teruggegeven.
Foutreacties
| Status | Wanneer dit optreedt |
|---|---|
400 |
Ontbrekende verplichte header (missing_account, of account_required bij Mailspace create); ongeldige/no-op-params; validatiefouten bij order- en site-resize (onbekende variant/locatie/term/product); no_default_payment_method; een app-wachtwoord-update zonder de verplichte allowed_ips-sleutel (allowed_ips_missing); een days-waarde die wel is meegestuurd maar geen heel getal is bij de metrics van transactionele e-mail van een site (invalid_days); OAuth picker-/DCR-fouten |
401 |
Authenticatie mislukt (geen/ongeldig token, IP geblokkeerd, trial-account, accountmismatch); admin-only endpoint met een niet-admin-credential |
402 |
Dienst opgeschort vanwege een onbetaalde factuur (service_suspended); registrar fee-gate (payment_required) |
403 |
Onvoldoende rol ({"errors":["Not Authorized"]}, of forbidden bij writes op DNS-zones / DNS-records); OAuth-scopefout (insufficient_scope); Shield niet in abonnement / premium vereist; site wacht op verwijdering (pending_delete); cPanel niet ingeschakeld voor de workspace (cpanel_not_enabled) |
404 |
Resource niet gevonden of niet toegankelijk voor dit token (bijv. unknown_task voor een task-id dat niet bij de site hoort) |
409 |
Conflict — Bunny-resource niet actief (cdn_not_active, shield_not_active); registrar-proces al onderweg (registration_busy); een pakketwijziging die al wordt doorgevoerd (resize_in_flight) |
422 |
Validatiefout of rechtenbeperking (bijv. overgeërfde rol, alleen voor resellers, resize-beperkingen); billing-settle-bewaking op een net aangemaakte site (billing_settling); cart-betaling kon niet worden gestart (cart_pay_failed) |
429 |
Rate limit overschreden (600 / 10 min) |
502 |
Upstream-fout (Bunny CDN/Shield, of domeinregistrar) |
503 |
Functie uitgeschakeld (feature_disabled, de domain-registration-flag); geen registrar geconfigureerd voor een TLD (registrar_unavailable); mailhosting niet geconfigureerd (stalwart_unavailable); cPanel tijdelijk onbereikbaar (cpanel_unavailable); een Mailspace-read die de mailserver niet kon uitvoeren (archived_items_unavailable, purged_mailboxes_unavailable, group_members_unavailable — zie Mailspace) |
Sites die op verwijdering wachten, zijn vergrendeld (403 pending_delete)
Een soft-deleted site is niet weg — hij blijft gedurende zijn bewaartermijn
adresseerbaar, maar is vergrendeld. GET /api/sites toont hem nog steeds
(met pending_delete: true en delete_scheduled_at), en
GET /api/sites/{id} geeft een beperkte payload terug met status
"pending_delete" in plaats van de details van een actieve site. Alles wat
hem zou wijzigen, wordt geweigerd met 403:
{
"errors": ["This site is pending deletion and is locked. Restore it to make changes."],
"code": "pending_delete",
"delete_scheduled_at": "2026-09-01T14:22:05Z"
}
Dit geldt voor PATCH en DELETE /api/sites/{id} en voor elke geneste
sub-resource van de site — domeinen en certificaten, back-ups en exports,
restores, cache, CDN, edge rules, Shield, varianten, tasks, metrics, logs en
SSO. De geneste endpoints zijn afgeschermd voor zowel reads als writes,
dus de sub-resources van een vergrendelde site antwoorden ook op een GET
met 403. Herstel de site om de vergrendeling op te heffen.
Functie- en plan-gating
De enige feature flag die API-endpoints gate't is domain-registration
(geeft 503 feature_disabled terug wanneer uit). Shield is plan-gated
(403 shield_not_in_plan, of shield_premium_required voor premium-only
writes). CDN/Shield nog niet voorzien op Bunny geeft 409 terug
(cdn_not_active / shield_not_active).
Asynchrone bewerkingen
De meeste provisioning-bewerkingen zijn asynchroon en geven 202 Accepted terug
met een referentie om te pollen.
-
Tasks — verschillende bewerkingen openen een Task, maar niet alle geven het id terug. Drie gevallen, en het verschil telt zodra je je polling inricht:
202met eentask_id— PHP-versiewijziging (PATCH /api/sites/{site-id}/variants/php) en cache inschakelen / uitschakelen / legen. Poll het teruggegeven id direct.202zonder task-id — herstarten, een back-up maken en verwijderen, een restore, en een site-domein promoveren / verwijderen. Er wordt een Task aangemaakt, maar de responsbody is leeg; zoek hem dus op viaGET /api/sites/{site-id}/tasks. Een site-domein toevoegen geeft wel eenidterug, maar dat is de guid van het nieuwe domein, geen task-id.- Helemaal geen Task — het verwijderen van een accountrol
(
DELETE /api/accounts/{account-id}/roles/{id}) en accountverwijdering (DELETE /api/accounts/{account-id}) antwoorden met een kale202. Er wordt niets aangemaakt om te pollen; lees het account of zijn rollen opnieuw uit om het resultaat te bevestigen.
Poll een task met
GET /api/tasks/:idofGET /api/sites/:site_id/tasks/:id. Taskstatussen:PENDING,RUNNING,OK,FAILED,CANCELLED,PAUSED. - Carts — site-aanmaak (POST /api/orders), site-resize / planwijziging (PATCH /api/sites/:idmetplan), en domeinorders (POST /api/orders/domain) worden gepolld via de cart, niet via een task: ze geven een cart-envelop terug; poll de cart op gematerialiseerde orders. - Registrar-processen — mutaties voor domeinregistratie kunnen een proces openen; poll het op voltooiing.
Afrondingscallback
Bij het aanmaken van een order kun je optioneel een callback meegeven, zodat je een
webhook ontvangt wanneer het asynchrone werk klaar is in plaats van te pollen:
{ "callback": { "url": "https://your-app.com/webhook", "authorization": "Bearer your-secret" } }
Zie Callbacks voor het volledige contract.
About-endpoint
CloudPress biedt een 'about'-endpoint dat informatie geeft over wie je bent ingelogd als, evenals informatie over beschikbare resources. Het accepteert elk geldig token, ongeacht de OAuth-scope.
GET /api/about
Teruggegeven params
- version: String | Informatie over de API-versie
- logged_in_as: String | Jouw gebruikers-ID
- account_scoped: String | Als je met een account hebt geauthenticeerd, is dit jouw ID.
- locations: Array
- id: String
- name: String
- products: Array
- id: String
- name: String
- description: String
- php: Array |
[]wanneer er geen versies beschikbaar zijn- id: Integer
- label: String
- is_default: Boolean
Voorbeeld
curl -H "Authorization: Bearer $CLOUDPRESS_TOKEN" \
https://your-instance/api/about