SEO Ops turns Google Search Console data into deduped work items your team can act on — via API, optional webhooks, and client digests from SEO Ops <reports@seo-ops.com>.
Pilot auth: paste your agency-scoped API key into Swagger Authorize (key only — no fake login page). It cannot access another agency and is never the SEO Ops admin key.
In Search Console → property → Settings → Users and permissions → Add user. Permission: Full (Owner not required).
gsc-analyzer-sa@kite-479022.iam.gserviceaccount.com
Paste what you see in the GSC property switcher —
you do not need the sc-domain: prefix. The API normalizes bare domains.
| What GSC shows | Send / paste | Stored as |
|---|---|---|
Domain icon + example.com |
example.com |
sc-domain:example.com |
| URL-prefix | https://www.example.com/ |
Same (trailing / ensured) |
Base URL: https://api.seo-ops.com
(fallback: the Cloud Run *.run.app host).
BearerGET /v1/properties — expect 200
Full markdown runbook:
docs/agency-onboarding.md in the repo (same steps, more curl detail).
POST /v1/properties — save the returned id.
# Replace YOUR_KEY and site_url curl -sS -X POST "https://api.seo-ops.com/v1/properties" \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "site_url": "https://www.example.com/", "label": "Example Client", "active": true, "days": 90, "rows": 500 }'
Add digest emails (as many as you need):
curl -sS -X POST "https://api.seo-ops.com/v1/properties/prop_YOUR_ID/recipients" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "client@example.com"}'
Optional: set webhook_url on the property for run-complete POSTs.
ContentEngine / PM poll of work items can wait until week two.
Smoke (no GSC):
POST /v1/properties/{id}/promote with a small fixture
opportunities payload — proves auth, items, and delivery.
Live:
POST /v1/properties/{id}/runs — GSC → Claude → work items (sync; wait for the response).
curl -sS -X POST "https://api.seo-ops.com/v1/properties/prop_YOUR_ID/runs" \ -H "Authorization: Bearer YOUR_KEY"
Then list and update items:
GET /v1/properties/{id}/items?status=backlog
PATCH /v1/items/{item_id} → {"status": "in_progress"}
Digests send after successful runs when recipients exist.
Stuck? Reply to Ryan with property id, exact site_url, and error body (redact the key).