The Web Ratings
For Coding Agents

Agent Onboarding Guide

Step-by-step API workflow for coding agents (Claude Code, Cursor) to autonomously set up TheWebRatings on a website: claim, verify, install widgets, validate

This page is written for coding agents (Claude Code, Cursor, and similar tools) that have been asked to set up TheWebRatings on a website. It is exact and complete: follow the steps in order, handle every error code in the table, and respect the placement rules.

TheWebRatings (TWR) collects verified in-app reviews for SaaS products via an embeddable widget. Each website gets a public profile page at https://thewebratings.com/apps/{slug}. The Pro plan unlocks display widgets (badge, bar, carousel), review replies, and disputes.

A machine-readable markdown version of this page is available at https://docs.thewebratings.com/agent-onboarding.md. Prefer the MCP server if your environment supports MCP — it wraps this exact flow in 7 tools.


What you need before starting

One thing only: a setup token from the site owner.

  • Format: twr_agent_…
  • Minted by the owner in Dashboard → Settings at thewebratings.com
  • Expires 7 days after creation
  • Becomes bound to ONE domain on first use — you cannot reuse it for a second site

If you do not have a token, stop and ask the owner to mint one. Do not guess or fabricate tokens.

You also need to know the domain being onboarded (e.g. acmecrm.com) and have write access to the site's own codebase plus the ability to deploy it (or a human who will deploy for you).

API conventions

  • Base URL: https://api.thewebratings.com/api/v1
  • Auth header (every request): X-Setup-Token: twr_agent_…
  • Response envelope (every response):
{
  "success": true,
  "status_code": 200,
  "message": "OK",
  "data": { },
  "error": null,
  "meta": {}
}

On failure, success is false and error is {"code": "SOME_CODE", "details": {…}}. Branch on error.code, not on the message text.

The golden rule

Always call setup/status first

GET /partners/setup/status/ is the stateless source of truth. Call it:

  1. Before doing anything else
  2. After any restart, crash, or context loss
  3. Whenever you are unsure what state the setup is in

Its next_steps array tells you exactly what to do next. Never assume state — always re-check.


Step 1: Check setup status

GET /partners/setup/status/?domain=acmecrm.com
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j

Response (fresh site, nothing done yet):

{
  "success": true,
  "status_code": 200,
  "message": "Setup status retrieved",
  "data": {
    "domain": "acmecrm.com",
    "exists": false,
    "website": null,
    "claimed_by_me": false,
    "claimed_by_other": false,
    "verified": false,
    "verification_pending": false,
    "has_api_key": false,
    "api_key": null,
    "plan": "free",
    "display_widgets_allowed": false,
    "next_steps": ["create_website"]
  },
  "error": null,
  "meta": {}
}

Response (mid-flow example — website created, verification started, tag not yet verified):

{
  "success": true,
  "status_code": 200,
  "message": "Setup status retrieved",
  "data": {
    "domain": "acmecrm.com",
    "exists": true,
    "website": { "id": 4821, "slug": "acme-crm", "name": "Acme CRM" },
    "claimed_by_me": true,
    "claimed_by_other": false,
    "verified": false,
    "verification_pending": true,
    "has_api_key": false,
    "api_key": null,
    "plan": "free",
    "display_widgets_allowed": false,
    "next_steps": ["add_meta_tag", "verify_claim"]
  },
  "error": null,
  "meta": {}
}

next_steps vocabulary

Act on these values, in the order returned:

ValueWhat to do
create_websiteStep 2
start_claim_verificationStep 3
add_meta_tagStep 4
verify_claimStep 5
install_collection_widgetSteps 6–7
install_display_widgetsStep 8 (Pro is active)
upgrade_for_display_widgetsSkip display widgets; relay upgrade link to owner (Step 8)
doneNothing left; run Step 9 validation and report

If claimed_by_other is true, stop immediately — the domain is verified by another account. Tell the owner to contact [email protected].

Step 2: Create the website

POST /partners/websites/
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j
Content-Type: application/json

{
  "domain": "acmecrm.com",
  "name": "Acme CRM",
  "app_url": "https://app.acmecrm.com",
  "website_url": "https://acmecrm.com",
  "category": "crm"
}

Only domain is required. Response — 201 when created, 200 when the domain is already linked to this account (both are success; proceed either way):

{
  "success": true,
  "status_code": 201,
  "message": "Website created",
  "data": {
    "id": 4821,
    "slug": "acme-crm",
    "name": "Acme CRM",
    "domain": "acmecrm.com",
    "app_url": "https://app.acmecrm.com",
    "verified": false
  },
  "error": null,
  "meta": {}
}

Step 3: Start claim verification

POST /partners/websites/start-claim-verification/
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j
Content-Type: application/json

{
  "domain": "acmecrm.com",
  "method": "html"
}

Response:

