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

  1. In the left menu open API and click + New key.
  2. Type a name that helps you recognise it, for example "CRM".
  3. For each service choose the permission: no access, read only, or read and write. Billing (orders and credit) is read only.
  4. If you like, add allowed IPs (one per line) and an expiry date.
  5. 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 statusMeaning
400The request body isn't a JSON object (invalid_body)
401Missing, wrong or expired key, a non-allowed IP, or a user who is blocked or removed from the account (unauthorized)
403The key lacks the permission for that service (forbidden)
404The resource doesn't exist, the key can't see it or the feature isn't enabled for your account (not_found)
409Not possible in the current state: the code says why, for example dns_not_hosted or site_not_active
422A field is missing or invalid (invalid_fields, with the fields in details.fields), or the server rejected a value (rejected)
429Too many requests (rate_limited): the key's hourly limit, or too many attempts with a wrong key from the same IP
500Unexpected error (internal_error)
503A 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

GET

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

GET/mecURL
curl "https://sitelyra.it/api/v1/me" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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

GET

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

NameTypeRequiredDescription
pageintegeroptionalPage, from 1 (default 1).
per_pageintegeroptionalDomains per page (default 100, at most 500).

Permission: domains:read

GET/domainscURL
curl "https://sitelyra.it/api/v1/domains?page=1&per_page=100" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: domains:read

GET/domains/{domain}cURL
curl "https://sitelyra.it/api/v1/domains/example.com" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
    }
  }
}

Domains

Nameservers

How it works in the panel: Nameservers.

GET

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

StatusCodeDescription
403forbiddenThe key is limited to some domains.

Permission: domains:read

GET/nameserver-groupscURL
curl "https://sitelyra.it/api/v1/nameserver-groups" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"]
    }
  ]
}
PUT

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

StatusCodeDescription
404not_foundThe domain or the group doesn't exist.
409operation_failedThe registry didn't accept the nameservers: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
groupstringrequiredNameserver group id.

Permission: domains:write

PUT/domains/{domain}/nameserverscURL
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"}'
200
{
  "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"
    }
  }
}

Domains

WHOIS privacy

How it works in the panel: WHOIS privacy.

PUT

Turn privacy on or off

/domains/{domain}/privacy

Hides or shows the registrant's details in the public WHOIS.

Specific errors

StatusCodeDescription
404not_foundThe domain doesn't exist or privacy isn't available for this domain.
409operation_failedThe registry didn't accept the change: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
enabledbooleanrequiredtrue to hide the details, false to show them.

Permission: domains:write

PUT/domains/{domain}/privacycURL
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}'
200
{
  "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"
    }
  }
}

Domains

Theft protection

How it works in the panel: Theft protection.

PUT

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

StatusCodeDescription
409unsupportedThe domain's extension has no transfer lock.
409operation_failedThe registry didn't accept the change: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
enabledbooleanrequiredtrue to turn the lock on, false to turn it off.

Permission: domains:write

PUT/domains/{domain}/lockcURL
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}'
200
{
  "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"
    }
  }
}

Domains

Transfer code

How it works in the panel: Transfer code.

POST

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

StatusCodeDescription
409operation_failedThe registry didn't return the code: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: domains:write

POST/domains/{domain}/auth-codecURL
curl -X POST "https://sitelyra.it/api/v1/domains/example.com/auth-code" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "authCode": "x7T#q2Lm9vRk"
  }
}

Domains

Glue records

How it works in the panel: Glue records.

Operations

GET

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

StatusCodeDescription
403forbiddenThe key is limited to some domains.

Permission: domains:read

GET/gluecURL
curl "https://sitelyra.it/api/v1/glue" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "name": "ns1.example.com",
      "ip": "203.0.113.10",
      "ip6": null,
      "domain": "example.com"
    }
  ]
}
GET

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

StatusCodeDescription
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: dns:read

