Authentication
Every request authenticates with an API key — a secret that identifies your
organization. Keys look like aglyn_sk_….
A key carries the organization's access, not a person's: it keeps working after the teammate who created it leaves, and it isn't limited by their role.
Create a key
- In the console, go to Organization → Settings → API keys.
- Choose Create API key, give it a name, and select its scopes.
- Copy the key when it's shown — it is displayed only once. Aglyn stores only a hash and can never show it again. If you lose it, revoke it and create a new one.
Only organization owners and admins can create or revoke keys; any member can see
the list. The list shows each key's name, scopes, a truncated prefix
(aglyn_sk_ab12cd…) to identify it, and roughly when it was last used — that
timestamp updates at most once a minute, so it's for spotting unused keys, not for
auditing individual calls.
Keys don't expire. A key stays valid until you revoke it, so rotate deliberately.
Send the key
Pass the key as a bearer token:
curl https://app.aglyn.com/api/v1/datasets \
-H "Authorization: Bearer aglyn_sk_your_key_here"
The header X-Api-Key: aglyn_sk_… is also accepted. If both are present,
Authorization: Bearer wins.
Check a key at any time with GET /v1/me, which tells you
which organization it belongs to and what it can do.
A missing, malformed, revoked, or expired key returns 401:
{ "error": { "type": "unauthorized", "message": "Invalid or missing API key" } }
If the organization's plan doesn't include API access, requests return 403
plan_required — the API is a Business and Advanced feature. A key
whose organization has been downgraded stops working without being revoked.
Scopes
A key is granted only the scopes you select, and a request that needs a scope the key
lacks returns 403 insufficient_scope. Grant the least a key needs.
| Scope | Grants |
|---|---|
datasets:read | List datasets, read records. |
datasets:write | Create, update, and delete records. |
contacts:read | List and read contacts. |
contacts:write | Add contacts, edit their name, tags and notes, and delete them. Never changes the email a contact is identified by, or where it came from. |
sites:read | List sites and read their details. |
sites:publish | Refresh a site's live pages so writes made over the API appear immediately. Changes no content. |
sites:write | Create new sites in the organization. Counts against your site allowance. Cannot rename or delete a site. |
forms:read | Read a site's form submissions. |
forms:write | Mark a site's form submissions read or unread, and delete them. Never edits what a visitor typed. |
orders:read | Read a site's store orders. |
orders:write | Record a shipment: mark an order fulfilled or delivered and attach a carrier and tracking number. Cannot cancel or refund an order, and never moves stock or money. |
products:read | Read a site's products, variants, prices and stock. |
media:read | List files in the organization library and in a site's media. |
media:write | Upload files to the organization library and to a site's media. Cannot replace, edit or delete an existing file. |
forms:write is deliberately narrow. It grants the read flag and the delete, and
nothing that rewrites a submission's fields — a submission is a record of what a
visitor typed, and an API that could edit it would make the inbox unattributable. See
form submissions.
contacts:write is narrow for the same kind of reason. It adds, edits and deletes
contacts, and cannot touch the two fields that would make the list untrustworthy: the
email a contact is unified on, and the sources recording where the person came
from. See contacts.
Several resources are read-only over the API, and the missing write scope is deliberate in each case rather than an oversight:
- Cancelling and refunding an order, and products, move money and stock.
orders:writestops precisely at the line where they begin: it records shipments, which change no money and no stock. A cancel returns held inventory and a refund returns money, each under its own transaction with its own decisions, so both stay in the console. A write scope for the rest belongs to the change that ships the endpoint, not ahead of it — a scope you can grant that grants nothing is a broken permission. - Renaming and deleting a site.
sites:writecreates; it deliberately stops there. A delete would erase a whole site — screens, versions, products, uploaded files — immediately, from one field in a request body, with no hold and no undo.
{
"error": {
"type": "insufficient_scope",
"message": "Missing the \"datasets:write\" scope",
"code": "datasets:write"
}
}
Scopes are independent — there's no hierarchy. datasets:write does not imply
datasets:read; a key that both writes and reads back needs both.
Two endpoints need no scope at all: GET /v1 and
GET /v1/me. Any valid key can call them.
Keep keys safe
- Treat a key like a password. Never commit it to source control or expose it in client-side code — it carries your organization's access.
- Use a separate key per integration so you can revoke one without affecting the others, and so the "last used" column tells you something.
- Revoke a key the moment it's no longer needed, from the same settings page. Revoking takes effect immediately.