Open App

API Reference

The ShowTrust REST API lets your agent or backend create projects, configure widgets, fetch embed snippets, and read testimonials. All endpoints live under /v1.

Base URL: https://api.showtrust.to

Stability: endpoints under /v1 are stable. We add fields and endpoints freely; we don't rename or remove existing fields without a new version.

Authentication#

Every /v1/* request requires two headers, with one exception: POST /v1/auth/agent-init is public — it's how an agent obtains its credentials in the first place. The account ID identifies you, the API key proves it's you.

NameTypeDescription
x-showtrust-account-idrequiredstringYour account ID. Visible at Settings → API.
x-api-keyrequiredstringYour API key. Starts with st_live_. Generated at Settings → API and shown once on creation.
bash
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/me

Responses use a { "message": "...", "data": ... } envelope. The real payload is always under data.

API key lifecycle#

  • Each account has one active API key at a time. Regenerating from Settings → API replaces the previous key — the old one stops working immediately.
  • The plaintext key is shown once on creation. If you lose it, you must regenerate. We only store a hash.
  • Calling POST /v1/auth/agent-init again for the same email while the account is still unclaimed rotates the key — the prior key is invalidated. After the user claims the account (sets a password via the magic link), agent-init returns the “account already exists” branch instead.

Endpoints#

POST/v1/auth/agent-init

Public. Sign up (or recognize) a user from their email. Returns a fresh API key if the email is new; otherwise tells the agent the account already exists and to ask the user for their existing key.

Request body
NameTypeDescription
emailrequiredstringThe user's email. Disposable-email domains are rejected.
json
{
  "email": "you@example.com"
}
Response 200 — new or unclaimed account

Save accountId and apiKey. The plaintext key is shown once and never again. The user has expiresInDays to click the magic link in their inbox — after that the project is removed.

Re-running this endpoint for the same unclaimed email rotates the key: the previous apiKey stops working. If your agent retries, overwrite the old credentials with the new ones from the latest response.

json
{
  "message": "Success",
  "data": {
    "accountId": "65f0e3a1c2b4d5e6f7a8b9c0",
    "apiKey": "st_live_...",
    "claimRequired": true,
    "expiresInDays": 3
  }
}
Response 200 — account already exists

No key is issued. The agent should ask the user to paste their existing API key from Settings → API in the dashboard. Only the legitimate account owner knows the key, so this naturally prevents account takeover via email enumeration.

json
{
  "message": "Success",
  "data": {
    "claimRequired": false,
    "accountExists": true,
    "message": "Account already exists. Paste your API key from Settings → API to continue."
  }
}
Rate limits

5 requests/hour per IP, 3 requests/hour per email. Exceeding either returns 429.

Errors

400 — missing email, malformed email, or disposable-email domain.
429 — rate limit exceeded.

Example
curl
curl -X POST \
     -H "Content-Type: application/json" \
     -d '{"email":"you@example.com"}' \
     https://api.showtrust.to/v1/auth/agent-init

GET/v1/me

Returns the account associated with the API key. Use this as a credential-validation check before any other call.

Headers
NameTypeDescription
x-showtrust-account-idrequiredstringYour account ID. Visible at Settings → API.
x-api-keyrequiredstringYour API key. Starts with st_live_. Generated at Settings → API and shown once on creation.
Response 200
json
{
  "message": "Success",
  "data": {
    "accountId": "65f0e3a1c2b4d5e6f7a8b9c0",
    "email": "you@example.com"
  }
}
Example
curl
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/me

GET/v1/projects

List the projects on your account. Most recent first, capped at 50.

Headers
NameTypeDescription
x-showtrust-account-idrequiredstringYour account ID. Visible at Settings → API.
x-api-keyrequiredstringYour API key. Starts with st_live_. Generated at Settings → API and shown once on creation.
Response 200

Each item is a full Project. status is "active" or "inactive" — new projects are always active. See GET /v1/projects/:id below for the full nested shape.

json
{
  "message": "Success",
  "data": [
    {
      "_id": "65f0e3a1c2b4d5e6f7a8b9c1",
      "userId": "65f0e3a1c2b4d5e6f7a8b9c0",
      "status": "active",
      "publicPageConfig": { "slug": "acme", ... },
      "widgetConfig": { "layout": "masonry", ... },
      "createdAt": "2026-05-21T10:30:00.000Z",
      "updatedAt": "2026-05-21T10:30:00.000Z"
    }
  ]
}
Example
curl
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/projects

POST/v1/projects

Create a new project. The project owns its own collection page and widget configuration.

Headers
NameTypeDescription
x-showtrust-account-idrequiredstringYour account ID. Visible at Settings → API.
x-api-keyrequiredstringYour API key. Starts with st_live_. Generated at Settings → API and shown once on creation.
Request body
NameTypeDescription
businessNamestringOptional. Used to derive the public-page slug when slug is omitted.
slugstringOptional. Becomes the public URL path (app.showtrust.to/<slug>). Max 60 chars; must be globally unique. The server normalizes whatever you send to lowercase + dashes (e.g. "Acme Inc." → "acme-inc"). If omitted, derived from businessName; if both are missing, a random project-xxxxxx is generated.
websitestringYour site URL. Auto-prefixed with https:// if missing scheme.
headlinestringOptional headline shown on the public collection page.
descriptionstringOptional sub-headline on the public collection page.
skipDemoTestimonialsbooleanOpt out of automatic demo-testimonial seeding on the user's first project. Default false. Has no effect on subsequent projects — demos only seed for first.
json
{
  "businessName": "Acme",
  "slug": "acme",
  "website": "acme.com",
  "skipDemoTestimonials": false
}
Behavior — demo testimonials
  • When this is the account's very first project, the server auto-seeds ~6 generic demo testimonials (themed with businessName) so the widget renders something on first install instead of an empty wall.
  • Demo entries get source: "demo" and status: "demo". They render in the public widget alongside approved testimonials, but the dashboard tags them clearly and exposes a "Clear demo data" button at Project → Testimonials.
  • To skip seeding, pass "skipDemoTestimonials": true. Ask the user if they want demos before calling — agents should not assume.
  • Programmatic cleanup is available via DELETE /v1/projects/:id/testimonials/demo.
Response 200

Returns the full project including the auto-generated _id and default widgetConfig. The public collection page is https://app.showtrust.to/<slug>, where slug is data.publicPageConfig.slug — the value you sent in slug, or the slugified businessName if you omitted it. See GET /v1/projects/:id below for the full response shape.

Errors
  • 400 with "This slug is already taken. Please choose a different one." — another project already owns that slug. Ask the user for a different one and retry.
  • 402 with code: "PROJECT_LIMIT_REACHED" — the account is at its project limit. Don't retry; surface the upgrade path.
Example
curl
curl -X POST \
     -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"businessName":"Acme","slug":"acme","skipDemoTestimonials":false}' \
     https://api.showtrust.to/v1/projects

GET/v1/projects/:id

Fetch a single project including its full public-page and widget configuration. This is the canonical project response shape — other endpoints that return a project return the same fields.

Path params
NameTypeDescription
idrequiredstringThe project ID returned from POST /v1/projects.
Response 200
json
{
  "message": "Success",
  "data": {
    "_id": "65f0e3a1c2b4d5e6f7a8b9c1",
    "userId": "65f0e3a1c2b4d5e6f7a8b9c0",
    "status": "active",
    "publicPageConfig": {
      "slug": "acme",
      "website": "https://acme.com",
      "headline": "Customers love Acme",
      "description": "Hear it from them.",
      "thankYouMessage": "Thanks for sharing!",
      "theme": "light",
      "buttonColor": "#5b6cff",
      "buttonTextColor": "#ffffff",
      "logo": null,
      "showConfetti": true,
      "collectFields": {
        "name": true,
        "email": true,
        "role": true,
        "company": true,
        "avatar": true,
        "rating": true
      }
    },
    "widgetConfig": {
      "theme": "dark",
      "layout": "masonry",
      "animation": "none",
      "palette": "indigo",
      "cardStyle": "default",
      "initialCount": 9,
      "showStars": true,
      "showDates": true,
      "showSource": true,
      "showCtaButton": true
    },
    "createdAt": "2026-05-21T10:30:00.000Z",
    "updatedAt": "2026-05-21T10:30:00.000Z"
  }
}

Fields: status is "active" or "inactive". The slug is set at creation time (see POST /v1/projects) and can't be renamed via v1 — manage it in the dashboard. Other fields inside publicPageConfig (logo, button colors, thank-you message, collected fields, etc.) are also dashboard-only today. See Not in v1 below.

Errors

404 — project not found, or the project doesn't belong to your account.

Example
curl
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/projects/$PROJECT_ID

PATCH/v1/projects/:id/widget-config

Partial update of the widget's display configuration. Only the fields you send are changed.

Path params
NameTypeDescription
idrequiredstringThe project ID.
Request body
NameTypeDescription
theme"light" | "dark"Color scheme.
layout"masonry" | "carousel" | "list"Card arrangement.
animation"none" | "horizontal" | "vertical"Card scrolling behavior. Only meaningful with layout=carousel.
palette"neutral" | "indigo" | "emerald" | "amber" | "rose" | "sky"Accent color used by card decorations.
cardStyle"default" | "quote" | "stripe" | "gradient" | "outlined"Visual treatment per card.
initialCountnumber (3–50)How many testimonials show before "Load more".
showStarsbooleanRender the star rating on each card.
showDatesbooleanRender the submission date on each card.
showSourcebooleanRender attribution on each card (e.g. linked X/Twitter handle when present).
showCtaButtonbooleanRender a "Show Trust to ___" CTA below the widget.
json
{
  "layout": "masonry",
  "palette": "indigo",
  "theme": "dark"
}
Errors

400 — a value is outside the allowed enum range.
404 — project not found.

Example
curl
curl -X PATCH \
     -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"layout":"masonry","palette":"indigo"}' \
     https://api.showtrust.to/v1/projects/$PROJECT_ID/widget-config

GET/v1/projects/:id/embed-snippet

Returns the embed snippet you (or your agent) paste into the user's website.

Path params
NameTypeDescription
idrequiredstringThe project ID.
Response 200
json
{
  "message": "Success",
  "data": {
    "projectId": "65f0e3a1c2b4d5e6f7a8b9c1",
    "widgetUrl": "https://app.showtrust.to/showtrustto-widget.js",
    "script": "<script>(function(){...})();</script>",
    "container": "<div id=\"showtrustto-widget\"></div>"
  }
}

See the framework-specific recipes in Integrations for where to put script and container in your codebase.

Example
curl
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/projects/$PROJECT_ID/embed-snippet

POST/v1/projects/:id/testimonials

Create a single testimonial directly. Equivalent to adding one manually in the dashboard — created entries land as approved and visible immediately. Note: you no longer need this for first-install placeholders — the server auto-seeds demos when the first project is created (see POST /v1/projects).

Path params
NameTypeDescription
idrequiredstringThe project ID.
Request body
NameTypeDescription
authorNamerequiredstringDisplay name on the card. Max 120 chars.
textrequiredstringThe testimonial body. Max 2000 chars.
ratingnumber (1–5)Star rating. Omit for no stars.
authorRolestringe.g. "CEO". Max 120 chars.
authorCompanystringe.g. "Acme". Max 120 chars.
authorAvatarstring (URL)Public image URL for the avatar. Max 500 chars.
json
{
  "authorName": "Jane Doe",
  "authorRole": "CEO",
  "authorCompany": "Acme",
  "rating": 5,
  "text": "Best testimonials platform we've used."
}
Behavior
  • Created entries get source: "manual" and status: "approved" — they show up in the widget immediately, with no review step.
  • The user can edit, pin, or delete them later from the dashboard at Project → Testimonials.
  • Use for bulk-importing real testimonials from another source, or for adding one-offs (e.g. a quote the user dictated). For first-install placeholders, the server already auto-seeds — see POST /v1/projects.
Response 200
json
{
  "message": "Success",
  "data": {
    "_id": "65f0e3a1c2b4d5e6f7a8b9d0",
    "projectId": "65f0e3a1c2b4d5e6f7a8b9c1",
    "status": "approved",
    "source": "manual",
    "authorName": "Jane Doe",
    "authorRole": "CEO",
    "authorCompany": "Acme",
    "text": "Best testimonials platform we've used.",
    "rating": 5,
    "submittedAt": "2026-05-21T10:30:00.000Z",
    "createdAt": "2026-05-21T10:30:00.000Z",
    "updatedAt": "2026-05-21T10:30:00.000Z"
  }
}
Errors

400 — missing authorName or text, or a field failed validation (e.g. rating outside 1–5, value over max length).
404 — project not found.

Example
curl
curl -X POST \
     -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"authorName":"Jane Doe","text":"Best platform ever.","rating":5}' \
     https://api.showtrust.to/v1/projects/$PROJECT_ID/testimonials

DELETE/v1/projects/:id/testimonials/demo

Bulk-delete all demo testimonials on a project. Call this once the user has added real testimonials and is ready to take the wall live.

Path params
NameTypeDescription
idrequiredstringThe project ID.
Behavior
  • Deletes every testimonial on this project with status: "demo". Approved, pending, and rejected entries are untouched.
  • Idempotent — calling it on a project with no demos returns { "deletedCount": 0 } and succeeds.
Response 200
json
{
  "message": "Success",
  "data": {
    "deletedCount": 6
  }
}
Errors

404 — project not found, or doesn't belong to your account.

Example
curl
curl -X DELETE \
     -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     https://api.showtrust.to/v1/projects/$PROJECT_ID/testimonials/demo

GET/v1/projects/:id/testimonials

List publicly-visible testimonials for a project (approved + demo). Offset pagination.

Path params
NameTypeDescription
idrequiredstringThe project ID.
Query params
NameTypeDescription
limitnumberHow many testimonials to return. Default 50, max 100.
offsetnumberHow many to skip from the start. Default 0.
Where testimonials come from
  • Visitors submit testimonials at the public collection page: https://app.showtrust.to/<slug> (where slug is project.publicPageConfig.slug). Share this URL with your customers.
  • You can also add testimonials manually from the dashboard, or import them in bulk.
  • New submissions land in pending and must be approved in the dashboard before they appear here. This endpoint returns testimonials with status: "approved" or "demo" — the same set that renders in the public widget. pending and rejected are dashboard-only.
  • On a brand-new account's first project, expect ~6 entries with status: "demo" auto-seeded by the server (see POST /v1/projects). Wipe them with DELETE /v1/projects/:id/testimonials/demo once real ones come in. On subsequent projects the list starts empty.
  • Items are returned newest-first by createdAt. Offset pagination is stable for already-collected testimonials, but newly approved ones will shift the offset of older items.
Enums
NameTypeDescription
status"pending" | "approved" | "rejected" | "demo"Only "approved" and "demo" are returned by this endpoint (the same set the public widget renders). "pending" and "rejected" exist in the dashboard only.
source"public_page" | "manual" | "import" | "demo""public_page" — submitted via the collection page. "manual" — added by you in the dashboard or via POST /testimonials. "import" — bulk-imported. "demo" — server-seeded placeholder for first-project onboarding.
Response 200

Optional fields (authorEmail, authorCompany, authorAvatar, twitter, rating, reviewedAt, pinned) are present only when set. The example below shows a fully-populated item.

json
{
  "message": "Success",
  "data": {
    "items": [
      {
        "_id": "65f0e3a1c2b4d5e6f7a8b9d0",
        "projectId": "65f0e3a1c2b4d5e6f7a8b9c1",
        "status": "approved",
        "source": "public_page",
        "authorName": "Jane Doe",
        "authorEmail": "jane@acme.com",
        "authorRole": "CEO",
        "authorCompany": "Acme",
        "authorAvatar": "https://cdn.showtrust.to/avatars/...",
        "twitter": {
          "id": "1234567890",
          "handle": "janedoe",
          "displayName": "Jane Doe",
          "avatarUrl": "https://pbs.twimg.com/...",
          "verified": true
        },
        "text": "Best testimonials platform we've used.",
        "rating": 5,
        "pinned": false,
        "submittedAt": "2026-05-12T08:14:00.000Z",
        "reviewedAt": "2026-05-12T08:20:00.000Z",
        "createdAt": "2026-05-12T08:14:00.000Z",
        "updatedAt": "2026-05-12T08:20:00.000Z"
      }
    ],
    "limit": 50,
    "offset": 0
  }
}
Example
curl
curl -H "x-showtrust-account-id: $ACCOUNT_ID" \
     -H "x-api-key: $API_KEY" \
     "https://api.showtrust.to/v1/projects/$PROJECT_ID/testimonials?limit=20&offset=0"

Not in v1#

A few common actions aren't exposed via the API today — they're dashboard-only at app.showtrust.to. If you need one of these, send users to the dashboard rather than hunt for a missing endpoint.

  • Logo upload and the rest of the public-page styling (logo, buttonColor, buttonTextColor, thankYouMessage, theme, showConfetti, collectFields) — manage at Project → Public Page.
  • Testimonials: approve / reject / pin / edit / delete — manage at Project → Testimonials. The v1 API can create approved testimonials (see POST /v1/projects/:id/testimonials) and list approved ones, but the moderation actions are dashboard-only.
  • Project deletion — manage at Project → Settings.
  • Subscription / billing — manage at Account → Billing.
  • Slug rename — you can choose the slug at project-creation time via POST /v1/projects, but renaming an existing project's slug is dashboard-only today.

Errors#

All errors return a JSON body with a message field:

json
{
  "message": "Invalid credentials"
}
NameTypeDescription
400 Bad RequestValidation failed — usually an enum value outside the allowed range.
401 UnauthorizedThe account ID + API key pair didn't match. Re-check both, or regenerate the key.
404 Not FoundThe resource doesn't exist or doesn't belong to your account.
429 Too Many RequestsRate limit exceeded. Currently only enforced on POST /v1/auth/agent-init (5/hr per IP, 3/hr per email). Wait an hour, then retry.

Was this page helpful?

ShowTrust

Collect testimonials. Show off the trust.

© Copyright 2026. All rights reserved.