n8n, Zapier and Make

HTTP node settings for calling Quorum from n8n, Zapier and Make, with a split routed to a person.

Each tool below calls Quorum with its HTTP node. The request is the same in all three.

MethodPOST
URLhttps://www.quorum.dog/v1/chat/completions
HeaderAuthorization: Bearer <your API key>
HeaderContent-Type: application/json
Timeout300 seconds

Body:

{
  "model": "QRUM:STAN",
  "messages": [
    { "role": "user", "content": "Should we refund this order? Customer message: ..." }
  ]
}

Create the key in your organization and store it in the tool's credential store. API keys bill the organization's API account. A deliberation runs several models, so raise the node's timeout to the value above.

The answer is at choices[0].message.content. Three fields on quorum tell the workflow what to do next:

FieldBranch
quorum.replayedtrue on a replay of an earlier call. A replay has no converged, remaining_friction, contested_passage or billed_usd, so check this first.
quorum.convergedfalse means the seats split. Send to a person.
quorum.remaining_frictionNot null also means a split. It is factual_conflict when the judge flagged a factual conflict between seats.

quorum.contested_passage is an object with seat, quote and why, or null. Put quote in the message to the person.

To see the Mode's surcharge and a verdict before you spend anything, call https://www.quorum.dog/v1/estimate with the same body. It is free. It returns estimated_price_usd and deliberation_value.verdict. The loop is estimate, deliberate, get_receipt, act.

n8n

  1. Add an HTTP Request node.
  2. Method POST. URL https://www.quorum.dog/v1/chat/completions.
  3. Authentication: Generic Credential Type, then Header Auth. Name Authorization, value Bearer <your API key>. Save it as a credential.
  4. Turn on Send Body. Body Content Type JSON. Specify Body Using JSON.
  5. Under Options, add Timeout and set it to 300000 (milliseconds).

Body, with the question taken from the previous node. JSON.stringify escapes quotes and line breaks:

{
  "model": "QRUM:STAN",
  "messages": [{ "role": "user", "content": {{ JSON.stringify($json.question) }} }]
}

Add an IF node after it. Condition, Boolean, is true: {{ $json.quorum.replayed === true || $json.quorum.converged === false || $json.quorum.remaining_friction != null }}. The true branch goes to your review step (Slack message, ticket, approval node) and the false branch continues. The replayed test comes first because a replay has no converged field.

Zapier

  1. Add an action: Webhooks by Zapier, event Custom Request.
  2. Method POST. URL https://www.quorum.dog/v1/chat/completions.
  3. Data: the JSON body above, with the question mapped from an earlier step.
  4. Headers: Authorization set to Bearer <your API key> and Content-Type set to application/json.
  5. Leave Unflatten on.

A question can contain quotes and line breaks. Build the body in a Code by Zapier step with JSON.stringify and map its output into the Data field, so the JSON stays valid.

Add a Paths step. The review path takes a response where quorum__replayed exists, quorum__converged is false, or quorum__remaining_friction exists. A replay has no quorum__converged field, so it needs its own rule.

Zapier limits how long an action waits for a response. Check the current limit for your plan against the 300-second timeout above. If the limit is shorter, call estimate in Zapier and run the deliberation from n8n or Make.

Make

  1. Add the HTTP module, action Make a request.
  2. URL https://www.quorum.dog/v1/chat/completions. Method POST.
  3. Headers: Authorization set to Bearer <your API key>, Content-Type set to application/json.
  4. Body type Raw. Content type JSON (application/json).
  5. Set Parse response to yes.
  6. Open Advanced settings and set Timeout to 300 seconds.

Build the request content with a Create JSON module or the JSON functions so the question is escaped. Then add a router after the HTTP module with a filter for the person-review route: quorum.replayed equals true, OR quorum.converged equals false, OR quorum.remaining_friction exists. A replay has no converged field, so it needs the first condition.

Idempotency

On any retry-prone trigger, add the header Idempotency-Key with a value that is stable for one question, such as the ticket id plus the step name. A repeat of a call that already succeeded replays the original answer and bills once. The replay matches on the key alone, so a key reused for a different question returns the first answer. The replay carries quorum.replayed: true. A call that ended capped is not replayed: a retry runs again and bills again.

Errors

rate_limit_exceeded and concurrency_limit_exceeded are 429 responses that carry a Retry-After header, in seconds. Set the node to retry on 429, 500 and 503, waiting the Retry-After value where the response has one. Branch on error.code, not on the message. All codes are in Errors and rate limits.

Next