API reference
Integrate in one POST
Send your automation's output to LoopQuest, a human reviews it, and a signed verdict webhooks back to you. Full machine-readable spec: openapi.json.
SDKs & no-code
Prefer not to hand-roll HTTP? These are drop-in, all backed by the same API:
TypeScript / Node SDK — @tomphillipsai/loopquest-sdk
npm i @tomphillipsai/loopquest-sdk
import { LoopQuest } from "@tomphillipsai/loopquest-sdk";
const lq = new LoopQuest({ apiKey: process.env.LOOPQUEST_KEY });
const { id } = await lq.createTask({
module: "swiper",
payload: { content },
callback_url: "https://your-app.com/loopquest/verdict",
});n8n — community node n8n-nodes-loopquest (Settings → Community Nodes). A Create Review Task action plus a Verdict trigger that fires when a human decides.
Dify — the LoopQuest tool plugin: Create review task and Get task status nodes for your workflows. Source.
Zapier — zapier-loopquest: a Create Review Task action; pair with Webhooks by Zapier for the verdict.
Make — make-loopquest: a custom app (or import the OpenAPI spec), with an instant webhook for verdicts.
Building elsewhere? The OpenAPI spec imports as a custom tool on most platforms.
Authentication
Bearer token on every request: a project API key(Workspaces → your project → API keys). Every task belongs to that key's project, and a key only ever reaches its own project's data — there is no shared pool.
Authorization: Bearer <your-key>
Ingest a task — POST /api/v1/tasks
curl -X POST https://loopquest.tomphillips.uk/api/v1/tasks \
-H "authorization: Bearer $LOOPQUEST_KEY" \
-H "content-type: application/json" \
-H "idempotency-key: order-4821" \
-d '{
"module": "swiper",
"source": "zendesk",
"payload": { "ticket": 4821, "predicted": "auto-approve" },
"card": {
"title": "Refund #4821",
"suggestion": { "label": "Auto-approve", "confidence": 0.96 },
"fields": [{ "label": "Amount", "value": "£2,400", "highlight": true }]
},
"callback_url": "https://your-app.com/loopquest/verdict",
"reviews_required": 2
}'Returns 201 { "id", "status" }. Optional fields: card (display hints incl. choices for multi-class), reviews_required (consensus), and golden + answer (calibration tasks).
Idempotency
Send an Idempotency-Key header. A retried POST with the same key returns the original task (200) instead of creating a duplicate.
Poll status — GET /api/v1/tasks/{id}
curl https://loopquest.tomphillips.uk/api/v1/tasks/<id> \
-H "authorization: Bearer $LOOPQUEST_KEY"
# { "id", "status": "reviewed", "verdict": true, "verdict_choice": null, ... }Scoped to your workspace — keys can only read their own org's tasks.
Verdict webhooks (signed)
When a task resolves, LoopQuest POSTs the verdict to your callback_url, signed with HMAC-SHA256 over the raw body in the X-LoopQuest-Signature header. Failed deliveries retry (up to 5 times). Verify before trusting:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Payload: { task_id, external_id, source, module, verdict, choice, reason, escalated, timed_out, reviewed_at }. verdict is true (approved), false (flagged) or null (escalated); external_id is echoed back so you can correlate the item you sent.
Verdict subscriptions — /api/v1/hooks
Instead of a per-task callback_url, subscribe one URL to everyverdict in your workspace. This powers the instant “New Verdict” triggers in no-code tools (Make, Zapier), which subscribe on activation and unsubscribe when turned off. Subscriptions are idempotent by URL.
curl -X POST https://loopquest.tomphillips.uk/api/v1/hooks \
-H "authorization: Bearer $LOOPQUEST_KEY" \
-H "content-type: application/json" \
-d '{ "url": "https://your-app.com/loopquest/verdict" }'
# -> { "id", "url", "event": "verdict" }
curl https://loopquest.tomphillips.uk/api/v1/hooks -H "authorization: Bearer $LOOPQUEST_KEY" # list
curl -X DELETE https://loopquest.tomphillips.uk/api/v1/hooks/<id> -H "authorization: Bearer $LOOPQUEST_KEY" # removeEach subscribed delivery is signed exactly like a callback_url verdict.
Rate limits
120 requests per 60 seconds per key. Over the limit returns 429 with a Retry-After header.