{
  "success": true,
  "status_code": 200,
  "message": "Verification started",
  "data": {
    "verification_token": "twr-verify-9f8e7d6c5b4a3a2b1c0d",
    "html_meta_tag": "<meta name=\"twr-site-verification\" content=\"twr-verify-9f8e7d6c5b4a3a2b1c0d\">",
    "website_id": 4821,
    "status": "pending"
  },
  "error": null,
  "meta": {}
}

Save html_meta_tag — you will place it in the customer's codebase next.

Step 4: Add the meta tag to the customer's codebase and deploy

This step happens in the site's own repository, not via the API. The meta tag must end up in the <head> of the page served at the site's app URL, live on the internet, before Step 5 can succeed.

Next.js (App Router)

Preferred — use the Metadata API in app/layout.tsx:

export const metadata = {
  other: {
    'twr-site-verification': 'twr-verify-9f8e7d6c5b4a3a2b1c0d',
  },
};

Or place the raw tag directly inside <head> in the root layout.

Plain HTML / server-rendered templates

Paste the tag verbatim into the <head> of the main HTML file or base template:

<head>
  <meta name="twr-site-verification" content="twr-verify-9f8e7d6c5b4a3a2b1c0d">
  ...
</head>

SPAs (Vite, CRA, Vue CLI, Angular)

Add the tag to the static index.html in the project root or public/ directory — not via JavaScript at runtime. The verifier fetches raw HTML; tags injected by client-side JS after page load may not be seen. If the SPA is served behind SSR/prerendering, ensure the tag is present in the initial HTML response.

