Skip to main content

Provisioning (headless signup)

POST /provision creates a free-tier Sealmetrics account without a browser — no card, no dashboard login, no OAuth round trip. It exists so an AI agent or an installer can go from "this site has no analytics" to "the tracker is live" inside a single conversation.

This is the endpoint behind the sealmetrics CLI and the provision_site tool in the AI Agentic Package.

Most people don't call this directly

If you just want an agent to set up analytics for you, install the Agentic Package or run the CLI — both wrap this endpoint and handle the provision key for you. Call the endpoint yourself only if you are building your own installer or integration.

Endpoint

POST/provision

Public and unauthenticated in the usual sense — there is no API key or session — but gated by a publishable provision key sent in the X-Provision-Key header. The key identifies the distribution channel (npm CLI, desktop extension, a partner integration) for attribution and rate limiting. It is publishable, not secret: it grants nothing except the ability to create free-tier accounts, under a rate limit.

The official CLI and MCP packages ship with a key embedded. If you are building your own integration and need your own key, email support@sealmetrics.com.

Request

curl -X POST https://my.sealmetrics.com/api/v1/provision \
-H "Content-Type: application/json" \
-H "X-Provision-Key: <publishable-provision-key>" \
-d '{
"site_name": "My Shop",
"domain": "myshop.com",
"email": "me@example.com",
"name": "Rafa",
"accept_terms": true,
"install_source": "my-installer",
"timezone": "Europe/Madrid"
}'
FieldTypeRequiredNotes
site_namestringYes1–255 characters.
emailstringYesValid email. Receives the claim link and the API key.
accept_termsbooleanYesMust be true. The agent passes this on the human's behalf, so make sure the human has actually seen the terms.
domainstringNoUp to 255 characters.
namestringNoThe person's name, up to 255 characters.
install_sourcestringNoUp to 64 characters. Free-form attribution label for your integration.
timezonestringNoIANA timezone, up to 64 characters. Determines how today, 30d and friends resolve for this site.

Response

{
"success": true,
"data": {
"success": true,
"account_id": "…",
"snippet": "<script …></script>",
"api_key": "sm_…",
"dashboard_url": "https://my.sealmetrics.com/…",
"claim_url": "https://my.sealmetrics.com/…",
"free_quota": { "events_total": 1000000 },
"next_steps": [
"Paste the snippet just before the closing </head> tag on every page.",
"Deploy your site so the tracker can start capturing pageviews.",
"Check your email to set a password and open your dashboard.",
"Read your analytics with the api_key via the Sealmetrics MCP server."
]
}
}
FieldDescription
account_idPass this as account_id to every stats endpoint.
snippetThe tracking script, ready to paste before </head>.
api_keyRead-only API key for this account. Also emailed to the user.
claim_urlMagic link for the human to set a password and take ownership.
free_quota.events_totalFree-tier event allowance — a lifetime cumulative cap, not a monthly one.
Handle api_key and claim_url as secrets

Both grant access to the new account. Never echo them into a chat transcript, a log, or a shared terminal — the official tools deliberately send them by email instead of printing them. If you build your own integration, do the same.

Free tier

A provisioned account starts on the free tier with 1,000,000 events total — cumulative over the life of the organization, not reset monthly. Rate limits follow the free-tier row in Rate Limits.

Errors

Statuserror.codeerror.message / meaning
400bad_requestaccept_terms was not true.
400invalid_inputA field failed validation — see error.message.
401unauthorizedMessage is provision_key_required (header missing) or invalid_provision_key (unknown or deactivated key).
409provision_unavailableThe account could not be created with those details. Deliberately ambiguous: it does not confirm whether the email is already registered. If a matching account exists, its owner is notified by email. Tell the user to log in and add a site from the dashboard.
429rate_limit_exceededRate-limited per IP and per provision key. Honour Retry-After.
503service_unavailableMessage is provisioning_disabled — headless provisioning is switched off globally. Not retryable on a short timescale.

Do not treat 409 provision_unavailable as "email taken" in your UI copy. The API will not tell you that, on purpose.

After provisioning

  1. Place the snippet before </head> and deploy.
  2. Confirm the pixel is live — via GET /sites/{id}/pixel/status (Sites), or the verify_setup MCP tool.
  3. Start reading data with the api_key: GET /stats/overview?account_id=<account_id>&period=7d.
  4. Point the user at claim_url so they can set a password.