GET/dns/{domain}/recordscURL
curl "https://sitelyra.it/api/v1/dns/example.com/records" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
    }
  ]
}
POST

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
422rejectedThe DNS server rejected the value: the message explains why.
409dns_limitThe domain's maximum number of records was reached (error.details.values.max).
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
typestringrequiredType, 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).
hoststringoptionalName: www, mail… Empty or @ = the domain itself.
ttlintegeroptionalTime to live in seconds (default 3600), one of these values: 60, 300, 600, 900, 1800, 3600, 21600, 43200, 86400, 172800, 259200, 604800, 1209600, 2592000.
fieldsobjectrequiredValues 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

POST/dns/{domain}/recordscURL
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"}}'
200
{
  "data": {
    "id": "512345678",
    "type": "A",
    "host": "www",
    "ttl": 3600,
    "value": "203.0.113.10",
    "fields": {
      "record": "203.0.113.10"
    },
    "system": false
  }
}
PUT

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

StatusCodeDescription
409system_recordIt's one of the zone's NS records, which can't be changed.
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
422rejectedThe DNS server rejected the value: the message explains why.
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredRecord id, from the record list.

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
typestringoptionalOptional: the type can't change; if you send it, it must match the record.
hoststringoptionalName: www, mail… Empty or @ = the domain itself.
ttlintegeroptionalTime to live in seconds (default 3600), one of these values: 60, 300, 600, 900, 1800, 3600, 21600, 43200, 86400, 172800, 259200, 604800, 1209600, 2592000.
fieldsobjectrequiredValues 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

PUT/dns/{domain}/records/{id}cURL
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"}}'
200
{
  "data": {
    "id": "512345678",
    "type": "A",
    "host": "www",
    "ttl": 600,
    "value": "203.0.113.20",
    "fields": {
      "record": "203.0.113.20"
    },
    "system": false
  }
}
DELETE

Delete a DNS record

/dns/{domain}/records/{id}

Deletes a record from the zone.

Specific errors

StatusCodeDescription
409system_recordIt's one of the zone's NS records, which can't be deleted.
422rejectedThe DNS server rejected the request: the message explains why.
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredRecord id, from the record list.

Permission: dns:write

DELETE/dns/{domain}/records/{id}cURL
curl -X DELETE "https://sitelyra.it/api/v1/dns/example.com/records/512345678" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}

DNS

DNS templates

How it works in the panel: DNS templates.

GET

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

GET/dns/templatescURL
curl "https://sitelyra.it/api/v1/dns/templates" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
          }
        }
      ]
    }
  ]
}
POST

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

StatusCodeDescription
409dns_limitThe template's records (all counted, including those already present) exceed the domain's maximum number of records (error.details.values.max).
422rejectedThe DNS server rejected one of the template's records: the message explains why.
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
slugstringrequiredTemplate name, from the DNS templates list.

Permission: dns:write

POST/dns/{domain}/templates/{slug}cURL
curl -X POST "https://sitelyra.it/api/v1/dns/example.com/templates/google-workspace" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "added": 2
  }
}

DNS

SOA

How it works in the panel: SOA.

GET

Get the SOA

/dns/{domain}/soa

Returns the zone's SOA: primary server, responsible person's email and timers in seconds.

Specific errors

StatusCodeDescription
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: dns:read

GET/dns/{domain}/soacURL
curl "https://sitelyra.it/api/v1/dns/example.com/soa" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "serial": "2026110701",
    "primaryNs": "ns1.example.net",
    "adminMail": "hostmaster@example.com",
    "refresh": 7200,
    "retry": 1800,
    "expire": 1209600,
    "defaultTtl": 3600
  }
}
PUT

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
422rejectedThe DNS server rejected the value: the message explains why.
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
adminMailstringoptionalEmail of the person responsible for the zone.
refreshintegeroptionalFrom 1200 to 43200 seconds.
retryintegeroptionalFrom 180 to 2419200 seconds.
expireintegeroptionalFrom 1209600 to 2419200 seconds.
defaultTtlintegeroptionalFrom 60 to 2419200 seconds.

Permission: dns:write

PUT/dns/{domain}/soacURL
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}'
200
{
  "data": {
    "serial": "2026110702",
    "primaryNs": "ns1.example.net",
    "adminMail": "dns@example.com",
    "refresh": 3600,
    "retry": 1800,
    "expire": 1209600,
    "defaultTtl": 3600
  }
}

