Ownware
Home›Revup›API
Revup · API

Revup API, as shipped in the download

Revup REST API, Webhooks & MCP

Revup ships a JSON REST API and signed webhooks so your booking system, POS or CRM can queue review requests the moment a job finishes — and so a private message from an unhappy customer reaches your helpdesk quickly. Every customer who rates is shown your public review link, whatever the rating.

Authentication

Create a key in Settings → API & Webhooks. Send it on every call:

Authorization: Bearer apk_...

Shown once at creation, stored as a SHA-256 hash. Revoke any time — revoking the key is the off switch.

Endpoints

Method & pathWhat it does
GET /api/pingVerify a key
GET /api/contactsNewest 500 contacts
POST /api/contactsCreate a contact (name + email or phone)
GET /api/requestsNewest 200 requests; ?status= filters
POST /api/requestsQueue (and by default send) review requests for a campaign
GET /api/feedbackPrivate messages from the rating page; ?handled=false for the open ones
GET /api/openapi.jsonOpenAPI 3.0 description

Queue requests after a job completes

curl -X POST https://reviews.example.com/api/requests \
  -H "Authorization: Bearer apk_..." -H "Content-Type: application/json" \
  -d '{"campaign_id":1,"contact_ids":[12,13,14]}'

Add "send": false to queue without sending — useful if you want a human to review the batch first.

Duplicate-suppressed. This reuses the same core the UI uses, so a contact who already has an open request for that campaign is not queued a second time. The response reports queued, sent, pending and failed counts so you can reconcile.

pending means the channel is not configured (no SMTP / no Twilio) — the request still exists and carries a gate_url you can send yourself.

Read the private messages

curl -H "Authorization: Bearer apk_..." \
  "https://reviews.example.com/api/feedback?handled=false"
{ "feedback": [ { "id": 4, "request_id": 19, "contact_id": 7,
                  "rating": 2, "message": "Waited 40 minutes.",
                  "handled": false, "created_at": "2026-08-06 11:44:02" } ], "count": 1 }

These are the private messages. A customer who rates below your threshold is shown your public review link like everyone else, and is also offered a private message to you — it lands here. Pull them into your helpdesk and close the loop.

The payload deliberately carries no gate token: a token is a capability to submit a rating, and replaying it is not something an integration should be able to do.

MCP — the agent endpoint (new in 3.0)

Revup speaks MCP (Model Context Protocol) on one route, so an assistant can watch your review pipeline and queue follow-ups without anyone building a bridge first.

POST /mcp
Authorization: Bearer apk_...          ← the SAME revocable key the REST API uses
Content-Type: application/json

Stateless streamable-HTTP: one JSON-RPC message per request, no session, no SSE. A GET gets 405 with Allow: POST, as the transport requires — and that answer is unauthenticated, so a client probing for MCP support learns you speak it before it has a key.

Connect it to an assistant

Mint the key in the app first: Settings → API keys. Choose Read only when the assistant should answer questions but never change anything — the endpoint then lists only the read tools and refuses the rest by name, so a careless prompt cannot write. Full access behaves as before.

Every client needs the same three facts, and nothing in the handshake is vendor-specific:

The addresshttps://reviews.example.com/mcp
The keyheader Authorization: Bearer apk_xxxx
The transportMCP over streamable HTTP, stateless

Claude — one command, or the same URL and header as a custom connector in the desktop and web apps:

claude mcp add --transport http revup https://reviews.example.com/mcp \
  --header "Authorization: Bearer apk_xxxx"

ChatGPT and the OpenAI API — one entry in the Responses API's tools array (in ChatGPT itself, the same URL and key go in as a connector):

{
  "type": "mcp",
  "server_label": "revup",
  "server_url": "https://reviews.example.com/mcp",
  "authorization": "apk_xxxx",
  "require_approval": "never"
}

Own Your AI reads a list of servers in this shape:

{
  "mcpServers": [
    { "id": "revup", "name": "Revup", "url": "https://reviews.example.com/mcp",
      "token": "apk_xxxx", "enabled": true }
  ]
}

**Every other client spells the same three facts differently — copy the shape from its own documentation, not from here.** VS Code is the clearest example of why: its configuration reference (read 6 September 2026) puts servers in .vscode/mcp.json under a "servers" object — *"an object that maps server names to their configurations"* — not an mcpServers array. Pasted as-is, the block above will not load there. The id, the URL and the token are what travel; the JSON around them belongs to whichever client you are configuring.

A local model, n8n, or your own code — n8n's MCP Client node takes the URL and the same Authorization: Bearer header; a model running on your own machine reaches it through any MCP client, so nothing leaves your network at all. Writing it yourself is one POST of JSON-RPC 2.0:

curl -X POST https://reviews.example.com/mcp \
  -H "Authorization: Bearer apk_xxxx" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Any client that speaks MCP's streamable-HTTP transport works, including ones that do not exist yet: Revup implements the protocol, not an integration with a particular vendor.

The tools

ToolWrites?What it does
list_requestsnoReview requests with status, rating and the customer they belong to. Filter by status, rated, limit.
request_detailnoOne request, plus any private feedback left against it.
create_requestYESQueues a review request for a customer and mints its one-time rating link.
response_statsnoResponse rate, average rating, how many raters opened your review page and how many left a private message — the dashboard's own figures.

status is queued (scheduled inside a send window), pending (waiting to be sent or copied), sent, or failed — the same four words the Requests screen uses.

What the endpoint refuses, and why

  • It cannot change the rating page. The threshold and the review URL are not writable over MCP. An agent may chase reviews; the page every customer sees stays with the owner.
  • No figure is recomputed. response_stats returns Revup::stats() — the same call the dashboard makes — so an agent can never quote a response rate Revup disagrees with.
  • create_request queues, it does not send. Sending goes out through your own SMTP, your own Twilio, or as a link you copy; that is the owner's action and the owner's cost.
  • It writes requests through the product's own creator, so the one-open-request-per-customer rule and token minting apply exactly as they do in the browser. A second request for a customer who already has one open is refused.
  • Arguments must be single values, unknown arguments are refused by name, and out-of-enum values are refused with the valid options listed.
  • Roles apply exactly as they do in the browser. A viewer's key is refused create_request.

Every MCP write lands in the audit trail beside the browser and API writes, naming the key's user as the actor and recording via: mcp.

Example

curl -X POST https://your-install/mcp \
  -H "Authorization: Bearer apk_..." -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"response_stats","arguments":{}}}'

Webhooks

Add a receiver in Settings → API & Webhooks and choose events:

EventFires when
request.sentA review request is dispatched
feedback.receivedA customer sends you a private message from the rating page — wire this to your helpdesk
rating.publicA customer opens your public review page from the rating page (any rating; once per request)

Every delivery is signed:

X-Revup-Event: feedback.received
X-Revup-Signature: sha256=<hmac_sha256(raw_body, your_webhook_secret)>

Compare with hash_hmac('sha256', $rawBody, $secret) and reject on mismatch.

Email notifications

Revup already had its own SMTP settings and mailer, so 2.0 adds no new mail configuration — just a notify address and one toggle in Settings: email me the moment a customer sends a private message. That is the one alert where minutes matter.

Errors

CodeMeaning
401Missing, unknown or revoked key
422Validation — detail names the offending field

← Back to Revup · Manual · Quickstart · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →