API
Serpel REST API reference
The Serpel REST API under https://serpel.app/api/v1 offers the same features as the dashboard and the CLI, as JSON over HTTPS. You authenticate with an API token that carries permissions called scopes. This page lists the scopes, errors, rate limits, credit rules and every endpoint, and ends with curl examples.
What is the base URL of the Serpel API?
All endpoints live under https://serpel.app/api/v1. Paths in this reference are relative to it, so /projects means https://serpel.app/api/v1/projects. Requests and responses use JSON. Send Content-Type: application/json with a body. GET https://serpel.app/api/v1 returns a machine-readable index of the endpoints without authentication, and GET https://serpel.app/api/health returns the service status.
How do you authenticate with the API?
Send an API token as a bearer token. Tokens start with vsk_. Create one in the dashboard under Settings, API tokens, with serpel tokens create or with POST /tokens.
GET /api/v1/projects HTTP/1.1
Host: serpel.app
Authorization: Bearer vsk_your_token- A token can only call endpoints whose scope it has. Without it, the API answers with 403
forbidden. - The project role still applies: viewers read, editors change, owners manage members and delete the project.
- The dashboard uses a session cookie instead of a token. Cookie requests that change data must come from the Serpel origin.
- OAuth access tokens issued to MCP clients only work at the MCP server. The REST API rejects them with 403
forbidden.
Which scopes can an API token have?
Serpel has 18 scopes. Choose the smallest set that your integration needs.
| Scope | Label in the dashboard | What it allows |
|---|---|---|
projects:read | Read projects | Read projects, overviews, members, reports, search data, web analytics, conversions and integrations. |
projects:write | Create and edit projects | Create, change and delete projects and members, connect search data, web analytics and integrations, and manage report recipients and webhooks. |
keywords:read | Read keyword lists | Read keyword lists, their keywords and saved research runs. |
keywords:write | Research keywords and edit lists | Run keyword research (uses credits), create and change keyword lists, import keywords and refresh metrics. |
audit:read | Read crawls and issues | Read crawls, pages, issues, comparisons and Core Web Vitals. |
audit:write | Start crawls | Start crawls. |
rankings:read | Read rankings | Read tracked keywords, rank history, stored search results, competitors, AI prompts and AI visibility. |
rankings:write | Track keywords and start rank checks | Track and remove keywords, start rank checks, AI checks and monitoring runs, and manage competitors and AI prompts. |
tasks:read | Read tasks | Read tasks. |
tasks:write | Create and edit tasks | Create, change and delete tasks. |
export:read | Export data | Export issues, keywords, rankings and tasks. |
billing:read | Read balance and usage | Read balance, usage, the credit ledger, the plan and the agent spending settings, and estimate costs. |
billing:write | Top up balance | Start checkouts, change or cancel the subscription and change the agent spending settings. Workspace owners only. |
codebase:read | Read codebase snapshots | Read codebase snapshots. |
codebase:write | Upload codebase snapshots | Upload codebase snapshots. |
recommendations:read | Read recommendations | Read recommendations. |
recommendations:write | Accept, dismiss and complete recommendations | Accept, dismiss, complete and reopen recommendations. |
mcp:read | Use the MCP server (read-only) | Use the MCP server, read-only. The REST API does not need this scope. |
Restrict a token to projects
A token can be limited to a list of projects with projectIds. Such a token sees only those projects. A project outside the list answers with 404 not_found, as if it did not exist, and lists leave it out. Tokens can also expire after 1 to 365 days.
curl -X POST https://serpel.app/api/v1/tokens \
-H "Authorization: Bearer $SERPEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "CI crawl", "scopes": ["projects:read", "audit:read", "audit:write"], "projectIds": ["0b6f0f0e-6d1a-4c8e-9a53-4f9d2d7b8a10"], "expiresInDays": 90}'In the response, token holds the metadata and secret holds the token itself. The secret is shown exactly once. Creating tokens needs a token with all permissions. A token restricted to projects can only create tokens for its own projects.
What do responses and pagination look like?
{ "data": { } }
{ "data": [ ], "pagination": { "limit": 50, "offset": 0, "total": 123 } }Single objects come in data. Lists add pagination. Lists accept limit (1 to 200, default 50), offset (from 0) and usually q to search. Every response carries an X-Request-ID header. You can send your own X-Request-ID (up to 128 letters, digits, ., _, : and -) and quote the value when you contact support.
How does the API report errors?
{
"error": {
"code": "validation_error",
"message": "Enter a domain.",
"details": [{ "path": "domain", "message": "Enter a domain." }]
}
}| HTTP | Code | Meaning |
|---|---|---|
| 400 | validation_error | The input is invalid. details lists path and message for each problem. |
| 400 | bad_request | The request is malformed, for example invalid JSON or a body over 2.5 MB. |
| 400 | authorization_pending, slow_down, expired_token, access_denied | Answers of the device login at POST /auth/device/token. |
| 401 | unauthorized | The token is missing, invalid, expired or revoked. |
| 402 | insufficient_credits | Not enough credits. details has balance, available and required. |
| 403 | forbidden | A scope or role is missing, an OAuth token was used on the REST API, or the workspace is blocked from paid operations. |
| 403 | plan_limit | The plan’s limits are exceeded: projects, tracked keywords, AI prompts or daily monitoring. details has plan and limits. |
| 404 | not_found | The item does not exist or the token cannot see it. |
| 409 | conflict | The state does not allow it, for example a project that already exists (details.existingProjectId). |
| 429 | rate_limited | Too many requests. The Retry-After header and details.retryAfterSeconds tell you how long to wait. |
| 429 | budget_exceeded | The workspace’s daily credit limit or a provider budget is reached. |
| 500 | internal_error | An error on the server. Retry later and quote the X-Request-ID. |
| 502 | provider_error | A data provider failed or could not be reached. |
| 503 | provider_not_configured | The data provider for this feature is not set up. |
What are the API rate limits?
| Limit | Applies to | Window |
|---|---|---|
| 600 requests | Each API token, for all endpoints. | One minute |
| 30 operations | Each workspace, for crawls, rank checks, AI checks, monitoring runs, keyword research and list refreshes. | One minute |
| 20 requests | Each IP address, for all free tool endpoints under /tools/, which need no token. | 10 minutes |
| 200 requests | Each IP address, for all free tool endpoints under /tools/. | One day |
When you exceed a limit, the API answers with HTTP 429 and rate_limited. Wait for the seconds in the Retry-After header, then continue. The MCP server has its own limit, described in the Claude Code guide.
How do idempotency keys work?
POST /keywords/research and POST /keyword-lists/{id}/refresh use credits and answer synchronously. Add an Idempotency-Key header with up to 200 letters, digits and the characters ., _, : and - to make a retry safe. A repeated request with the same key does not call the data provider again and does not book credits again. Without the header, the server generates a random key, which protects nothing on a retry. The CLI creates a key for you and accepts --idempotency-key.
How do credits work in the API?
Reading data is free. These operations use credits, at the prices of the dashboard:
| Operation | Unit | Credits |
|---|---|---|
| Scheduled monitoring, up to top 50 | per keyword | 2 |
| Scheduled monitoring, top 100 | per keyword | 3 |
| Rank check right now, up to top 50 | per keyword | 5 |
| Rank check right now, top 100 | per keyword | 9 |
| ChatGPT answer check | per question | 2 |
| Google AI Overview check | per question | 2 |
| Keyword research | per search | 8 + 4 per 50 results |
| Keyword research by domain | per domain | 4 + 2 per 50 results |
| Site crawl | per 20 pages | 1 |
Estimate a cost first with POST /billing/estimate. It needs billing:read, books nothing and returns minCredits, maxCredits and a breakdown. Supported operations are rankCheck, aiCheck, keywordResearch, keywordListRefresh, keywordMetrics, crawl and monitoring.
curl -X POST https://serpel.app/api/v1/billing/estimate \
-H "Authorization: Bearer $SERPEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"operation": "rankCheck", "params": {"keywordCount": 20, "depth": 50}}'If the balance is too low for an operation, the API answers with HTTP 402.
{
"error": {
"code": "insufficient_credits",
"message": "The available credits balance isn’t sufficient for this operation.",
"details": { "balance": 3, "available": 3, "required": 12 }
}
}Which endpoints does the REST API have?
The groups below follow the index that GET /api/v1 returns. Path parameters appear in braces. Methods in one row share the path. The scope line above each table names the scopes the endpoints need.
Authentication
These endpoints serve the sign-up and sign-in screens of the dashboard and need no token. The Google endpoints are browser redirects, not JSON calls.
| Endpoint | Methods | What it does |
|---|---|---|
/auth/signup | POST | Create an account with a personal workspace and send a confirmation email |
/auth/verify-email | POST | Verify the email address with a one-time token valid for 24 hours |
/auth/password-reset/request | POST | Request a password reset without revealing whether an account exists |
/auth/password-reset/confirm | POST | Set a new password with a one-time token valid for one hour |
/auth/google/start | GET | Start signing in or signing up with Google as a browser redirect (query intent login, signup or reauthenticate, optional next path); creates a one-time state, PKCE verifier and nonce bound to a short-lived cookie |
/auth/google/callback | GET | Return address of Google: checks state, cookie binding, code and ID token, then signs in, links the account by verified email address or asks for the terms; redirects to the dashboard or back to the sign-in page with an error code |
/auth/google/complete | POST | Create the account after the first Google sign-in once the terms are accepted ({ acceptTerms: true }, cookie from the callback) |
/cancellation-requests | POST | Cancel a subscription without signing in (§ 312k BGB), store the receipt with a timestamp and confirm it by email |
Free tools
These endpoints need no token. They share one limit per IP address instead: 20 requests per 10 minutes and 200 per day. GET results are cached for a short time: 1 minute for the schema validator and the redirect checker, 5 minutes for the sitemap checker and 10 minutes for the robots.txt check.
| Endpoint | Methods | What it does |
|---|---|---|
/tools/robots-check | GET | Check without signing in which AI crawlers a domain’s robots.txt allows on the homepage, plus its llms.txt and sitemaps (domain query parameter) |
/tools/schema-validate | GET, POST | Validate JSON-LD, Microdata and RDFa without signing in. GET takes a public page URL (url query parameter) and reads its static HTML. POST takes a JSON body with a code field and checks pasted JSON-LD or HTML up to 512 KB. Returns the detected items by type with properties, errors and warnings with property paths, and Google rich result eligibility |
/tools/redirect-check | GET | Trace the redirect chain of a URL without signing in (url query parameter, optional userAgent: browser, googlebot, googlebotSmartphone, bingbot or gptbot). Returns every hop with status code, Location, response time and server header for up to 10 redirects, loop and downgrade detection, a meta refresh on the final page and recommendations |
/tools/sitemap-check | GET | Validate the XML sitemaps of a domain or a sitemap URL without signing in (url query parameter). Discovers sitemaps through robots.txt and the default locations, checks status, content type, gzip, XML, namespace, limits and entries of up to 10 child sitemaps, and samples the status of up to 20 listed URLs |
Account
GET /me works with any valid token. Changing the profile and using /tokens need a token with all permissions. /account/export, /account/delete, /account/password/set and /account/identities/google need a dashboard session, not an API token.
| Endpoint | Methods | What it does |
|---|---|---|
/me | GET, PATCH | Signed-in user and token permissions; change name and email address |
/account/export | GET | Download account data, workspace, projects, integrations and export links as JSON |
/account/delete | POST | Delete the account with session and password, or, without a password, after a confirmation with Google from the last 10 minutes; permanent cleanup after 30 days |
/account/security | GET | Sign-in methods of the account: password set or not, linked Google account, and whether a recent confirmation with Google is valid |
/account/password/set | POST | Set the first password of an account that signed up with Google; needs a confirmation with Google from the last 10 minutes |
/account/identities/google | DELETE | Unlink the Google account; only possible when the account has a password |
/tokens | GET, POST | List and create API tokens |
/tokens/{id} | DELETE | Revoke a token |
/providers | GET | Data providers, daily budget, usage and last use |
/favicons/{domain} | GET | Logo of a domain for the interface, fetched server-side and cached for 7 days |
Billing
Reading needs billing:read. Checkouts and changes need billing:write and the workspace owner role.
| Endpoint | Methods | What it does |
|---|---|---|
/billing/summary | GET | Read balance, daily limit and usage of the last 30 days |
/billing/estimate | POST | Estimate the credit cost of an operation without booking it |
/billing/ledger | GET | Read the entries of the workspace credit ledger |
/billing/checkout-sessions | POST | Create a Stripe Checkout for a credit pack or a custom amount |
/billing/subscription | GET, PATCH | Read plan, limits and subscription or change the plan |
/billing/subscription-sessions | POST | Create a Stripe Checkout for a Starter or Pro subscription |
/billing/subscription/cancel | POST | Cancel the subscription at the end of the billing period |
/billing/subscription/resume | POST | Undo the cancellation of the subscription |
/billing/portal-sessions | POST | Open the Stripe customer portal for payment details and invoices |
/billing/agent-spending | GET, PATCH | Read or change the “Agents can spend credits” setting with daily limit and today’s usage |
/billing/stripe-webhook | POST | Process signed Stripe events idempotently into payments and the credit ledger |
MCP and connected apps
These endpoints need a dashboard session, or a token with all permissions for the two read and disconnect endpoints.
| Endpoint | Methods | What it does |
|---|---|---|
/oauth/consent | POST | Decide on an app’s OAuth request (session only, with CSRF token) |
/oauth/apps | GET | Apps connected via OAuth with workspace, permissions and last use |
/oauth/apps/{id} | DELETE | Disconnect a connected app and revoke all its tokens |
Projects
projects:read to read, projects:write to create and change. Changing a project needs the editor role, deleting it and managing members the owner role.
| Endpoint | Methods | What it does |
|---|---|---|
/projects | GET, POST | List and create projects |
/projects/{id} | GET, PATCH, DELETE | Read a project, change settings (including JavaScript rendering, Slack, Discord and custom webhook, channel name, search volume), delete it |
/projects/{id}/overview | GET | Overview with score, rankings, AI visibility and next steps |
/projects/{id}/members | GET, POST | List and add members |
/projects/{id}/export | GET | Export issues, keywords, rankings or tasks as CSV or JSON |
Audit
audit:read to read, audit:write to start crawls.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/crawls | GET, POST | List and start crawls |
/projects/{id}/crawls/compare | GET | Compare two crawls: new, fixed and changed issues |
/projects/{id}/issues | GET | Issues of the crawl with score and comparison |
/projects/{id}/issues/{code} | GET | Affected URLs of an issue |
/crawls/{id} | GET | Read a crawl, with statistics on rendering, link checks and Core Web Vitals |
/crawls/{id}/pages | GET | Checked URLs of a crawl, with HTML size and rendering flags |
/crawls/{id}/pages/{pageId} | GET | A page with links, issues and signals (rendering, hreflang, structured data, soft 404) |
/crawls/{id}/web-vitals | GET | Core Web Vitals of the crawl from PageSpeed Insights: lab and field values per URL and device |
Keywords and rankings
keywords:read and keywords:write for research and lists, rankings:read and rankings:write for tracked keywords and competitors. Research and list refreshes accept an Idempotency-Key header.
| Endpoint | Methods | What it does |
|---|---|---|
/keywords/research | GET, POST | Start keyword research with idempotency and credits; read the history with cost and duration |
/keyword-lists | GET, POST | Manage keyword lists |
/keyword-lists/{id}/refresh | POST | Refresh list metrics idempotently, billed in credits |
/projects/{id}/rankings | GET, POST | List and add tracked keywords |
/projects/{id}/rankings/run | POST | Start a ranking check right away |
/rank-keywords/{id}/history | GET | Position history of a keyword |
/rank-keywords/{id}/serp | GET | Stored search results of the last check |
/locations | GET | Search locations for local rank tracking |
/projects/{id}/competitors | GET, POST | List and add competitors |
/projects/{id}/competitors/overview | GET | Visibility of you and your competitors |
/projects/{id}/competitors/suggestions | GET | Competitor suggestions from the search results |
/projects/{id}/competitors/comparison | GET | Positions of you and your competitors, keyword by keyword |
AI visibility and monitoring
rankings:read and rankings:write for AI visibility and monitoring runs, projects:read and projects:write for reports, recipients and webhooks.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/ai-visibility | GET | Citations in ChatGPT and Google AI Overviews, access for AI crawlers |
/projects/{id}/ai-prompts | GET, POST | List and create prompts for ChatGPT, each with the result of Google AI Overviews |
/projects/{id}/ai-prompts/run | POST | Check prompts right away, also in Google AI Overviews when the switch is on |
/projects/{id}/monitoring/run | POST | Start monitoring with a report right away |
/reports | GET | Reports, optionally only unread ones, with status and duration of the email delivery |
/projects/{id}/report-recipients | GET, POST | Email recipients of the reports and delivery status, with sandbox mode for Amazon SES |
/projects/{id}/report-recipients/test | POST | Send a test email to the recipients |
/reports/{id}/email | POST | Send a report by email again |
/reports/{id}/email-preview | GET | Email of a report as HTML |
/projects/{id}/webhook/test | POST | Send a test message to Slack, Discord and your own URL, or to a single target (channel) |
Account integrations
projects:read to read, projects:write to connect, map and disconnect.
| Endpoint | Methods | What it does |
|---|---|---|
/integrations | GET | Google, Bing, PostHog and Plausible with assignment per project |
/integrations/google/authorize | POST | Authorise Google for Search Console and Analytics |
/integrations/{bing|posthog|plausible} | POST, DELETE | Connect with an API key or disconnect |
/integrations/{provider}/sync | POST | Reassign projects |
Search data
projects:read to read, projects:write to connect and disconnect.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/search-console | GET | Connections to Google Search Console and Bing Webmaster Tools |
/projects/{id}/search-console/google/authorize | POST | Create the authorisation URL for Google |
/projects/{id}/search-console/bing | POST | Connect Bing Webmaster Tools with an API key |
/projects/{id}/search-console/{provider} | PATCH, DELETE | Choose a property or disconnect |
/projects/{id}/search-performance | GET | Clicks, impressions, CTR and position per query or page, from the stored history when it fully covers the period, otherwise live |
Web analytics
projects:read to read, projects:write to connect and change.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/analytics | GET | Connections to PostHog, Plausible and Google Analytics |
/projects/{id}/analytics/{provider} | POST | Connect PostHog or Plausible with an API key |
/projects/{id}/analytics/google_analytics/authorize | POST | Create the authorisation URL for Google Analytics |
/projects/{id}/analytics/{provider} | PATCH, DELETE | Choose a property or disconnect |
/projects/{id}/analytics-report | GET | Visitors, visits, bounce rate per day, top pages, entry pages, sources and devices |
/projects/{id}/analytics/{provider}/conversion-events | GET, PUT | Read the provider’s events and choose the events that count as a conversion (at most 10) |
/projects/{id}/conversions | GET | Sessions, conversions and conversion rate per entry page from the daily sync |
Recommendations and codebase
recommendations:read and recommendations:write, codebase:read and codebase:write.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/recommendations | GET | Recommendations (“opportunities”) with impact, confidence, effort, evidence and data sources, filterable by status and rule |
/recommendations/{id} | GET, PATCH | Read a recommendation, accept it, dismiss it, mark it as done or reopen it |
/projects/{id}/codebase-snapshots | GET, POST | List and upload codebase snapshots (at most 2 MB, 20 per day and project, free of charge) |
/codebase-snapshots/{id} | GET | Snapshot with routes, mapping to live pages, deviations and diff to the previous snapshot |
Tasks and jobs
tasks:read and tasks:write for tasks. Jobs follow the scope of their type: audit:read for crawls, rankings:read for the other jobs.
| Endpoint | Methods | What it does |
|---|---|---|
/projects/{id}/tasks | GET, POST | List and create tasks |
/tasks/{id} | GET, PATCH, DELETE | Read a task, change its status, delete it |
/jobs | GET | Running and finished background jobs |
/jobs/{id}/cancel | POST | Cancel a job |
/projects/{id}/activity | GET | History of a project: jobs, reports by email and keyword research with duration and cost |
More endpoints
These endpoints exist as well and are used by the CLI, but the index does not list them.
| Endpoint | Methods | What it does | Scope |
|---|---|---|---|
/auth/device | POST | Start a device login, as serpel auth login does | No token |
/auth/device/token | POST | Exchange the device code for a token once the user approved it | No token |
/auth/logout | POST | Revoke the token that sends the request | Any valid token |
/jobs/{id} | GET | Read one job with status, progress, result and last error | audit:read for crawls, rankings:read for the other jobs |
/jobs/{id}/retry | POST | Restart a failed or cancelled job | audit:write for crawls, rankings:write for the other jobs |
/projects/{id}/rankings/summary | GET | Top 3, top 10, average position and changes of all tracked keywords | rankings:read |
/rank-keywords/{id} | DELETE | Remove a tracked keyword with its history | rankings:write |
/projects/{id}/competitors/{competitorId} | DELETE | Remove a competitor | rankings:write |
/ai-prompts/{id}/history | GET | Check history of a prompt for ChatGPT and Google AI Overviews | rankings:read |
/ai-prompts/{id} | DELETE | Remove a prompt with all its results | rankings:write |
/keywords/research/{runId} | GET | Read a saved research run without querying the provider | keywords:read |
/keyword-lists/{id} | GET, PATCH, DELETE | Read, rename or delete a keyword list | keywords:read to read, keywords:write to change |
/keyword-lists/{id}/items | GET, POST | List the keywords of a list or add keywords | keywords:read to read, keywords:write to add |
/keyword-lists/{id}/items/{itemId} | DELETE | Remove a keyword from a list | keywords:write |
/keyword-lists/{id}/import | POST | Import keywords from CSV text | keywords:write |
/keyword-lists/{id}/export | GET | Export a keyword list as a CSV or JSON file | export:read |
/projects/{id}/members/{userId} | DELETE | Remove a member from a project | projects:write, owner role |
/projects/{id}/report-recipients/{recipientId} | DELETE | Remove an email recipient of the reports | projects:write |
/reports/{id} | GET | Read one report | projects:read |
/reports/{id}/read | POST | Mark a report as read | projects:read |
/reports/read-all | POST | Mark all reports, or those of one project, as read | projects:read |
/reports/unread-count | GET | Number of unread reports | projects:read |
/projects/{id}/favicon | GET | Website icon of a project, fetched server-side | projects:read |
What do complete API examples look like?
The examples assume that SERPEL_TOKEN holds a token with the scopes named in each step. The responses are abridged to the fields you need next, and their values are illustrative. The real responses contain more fields.
Create a project
Needs projects:write. The API returns HTTP 201. If you already have a project for the domain, it answers with 409 conflict and the ID of the existing project in details.existingProjectId.
curl -X POST https://serpel.app/api/v1/projects \
-H "Authorization: Bearer $SERPEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com", "name": "Example", "country": "US", "language": "en"}'{
"data": {
"id": "0b6f0f0e-6d1a-4c8e-9a53-4f9d2d7b8a10",
"name": "Example",
"domain": "example.com",
"country": "US",
"language": "en",
"role": "owner"
}
}Start a crawl and read the issues
Needs audit:write to start and audit:read to follow the job. The crawl runs in a worker, so the API answers with 202 and a job. If a crawl is already running, you get that crawl back with HTTP 200 and alreadyRunning: true. Poll GET /jobs/{id} until status is succeeded, failed or cancelled, then read the issues. maxPages can be 1 to 1000.
curl -X POST https://serpel.app/api/v1/projects/$PROJECT_ID/crawls \
-H "Authorization: Bearer $SERPEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"maxPages": 200}'{
"data": {
"crawl": {
"id": "7d2a4c1e-3b9f-4e0a-8c55-2f61b0a9d3e4",
"status": "queued",
"maxPages": 200,
"pagesCrawled": 0
},
"job": {
"id": "c41e8f27-5a6d-4b13-9d70-e8a2f4b6c915",
"type": "crawl",
"status": "queued"
},
"alreadyRunning": false
}
}curl https://serpel.app/api/v1/jobs/$JOB_ID \
-H "Authorization: Bearer $SERPEL_TOKEN"
curl https://serpel.app/api/v1/projects/$PROJECT_ID/issues \
-H "Authorization: Bearer $SERPEL_TOKEN"Research keywords
Needs keywords:write and uses credits. A keyword research costs 8 credits plus 4 credits per block of 50 results, so 20 results cost 12 credits. The Idempotency-Key makes a retry safe. credits.charged and credits.balance show what the call cost and what is left.
curl -X POST https://serpel.app/api/v1/keywords/research \
-H "Authorization: Bearer $SERPEL_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: research-cold-brew-2026-10-10" \
-d '{"mode": "keyword", "keyword": "cold brew concentrate", "country": "US", "language": "en", "limit": 20}'{
"data": {
"runId": "5e9b7a30-1c4d-4f82-b6a1-0d3c8e2f7a46",
"mode": "keyword",
"query": "cold brew concentrate",
"country": "US",
"language": "en",
"cached": false,
"items": [
{
"keyword": "cold brew concentrate",
"relation": "seed",
"searchVolume": 2900,
"cpc": 1.45,
"keywordDifficulty": 38,
"intent": "commercial"
}
],
"credits": {
"charged": 12,
"balance": 488
}
}
}Read rankings
Needs rankings:read. Each tracked keyword has its latest check and a change against the previous one; a positive change means the keyword moved up. A position of null with status ok means the page was not found within the checked depth.
curl "https://serpel.app/api/v1/projects/$PROJECT_ID/rankings?limit=2&q=cold%20brew" \
-H "Authorization: Bearer $SERPEL_TOKEN"{
"data": [
{
"id": "a3f1c9d2-6b8e-4d57-9c20-7e4b1a5d8f03",
"keyword": "cold brew concentrate",
"country": "US",
"language": "en",
"device": "desktop",
"searchVolume": 2900,
"latest": {
"checkedAt": "2026-10-09T06:00:12.000Z",
"depth": 50,
"position": 11,
"url": "https://example.com/cold-brew-concentrate",
"status": "ok"
},
"change": 3
}
],
"pagination": { "limit": 2, "offset": 0, "total": 1 }
}Updated 10 Oct 2026
See also
- SEO APISerpel’s SEO API is a REST API for rank tracking, site audits, AI visibility and search data, with bearer tokens, JSON responses and credit-based pricing.
- Serpel CLI referenceReference for the serpel command line: install, sign-in, every command group, JSON output, exit codes and a GitHub Actions example.
- Connect Claude Code to Serpel over MCPConnect Claude Code to the Serpel MCP server with one command, sign in with OAuth and let the agent read rankings, audits and search data.
- Developer docs for the CLI, API and MCPSerpel developer documentation: set up the CLI, call the REST API with a scoped token and connect Claude Code, Cursor or Codex to the MCP server.