DNS

DNSSEC

How it works in the panel: DNSSEC.

GET

DNSSEC status

/dns/{domain}/dnssec

Returns the DNSSEC status: off, pending (zone signed, keys on their way to the registry) or active.

Specific errors

StatusCodeDescription
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: dns:read

GET/dns/{domain}/dnsseccURL
curl "https://sitelyra.it/api/v1/dns/example.com/dnssec" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "state": "active"
  }
}
PUT

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

StatusCodeDescription
422invalid_fieldsenabled is missing or isn't true/false: error.details.fields says so.
422rejectedThe DNS server rejected the request: the message explains why.
409dns_not_hostedThe domain doesn't use our nameservers, or its zone isn't ready yet: manage the records where its DNS is hosted.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
enabledbooleanrequiredtrue to turn on, false to turn off.

Permission: dns:write

PUT/dns/{domain}/dnsseccURL
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}'
200
{
  "data": {
    "state": "pending"
  }
}

Hosting

Sites

How it works in the panel: Sites.

GET

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

NameTypeRequiredDescription
pageintegeroptionalPage, from 1.
per_pageintegeroptionalSites per page (default 100, at most 500).

Permission: hosting:read

GET/hostingcURL
curl "https://sitelyra.it/api/v1/hosting" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}cURL
curl "https://sitelyra.it/api/v1/hosting/example.com" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
    }
  }
}
GET

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

StatusCodeDescription
409site_not_activeThe site isn't active (being created, suspended or failed).
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/ftp-userscURL
curl "https://sitelyra.it/api/v1/hosting/example.com/ftp-users" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "user": "example_com_dev",
      "directory": "/srv/sites/example_com/www/dev",
      "quotaMb": 0,
      "active": true,
      "primary": false
    }
  ]
}
POST

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

StatusCodeDescription
422invalidThe name or the folder isn't valid.
409too_longThe full name is longer than 32 characters.
409takenThe name is already taken.
409limitThe plan has no more FTP users available.
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
suffixstringrequired2 to 16 lowercase letters or digits: the name becomes <site user>_<suffix>.
directorystringoptionalFolder inside www it's limited to (for example dev): letters, digits, ., _, - and /; created if missing. Empty = the whole site.

Permission: hosting:write

POST/hosting/{domain}/ftp-userscURL
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"}'
200
{
  "data": {
    "user": "example_com_dev",
    "password": "Hq7mT2kPz9xRw4sN"
  }
}
PATCH

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
userstringrequiredFTP user name, from the FTP user list.

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
activebooleanrequiredfalse to suspend, true to reactivate.

Permission: hosting:write

PATCH/hosting/{domain}/ftp-users/{user}cURL
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}'
200
{
  "data": {
    "user": "example_com_dev",
    "active": false
  }
}
DELETE

Delete an FTP user

/hosting/{domain}/ftp-users/{user}

Deletes an added FTP user. The files stay on the site.

Specific errors

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
userstringrequiredFTP user name, from the FTP user list.

Permission: hosting:write

DELETE/hosting/{domain}/ftp-users/{user}cURL
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/ftp-users/example_com_dev" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}
POST

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
userstringrequiredFTP user name, from the FTP user list.

Permission: hosting:write

POST/hosting/{domain}/ftp-users/{user}/passwordcURL
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/ftp-users/example_com/password" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "user": "example_com",
    "password": "Tz4kQ8mW2pXn7Rv3"
  }
}
GET

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

StatusCodeDescription
409not_activeThe site isn't active.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/gitcURL
curl "https://sitelyra.it/api/v1/hosting/example.com/git" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
    }
  }
}
PUT

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

StatusCodeDescription
409git_repo_invalidThe repository URL isn't valid.
409git_branch_invalidThe branch name isn't valid.
409git_unsupportedThe site doesn't support Git.
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
urlstringrequiredSSH (git@host:path or ssh://…) or HTTPS repository URL without credentials, at most 300 characters.
branchstringoptionalBranch to pull, at most 100 characters (default main).

Permission: hosting:write

PUT/hosting/{domain}/gitcURL
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"}'
200
{
  "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
  }
}
DELETE

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:write

