API Reference

Every button in the panel is an API call

The Vouch Dock panel is just a client of this API. Everything it does — creating sites, publishing offers, moderating reviews, pulling stats — you can do from your own scripts, n8n flows, or AI agents. Same endpoints, same data, no artificial limits.

Quickstart

Two minutes from zero to your first API call:

  1. In the panel, open API Keys in the sidebar and click + New key. Give it a name and a scope.
  2. Copy the key — it's shown exactly once. We store only its hash, so it can't be recovered later.
  3. Send it as a Bearer token:
curl
curl https://app.vouchdock.com/v1/sites \
  -H "Authorization: Bearer vd_live_your_key_here"

That's the whole setup. No OAuth dance, no refresh tokens, no sandbox environment — the same production API the panel uses.

Authentication

All endpoints live under https://app.vouchdock.com/v1/ and expect a tenant API key in the Authorization header:

Header
Authorization: Bearer vd_live_...

Scopes

ScopeWhat it can do
readGET endpoints only — content export, stats, link health. Mutations return 403.
writeFull content management: sites, categories, offers, reviews, articles, media, monetization. Team and API-key management stay login-only, so a leaked key can't lock you out or mint more keys.

Revoking a key in the panel kills it instantly — the very next request gets a 401.

One key per integration. Name keys after the tool that uses them ("n8n nightly sync", "import script"). When something goes wrong you'll know exactly which integration is acting up from the last used timestamp — and you can revoke one without breaking the rest.

Login sessions

For interactive flows (your own UI on top, or owner-level actions like key management) there's also POST /auth/login with email + password, returning a short-lived JWT used the same way; POST /auth/resend-verification re-sends the verification email. API keys are the right choice for automation; JWT is for sessions.

Conventions

  • JSON in, JSON out. Send Content-Type: application/json on POST/PATCH. Media upload is the one multipart/form-data exception.
  • IDs are UUIDs. Path parameters like :id, :oid, :cid take UUIDs returned by list/create calls.
  • Site scoping. Content belongs to a site: list via /sites/:id/…, then address items directly (/offers/:oid).
  • Changes go live in ~5 seconds. The public renderer caches settings briefly; edits appear on your domains within seconds, no deploy.
  • Full-update semantics on PATCH. Updates replace the stored record — omitted optional fields are cleared. Read first, modify, send back.
  • Plan gating. Some groups (link health, cloaking, postbacks, comparison tables, media library, lead generation (contacts), audit log) depend on your plan; a gated endpoint returns 403 naming the missing feature. Check Account & team.

Errors

StatusMeaning
400Invalid payload — missing or malformed fields.
401Missing, invalid or revoked API key.
403Key scope too narrow (read key attempting a write), or the feature isn't in your plan.
404Not found, or belongs to another tenant (we don't confirm existence across tenants).
409Conflict — e.g. a slug already taken within the site.
500Our side. If it persists, open a ticket from the panel.

Reference sections

The full field-by-field reference, split by resource. Every create/update payload documented with types, defaults and examples.

Full workflow example

From empty account to a ranked offer with a review, in five calls:

bash
API=https://app.vouchdock.com/v1
KEY=vd_live_your_key_here

# 1. your sites
SITE=$(curl -s $API/sites -H "Authorization: Bearer $KEY" \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['sites'][0]['id'])")

# 2. a category
CAT=$(curl -s -X POST $API/sites/$SITE/categories \
  -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d '{"name":"VPN Services","slug":"vpn-services"}' \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")

# 3. an offer in it
OFFER=$(curl -s -X POST $API/sites/$SITE/offers \
  -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d "{\"name\":\"Acme VPN\",\"slug\":\"acme-vpn\",\"category_ids\":[\"$CAT\"],\"url\":\"https://acmevpn.example.com\",\"rank\":1,\"status\":\"active\",\"link_slots\":[\"toplink\"]}" \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")

# 4. a consumer review on it
curl -s -X POST $API/reviews \
  -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d "{\"offer_id\":\"$OFFER\",\"site_id\":\"$SITE\",\"title\":\"Solid for the price\",\"content\":\"Been using it six months…\",\"rating\":5,\"author_name\":\"Mike T.\",\"status\":\"approved\"}"

# 5. watch it appear — public pages reflect changes within seconds
curl -s https://your-site-domain.com/ | grep -o "Acme VPN"

Build on it

Bulk-import a portfolio of sites, sync offers from your own database, wire moderation into Slack, auto-publish articles from your AI pipeline — if the panel can do it, so can your code.