REST API
The Integrations page is the way into your account for a program. It offers two interfaces over one set of operations, and every action passes the same validation as the panel interface.
| Interface | For | Authenticated with |
|---|---|---|
| REST API, this page | Your scripts and integrations. | API keys that you create. |
| MCP server | AI tools. | OAuth, with no key at all. |
Both reach everything the panel manages: databases, app servers, websites and mail domains, mailboxes and forwarders, DNS records, containers, files, shares, OIDC applications, and the mail logs.
The live API reference (Integrations → API Documentation) comes from the server itself, so it's always the authoritative list.
API keys
Create a key under Integrations → API Keys, with:
- a name, so you know which script it belongs to,
- a set of scopes, and
- an optional expiry.
It looks like epat_…. Put it in your integration right away; after that
the panel shows only its start.
- If you lose a key, create a new one.
- If a key leaks, press Revoke. That's immediate and permanent.
The list shows each key's last use. Revoke one that nobody has used for months.
A scope has the form resource:access, e.g. database:readonly or
appserver:readwrite, plus two umbrella scopes, all:readonly and
all:readwrite. Write access includes read access.
A monitoring script needs all:readonly, not all:readwrite. A key with
all:readwrite and no expiry has the same power as your account.
A call carries the key as a bearer token:
curl -H "Authorization: Bearer epat_..." \
https://panel.example.com/api/v1/databases
What the API looks like
The REST API follows JSON:API, so every response has the same predictable shape, whatever the endpoint:
- what you asked for is under
data, - its fields under
attributes, and - its links to other things under
relationships.
{
"data": [
{
"type": "databases",
"id": "019dd…",
"attributes": { "databaseName": "myaccount_blog" },
"links": { "self": "/api/v1/databases/019dd…" }
}
],
"links": { "self": "/api/v1/databases" }
}
Three things to know before writing code against it:
- A write sends the same shape back. To create a database, post
{"data": {"type": "databases", "attributes": {…}}}withContent-Type: application/vnd.api+json. - A long list comes in pages. Follow
links.nextuntil it no longer appears. Don't build page numbers yourself: the cursors are opaque, and the link already carries the filter you applied. - Errors come as a list. A failed request answers with an
errorsarray, one entry per problem, each naming its field, so a form with two bad values reports both at once. Decide on the HTTP status code, not the message text.
Most paths accept a human-readable name as well as an id:
/api/v1/accounts/alice@example.com works the same as the UUID. So most
scripts need no lookup first.
Bot challenge
A website's bot challenge is under its
website service, which the path names by id or by hostname. Reading needs
service:readonly, changing service:readwrite.
| Method and path | What |
|---|---|
GET /api/v1/website-services/{website}/bot-challenge | The rules with their modes, the settings, the exemptions of the website and of the server, whether Adaptive is switched on, and the crawlers that can be named. |
POST /api/v1/website-services/{website}/bot-challenge/rules | Gate a path: path, and mode adaptive or always. Without a mode it's always while Adaptive is in its trial period (adaptiveEnforced is false), adaptive after. |
GET, PATCH, DELETE /api/v1/website-services/{website}/bot-challenge/rules/{rule} | Read a rule, change its mode, or remove it. |
PUT /api/v1/website-services/{website}/bot-challenge/settings | Change difficulty (a preset name such as medium), passLifetime (seconds), requestsPerPass (0 for no limit) or exemptions. Send only what changes. |
exemptions holds kinds (search, ai), crawlers (names from
availableCrawlers) and networks, and replaces the website's additions
whole. A path or an exemption the panel refuses answers 400 with the
reason, the same one the tab shows; an unknown website or rule answers 404,
and a value outside a field's choices, such as a difficulty that isn't a
preset, 422. Advice that doesn't stop a rule, such as
a rule ending in /index.php, is in the rule's warnings.
When to use MCP instead
When an AI tool calls your account, rather than code you wrote, connect it to the MCP server. It offers the same operations, authenticates over OAuth with no key to store, and describes each operation to the model so it can choose the right one.
API keys and MCP connections are separate credential systems. Revoke an MCP client under Integrations → OAuth → Connected apps, not on the API Keys page.