Then deploy. Confirm the tag is actually live (e.g. curl -s https://app.acmecrm.com | grep twr-site-verification) before calling verify. If deployment is manual, hand off to the owner and resume from Step 1 (status check) once deployed.

Step 5: Verify the claim

POST /partners/websites/verify-claim/
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j
Content-Type: application/json

{
  "domain": "acmecrm.com"
}

Response:

{
  "success": true,
  "status_code": 200,
  "message": "Domain verified",
  "data": {
    "status": "verified",
    "domain": "acmecrm.com",
    "website_id": 4821
  },
  "error": null,
  "meta": {}
}

Successful verification auto-creates a default API key for the website. You do not need a separate key-creation call — fetch it via Step 1 (data.api_key) or Step 6 (embedded in collection_snippet).

If you get VERIFICATION_FAILED, read error.details.failure_reason, confirm the tag is deployed at the correct URL, wait for the deploy/CDN to settle, and retry. Do not retry in a tight loop — wait at least 30–60 seconds between attempts.

Step 6: Fetch the snippets

GET /partners/setup/snippets/?domain=acmecrm.com
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j

Response:

{
  "success": true,
  "status_code": 200,
  "message": "Snippets retrieved",
  "data": {
    "verification_meta_tag": null,
    "collection_snippet": "<script src=\"https://cdn.thewebratings.com/twr.min.js\"></script>\n<script>TheWebRatings.init({ apiKey: 'twr_live_a1b2c3d4e5f60718293a4b5c' });</script>",
    "collection_note": "Install only inside authenticated areas of the app.",
    "display_script_tag": "<script src=\"https://cdn.thewebratings.com/twr-display.min.js\" defer></script>",
    "display_snippets": {
      "badge": "<div data-twr-widget=\"badge\" data-twr-slug=\"acme-crm\" data-twr-theme=\"auto\" data-twr-size=\"md\"></div>",
      "bar": "<div data-twr-widget=\"bar\" data-twr-slug=\"acme-crm\" data-twr-theme=\"auto\" data-twr-size=\"md\"></div>",
      "carousel": "<div data-twr-widget=\"carousel\" data-twr-slug=\"acme-crm\" data-twr-theme=\"auto\" data-twr-size=\"md\"></div>"
    },
    "display_requires_pro": true,
    "display_widgets_allowed": false,
    "upgrade_url": "https://thewebratings.com/pricing",
    "profile_url": "https://thewebratings.com/apps/acme-crm",
    "docs_url": "https://docs.thewebratings.com"
  },
  "error": null,
  "meta": {}
}

verification_meta_tag is null once the site is verified. collection_snippet is null until verification succeeds (no API key exists yet).

Step 7: Install the collection widget

Authenticated areas ONLY

The collection widget auto-prompts users to leave a review. Install it only inside logged-in / authenticated areas of the app (dashboard layout, member portal, admin panel). Installing it on public pages will prompt anonymous visitors, who cannot leave verified reviews. Never put it in a public root layout, landing page, or marketing page.

Add to the authenticated layout of the customer's app:

<script src="https://cdn.thewebratings.com/twr.min.js"></script>
<script>TheWebRatings.init({ apiKey: 'twr_live_a1b2c3d4e5f60718293a4b5c' });</script>

Use the exact apiKey from Step 6's collection_snippet (or api_key from Step 1). In React/Next.js apps, load the script in the authenticated layout component and call TheWebRatings.init after it loads (e.g. next/script with onLoad, or a useEffect that appends the script). See framework guides for full examples.

Step 8: Install display widgets (Pro only)

Display widgets show collected reviews on public marketing pages (landing page, pricing page, footer). They are the opposite of the collection widget: public pages only.

Check display_widgets_allowed from Step 1 or Step 6. The server enforces this — it is not a client-side flag you can bypass.

If display_widgets_allowed is false: install nothing for display. Finish the remaining steps, then tell the owner verbatim intent: "Upgrade at https://thewebratings.com/pricing to enable display widgets, then re-run." Do not treat this as an error.

If true: add the script once per page, then one <div> per widget:

<script src="https://cdn.thewebratings.com/twr-display.min.js" defer></script>
<div data-twr-widget="badge" data-twr-slug="acme-crm" data-twr-theme="auto" data-twr-size="md"></div>
AttributeValues
data-twr-widgetbadge | bar | carousel
data-twr-slugThe website slug from Step 1/2 (e.g. acme-crm)
data-twr-themelight | dark | auto
data-twr-sizesm | md | lg

A sensible default: badge in the site footer or near pricing CTAs. Use the exact snippets from Step 6's display_snippets.

Step 9: Validate the installation

After deploying the widget changes, ask the API to fetch a live page and confirm what it finds:

POST /partners/setup/validate/
X-Setup-Token: twr_agent_8fK2mQ9xL4vN7pR3sT6wY1zB5cD0eH8j
Content-Type: application/json

{
  "url": "https://acmecrm.com/"
}

Response:

{
  "success": true,
  "status_code": 200,
  "message": "Validation complete",
  "data": {
    "url_checked": "https://acmecrm.com/",
    "fetched_status": 200,
    "collection_widget_found": false,
    "display_widget_found": true,
    "display_widget_types_found": ["badge"],
    "meta_tag_found": true
  },
  "error": null,
  "meta": {}
}

Validate the pages you actually changed. Note: the collection widget lives behind login, so a public-URL validation will correctly report collection_widget_found: false — that is expected, not a failure. Validate a public marketing page for display widgets, and rely on code review + deploy logs for the authenticated collection snippet.


Error codes

Handle every code below. error.code is the branching key.

CodeHTTPMeaningAction
TOKEN_INVALID401Token malformed or unknownAsk the owner to mint a fresh token in Dashboard → Settings
TOKEN_REVOKED401Token was revokedAsk the owner to mint a fresh token in Dashboard → Settings
TOKEN_EXPIRED401Token older than 7 daysAsk the owner to mint a fresh token in Dashboard → Settings
SETUP_TOKEN_NOT_ALLOWED403Endpoint not permitted with a setup tokenDo not retry; use only the endpoints documented on this page
TOKEN_SCOPE403Token is bound to a different domainAsk the owner to mint a new token for this site
ALREADY_CLAIMED409Site verified by another accountStop; owner should contact [email protected]
NO_ATTEMPT400verify-claim called before start-claim-verificationCall Step 3 first, then retry
VERIFICATION_FAILED400Meta tag not found at the app URL (details.failure_reason explains)Confirm the tag is deployed and the URL is correct, wait for the deploy, retry
RACE_CONDITION409Someone else verified this domain firstStop and report to the owner
PLAN_LIMIT_REACHED403Website limit reached (free = 1, pro = 5)Tell the owner to upgrade at thewebratings.com/pricing
UPGRADE_REQUIRED403Pro feature on a free planFinish everything else; relay the upgrade link to the owner
WEBSITE_NOT_FOUND404Domain has no website recordRe-check with the status endpoint (Step 1)
NOT_OWNER403Website not owned by this accountRe-check with the status endpoint (Step 1)
URL_NOT_ALLOWED400Validate URL is blocked (wrong domain, non-https, private)Use a public https URL on the claimed domain
UNREACHABLE400Validate could not fetch the siteConfirm the site is live and publicly reachable, then retry

Placement rules (summary)

WidgetWhereWhy
Collection widget (twr.min.js)Authenticated areas only — dashboard, member portal, adminIt auto-prompts the current user for a review; anonymous visitors must never see it
Display widgets (twr-display.min.js)Public marketing pages — landing, pricing, footerThey show social proof to prospects; Pro plan required, server-enforced
Verification meta tag<head> of the page at the site's app URL, in raw HTMLThe verifier fetches raw HTML; runtime-injected tags may not be detected

Final checklist

Before reporting completion to the owner, confirm:

  • GET /partners/setup/status/ returns verified: true and has_api_key: true
  • Verification meta tag is live in the deployed site's <head> (leave it in place — do not remove it after verification)
  • Collection snippet installed only in authenticated layouts, with the real API key (no placeholder)
  • Display widgets: installed on public pages if display_widgets_allowed: true; otherwise nothing installed and the upgrade message relayed to the owner
  • POST /partners/setup/validate/ run against a changed public page; results reported
  • next_steps from the status endpoint is ["done"] (or ["upgrade_for_display_widgets"] on the free plan)
  • Reported to the owner: what was installed, where, the profile URL (https://thewebratings.com/apps/{slug}), and any remaining manual actions

See also