Agency
Agency API
Everything the agency workspace does — clients, websites, install checks, branding, your domain, embed links and usage — from your own backend.
Base URL
https://api.seentics.com/api/v1/agencyJSON in, JSON out. Every endpoint, with its fields and examples, is in the API reference.
Authentication
Send an account API key in the X-API-Key header.
- Open any website's
Developerspage,API keystab, and chooseNew account key. From the workspace,API → Create an API keyopens it for you (/websites/<id>/developers?new=agency). - Pick the
Agency APIaccess preset. It grantsagency:readandagency:write. - Copy the key — it is shown once — and keep it on your server. Never put it in a browser or an app.
| Scope | Allows |
|---|---|
agency:read | GET requests. |
agency:write | Everything else: POST, PUT, PATCH, DELETE. |
Scopes are strict: agency:write does not include reading, so a key that creates clients and lists them needs both. A missing scope is 403 forbidden. Keys can only be created by someone signed in, never by another key. More on keys in API keys.
The workspace itself uses the same API with your dashboard session. Team members can use it if their role allows managing the agency workspace.
Agency plan required
403 agency_plan_required.Quick start
Onboard a client end to end: create the client, add its website, get the install snippet, and read this month's usage. Put your key in an environment variable first:
export SEENTICS_API_KEY=snt_acct_your_account_keyThe IDs below are examples: use the ones each step gives back.
1. Create a client
Answers the new client. Keep its id for the next step.
curl -X POST "https://api.seentics.com/api/v1/agency/clients" \
-H "X-API-Key: $SEENTICS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"Acme Bakery","company":"Acme Bakery Ltd"}'2. Add the client’s website
Answers { website, install }: the website, and its install snippet in install.snippet_html.
curl -X POST "https://api.seentics.com/api/v1/agency/clients/5bbeaa88-b089-4923-ad54-8fdcbbcdba94/websites" \
-H "X-API-Key: $SEENTICS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"Acme Bakery","url":"https://acmebakery.test"}'3. Get the install snippet and tracking status
Any time later. verification.status is not_seen until the first event arrives, then receiving.
curl -X GET "https://api.seentics.com/api/v1/agency/websites/2f60eb30-722c-4fbf-8afa-99fe0e67f6d9/install" \
-H "X-API-Key: $SEENTICS_API_KEY"4. Read this month’s usage
Your plan’s pool, what has been used, and any overage, for the current UTC month.
curl -X GET "https://api.seentics.com/api/v1/agency/usage" \
-H "X-API-Key: $SEENTICS_API_KEY"Once the snippet is on the site and it has had a visitor, POST /agency/websites/:id/verify answers receiving.
Responses and pagination
- Success is
{ "data": … }. Creating something answers201; deletes answer204with no body. - Lists add
"page": { "next_cursor", "has_more" }. Ask for up to 100 rows with?limit=(default 25), and for the next page pass?cursor=with the previousnext_cursor. Stop whenhas_moreisfalse. - Every response carries an
X-Request-IDheader. Send your ownX-Request-IDto tie our logs to yours.
{
"data": [{ "id": "5bbeaa88-…", "name": "Acme Bakery", "status": "active", … }],
"page": { "next_cursor": null, "has_more": false }
}Errors
Errors share one shape. Switch on code, show message to a person, and quote request_id when you contact support.
{
"error": {
"code": "validation_failed",
"message": "name: Required",
"details": { … },
"request_id": "b3f1c2a4-…"
}
}| Status | Code | Meaning |
|---|---|---|
401 | unauthorized | No session or API key, or it is no longer valid. |
403 | forbidden | The key lacks the scope, or the team member lacks agency access. |
403 | agency_plan_required | The account is not on the Agency plan. |
404 | not_found | No such client, website, embed or alert in this account. |
422 | validation_failed | The body or query is invalid; details says which field. |
409 | conflict | Already exists, such as an external ID or hostname in use. |
409 | idempotency_conflict | The same Idempotency-Key was sent with a different body. |
429 | rate_limited | 120 requests a minute per key (60 writes); wait and retry. |
502 | provider_error | Our DNS or certificate provider failed; retry later. 503 when the service, or custom domains, are not available. |
details appears when there is more to say — the field that failed, or the scope a key is missing (required_scope).
Idempotency
Send an Idempotency-Key header — any unique string up to 255 characters, such as a UUID — on every POST. Then a retry after a timeout can't create the same client twice.
- A retry with the same key and the same body, within 24 hours, gets the first response again, with the header
Idempotent-Replayed: true. Nothing runs twice. - The same key with a different body is
409 idempotency_conflict. - The same key while the first request is still running is
409 conflict; retry shortly. - If the first request failed with a
5xx, the key is released and a retry runs again.
Keys are per account, and only POST uses them: repeating a PUT or PATCH gives the same result anyway.
Rate limits
| Caller | Limit |
|---|---|
| An API key | 120 requests a minute, of which up to 60 may be writes |
| A dashboard session | 600 requests a minute per account |
| Adding or replacing the custom domain | 10 times an hour |
Over the limit, the answer is 429 rate_limited with a Retry-After header in seconds. Wait that long, then retry — with the same Idempotency-Key for a POST.