DELETE/hosting/{domain}/gitcURL
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/git" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}
POST

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:write

POST/hosting/{domain}/git/pullcURL
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/git/pull" \
  -H "Authorization: Bearer $API_KEY"
202
{
  "data": {
    "queued": true
  }
}
GET

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

StatusCodeDescription
409site_not_activeThe site isn't active (being created, suspended or failed).
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/databasescURL
curl "https://sitelyra.it/api/v1/hosting/example.com/databases" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "name": "example_com",
      "primary": true,
      "sizeBytes": 52428800
    },
    {
      "name": "example_com_shop",
      "primary": false,
      "sizeBytes": 1048576
    }
  ]
}
POST

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

StatusCodeDescription
422invalidThe name isn't valid.
409too_longThe full name is longer than 32 characters.
409takenThe name is already taken.
409limitThe plan has no more databases available.
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
suffixstringrequired2 to 16 lowercase letters or digits: the name becomes <site prefix>_<suffix>.

Permission: hosting:write

POST/hosting/{domain}/databasescURL
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"}'
200
{
  "data": {
    "name": "example_com_shop",
    "user": "example_com_shop",
    "password": "pX7rK2mQ9tW4zN8vB3sL"
  }
}
DELETE

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
namestringrequiredDatabase name, from the database list.

Permission: hosting:write

DELETE/hosting/{domain}/databases/{name}cURL
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/databases/example_com_shop" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}
POST

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

StatusCodeDescription
409not_activeThe site isn't active.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
namestringrequiredDatabase name, from the database list.

Permission: hosting:write

POST/hosting/{domain}/databases/{name}/passwordcURL
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/databases/example_com_shop/password" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "name": "example_com_shop",
    "password": "mR8tK3wQ7pZ2xN9vL4sB"
  }
}
GET

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/phpmyadmin/ipscURL
curl "https://sitelyra.it/api/v1/hosting/example.com/phpmyadmin/ips" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "id": "cm3pma0000001qz8f1a2b3c4d",
      "ip": "203.0.113.50",
      "note": "Ufficio",
      "expiresAt": "2026-12-07T10:00:00.000Z",
      "createdAt": "2026-11-07T10:00:00.000Z"
    }
  ]
}
POST

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

StatusCodeDescription
409ip_invalidThe address isn't valid.
409ip_limitThere are already 5 allowed IPs.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
ipstringrequiredOne IPv4 or IPv6 address (not a network).
notestringoptionalNote, 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

POST/hosting/{domain}/phpmyadmin/ipscURL
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"}'
200
{
  "data": [
    {
      "id": "cm3pma0000001qz8f1a2b3c4d",
      "ip": "203.0.113.50",
      "note": "Ufficio",
      "expiresAt": "2026-12-07T10:00:00.000Z",
      "createdAt": "2026-11-07T10:00:00.000Z"
    }
  ]
}
DELETE

Remove an IP from phpMyAdmin

/hosting/{domain}/phpmyadmin/ips/{id}

Removes an IP from those allowed to phpMyAdmin.

Specific errors

StatusCodeDescription
409busyYou made more than 60 changes in an hour: retry shortly.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredIP id, from the allowed IP list.

Permission: hosting:write

DELETE/hosting/{domain}/phpmyadmin/ips/{id}cURL
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/phpmyadmin/ips/cm3pma0000001qz8f1a2b3c4d" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}

Hosting

PHP settings

How it works in the panel: PHP settings.

GET

PHP version and settings

/hosting/{domain}/php

Returns the site's PHP version, its current settings and the values you can choose.

Specific errors

StatusCodeDescription
409site_not_activeThe site isn't active (being created, suspended or failed).
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/phpcURL
curl "https://sitelyra.it/api/v1/hosting/example.com/php" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"]
      }
    }
  }
}
PATCH

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

StatusCodeDescription
422invalidVersion or value not allowed, or nothing to change.
422invalid_fieldsA field isn't valid (for example a setting in settings that doesn't exist): error.details.fields says which one.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
versionstringoptionalPHP version, for example 8.3.
settingsobjectoptionalSettings to change: memory_limit, upload_max_filesize, post_max_size, max_execution_time.

