{% extends "baseTemplate/index.html" %} {% load static %} {% comment %} CloudPanel — REST API reference. Everything below the token panel is rendered from `api.views.endpoint_catalogue()`, the same declarative list the drift check compares against the router's registry. Nothing on this page is hand-maintained per endpoint, so the docs cannot fall behind the routes without the banner at the top saying so. {% endcomment %} {% block title %}API Reference{% endblock %} {% block styles %} {% endblock %} {% block content %}

REST API reference

Version {{ apiVersion }} · base URL {{ baseURL }}/api/

{% if drift %} {% endif %}
Your API token

Tokens inherit your ACL exactly. Anything you cannot do in the panel, your token cannot do either.

{% if tokenIssued %}

Active token

Prefix {{ tokenPrefix }} · rate limit {% if policy %}{{ policy.rateLimitPerMinute }}{% else %}{{ defaultRate }}{% endif %} requests/minute · writes are additionally capped at {{ writeRate }}/minute.

{% if policy and policy.allowedIPList %}

Source allowlist: {% for entry in policy.allowedIPList %}{{ entry }}{% if not forloop.last %}, {% endif %}{% endfor %}

{% else %}

No source restriction is configured. Add one with allowedIPs when you issue the token.

{% endif %} {% else %}

No token has been issued for {{ currentACL.userName }} yet.

{% endif %}

New token — shown once

Store it now. The panel keeps only the hashable key and there is no endpoint that reads it back — rotate if you lose it.

Every request

curl '{{ baseURL }}/api/{{ apiVersion }}/websites' \
  -H 'Authorization: Token <your token>'

Responses always carry status (1 or 0) and error_message. Lists add count, next, previous and data. Errors add a stable errorCode.

{% for group in catalogue %}

{{ group.name }}

{{ group.blurb|safe }}

{% for endpoint in group.endpoints %}
{{ endpoint.method }} {{ endpoint.path }}

{{ endpoint.summary }}

{% if endpoint.params %}

Parameters

{% for name, required, description in endpoint.params %} {% endfor %}
Name Required Description
{{ name }} {% if required %}required {% else %}optional{% endif %} {{ description }}
{% else %}

Parameters

None.

{% endif %}

Example request

{{ endpoint.curl }}

Example response

{{ endpoint.response }}
{% endfor %}
{% endfor %}

Errors

Every failure uses the same envelope, whatever produced it.

Shape

{
  "status": 0,
  "error_message": "Domain not found.",
  "errorCode": "not_found",
  "requestID": "9f2c41ab.3d1e7c0b9a4f2e61"
}

Status codes

400Malformed or invalid input.
401Missing, unknown or revoked token.
403Authenticated, but the ACL says no.
404Does not exist — or is not yours.
409Conflicts with the current state.
429Rate limit exceeded.
502The server-side operation failed.

A resource that exists but belongs to another account answers 404, never 403 — a 403 would confirm the domain is hosted here.

{% if recentCalls %}

Your last API calls

Every call is recorded with the token prefix, never the token.

{% for entry in recentCalls %} {% endfor %}
When Method Endpoint Status ms Source
{{ entry.timestamp|date:"Y-m-d H:i:s" }} {{ entry.method }} {{ entry.endpoint }} {{ entry.statusCode }} {{ entry.responseTime }} {{ entry.ipAddress }}
{% endif %}
{% endblock %} {% block scripts %} {% endblock %}