Developer
Public API
Authenticate, call endpoints, and handle errors against the ReachSurge REST API.
Overview
The ReachSurge REST API gives you programmatic access to your websites, analytics, citations, competitors, and Entity Authority data. Available on Growth and above. API keys are created by the workspace owner; a Growth team's members cannot mint one from an inherited plan. To fetch your published ARTICLE content instead (available on Starter), see the Content API, which uses a separate rsc_live_ token. Base URL:
https://reachsurge.ai/api/v1
Generate and manage keys in Settings → API Keys. Full endpoint reference lives at Settings → API Keys → API Docs.
Authentication
Every request needs a Bearer token in the Authorization header. Pass your API key (the full string that starts with rs_live_ or rs_test_):
curl -H "Authorization: Bearer rs_live_YOUR_KEY" \
https://reachsurge.ai/api/v1/websites
Both key types read your live production data. rs_test_ is a naming convention only. There is no sandbox. Treat every key, including test keys, as a production credential: never commit one to a repository, and rotate immediately if you have. You can revoke a key at any time from Settings → API.
Rate limits
Limits are enforced per API key, both per-minute (burst protection) and per-day (quota).
| Plan | Per minute | Per day |
|---|---|---|
| Free | n/a | n/a |
| Starter | 60 | 500 |
| Growth | 300 | 1,000 |
| Enterprise | 1,000 | 10,000 |
Every response includes X-RateLimit-Remaining and X-RateLimit-Reset headers so you can pace your client. When you exceed a limit you'll get a 429 with a Retry-After value in seconds.
Endpoints
| Method | Path | Returns |
|---|---|---|
GET | /api/v1/websites | Your websites |
GET | /api/v1/analytics?website_id=&period=30d | Daily traffic + AI citations |
GET | /api/v1/citations?website_id= | Per-engine citation feed |
GET | /api/v1/competitors?website_id= | Share-of-voice + competitor list |
GET | /api/v1/authority?website_id= | Entity Authority Score breakdown |
Use website_id (snake_case) on every endpoint that takes one, and period (7d, 30d or 90d) to choose the window. There is no from/to range parameter.
Error format
All errors return JSON with the same shape so your client can branch on error.code rather than parsing strings:
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry after 42s" } }
| Status | error.code | When |
|---|---|---|
| 401 | unauthorized | Missing Authorization header |
| 401 | invalid_key | Key revoked or wrong format |
| 400 | bad_request | Required parameter missing (usually website_id) |
| 403 | insufficient_scope | Key doesn't carry the scope the endpoint needs |
| 404 | not_found | website_id not in your team |
| 429 | rate_limited | Per-minute burst exceeded. Honour Retry-After |
| 429 | daily_quota_exceeded | Daily cap exhausted. Carries X-DailyQuota-* headers, not X-RateLimit-* |
| 500 | server_error | Something on our side, safe to retry with exponential backoff |
Webhooks (push instead of poll)
For real-time events (new citation, backlink verified, crawl complete, content refreshed, competitor alert), subscribe in Settings → Webhooks. Each delivery is signed with HMAC-SHA256 in the X-ReachSurge-Signature header. See the Webhooks article for verification code.
FAQ
Can I rotate a leaked key without downtime? Yes. Create a new key, deploy it to your client, then revoke the old one. Both keys work simultaneously until the old one is revoked.
What's the difference between live and test keys?
Both key types resolve the same team, the same plan tier, and the same quotas, and both read live production data. The rs_live_ / rs_test_ prefix is a label to help you tell keys apart in your own config. It does not change what the key can reach. If you need an isolated dataset for CI, use a separate account.
Do you have client libraries? Not officially yet. The API is plain REST + JSON. Any HTTP client works. We're tracking demand for Node and Python SDKs; ping us via Contact if that would unblock you.