Permission: hosting:write

PATCH/hosting/{domain}/phpcURL
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"}}'
202
{
  "data": {
    "queued": true
  }
}
GET

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

StatusCodeDescription
409cron_not_in_planThe plan doesn't include cron jobs.
409site_not_activeThe site isn't active (being created, suspended or failed).
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/croncURL
curl "https://sitelyra.it/api/v1/hosting/example.com/cron" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "id": "a1b2c3d4",
      "minute": "*/15",
      "hour": "*",
      "day": "*",
      "month": "*",
      "weekday": "*",
      "command": "php cron.php"
    }
  ]
}
POST

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
409cron_limitThe site already has 20 cron jobs.
409cron_scheduleThe schedule isn't valid.
409cron_too_oftenMore often than once every 5 minutes.
409cron_commandThe command is empty, longer than 1000 characters or contains % or a line break.
409cron_plan_missingThe plan doesn't include cron jobs.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
minutestringrequiredMinute (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).
hourstringrequiredHour (0-23) or *.
daystringrequiredDay of month (1-31) or *.
monthstringrequiredMonth (1-12) or *.
weekdaystringrequiredDay of week (0-7, 0 and 7 = Sunday) or *.
commandstringrequiredOne-line command (up to 1000 characters, no %), run in the site's www folder: for example php cron.php.

Permission: hosting:write

POST/hosting/{domain}/croncURL
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"}'
202
{
  "data": {
    "queued": true
  }
}
PUT

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
404not_foundThe cron job isn't there.
409cron_scheduleThe schedule isn't valid.
409cron_too_oftenMore often than once every 5 minutes.
409cron_commandThe command is empty, longer than 1000 characters or contains % or a line break.
409cron_plan_missingThe plan doesn't include cron jobs.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredCron job id, from the cron job list.

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
minutestringrequiredMinute (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).
hourstringrequiredHour (0-23) or *.
daystringrequiredDay of month (1-31) or *.
monthstringrequiredMonth (1-12) or *.
weekdaystringrequiredDay of week (0-7, 0 and 7 = Sunday) or *.
commandstringrequiredOne-line command (up to 1000 characters, no %), run in the site's www folder: for example php cron.php.

Permission: hosting:write

PUT/hosting/{domain}/cron/{id}cURL
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"}'
202
{
  "data": {
    "queued": true
  }
}
DELETE

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

StatusCodeDescription
404not_foundThe cron job isn't there.
409cron_plan_missingThe plan doesn't include cron jobs.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredCron job id, from the cron job list.

Permission: hosting:write

DELETE/hosting/{domain}/cron/{id}cURL
curl -X DELETE "https://sitelyra.it/api/v1/hosting/example.com/cron/a1b2c3d4" \
  -H "Authorization: Bearer $API_KEY"
202
{
  "data": {
    "queued": true
  }
}
GET

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/malwarecURL
curl "https://sitelyra.it/api/v1/hosting/example.com/malware" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
    }
  ]
}
POST

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

StatusCodeDescription
409scan_busyThe site is already queued or being scanned.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:write

POST/hosting/{domain}/malware/scancURL
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/malware/scan" \
  -H "Authorization: Bearer $API_KEY"
202
{
  "data": {
    "queued": true
  }
}
POST

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

StatusCodeDescription
404not_foundThe file isn't there or isn't quarantined (for example it was already restored).
409restore_existsThere's already a file with the same name on the site.
409busyYou made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredFile id, from Files found by the malware scanner.

Permission: hosting:write

POST/hosting/{domain}/malware/{id}/restorecURL
curl -X POST "https://sitelyra.it/api/v1/hosting/example.com/malware/cm3mal0000001qz8f1a2b3c4d/restore" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "restored": "www/wp-content/uploads/x.php"
  }
}
GET

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

StatusCodeDescription
409site_not_activeThe site isn't active (being created, suspended or failed).
503unavailableThe server isn't responding (retry later), or WordPress isn't installed on the site.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: hosting:read

