The Better Search Console REST API allows you to programmatically manage your websites, URLs, sitemaps, and indexation. All endpoints require authentication.
Authenticate requests using the X-API-TOKEN header with your 64-character hex API token (available in your account settings).
curl -H "X-API-TOKEN: your_token_here" \
https://<your-host>/api/dashboardshttps://<your-host>/apiList endpoints return a paginated envelope:
{
"data": [...],
"page": 1,
"per_page": 20,
"total": 42,
"total_pages": 3
}Single-resource endpoints return the object directly. Errors return { "error": "..." } with status 400 (bad params), 401 (no auth), or 404 (not found / not owned).
All errors return a JSON object:
{
"error": "Description of what went wrong"
}Validation errors (400) include a fieldErrors object with per-field messages.
API endpoints share rate limits with the MCP server. See the MCP documentation for tier details. When rate-limited, the API returns 429 Too Many Requests.
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/me | Get the authenticated user's profile. | - | { id, email, nickname, subscriptionType, newsletterEmail, hasPreviouslyBeenPremium } | 200, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/websites | List all websites owned by the caller. | - | { data: [...] } | 200, 401 |
| GET | /api/websites/[id] | Get a single website (404 if not owned). | - | Website object | 200, 400, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| POST | /api/indexation/google | Submit a URL to Google for indexing. | { website_id, url_id } | { success, result } | 200, 400, 401, 404 |
| POST | /api/indexation/bing | Submit a URL to Bing for indexing. | { website_id, url_id } | { success, result } | 200, 400, 401, 404 |
| POST | /api/indexation/bulk | Submit multiple URLs for indexing. | { website_id, url_ids } | { success, results } | 200, 400, 401 |
| POST | /api/indexation/check | Check indexation status of a URL. | { website_id, url_id } | { success, status } | 200, 400, 401, 404 |
| POST | /api/indexation/check/bulk | Check indexation status of multiple URLs. | { website_id, url_ids } | { success, results } | 200, 400, 401 |
| PUT | /api/indexation/coverage-state | Get coverage state summary for a website. | { website_id } | { states } | 200, 401, 404 |
| POST | /api/indexation/disable/bulk | Disable indexation for multiple URLs. | { website_id, url_ids } | { success, count } | 200, 400, 401 |
| POST | /api/indexation/reenable/bulk | Re-enable indexation for multiple URLs. | { website_id, url_ids } | { success, count } | 200, 400, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/sitemaps | List sitemaps for a website. | None (query: ?website_id=) | { data: [...] } | 200, 400, 401, 404 |
| GET | /api/sitemaps/[id] | Get a single sitemap (404 if not owned). | - | Sitemap object | 200, 400, 401, 404 |
| POST | /api/sitemaps/add | Add a new sitemap to a website. | { website_id, sitemap_url } | { success, sitemap } | 201, 400, 401, 404 |
| DELETE | /api/sitemaps/[id] | Delete a sitemap. | None | { success } | 200, 401, 404 |
| POST | /api/sitemaps/[id]/process | Process/crawl a sitemap to discover URLs. | None | { success, urls_found } | 200, 401, 404 |
| POST | /api/sitemaps/process-all | Process all sitemaps for a website. | { website_id } | { success, processed } | 200, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/urls | Paginated list. Query: website_id (required), page, per_page (max 100), search, sitemap, coverage_state, indexation (indexed|not-indexed|unknown), fields=url (returns string[]). | None | { data, page, per_page, total, total_pages } | 200, 400, 401, 404 |
| GET | /api/urls/[id] | Get a single URL with sitemap and urlData. | - | Url object | 200, 400, 401, 404 |
| DELETE | /api/urls/[id] | Delete a single URL. | None | { success } | 200, 401, 404 |
| POST | /api/urls/delete/bulk | Delete multiple URLs. | { website_id, url_ids } | { success, deleted } | 200, 400, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/url-data | Paginated list of PageSpeed data for owned URLs. Query: website_id (required), page, per_page. | None | { data, page, per_page, total, total_pages } | 200, 400, 401, 404 |
| GET | /api/url-data/[id] | Get a single URL data record (404 if not owned). | - | UrlData object | 200, 400, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/dashboards | List custom dashboards for the authenticated user. | None | { dashboards } | 200, 401 |
| POST | /api/dashboards | Create a new custom dashboard. | { website_id, name } | { success, dashboard } | 201, 400, 401 |
| GET | /api/dashboards/[id] | Get a dashboard with its widgets. | None | { dashboard, widgets } | 200, 401, 404 |
| PUT | /api/dashboards/[id] | Update a dashboard. | { name, is_default } | { success, dashboard } | 200, 400, 401, 404 |
| DELETE | /api/dashboards/[id] | Delete a dashboard. | None | { success } | 200, 401, 404 |
| GET | /api/dashboards/[id]/data | Get data for all widgets in a dashboard. | None | { data } | 200, 401, 404 |
| POST | /api/dashboards/[id]/widgets | Add a widget to a dashboard. | { type, title, position, span, config } | { success, widget } | 201, 400, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/dashboard/chart-data | Fetch GSC performance chart data for the overview dashboard. | { website_id, start_date, end_date, dimensions? } | { rows } | 200, 400, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/prompt-analyses | Paginated list of prompt analyses. Query: website_id (required), page, per_page. PHP-serialized fields are decoded. | None | { data, page, per_page, total, total_pages } | 200, 400, 401, 404 |
| GET | /api/prompt-analyses/[id] | Get a single prompt analysis (decoded). 404 if not owned. | - | PromptAnalysis object | 200, 400, 401, 404 |
| POST | /api/prompt-analyses/create | Create a new prompt analysis. | { website_id, prompt, models, targeted_keywords? } | { success, analysis } | 201, 400, 401 |
| PUT | /api/prompt-analyses/[id]/keywords | Get keyword mentions for a prompt analysis. | None | { keywords } | 200, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| PUT | /api/settings/website/[id] | Update website settings. | { name, auto_indexing, auto_sitemap_refresh, ... } | { success, website } | 200, 400, 401, 404 |
| GET | /api/bing/status | Bing Webmaster Tools connection state and URL submission quota for a website. | ?website_id= | { configured, ok, reason, sites, quota } | 200, 400, 401, 404 |
| GET | /api/bing/feeds | Sitemaps Bing has for a website. | ?website_id= | { feeds } | 200, 400, 401, 404, 502 |
| POST | /api/bing/feeds | Submit a sitemap to Bing Webmaster Tools. | { website_id, feed_url } | { success, feed_url } | 201, 400, 401, 404, 502 |
| POST | /api/bing/oauth/disconnect | Forget the stored Bing OAuth tokens for the signed-in user. | — | { success } | 200, 401 |
| POST | /api/settings/website/[id]/service-account | Upload a Google service account JSON key. | FormData with file | { success } | 200, 400, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| POST | /api/tools/generate-robots | Generate a robots.txt file for a website. | { website_id, rules? } | { content } | 200, 400, 401 |
| POST | /api/tools/generate-sitemap | Generate an XML sitemap for a website. | { website_id, urls? } | { xml } | 200, 400, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/filters | List saved filters for a website. | None (query: ?website_id=) | { filters } | 200, 401 |
| DELETE | /api/filters/[id] | Delete a saved filter. | None | { success } | 200, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| POST | /api/reports/generate | Generate a PDF report for a website. | { website_id, date_range?, branding? } | PDF binary or { url } | 200, 400, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/blog-posts | Paginated list of published blog posts (id, title, slug, image, createdAt, meta fields). Query: page, per_page. | None | { data, page, per_page, total, total_pages } | 200, 401 |
| GET | /api/blog-posts/[slug] | Get a single blog post by slug. | - | BlogPost object | 200, 401, 404 |
| POST | /api/blog | Create a new blog post. | { title, slug, content, image?, metaTitle?, metaDescription?, ogTitle, ogDescription, keywords, articleSection } | { success, post } | 201, 400, 401, 409 |
| PUT | /api/blog/[slug] | Update a blog post (author only). | Same as create | { success, post } | 200, 400, 401, 404, 409 |
| DELETE | /api/blog/[slug] | Delete a blog post (author only). | None | { success } | 200, 401, 404 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| GET | /api/models | List all available AI models (id, name, price). Requires auth but not user-scoped. | - | { data: [...] } | 200, 401 |
| Method | Path | Description | Body | Response | Statuses |
|---|---|---|---|---|---|
| PATCH | /api/admin/users/[id] | Change user subscription type (admin only). | { subscriptionType } | { success, old, new } | 200, 400, 401, 403, 404 |