SiteLyra API
Overview
Introduction
With the SiteLyra API your software manages your account's domains, DNS, hosting and email, and reads orders and credit, without going through the panel. Responses are JSON.
With the API you can, for example, add and change DNS records, create mailboxes and forwards, FTP users and databases, change PHP, manage cron jobs, WordPress and Git. Purchases and renewals are always done on the website.
Creating a key
- In the left menu open API and click + New key.
- Type a name that helps you recognise it, for example "CRM".
- For each service choose the permission: no access, read only, or read and write. Billing (orders and credit) is read only.
- If you like, add allowed IPs (one per line) and an expiry date.
- Click New key and copy the key right away: we don't store it, so once the window is closed it can't be shown again.
A key can do what its creator can do: if you work on someone else's account with a limited role, the key has the same limits, and if you're removed from the account it stops working. The owner and admins see and can revoke all the account's keys.
Authentication
Every request carries the key in the Authorization header. In the examples the key is in the API_KEY variable:
export API_KEY="sl_…"
curl "https://sitelyra.it/api/v1/me" -H "Authorization: Bearer $API_KEY"
Test your key (/api/v1/me) returns the key, the account it works on and its effective permissions.
Responses and errors
Successful responses have the data in data. The lists of domains, sites, mail domains, orders and credit transactions also have meta with page, perPage and total and are paged with ?page=2&per_page=100 (100 per page by default, at most 500); the other lists come in data without pages. Requests that make changes send a JSON body, with the Content-Type: application/json header.
Some hosting changes (PHP, cron, hotlinking, WordPress, Git) are queued on the server and applied within seconds: the response is 202 with "queued": true. The same goes for the malware scan, whose results arrive within an hour.
Errors always look like { "error": { "code": "…", "message": "…" } }, sometimes with details:
| HTTP status | Meaning |
|---|---|
| 400 | The request body isn't a JSON object (invalid_body) |
| 401 | Missing, wrong or expired key, a non-allowed IP, or a user who is blocked or removed from the account (unauthorized) |
| 403 | The key lacks the permission for that service (forbidden) |
| 404 | The resource doesn't exist, the key can't see it or the feature isn't enabled for your account (not_found) |
| 409 | Not possible in the current state: the code says why, for example dns_not_hosted or site_not_active |
| 422 | A field is missing or invalid (invalid_fields, with the fields in details.fields), or the server rejected a value (rejected) |
| 429 | Too many requests (rate_limited): the key's hourly limit, or too many attempts with a wrong key from the same IP |
| 500 | Unexpected error (internal_error) |
| 503 | A service (DNS, web server, registry) isn't responding: retry shortly (unavailable) |
Each call also lists its specific errors.
Limits
Each key can make at most 1,000 reads and 100 changes per hour (beyond that: 429). Hosting changes also have the panel's limit: 60 per hour per person (beyond that: 409 busy). After 60 requests with a wrong key within 10 minutes, the IP gets 429 for the rest of those 10 minutes. Each person can have up to 20 keys per account.
Passwords
The API never shows stored passwords (FTP, databases, mailboxes, WordPress). We generate passwords when you create a mailbox, an FTP user or a database, or when you ask for a new one, and they're shown only once, in the response.
Activity log
Every change made with a key goes into the account's activity log, with the key's name and the IP it came from.
Revoking a key
In API open the key's ⋮ menu and choose Revoke: software using it stops working at once. If a key ends up in the wrong hands, revoke it and create a new one.
Account
API key
Operations
Test your key
/me
Returns the key, who created it, the account it works on and the effective permission for each service. It's the simplest call to check that the key works.
In permissions each service is read, write or null (no access). Effective permissions can be fewer than those chosen at creation: for example a read-only role can't make changes, and only the owner and admins see billing. limitedToDomains lists the domains the key is limited to, or is null if it sees the whole account.
Permission: any valid key
curl "https://sitelyra.it/api/v1/me" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"key": {
"name": "Gestionale"
},
"user": {
"email": "mario@example.com"
},
"account": {
"name": "Mario Rossi",
"email": "mario@example.com",
"role": "owner",
"limitedToDomains": null
},
"permissions": {
"domains": "write",
"dns": "write",
"hosting": "read",
"mail": "write",
"billing": "read"
}
}
}Domains
Domains
Operations
List domains
/domains
Returns the account's domains in alphabetical order, paginated.
Each domain has: name (ASCII), nameUnicode (with accents), status, registeredAt and expiresAt (ISO 8601 dates, null if unknown), autoRenew, lock (transfer lock), privacy (hidden WHOIS), nameservers and dns (hosted: the zone is on our DNS; dnssec: off, pending or active).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | integer | optional | Page, from 1 (default 1). |
per_page | integer | optional | Domains per page (default 100, at most 500). |
Permission: domains:read
curl "https://sitelyra.it/api/v1/domains?page=1&per_page=100" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"name": "example.com",
"nameUnicode": "example.com",
"status": "active",
"registeredAt": "2024-03-01T10:00:00.000Z",
"expiresAt": "2027-03-01T10:00:00.000Z",
"autoRenew": true,
"lock": true,
"privacy": true,
"nameservers": ["ns1.example.net", "ns2.example.net"],
"dns": {
"hosted": true,
"dnssec": "off"
}
}
],
"meta": {
"page": 1,
"perPage": 100,
"total": 1
}
}Get a domain
/domains/{domain}
Returns a domain: status, expiry, auto-renewal, lock, privacy, nameservers and DNS.
Each domain has: name (ASCII), nameUnicode (with accents), status, registeredAt and expiresAt (ISO 8601 dates, null if unknown), autoRenew, lock (transfer lock), privacy (hidden WHOIS), nameservers and dns (hosted: the zone is on our DNS; dnssec: off, pending or active).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: domains:read
curl "https://sitelyra.it/api/v1/domains/example.com" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"name": "example.com",
"nameUnicode": "example.com",
"status": "active",
"registeredAt": "2024-03-01T10:00:00.000Z",
"expiresAt": "2027-03-01T10:00:00.000Z",
"autoRenew": true,
"lock": true,
"privacy": true,
"nameservers": ["ns1.example.net", "ns2.example.net"],
"dns": {
"hosted": true,
"dnssec": "off"
}
}
}List nameserver groups
/nameserver-groups
Returns the nameserver groups you can assign to domains: ours (system: true) and those created in your account.
Not available to users limited to some domains, as in the panel.
Specific errors
| Status | Code | Description |
|---|---|---|
| 403 | forbidden | The key is limited to some domains. |
Permission: domains:read
curl "https://sitelyra.it/api/v1/nameserver-groups" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "cm3k9x2ab0000qz8f1a2b3c4d",
"label": "SiteLyra",
"system": true,
"nameservers": ["ns1.example.net", "ns2.example.net"]
},
{
"id": "cm3k9x2ab0001qz8f7h2d4e5g",
"label": "Miei server",
"system": false,
"nameservers": ["ns1.example.com", "ns2.example.com"]
}
]
}Change nameservers
/domains/{domain}/nameservers
Assigns a nameserver group to the domain: ours or one of your account's groups.
Read the group ids with Nameserver groups. When you switch to our nameservers the DNS zone is created automatically, with the default records.
Specific errors
| Status | Code | Description |
|---|---|---|
| 404 | not_found | The domain or the group doesn't exist. |
| 409 | operation_failed | The registry didn't accept the nameservers: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
group | string | required | Nameserver group id. |
Permission: domains:write
curl -X PUT "https://sitelyra.it/api/v1/domains/example.com/nameservers" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"group":"cm3k9x2ab0001qz8f7h2d4e5g"}'{
"data": {
"name": "example.com",
"nameUnicode": "example.com",
"status": "active",
"registeredAt": "2024-03-01T10:00:00.000Z",
"expiresAt": "2027-03-01T10:00:00.000Z",
"autoRenew": true,
"lock": true,
"privacy": true,
"nameservers": ["ns1.example.com", "ns2.example.com"],
"dns": {
"hosted": false,
"dnssec": "off"
}
}
}Operations
Turn privacy on or off
/domains/{domain}/privacy
Hides or shows the registrant's details in the public WHOIS.
Specific errors
| Status | Code | Description |
|---|---|---|
| 404 | not_found | The domain doesn't exist or privacy isn't available for this domain. |
| 409 | operation_failed | The registry didn't accept the change: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
enabled | boolean | required | true to hide the details, false to show them. |
Permission: domains:write
curl -X PUT "https://sitelyra.it/api/v1/domains/example.com/privacy" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'{
"data": {
"name": "example.com",
"nameUnicode": "example.com",
"status": "active",
"registeredAt": "2024-03-01T10:00:00.000Z",
"expiresAt": "2027-03-01T10:00:00.000Z",
"autoRenew": true,
"lock": true,
"privacy": true,
"nameservers": ["ns1.example.net", "ns2.example.net"],
"dns": {
"hosted": true,
"dnssec": "off"
}
}
}Operations
Turn the transfer lock on or off
/domains/{domain}/lock
Turns the transfer lock on or off: while it's on, nobody can transfer the domain to another provider.
To transfer the domain elsewhere, turn the lock off and read the transfer code.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | unsupported | The domain's extension has no transfer lock. |
| 409 | operation_failed | The registry didn't accept the change: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
enabled | boolean | required | true to turn the lock on, false to turn it off. |
Permission: domains:write
curl -X PUT "https://sitelyra.it/api/v1/domains/example.com/lock" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":false}'{
"data": {
"name": "example.com",
"nameUnicode": "example.com",
"status": "active",
"registeredAt": "2024-03-01T10:00:00.000Z",
"expiresAt": "2027-03-01T10:00:00.000Z",
"autoRenew": true,
"lock": false,
"privacy": true,
"nameservers": ["ns1.example.net", "ns2.example.net"],
"dns": {
"hosted": true,
"dnssec": "off"
}
}
}Operations
Get the transfer code
/domains/{domain}/auth-code
Reads the transfer code (EPP or auth code) from the registry: you need it to move the domain to another provider.
We don't store the code: it's read on the spot and every read is kept in the activity log. It needs the domains write permission and a role that can see passwords.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | operation_failed | The registry didn't return the code: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: domains:write
curl -X POST "https://sitelyra.it/api/v1/domains/example.com/auth-code" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"authCode": "x7T#q2Lm9vRk"
}
}Operations
List glue records
/glue
Returns the account's glue records: host name, IPv4, IPv6 and the domain they belong to.
Not available to users limited to some domains, as in the panel.
Specific errors
| Status | Code | Description |
|---|---|---|
| 403 | forbidden | The key is limited to some domains. |
Permission: domains:read
curl "https://sitelyra.it/api/v1/glue" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"name": "ns1.example.com",
"ip": "203.0.113.10",
"ip6": null,
"domain": "example.com"
}
]
}List DNS records
/dns/{domain}/records
Returns the records of the zone on our DNS, in zone-file order.
Each record has id, type, host (empty = the domain), ttl, value (the value on one line, as in the panel) and fields (the single values, the same ones you send to change it). Records with system: true are the zone's NS: you can see them but not change them.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: dns:read
curl "https://sitelyra.it/api/v1/dns/example.com/records" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "512345670",
"type": "NS",
"host": "",
"ttl": 3600,
"value": "ns1.example.net",
"fields": {
"record": "ns1.example.net"
},
"system": true
},
{
"id": "512345679",
"type": "MX",
"host": "",
"ttl": 3600,
"value": "10 mail.example.com",
"fields": {
"priority": "10",
"record": "mail.example.com"
},
"system": false
},
{
"id": "512345678",
"type": "A",
"host": "www",
"ttl": 3600,
"value": "203.0.113.10",
"fields": {
"record": "203.0.113.10"
},
"system": false
}
]
}Add a DNS record
/dns/{domain}/records
Adds a record to the zone and returns it with its id. If the new record can't be recognised in the zone's list, the response is {"created": true}.
Email example: {"type":"MX","host":"","fields":{"priority":10,"record":"mail.example.com"}}. TXT example: {"type":"TXT","host":"_dmarc","fields":{"record":"v=DMARC1; p=none"}}.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 422 | rejected | The DNS server rejected the value: the message explains why. |
| 409 | dns_limit | The domain's maximum number of records was reached (error.details.values.max). |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
type | string | required | Type, upper or lower case: A, AAAA, ALIAS, CAA, CERT, CNAME, DNAME, DS, HINFO, HTTPS, LOC, MX, NAPTR, NS, OPENPGPKEY, PTR, RP, SMIMEA, SPF, SRV, SSHFP, SVCB, TLSA, TXT, WR (web redirect). |
host | string | optional | Name: www, mail… Empty or @ = the domain itself. |
ttl | integer | optional | Time to live in seconds (default 3600), one of these values: 60, 300, 600, 900, 1800, 3600, 21600, 43200, 86400, 172800, 259200, 604800, 1209600, 2592000. |
fields | object | required | Values for the type, as strings or numbers. Almost always record (the address, name or text); MX and SRV also priority (0 to 65535), SRV weight and port (0 to 65535), CAA caa_flag (0 or 128), caa_type (issue, issuewild, iodef, issuemail, issuevmc, contactemail, contactphone) and caa_value, WR redirect_type (301 or 302), frame and save_path (0 or 1). |
Permission: dns:write
curl -X POST "https://sitelyra.it/api/v1/dns/example.com/records" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"A","host":"www","ttl":3600,"fields":{"record":"203.0.113.10"}}'{
"data": {
"id": "512345678",
"type": "A",
"host": "www",
"ttl": 3600,
"value": "203.0.113.10",
"fields": {
"record": "203.0.113.10"
},
"system": false
}
}Update a DNS record
/dns/{domain}/records/{id}
Rewrites a record: name, time to live and values. The type can't change (delete it and add a new one instead).
Send all the record's values, not just the ones that change: missing ones are removed, a missing host = the domain itself, a missing ttl = 3600. Returns the updated record (or {"updated": true} if it can't be found in the zone's list).
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | system_record | It's one of the zone's NS records, which can't be changed. |
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 422 | rejected | The DNS server rejected the value: the message explains why. |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Record id, from the record list. |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
type | string | optional | Optional: the type can't change; if you send it, it must match the record. |
host | string | optional | Name: www, mail… Empty or @ = the domain itself. |
ttl | integer | optional | Time to live in seconds (default 3600), one of these values: 60, 300, 600, 900, 1800, 3600, 21600, 43200, 86400, 172800, 259200, 604800, 1209600, 2592000. |
fields | object | required | Values for the type, as strings or numbers. Almost always record (the address, name or text); MX and SRV also priority (0 to 65535), SRV weight and port (0 to 65535), CAA caa_flag (0 or 128), caa_type (issue, issuewild, iodef, issuemail, issuevmc, contactemail, contactphone) and caa_value, WR redirect_type (301 or 302), frame and save_path (0 or 1). |
Permission: dns:write
curl -X PUT "https://sitelyra.it/api/v1/dns/example.com/records/512345678" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"host":"www","ttl":600,"fields":{"record":"203.0.113.20"}}'{
"data": {
"id": "512345678",
"type": "A",
"host": "www",
"ttl": 600,
"value": "203.0.113.20",
"fields": {
"record": "203.0.113.20"
},
"system": false
}
}Delete a DNS record
/dns/{domain}/records/{id}
Deletes a record from the zone.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | system_record | It's one of the zone's NS records, which can't be deleted. |
| 422 | rejected | The DNS server rejected the request: the message explains why. |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Record id, from the record list. |
Permission: dns:write
curl -X DELETE "https://sitelyra.it/api/v1/dns/example.com/records/512345678" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}List DNS templates
/dns/templates
Returns the templates you can apply to a zone (for example Google Workspace or Microsoft 365), with the records they add.
name and description are in English; description can be null. Record values can contain placeholders ({domain}, {domainDashed}, {serverIp4}, {serverIp6}) that are filled in when the template is applied.
Permission: dns:read
curl "https://sitelyra.it/api/v1/dns/templates" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"slug": "google-workspace",
"name": "Google Workspace",
"description": "Gmail for your domain: Google mail server and SPF.",
"records": [
{
"type": "MX",
"host": "",
"ttl": 3600,
"fields": {
"priority": "1",
"record": "smtp.google.com"
}
},
{
"type": "TXT",
"host": "",
"ttl": 3600,
"fields": {
"record": "v=spf1 include:_spf.google.com ~all"
}
}
]
}
]
}Apply a DNS template
/dns/{domain}/templates/{slug}
Adds the template's missing records to the zone; existing ones stay. added says how many records were added.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | dns_limit | The template's records (all counted, including those already present) exceed the domain's maximum number of records (error.details.values.max). |
| 422 | rejected | The DNS server rejected one of the template's records: the message explains why. |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
slug | string | required | Template name, from the DNS templates list. |
Permission: dns:write
curl -X POST "https://sitelyra.it/api/v1/dns/example.com/templates/google-workspace" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"added": 2
}
}Operations
Get the SOA
/dns/{domain}/soa
Returns the zone's SOA: primary server, responsible person's email and timers in seconds.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: dns:read
curl "https://sitelyra.it/api/v1/dns/example.com/soa" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"serial": "2026110701",
"primaryNs": "ns1.example.net",
"adminMail": "hostmaster@example.com",
"refresh": 7200,
"retry": 1800,
"expire": 1209600,
"defaultTtl": 3600
}
}Update the SOA
/dns/{domain}/soa
Changes the SOA's responsible email and timers. The primary server is always ours.
Fields you don't send stay as they are.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 422 | rejected | The DNS server rejected the value: the message explains why. |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
adminMail | string | optional | Email of the person responsible for the zone. |
refresh | integer | optional | From 1200 to 43200 seconds. |
retry | integer | optional | From 180 to 2419200 seconds. |
expire | integer | optional | From 1209600 to 2419200 seconds. |
defaultTtl | integer | optional | From 60 to 2419200 seconds. |
Permission: dns:write
curl -X PUT "https://sitelyra.it/api/v1/dns/example.com/soa" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"adminMail":"dns@example.com","refresh":3600}'{
"data": {
"serial": "2026110702",
"primaryNs": "ns1.example.net",
"adminMail": "dns@example.com",
"refresh": 3600,
"retry": 1800,
"expire": 1209600,
"defaultTtl": 3600
}
}DNSSEC status
/dns/{domain}/dnssec
Returns the DNSSEC status: off, pending (zone signed, keys on their way to the registry) or active.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: dns:read
curl "https://sitelyra.it/api/v1/dns/example.com/dnssec" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"state": "active"
}
}Turn DNSSEC on or off
/dns/{domain}/dnssec
Turns DNSSEC on (zone signing, keys sent to the registry as soon as they're ready) or off (keys removed from the registry first, then the signing).
After you turn it on the status stays pending for a few minutes, then becomes active.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | enabled is missing or isn't true/false: error.details.fields says so. |
| 422 | rejected | The DNS server rejected the request: the message explains why. |
| 409 | dns_not_hosted | The domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
enabled | boolean | required | true to turn on, false to turn off. |
Permission: dns:write
curl -X PUT "https://sitelyra.it/api/v1/dns/example.com/dnssec" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'{
"data": {
"state": "pending"
}
}Operations
List sites
/hosting
Returns the account's hosting sites in alphabetical order, paginated.
Each site has: domain, status (active, provisioning, suspended…), plan, app (wordpress or null), mainSite (the main site, if the site was added to a plan), startsAt and expiresAt, autoRenew, limits (disk in MB, databases, FTP users, mailboxes; -1 = unlimited) and features (plan features).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | integer | optional | Page, from 1. |
per_page | integer | optional | Sites per page (default 100, at most 500). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"domain": "example.com",
"domainUnicode": "example.com",
"status": "active",
"plan": {
"slug": "plus",
"name": "Plus"
},
"app": "wordpress",
"mainSite": null,
"startsAt": "2026-01-10T09:00:00.000Z",
"expiresAt": "2027-01-10T09:00:00.000Z",
"autoRenew": true,
"limits": {
"diskMb": 20480,
"databases": 10,
"ftpUsers": 10,
"mailboxes": 10
},
"features": ["ssl", "wordpress", "backup", "cron"]
}
],
"meta": {
"page": 1,
"perPage": 100,
"total": 1
}
}Get a site
/hosting/{domain}
Returns a site with its status on the server: PHP version, disk usage, running state and WordPress.
Each site has: domain, status (active, provisioning, suspended…), plan, app (wordpress or null), mainSite (the main site, if the site was added to a plan), startsAt and expiresAt, autoRenew, limits (disk in MB, databases, FTP users, mailboxes; -1 = unlimited) and features (plan features). If the site isn't active or the server doesn't respond, the site data still comes back, with server: null.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"domain": "example.com",
"domainUnicode": "example.com",
"status": "active",
"plan": {
"slug": "plus",
"name": "Plus"
},
"app": "wordpress",
"mainSite": null,
"startsAt": "2026-01-10T09:00:00.000Z",
"expiresAt": "2027-01-10T09:00:00.000Z",
"autoRenew": true,
"limits": {
"diskMb": 20480,
"databases": 10,
"ftpUsers": 10,
"mailboxes": 10
},
"features": ["ssl", "wordpress", "backup", "cron"],
"server": {
"phpVersion": "8.3",
"diskUsedBytes": 734003200,
"diskLimitBytes": 21474836480,
"running": true,
"wordpress": true
}
}
}List FTP users
/hosting/{domain}/ftp-users
Returns the FTP users added to the site, with folder (directory, the full path on the server) and status; quotaMb 0 = no quota of its own. The site's main user isn't in the list (primary is always false). Passwords are never readable.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/ftp-users" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"user": "example_com_dev",
"directory": "/srv/sites/example_com/www/dev",
"quotaMb": 0,
"active": true,
"primary": false
}
]
}Add an FTP user
/hosting/{domain}/ftp-users
Creates an FTP user limited to a folder of the site. We generate the password and it's shown only in this response.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid | The name or the folder isn't valid. |
| 409 | too_long | The full name is longer than 32 characters. |
| 409 | taken | The name is already taken. |
| 409 | limit | The plan has no more FTP users available. |
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
suffix | string | required | 2 to 16 lowercase letters or digits: the name becomes <site user>_<suffix>. |
directory | string | optional | Folder inside www it's limited to (for example dev): letters, digits, ., _, - and /; created if missing. Empty = the whole site. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/ftp-users" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"suffix":"dev","directory":"dev"}'{
"data": {
"user": "example_com_dev",
"password": "Hq7mT2kPz9xRw4sN"
}
}Suspend or reactivate an FTP user
/hosting/{domain}/ftp-users/{user}
Suspends or reactivates an added FTP user. The main user always stays active.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
user | string | required | FTP user name, from the FTP user list. |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
active | boolean | required | false to suspend, true to reactivate. |
Permission: hosting:write
curl -X PATCH "https://sitelyra.it/api/v1/hosting/example.com/ftp-users/example_com_dev" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"active":false}'{
"data": {
"user": "example_com_dev",
"active": false
}
}Delete an FTP user
/hosting/{domain}/ftp-users/{user}
Deletes an added FTP user. The files stay on the site.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
user | string | required | FTP user name, from the FTP user list. |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/ftp-users/example_com_dev" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}New FTP password
/hosting/{domain}/ftp-users/{user}/password
Generates a new password for an FTP user, the main one included. The old one stops working at once; the new one is shown only in this response.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
user | string | required | FTP user name, from the FTP user list. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/ftp-users/example_com/password" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"user": "example_com",
"password": "Tz4kQ8mW2pXn7Rv3"
}
}Site Git repository
/hosting/{domain}/git
Returns the repository linked to the site: URL, branch, deploy key to add to the repository (read only), last commit and the result of the last pull.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/git" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"supported": true,
"configured": true,
"url": "git@github.com:example/site.git",
"branch": "main",
"publicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI… deploy@example.com",
"head": {
"hash": "3f2a9c1e8b7d6a5f4e3d2c1b0a9f8e7d6c5b4a32",
"subject": "Nuova home",
"date": "2026-11-06T19:20:00+01:00"
},
"wwwEmpty": false,
"lastPull": {
"ok": true,
"message": null,
"hash": "3f2a9c1e8b7d6a5f4e3d2c1b0a9f8e7d6c5b4a32",
"subject": "Nuova home",
"at": "2026-11-06T18:21:00.000Z"
}
}
}Link a Git repository
/hosting/{domain}/git
Links a repository to the site, or changes its URL and branch. Returns the status, with the deploy key to add to the repository.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | git_repo_invalid | The repository URL isn't valid. |
| 409 | git_branch_invalid | The branch name isn't valid. |
| 409 | git_unsupported | The site doesn't support Git. |
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
url | string | required | SSH (git@host:path or ssh://…) or HTTPS repository URL without credentials, at most 300 characters. |
branch | string | optional | Branch to pull, at most 100 characters (default main). |
Permission: hosting:write
curl -X PUT "https://sitelyra.it/api/v1/hosting/example.com/git" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"git@github.com:example/site.git","branch":"main"}'{
"data": {
"supported": true,
"configured": true,
"url": "git@github.com:example/site.git",
"branch": "main",
"publicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI… deploy@example.com",
"head": null,
"wwwEmpty": true,
"lastPull": null
}
}Unlink the Git repository
/hosting/{domain}/git
Unlinks the repository from the site and deletes the deploy key: if you link another one, the key is new. The site's files stay.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/git" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}Update the site from Git
/hosting/{domain}/git/pull
Pulls the latest changes of the linked branch into the site.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true. Read the result in Site Git repository, field lastPull (ok: false with the reason in message if the update fails). The first update needs an empty www folder (field wwwEmpty). You can call it from a pipeline (for example GitHub Actions) after every push.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/git/pull" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"queued": true
}
}List databases
/hosting/{domain}/databases
Returns the site's databases: the one created with the site (primary: true) and the added ones, with their size in bytes (null if it can't be read).
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/databases" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"name": "example_com",
"primary": true,
"sizeBytes": 52428800
},
{
"name": "example_com_shop",
"primary": false,
"sizeBytes": 1048576
}
]
}Add a database
/hosting/{domain}/databases
Creates a MariaDB database with its user (same name). We generate the password and it's shown only in this response.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid | The name isn't valid. |
| 409 | too_long | The full name is longer than 32 characters. |
| 409 | taken | The name is already taken. |
| 409 | limit | The plan has no more databases available. |
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
suffix | string | required | 2 to 16 lowercase letters or digits: the name becomes <site prefix>_<suffix>. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/databases" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"suffix":"shop"}'{
"data": {
"name": "example_com_shop",
"user": "example_com_shop",
"password": "pX7rK2mQ9tW4zN8vB3sL"
}
}Delete a database
/hosting/{domain}/databases/{name}
Deletes an added database with all its data. The database created with the site can't be deleted.
Deleting can't be undone.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
name | string | required | Database name, from the database list. |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/databases/example_com_shop" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}New database password
/hosting/{domain}/databases/{name}/password
Generates a new password for an added database: it's shown only in this response. Remember to update it in your site.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | not_active | The site isn't active. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
name | string | required | Database name, from the database list. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/databases/example_com_shop/password" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"name": "example_com_shop",
"password": "mR8tK3wQ7pZ2xN9vL4sB"
}
}IPs allowed to phpMyAdmin
/hosting/{domain}/phpmyadmin/ips
Returns the IPs allowed to open phpMyAdmin. They apply to all the account's sites, 30 days each, at most 5.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/phpmyadmin/ips" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "cm3pma0000001qz8f1a2b3c4d",
"ip": "203.0.113.50",
"note": "Ufficio",
"expiresAt": "2026-12-07T10:00:00.000Z",
"createdAt": "2026-11-07T10:00:00.000Z"
}
]
}Allow an IP to phpMyAdmin
/hosting/{domain}/phpmyadmin/ips
Allows an IP to phpMyAdmin for 30 days; if it's already there, the 30 days start again. Returns the updated list.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | ip_invalid | The address isn't valid. |
| 409 | ip_limit | There are already 5 allowed IPs. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
ip | string | required | One IPv4 or IPv6 address (not a network). |
note | string | optional | Note, up to 100 characters: longer ones are cut (for example "Office"). If the IP is already there and the note is empty, the previous one stays. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/phpmyadmin/ips" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"ip":"203.0.113.50","note":"Ufficio"}'{
"data": [
{
"id": "cm3pma0000001qz8f1a2b3c4d",
"ip": "203.0.113.50",
"note": "Ufficio",
"expiresAt": "2026-12-07T10:00:00.000Z",
"createdAt": "2026-11-07T10:00:00.000Z"
}
]
}Remove an IP from phpMyAdmin
/hosting/{domain}/phpmyadmin/ips/{id}
Removes an IP from those allowed to phpMyAdmin.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | IP id, from the allowed IP list. |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/phpmyadmin/ips/cm3pma0000001qz8f1a2b3c4d" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}PHP version and settings
/hosting/{domain}/php
Returns the site's PHP version, its current settings and the values you can choose.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/php" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"version": "8.3",
"settings": {
"memory_limit": "256M",
"upload_max_filesize": "64M",
"post_max_size": "64M",
"max_execution_time": "60"
},
"available": {
"versions": ["8.1", "8.2", "8.3", "8.4"],
"settings": {
"memory_limit": ["128M", "256M", "512M", "1024M"],
"upload_max_filesize": ["16M", "32M", "64M", "128M", "256M", "512M"],
"post_max_size": ["16M", "32M", "64M", "128M", "256M", "512M"],
"max_execution_time": ["30", "60", "120", "300"]
}
}
}
}Change PHP
/hosting/{domain}/php
Changes the site's PHP version and/or settings, with the values listed by PHP version and settings.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid | Version or value not allowed, or nothing to change. |
| 422 | invalid_fields | A field isn't valid (for example a setting in settings that doesn't exist): error.details.fields says which one. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
version | string | optional | PHP version, for example 8.3. |
settings | object | optional | Settings to change: memory_limit, upload_max_filesize, post_max_size, max_execution_time. |
Permission: hosting:write
curl -X PATCH "https://sitelyra.it/api/v1/hosting/example.com/php" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"version":"8.4","settings":{"memory_limit":"512M"}}'{
"data": {
"queued": true
}
}List cron jobs
/hosting/{domain}/cron
Returns the site's cron jobs, with the schedule in the five crontab fields and the command.
Only for plans that include cron jobs.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | cron_not_in_plan | The plan doesn't include cron jobs. |
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/cron" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "a1b2c3d4",
"minute": "*/15",
"hour": "*",
"day": "*",
"month": "*",
"weekday": "*",
"command": "php cron.php"
}
]
}Add a cron job
/hosting/{domain}/cron
Adds a cron job to the site: at most 20, no more often than once every 5 minutes.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 409 | cron_limit | The site already has 20 cron jobs. |
| 409 | cron_schedule | The schedule isn't valid. |
| 409 | cron_too_often | More often than once every 5 minutes. |
| 409 | cron_command | The command is empty, longer than 1000 characters or contains % or a line break. |
| 409 | cron_plan_missing | The plan doesn't include cron jobs. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
minute | string | required | Minute (0-59), as in crontab: 0, */15, 0,30, 10-20…; the same forms work for the other four fields (digits and * , - / only, up to 120 characters). |
hour | string | required | Hour (0-23) or *. |
day | string | required | Day of month (1-31) or *. |
month | string | required | Month (1-12) or *. |
weekday | string | required | Day of week (0-7, 0 and 7 = Sunday) or *. |
command | string | required | One-line command (up to 1000 characters, no %), run in the site's www folder: for example php cron.php. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/cron" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"minute":"0","hour":"3","day":"*","month":"*","weekday":"*","command":"php cron.php"}'{
"data": {
"queued": true
}
}Update a cron job
/hosting/{domain}/cron/{id}
Rewrites a cron job's schedule and command.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 404 | not_found | The cron job isn't there. |
| 409 | cron_schedule | The schedule isn't valid. |
| 409 | cron_too_often | More often than once every 5 minutes. |
| 409 | cron_command | The command is empty, longer than 1000 characters or contains % or a line break. |
| 409 | cron_plan_missing | The plan doesn't include cron jobs. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Cron job id, from the cron job list. |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
minute | string | required | Minute (0-59), as in crontab: 0, */15, 0,30, 10-20…; the same forms work for the other four fields (digits and * , - / only, up to 120 characters). |
hour | string | required | Hour (0-23) or *. |
day | string | required | Day of month (1-31) or *. |
month | string | required | Month (1-12) or *. |
weekday | string | required | Day of week (0-7, 0 and 7 = Sunday) or *. |
command | string | required | One-line command (up to 1000 characters, no %), run in the site's www folder: for example php cron.php. |
Permission: hosting:write
curl -X PUT "https://sitelyra.it/api/v1/hosting/example.com/cron/a1b2c3d4" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"minute":"30","hour":"4","day":"*","month":"*","weekday":"1","command":"php report.php"}'{
"data": {
"queued": true
}
}Delete a cron job
/hosting/{domain}/cron/{id}
Deletes a cron job from the site.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 404 | not_found | The cron job isn't there. |
| 409 | cron_plan_missing | The plan doesn't include cron jobs. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Cron job id, from the cron job list. |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/cron/a1b2c3d4" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"queued": true
}
}Hotlink protection status
/hosting/{domain}/hotlink
Tells whether hotlink protection is on (the site's images can't be shown on other sites) and which domains are allowed.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/hotlink" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"enabled": true,
"domains": ["example.org"]
}
}Turn hotlink protection on or off
/hosting/{domain}/hotlink
Turns hotlink protection on or off. Turning it off also removes the allowed domains.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid | Protection is already in the requested state. |
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
enabled | boolean | required | true to turn on, false to turn off. |
Permission: hosting:write
curl -X PUT "https://sitelyra.it/api/v1/hosting/example.com/hotlink" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'{
"data": {
"queued": true
}
}Allow a domain to hotlink
/hosting/{domain}/hotlink/domains
Lets another domain show the site's images. Protection must be on.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 409 | domain_invalid | The domain isn't valid. |
| 409 | domain_exists | The domain is already allowed (or is the site's own domain). |
| 409 | domain_limit | The maximum number of allowed domains (20) was reached. |
| 409 | not_active | The site isn't active, or protection is off. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain to allow, for example example.org (accented names work too; www. is dropped). The response returns it in punycode. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/hotlink/domains" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"example.org"}'{
"data": {
"queued": true,
"domain": "example.org"
}
}Remove a domain from hotlinking
/hosting/{domain}/hotlink/domains/{allowed}
Removes a domain from those allowed to show the site's images.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true.
Specific errors
| Status | Code | Description |
|---|---|---|
| 404 | not_found | The domain isn't among the allowed ones. |
| 409 | not_active | The site isn't active, or protection is off. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
allowed | string | required | Allowed domain to remove. |
Permission: hosting:write
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/hotlink/domains/example.org" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"queued": true
}
}Files found by the malware scanner
/hosting/{domain}/malware
Returns the files found by the site's malware scans, most recent first (up to 500): quarantined (quarantined) or restored (restored).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/malware" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "cm3mal0000001qz8f1a2b3c4d",
"path": "www/wp-content/uploads/x.php",
"signature": "{HEX}php.cmdshell.1",
"status": "quarantined",
"detectedAt": "2026-11-06T03:10:00.000Z",
"restoredAt": null
}
]
}Start a scan
/hosting/{domain}/malware/scan
Starts a full scan of the site now. Results appear in Files found by the malware scanner within an hour.
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | scan_busy | The site is already queued or being scanned. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/malware/scan" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"queued": true
}
}Restore a file from quarantine
/hosting/{domain}/malware/{id}/restore
Puts a quarantined file back on the site, if it's a false positive.
Specific errors
| Status | Code | Description |
|---|---|---|
| 404 | not_found | The file isn't there or isn't quarantined (for example it was already restored). |
| 409 | restore_exists | There's already a file with the same name on the site. |
| 409 | busy | You made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | File id, from Files found by the malware scanner. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/malware/cm3mal0000001qz8f1a2b3c4d/restore" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"restored": "www/wp-content/uploads/x.php"
}
}WordPress status
/hosting/{domain}/wordpress
Returns the WordPress version, the available update, plugins, themes and the result of the last action (if it's from the last hour).
Specific errors
| Status | Code | Description |
|---|---|---|
| 409 | site_not_active | The site isn't active (being created, suspended or failed). |
| 503 | unavailable | The server isn't responding (retry later), or WordPress isn't installed on the site. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: hosting:read
curl "https://sitelyra.it/api/v1/hosting/example.com/wordpress" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"version": "6.8.3",
"coreUpdate": null,
"plugins": [
{
"name": "akismet",
"title": "Akismet Anti-spam",
"status": "active",
"version": "5.5",
"update": false,
"updateVersion": null,
"autoUpdate": true
}
],
"themes": [
{
"name": "twentytwentyfive",
"title": "Twenty Twenty-Five",
"status": "active",
"version": "1.3",
"update": false,
"updateVersion": null
}
],
"lastAction": {
"action": "plugin-update",
"name": "akismet",
"ok": true,
"message": null,
"at": "2026-11-07T10:05:00.000Z"
}
}
}Install WordPress
/hosting/{domain}/wordpress/install
Installs WordPress on the site, if the plan includes it and the site folder is empty.
The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true. The WordPress administrator password is shown in the panel, in the site's WordPress tab: the API doesn't return it.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 409 | plan_missing | The plan doesn't include WordPress. |
| 409 | already_installed | WordPress is already installed. |
| 409 | not_empty | There are other files in the site folder. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
locale | string | optional | WordPress language: it (default) or en. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/wordpress/install" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"locale":"it"}'{
"data": {
"queued": true
}
}WordPress plugins, themes and updates
/hosting/{domain}/wordpress/actions
Activates, updates or deletes plugins and themes, or updates WordPress.
Actions: plugin-activate, plugin-deactivate, plugin-update, plugin-delete, plugin-autoupdate-on, plugin-autoupdate-off, theme-activate, theme-update, theme-delete (with name), plugins-update-all and core-update (without name). Active plugins and themes can't be deleted. The change is queued on the server and applied within seconds, one at a time per site: the response is 202 with queued: true. Read the result in WordPress status, field lastAction.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_fields | A field is missing or invalid: error.details.fields says which one. |
| 422 | invalid | The action doesn't exist, or name is missing, invalid or not needed for the action. |
| 404 | not_found | The plugin or theme isn't there. |
| 409 | in_use | The plugin or theme is active and can't be deleted. |
| 409 | not_active | The site isn't active. |
| 409 | busy | Another change is already running on the site, or you made more than 60 changes in an hour: retry shortly. |
| 503 | unavailable | The server isn't responding: retry later. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
action | string | required | Action from the list above. |
name | string | optional | Plugin or theme name (field name of WordPress status): required for plugin and theme actions, must be left out for plugins-update-all and core-update. |
Permission: hosting:write
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/wordpress/actions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"action":"plugin-update","name":"akismet"}'{
"data": {
"queued": true
}
}Operations
List email domains
Returns the account's domains with email, in alphabetical order, with the plan limits and how many mailboxes and forwards they have.
mainDomain is the main domain when the domain is added to another one's plan: in that case the limits are shared.
In the limits, -1 means unlimited. counts gives how many mailboxes and forward rows (one per recipient) the domain has.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | integer | optional | Page, from 1. |
per_page | integer | optional | Domains per page (default 100, at most 500). |
Permission: mail:read
curl "https://sitelyra.it/api/v1/mail" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"domain": "example.com",
"domainUnicode": "example.com",
"active": true,
"mainDomain": null,
"limits": {
"mailboxes": 10,
"storageMb": 51200,
"forwards": 100,
"dailySend": 500
},
"counts": {
"mailboxes": 3,
"forwards": 2
}
}
],
"meta": {
"page": 1,
"perPage": 100,
"total": 1
}
}Get an email domain
/mail/{domain}
Returns an email domain with its limits and usage: mailboxes, assigned storage in MB and forwards.
usage.mailboxes and usage.assignedStorageMb cover the whole plan, also when it's shared with other domains. usage.forwards counts this domain's forward rows (one per recipient), while limits.forwards counts forwarded addresses.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: mail:read
curl "https://sitelyra.it/api/v1/mail/example.com" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"domain": "example.com",
"domainUnicode": "example.com",
"active": true,
"mainDomain": null,
"limits": {
"mailboxes": 10,
"storageMb": 51200,
"forwards": 100,
"dailySend": 500
},
"usage": {
"mailboxes": 3,
"assignedStorageMb": 15360,
"forwards": 2
}
}
}List mailboxes
/mail/{domain}/mailboxes
Returns the domain's mailboxes with storage, messages and last IMAP and POP3 login. Passwords are never readable.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: mail:read
curl "https://sitelyra.it/api/v1/mail/example.com/mailboxes" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "cm3mbx0000001qz8f1a2b3c4d",
"address": "info@example.com",
"displayName": "Info",
"active": true,
"quotaMb": 5120,
"protocols": {
"imap": true,
"pop3": true,
"smtp": true
},
"sendCopyTo": null,
"createdAt": "2026-02-01T09:00:00.000Z",
"usedBytes": 104857600,
"messages": 1250,
"lastLogin": {
"imap": "2026-11-07T08:30:00.000Z",
"pop3": null
}
}
]
}Create a mailbox
/mail/{domain}/mailboxes
Creates a mailbox. We generate the password and it's shown only in this response.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_local_part | The part before the @ isn't valid. |
| 422 | invalid_quota | The storage isn't between 100 and 102400 MB. |
| 409 | already_exists | The address already exists, as a mailbox or as a forward. |
| 409 | mailbox_limit | The plan has no more mailboxes available. |
| 409 | storage_limit | The requested storage exceeds the plan's free storage. |
| 409 | domain_inactive | Email isn't active on the domain. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
localPart | string | required | Part before the @, for example info: 1 to 64 characters among unaccented letters, digits, ., - and _, starting and ending with a letter or digit and without ... Uppercase letters become lowercase. |
quotaMb | integer | required | Mailbox storage in MB, from 100 to 102400 (100 GB), within the plan's free storage. |
displayName | string | optional | Name shown to recipients, for example "Info" (at most 128 characters). |
Permission: mail:write
curl -X POST "https://sitelyra.it/api/v1/mail/example.com/mailboxes" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"localPart":"info","quotaMb":5120,"displayName":"Info"}'{
"data": {
"id": "cm3mbx0000001qz8f1a2b3c4d",
"address": "info@example.com",
"displayName": "Info",
"active": true,
"quotaMb": 5120,
"protocols": {
"imap": true,
"pop3": true,
"smtp": true
},
"sendCopyTo": null,
"createdAt": "2026-02-01T09:00:00.000Z",
"password": "Kp4mW8tQ2xRz7nVs"
}
}Get a mailbox
/mail/{domain}/mailboxes/{id}
Returns a mailbox's settings: name, storage, status, allowed protocols and copy of sent messages.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Mailbox id, from the mailbox list. |
Permission: mail:read
curl "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"id": "cm3mbx0000001qz8f1a2b3c4d",
"address": "info@example.com",
"displayName": "Info",
"active": true,
"quotaMb": 5120,
"protocols": {
"imap": true,
"pop3": true,
"smtp": true
},
"sendCopyTo": null,
"createdAt": "2026-02-01T09:00:00.000Z"
}
}Update a mailbox
/mail/{domain}/mailboxes/{id}
Changes a mailbox's settings. Fields you don't send stay as they are.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_quota | The storage isn't between 100 and 102400 MB. |
| 422 | invalid_address | The copy address isn't valid. |
| 409 | storage_limit | The requested storage exceeds the plan's free storage. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Mailbox id, from the mailbox list. |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
displayName | string | optional | Name shown to recipients (at most 128 characters); null to remove it. |
quotaMb | integer | optional | Mailbox storage in MB, from 100 to 102400 (100 GB), within the plan's free storage. |
active | boolean | optional | false suspends the mailbox: it doesn't receive mail and can't sign in. |
protocols | object | optional | Allowed protocols: imap, pop3, smtp (true or false). |
sendCopyTo | string | optional | Address that gets a copy of every sent message; null to remove it. |
Permission: mail:write
curl -X PATCH "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"quotaMb":10240,"protocols":{"pop3":false}}'{
"data": {
"id": "cm3mbx0000001qz8f1a2b3c4d",
"address": "info@example.com",
"displayName": "Info",
"active": true,
"quotaMb": 10240,
"protocols": {
"imap": true,
"pop3": false,
"smtp": true
},
"sendCopyTo": null,
"createdAt": "2026-02-01T09:00:00.000Z"
}
}Delete a mailbox
/mail/{domain}/mailboxes/{id}
Deletes a mailbox with all its messages.
Deleting can't be undone.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Mailbox id, from the mailbox list. |
Permission: mail:write
curl -X DELETE "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}New mailbox password
/mail/{domain}/mailboxes/{id}/password
Generates a new password for the mailbox. The old one stops working at once; the new one is shown only in this response.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Mailbox id, from the mailbox list. |
Permission: mail:write
curl -X POST "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d/password" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"address": "info@example.com",
"password": "Wq7nT3kP9mRz2xVs"
}
}List forwards
/mail/{domain}/forwards
Returns the domain's forwards: one row per recipient, as in the panel.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Permission: mail:read
curl "https://sitelyra.it/api/v1/mail/example.com/forwards" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"id": "cm3fwd0000001qz8f1a2b3c4d",
"source": "vendite@example.com",
"destination": "mario@example.org",
"active": true
}
]
}Create a forward
/mail/{domain}/forwards
Forwards messages for an address of the domain to one or more recipients. Returns the address's rows.
If the address already has a forward, the new recipients are added to the existing ones and the response contains all the address's rows.
Specific errors
| Status | Code | Description |
|---|---|---|
| 422 | invalid_local_part | The part before the @ isn't valid. |
| 422 | invalid_address | A recipient isn't valid or the list is empty. |
| 409 | forward_loop | The address would forward to itself. |
| 409 | already_exists | The address is already a mailbox. |
| 409 | forward_limit | The plan has no more forwards available (the limit counts addresses, not recipients). |
| 409 | domain_inactive | Email isn't active on the domain. |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
Request body
JSON, with the Content-Type: application/json header.
| Name | Type | Required | Description |
|---|---|---|---|
localPart | string | required | Part before the @ of the address to forward, for example sales: 1 to 64 characters among unaccented letters, digits, ., - and _, starting and ending with a letter or digit and without ... Uppercase letters become lowercase. |
destinations | array | required | Addresses that receive the messages, at least one, also outside the domain. |
Permission: mail:write
curl -X POST "https://sitelyra.it/api/v1/mail/example.com/forwards" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"localPart":"vendite","destinations":["mario@example.org"]}'{
"data": [
{
"id": "cm3fwd0000001qz8f1a2b3c4d",
"source": "vendite@example.com",
"destination": "mario@example.org",
"active": true
}
]
}Delete a forward
/mail/{domain}/forwards/{id}
Deletes a forward row, that is one recipient. The address's other recipients stay.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
domain | string | required | Domain name, for example example.com (accented names such as café.fr work too). |
id | string | required | Row id, from the forward list. |
Permission: mail:write
curl -X DELETE "https://sitelyra.it/api/v1/mail/example.com/forwards/cm3fwd0000001qz8f1a2b3c4d" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"deleted": true
}
}List orders
/billing/orders
Returns the account's orders, most recent first, with their items and pro forma.
Needs the "Billing" permission and a role that sees billing in the panel (owner or admin, not limited to some domains). Amounts are in euro cents. Statuses: pending_payment, paid, processing, completed, partial, failed, cancelled. Order type (kind): purchase or topup (credit top-up). Payment (paymentMethod): stripe (card or PayPal), bank_transfer, credit (prepaid credit) or free (free order, with no pro forma: proforma is null). Item types: domain_register, domain_transfer, domain_renew, hosting, hosting_renew, email, mail_pack, mail_storage, mail_renew, credit_topup; item status: pending, done, failed.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
status | string | optional | Only orders with these statuses, comma separated (for example pending_payment,processing); unknown statuses are ignored, and with no valid status all orders are returned. |
page | integer | optional | Page, from 1. |
per_page | integer | optional | Orders per page (default 100, at most 500). |
Permission: billing:read
curl "https://sitelyra.it/api/v1/billing/orders?status=completed" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"number": "DLC-2026-000123",
"kind": "purchase",
"status": "completed",
"paymentMethod": "credit",
"currency": "EUR",
"subtotalCents": 1500,
"discountCents": 0,
"vatPercent": 22,
"vatCents": 330,
"totalCents": 1830,
"couponCode": null,
"proforma": {
"number": "PF-2026-000098",
"issuedAt": "2026-11-02T09:58:00.000Z"
},
"createdAt": "2026-11-02T09:58:00.000Z",
"paidAt": "2026-11-02T10:00:00.000Z",
"expiresAt": null,
"cancelledAt": null,
"items": [
{
"type": "domain_register",
"domain": "example.com",
"years": 1,
"quantity": 1,
"priceCents": 1500,
"status": "done"
}
]
}
],
"meta": {
"page": 1,
"perPage": 100,
"total": 1
}
}Get an order
/billing/orders/{number}
Returns an order by its number, with its items and pro forma.
Needs the "Billing" permission and a role that sees billing in the panel (owner or admin, not limited to some domains). Amounts are in euro cents; the fields are those of List orders.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
number | string | required | Order number, for example DLC-2026-000123 (lowercase works too). A number in another format gives 404. |
Permission: billing:read
curl "https://sitelyra.it/api/v1/billing/orders/DLC-2026-000123" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"number": "DLC-2026-000123",
"kind": "purchase",
"status": "completed",
"paymentMethod": "credit",
"currency": "EUR",
"subtotalCents": 1500,
"discountCents": 0,
"vatPercent": 22,
"vatCents": 330,
"totalCents": 1830,
"couponCode": null,
"proforma": {
"number": "PF-2026-000098",
"issuedAt": "2026-11-02T09:58:00.000Z"
},
"createdAt": "2026-11-02T09:58:00.000Z",
"paidAt": "2026-11-02T10:00:00.000Z",
"expiresAt": null,
"cancelledAt": null,
"items": [
{
"type": "domain_register",
"domain": "example.com",
"years": 1,
"quantity": 1,
"priceCents": 1500,
"status": "done"
}
]
}
}Credit balance
/billing/credit
Returns the account's prepaid credit balance. If the account has never had credit, balanceCents is 0 and updatedAt is null.
Needs the "Billing" permission and a role that sees billing in the panel (owner or admin, not limited to some domains). Amounts are in euro cents.
Permission: billing:read
curl "https://sitelyra.it/api/v1/billing/credit" \
-H "Authorization: Bearer $API_KEY"{
"data": {
"currency": "EUR",
"balanceCents": 5000,
"updatedAt": "2026-11-02T10:00:00.000Z"
}
}Credit transactions
/billing/credit/transactions
Returns the credit transactions, most recent first: credits positive, debits negative, with the balance after each one.
Needs the "Billing" permission and a role that sees billing in the panel (owner or admin, not limited to some domains). Amounts are in euro cents. Types: topup, order (order payment), refund, manual (adjustment).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | integer | optional | Page, from 1. |
per_page | integer | optional | Transactions per page (default 100, at most 500). |
Permission: billing:read
curl "https://sitelyra.it/api/v1/billing/credit/transactions" \
-H "Authorization: Bearer $API_KEY"{
"data": [
{
"type": "order",
"amountCents": -1830,
"balanceAfterCents": 5000,
"order": "DLC-2026-000123",
"note": null,
"createdAt": "2026-11-02T10:00:00.000Z"
}
],
"meta": {
"page": 1,
"perPage": 100,
"total": 1
}
}