Account API
Read a Reggio Digital account from your own software: websites, backups and visits, support requests, domains and DNS, invoices and plans.
The account API lets your own software read what a business has with us: its websites, their backups and visits, its support requests, its domains and DNS records, and its invoices and plans. Build a status board, pull invoices into your accounting, or let your own monitoring see when a support request is answered.
Everything on this page only reads. Nothing here can change a website, spend money or move a domain.
Getting a key
The business makes the key under API keys in their dashboard and picks what it can read. Anyone on the account can make one, but a key can never read more than the person who made it can see: support requests need access to Support, and invoices need access to Billing. The key belongs to the account, so it keeps working when that person leaves.
| Ability | Lets the key read |
|---|---|
websites:read |
Websites, their backups and their monthly visits. |
tickets:read |
Every support request on the account and the replies on each. |
domains:read |
Domains, their renewal dates, and the DNS records on each zone. |
billing:read |
Invoices, and the plans and add-ons being paid for. |
A key without the ability a call needs gets a 403 with forbidden. Call GET /me to see what a key has.
An account that has not bought anything yet still gets answers. Its lists are simply empty.
Lists and pages
Every list comes back in the same shape, newest first:
{
"data": [],
"has_more": true,
"next_cursor": "eyJpZCI6MTE4LCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
limitsets how many come back, from 1 to 100. The default is 25.- When
has_moreistrue, ask again withcursorset to thenext_cursoryou were given, exactly as it came. When it isfalse, you have everything andnext_cursorisnull. - A cursor rather than a page number means a record added while you are paging never shows up twice.
A limit out of range, or a cursor we did not give you, gets a 422 with invalid_request.
An id that is not on this account, or belongs to another account, gets a 404 with not_found. We never say whether it exists somewhere else.
Websites
Needs websites:read.
Listing websites
GET /api/v1/websites
curl https://reggiodigital.com/api/v1/websites?limit=25 \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 118,
"name": "Glass Jug Beer Lab",
"url": "https://glassjugbeer.com",
"status": "active",
"is_staging": false,
"staging_of": null,
"hosting": "reggio",
"wordpress_version": "6.8.2",
"php_version": "8.3",
"uptime": {
"status": "up",
"checked_at": "2026-09-25T13:55:00+00:00",
"changed_at": "2026-09-02T04:10:00+00:00"
},
"created_at": "2025-03-14T16:20:00+00:00"
}
],
"has_more": false,
"next_cursor": null
}
statusisactive,suspendedormaintenance.hostingisreggiowhen we host it,pressablefor a site still on our previous host, andexternalfor a site hosted somewhere else that we look after.- A staging copy has
is_stagingset andstaging_ofholding the id of the live site it was copied from. uptime.statusisup,downorunknownuntil we have checked it.
One website
GET /api/v1/websites/{id}
curl https://reggiodigital.com/api/v1/websites/118 \
-H "Authorization: Bearer $REGGIO_API_KEY"
Answers with one website in the shape above, on its own rather than inside data.
Backups
GET /api/v1/websites/{id}/backups
curl https://reggiodigital.com/api/v1/websites/118/backups \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": "a1b2c3d4",
"type": "full",
"status": "completed",
"created_at": "2026-09-25T05:30:00+00:00"
}
],
"has_more": false,
"next_cursor": null
}
The restore points the dashboard lists, up to the latest 50, newest first. Downloading or restoring a backup stays in the dashboard. A site hosted somewhere else has none.
Visits
GET /api/v1/websites/{id}/traffic
curl https://reggiodigital.com/api/v1/websites/118/traffic \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{ "month": "2026-08", "visits": 18240, "storage_mb": 2140 },
{ "month": "2026-09", "visits": 15321, "storage_mb": 2188 }
],
"has_more": false,
"next_cursor": null
}
Twelve months, oldest first, ending with the current billing month. These are the figures on the website's page in the dashboard. storage_mb is the latest reading in that month, or null when we have none.
Support requests
Needs tickets:read.
Listing support requests
GET /api/v1/tickets
curl https://reggiodigital.com/api/v1/tickets?status=open \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 2051,
"title": "Contact form stopped sending",
"description": "Nothing has arrived from the contact page since Tuesday.",
"status": "open",
"priority": "high",
"category": "support",
"website_id": 118,
"opened_by": "Sam Rivera",
"created_at": "2026-09-24T14:02:00+00:00",
"updated_at": "2026-09-25T09:12:00+00:00"
}
],
"has_more": false,
"next_cursor": null
}
- Add
statusto see onlyopen,pendingorclosedrequests. priorityislow,medium,highorurgent.website_idisnullwhen the request is about the account rather than one site.
GET /api/v1/tickets/{id} answers with one request in the same shape.
Replies
GET /api/v1/tickets/{id}/comments
curl https://reggiodigital.com/api/v1/tickets/2051/comments \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 88412,
"author": "Jordan at Reggio Digital",
"body": "Found it. The form was sending from an address that is no longer set up. It is fixed and the missed messages have been resent.",
"created_at": "2026-09-25T09:12:00+00:00"
}
],
"has_more": false,
"next_cursor": null
}
Newest first. Attachments stay in the dashboard for now.
Domains and DNS
Needs domains:read.
Domains
GET /api/v1/domains
curl https://reggiodigital.com/api/v1/domains \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 64,
"domain": "glassjugbeer.com",
"status": "active",
"registered_at": "2019-05-02T00:00:00+00:00",
"expires_at": "2027-05-02T00:00:00+00:00",
"auto_renew": true,
"locked": true,
"nameservers": ["ada.ns.cloudflare.com", "rob.ns.cloudflare.com"],
"website_id": 118
}
],
"has_more": false,
"next_cursor": null
}
The domains registered or transferred to us. GET /api/v1/domains/{id} answers with one. A transfer code is never available here; request one from the domain's page in the dashboard.
DNS zones and records
GET /api/v1/dns-zones lists the zones we run DNS for, and GET /api/v1/dns-zones/{id} answers with one:
{
"id": 37,
"name": "glassjugbeer.com",
"status": "active",
"paused": false,
"name_servers": ["ada.ns.cloudflare.com", "rob.ns.cloudflare.com"],
"records": 14,
"activated_at": "2024-01-18T10:00:00+00:00"
}
GET /api/v1/dns-zones/{id}/records lists the records on a zone:
curl https://reggiodigital.com/api/v1/dns-zones/37/records \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 5120,
"type": "A",
"name": "glassjugbeer.com",
"content": "203.0.113.10",
"ttl": 1,
"priority": null,
"proxied": true
}
],
"has_more": false,
"next_cursor": null
}
A ttl of 1 means automatic. priority is set on MX and SRV records only.
Billing
Needs billing:read.
Invoices
GET /api/v1/invoices
curl https://reggiodigital.com/api/v1/invoices \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 9031,
"number": "RD-2026-0412",
"status": "paid",
"currency": "USD",
"subtotal": "95.00",
"tax": "0.00",
"discount": "0.00",
"total": "95.00",
"amount_paid": "95.00",
"amount_due": "0.00",
"description": "Monthly plan",
"period_start": "2026-09-01T00:00:00+00:00",
"period_end": "2026-10-01T00:00:00+00:00",
"due_date": "2026-09-01T00:00:00+00:00",
"paid_at": "2026-09-01T06:02:00+00:00",
"created_at": "2026-09-01T06:00:00+00:00"
}
],
"has_more": false,
"next_cursor": null
}
- Amounts are strings with two decimal places, in the invoice's
currency, so nothing is lost to rounding. statusisdraft,open,paid,voidoruncollectible.GET /api/v1/invoices/{id}answers with one. The PDF stays in the dashboard for now.
Plans and add-ons
GET /api/v1/subscriptions
curl https://reggiodigital.com/api/v1/subscriptions \
-H "Authorization: Bearer $REGGIO_API_KEY"
{
"data": [
{
"id": 412,
"label": "Business Hosting (Plan #412)",
"status": "active",
"is_plan": true,
"items": [
{ "name": "Business Hosting", "quantity": 1, "price": "95.00", "interval": "month" },
{ "name": "Transactional Email", "quantity": 1, "price": "15.00", "interval": "month" }
],
"sites": 3,
"site_limit": 5,
"trial_ends_at": null,
"ends_at": null
}
],
"has_more": false,
"next_cursor": null
}
Everything the account is paying for, the same as the billing page. An account can have more than one plan, so read every entry rather than the first. is_plan is false for a subscription that only holds add-ons such as email, and sites and site_limit only mean something when it is true. ends_at is set when a plan has been cancelled and is running to the end of what was paid for.