API and webhooks

Scale plan · JSON over HTTPS · version 1

Everything the console shows, from your own tools: sites, runs, every change, keywords with demand and position, AI visibility, and the approval queue. Webhooks tell you the moment something happens, signed so you can trust them.

Authentication

Create a token under Settings › API and webhooks. Send it as a bearer token. Tokens are stored hashed and can be revoked at any time.

curl https://app.seenoria.com/api/v1/me \
  -H "Authorization: Bearer sk_..."

Limits: 120 requests a minute per token. All timestamps are ISO 8601 in UTC.

Endpoints

Method and pathReturns
GET /api/v1/meAccount name, plan, number of sites, token name.
GET /api/v1/sitesEvery site: slug, name, domain, CMS, status, mode (dry_run or live), last run time.
GET /api/v1/sites/{slug}One site with its last run, 28-day clicks, impressions, sessions, AI answers checked and cited, connection health, approvals waiting, and the client report link.
GET /api/v1/sites/{slug}/runs?limit=30Nightly runs, newest first: status, one-line summary, cost.
GET /api/v1/sites/{slug}/changes?from=2026-09-01&to=2026-09-30&limit=100Every change with before and after values, who did it and why. Kinds: applied, reverted.
GET /api/v1/sites/{slug}/keywordsTracked keywords with priority, target page, monthly searches, CPC, competition, latest Google position and why the agent tracks it.
GET /api/v1/sites/{slug}/ai-visibilityThe latest night's AI answers: each buyer question, platform, whether the site was named, at which position, and which competitors were.
GET /api/v1/sites/{slug}/approvalsChanges waiting for a decision, with the proposed before and after and the reason.
POST /api/v1/sites/{slug}/approvals/{id}Body {"decision": "approve" | "reject", "note": "optional"}. Approved changes apply on the next nightly run.

Responses wrap the result in data. Errors return a JSON error with the HTTP status: 401 for a bad token, 404 for a site or approval that is not yours, 422 for a bad body, 429 when you exceed the limit.

Webhooks

Add an HTTPS URL under Settings › API and webhooks and pick the events, or leave all unticked for everything. Each delivery is a JSON POST:

{
  "id": 512,
  "event": "approval.needed",
  "site_id": 3,
  "occurred_at": "2026-10-01T23:04:11+00:00",
  "data": { "action_id": 981, "site": "harbour", "type": "blog_post",
            "target": "https://harbour-accountants.com/blog/vat-deadlines",
            "rationale": "...", "url": "https://app.seenoria.com/approvals" }
}
EventWhen
run.finishedA nightly run finished
approval.neededA change is waiting for a decision
change.appliedA change was applied on the site
change.revertedA change was reverted
report.monthlyThe monthly client report was sent
pingThe "Send test" button.

Verifying a delivery

Every request carries X-Seenoria-Signature: sha256=<hex>, the HMAC-SHA256 of the raw body with the webhook's secret, plus X-Seenoria-Event and X-Seenoria-Delivery. Compute the HMAC over the exact bytes you received and compare with a constant-time function. Answer with any 2xx within ten seconds; anything else is retried after 1, 5, 30, 120 and 720 minutes, then marked failed. The console shows the last result next to each webhook.

# Python
import hmac, hashlib
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers["X-Seenoria-Signature"])
See it work on your site, free for 60 days.No card. First report in two weeks.
Start free