GET/hosting/{domain}/wordpresscURL
curl "https://sitelyra.it/api/v1/hosting/example.com/wordpress" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
    }
  }
}
POST

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
409plan_missingThe plan doesn't include WordPress.
409already_installedWordPress is already installed.
409not_emptyThere are other files in the site folder.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
localestringoptionalWordPress language: it (default) or en.

Permission: hosting:write

POST/hosting/{domain}/wordpress/installcURL
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"}'
202
{
  "data": {
    "queued": true
  }
}
POST

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

StatusCodeDescription
422invalid_fieldsA field is missing or invalid: error.details.fields says which one.
422invalidThe action doesn't exist, or name is missing, invalid or not needed for the action.
404not_foundThe plugin or theme isn't there.
409in_useThe plugin or theme is active and can't be deleted.
409not_activeThe site isn't active.
409busyAnother change is already running on the site, or you made more than 60 changes in an hour: retry shortly.
503unavailableThe server isn't responding: retry later.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
actionstringrequiredAction from the list above.
namestringoptionalPlugin 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

POST/hosting/{domain}/wordpress/actionscURL
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"}'
202
{
  "data": {
    "queued": true
  }
}

Email

Email domains

How it works in the panel: Email domains.

GET

List email domains

/mail

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

NameTypeRequiredDescription
pageintegeroptionalPage, from 1.
per_pageintegeroptionalDomains per page (default 100, at most 500).

Permission: mail:read

GET/mailcURL
curl "https://sitelyra.it/api/v1/mail" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: mail:read

GET/mail/{domain}cURL
curl "https://sitelyra.it/api/v1/mail/example.com" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
    }
  }
}
GET

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: mail:read

GET/mail/{domain}/mailboxescURL
curl "https://sitelyra.it/api/v1/mail/example.com/mailboxes" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
      }
    }
  ]
}
POST

Create a mailbox

/mail/{domain}/mailboxes

Creates a mailbox. We generate the password and it's shown only in this response.

Specific errors

StatusCodeDescription
422invalid_local_partThe part before the @ isn't valid.
422invalid_quotaThe storage isn't between 100 and 102400 MB.
409already_existsThe address already exists, as a mailbox or as a forward.
409mailbox_limitThe plan has no more mailboxes available.
409storage_limitThe requested storage exceeds the plan's free storage.
409domain_inactiveEmail isn't active on the domain.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
localPartstringrequiredPart 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.
quotaMbintegerrequiredMailbox storage in MB, from 100 to 102400 (100 GB), within the plan's free storage.
displayNamestringoptionalName shown to recipients, for example "Info" (at most 128 characters).

Permission: mail:write

POST/mail/{domain}/mailboxescURL
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"}'
200
{
  "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

Get a mailbox

/mail/{domain}/mailboxes/{id}

Returns a mailbox's settings: name, storage, status, allowed protocols and copy of sent messages.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredMailbox id, from the mailbox list.

Permission: mail:read

GET/mail/{domain}/mailboxes/{id}cURL
curl "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
  }
}
PATCH

Update a mailbox

/mail/{domain}/mailboxes/{id}

Changes a mailbox's settings. Fields you don't send stay as they are.

Specific errors

StatusCodeDescription
422invalid_quotaThe storage isn't between 100 and 102400 MB.
422invalid_addressThe copy address isn't valid.
409storage_limitThe requested storage exceeds the plan's free storage.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredMailbox id, from the mailbox list.

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
displayNamestringoptionalName shown to recipients (at most 128 characters); null to remove it.
quotaMbintegeroptionalMailbox storage in MB, from 100 to 102400 (100 GB), within the plan's free storage.
activebooleanoptionalfalse suspends the mailbox: it doesn't receive mail and can't sign in.
protocolsobjectoptionalAllowed protocols: imap, pop3, smtp (true or false).
sendCopyTostringoptionalAddress that gets a copy of every sent message; null to remove it.

Permission: mail:write

PATCH/mail/{domain}/mailboxes/{id}cURL
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}}'
200
{
  "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

Delete a mailbox

/mail/{domain}/mailboxes/{id}

Deletes a mailbox with all its messages.

Deleting can't be undone.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredMailbox id, from the mailbox list.

Permission: mail:write

DELETE/mail/{domain}/mailboxes/{id}cURL
curl -X DELETE "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}
POST

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

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredMailbox id, from the mailbox list.

Permission: mail:write

POST/mail/{domain}/mailboxes/{id}/passwordcURL
curl -X POST "https://sitelyra.it/api/v1/mail/example.com/mailboxes/cm3mbx0000001qz8f1a2b3c4d/password" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "address": "info@example.com",
    "password": "Wq7nT3kP9mRz2xVs"
  }
}
GET

List forwards

/mail/{domain}/forwards

Returns the domain's forwards: one row per recipient, as in the panel.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Permission: mail:read

GET/mail/{domain}/forwardscURL
curl "https://sitelyra.it/api/v1/mail/example.com/forwards" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": [
    {
      "id": "cm3fwd0000001qz8f1a2b3c4d",
      "source": "vendite@example.com",
      "destination": "mario@example.org",
      "active": true
    }
  ]
}
POST

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

StatusCodeDescription
422invalid_local_partThe part before the @ isn't valid.
422invalid_addressA recipient isn't valid or the list is empty.
409forward_loopThe address would forward to itself.
409already_existsThe address is already a mailbox.
409forward_limitThe plan has no more forwards available (the limit counts addresses, not recipients).
409domain_inactiveEmail isn't active on the domain.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).

Request body

JSON, with the Content-Type: application/json header.

NameTypeRequiredDescription
localPartstringrequiredPart 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.
destinationsarrayrequiredAddresses that receive the messages, at least one, also outside the domain.

Permission: mail:write

POST/mail/{domain}/forwardscURL
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"]}'
200
{
  "data": [
    {
      "id": "cm3fwd0000001qz8f1a2b3c4d",
      "source": "vendite@example.com",
      "destination": "mario@example.org",
      "active": true
    }
  ]
}
DELETE

Delete a forward

/mail/{domain}/forwards/{id}

Deletes a forward row, that is one recipient. The address's other recipients stay.

Path parameters

NameTypeRequiredDescription
domainstringrequiredDomain name, for example example.com (accented names such as café.fr work too).
idstringrequiredRow id, from the forward list.

Permission: mail:write

DELETE/mail/{domain}/forwards/{id}cURL
curl -X DELETE "https://sitelyra.it/api/v1/mail/example.com/forwards/cm3fwd0000001qz8f1a2b3c4d" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "deleted": true
  }
}

Billing

Orders

How it works in the panel: Orders.

GET

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

NameTypeRequiredDescription
statusstringoptionalOnly orders with these statuses, comma separated (for example pending_payment,processing); unknown statuses are ignored, and with no valid status all orders are returned.
pageintegeroptionalPage, from 1.
per_pageintegeroptionalOrders per page (default 100, at most 500).

Permission: billing:read

GET/billing/orderscURL
curl "https://sitelyra.it/api/v1/billing/orders?status=completed" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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

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

NameTypeRequiredDescription
numberstringrequiredOrder number, for example DLC-2026-000123 (lowercase works too). A number in another format gives 404.

Permission: billing:read

GET/billing/orders/{number}cURL
curl "https://sitelyra.it/api/v1/billing/orders/DLC-2026-000123" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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"
      }
    ]
  }
}

Billing

Prepaid credit

How it works in the panel: Prepaid credit.

GET

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

GET/billing/creditcURL
curl "https://sitelyra.it/api/v1/billing/credit" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "data": {
    "currency": "EUR",
    "balanceCents": 5000,
    "updatedAt": "2026-11-02T10:00:00.000Z"
  }
}
GET

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

NameTypeRequiredDescription
pageintegeroptionalPage, from 1.
per_pageintegeroptionalTransactions per page (default 100, at most 500).

Permission: billing:read

GET/billing/credit/transactionscURL
curl "https://sitelyra.it/api/v1/billing/credit/transactions" \
  -H "Authorization: Bearer $API_KEY"
200
{
  "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
  }
}