REST and n8n
Call Felspar from code or an automation tool with three HTTP requests - brief, decision, verify - plus job lists and output checks.
Any code or automation that can send HTTP requests can use Felspar. Three calls cover the whole loop.
| Step | Request |
|---|---|
| 1. What does the job need? | GET https://api.felspar.ai/v0/jobs/{job}/brief |
| 2. Decide | POST https://api.felspar.ai/v0/jobs/{job}/decisions |
| 3. Verify before acting | POST https://api.felspar.ai/v0/executions/{executionObjectId}/verify |
Two more routes are there when you need them: GET /v0/jobs lists the jobs the key may run, and POST /v0/jobs/{job}/output-checks checks text written for a decision. The examples below use a fictional marketing team’s review-claim job, whose subject is a campaign asset identified by its asset ID.
Every request carries the agent’s key: Authorization: Bearer <agent key>. Get one from Register an agent.
1. Get the brief
curl -s https://api.felspar.ai/v0/jobs/review-claim/brief \
-H "Authorization: Bearer $FELSPAR_AGENT_KEY"
The brief is the same for every caller until a new release, so cache it per job. It starts with the job’s purpose and subject (subject.send says which ID to send), then lists each question’s key, what to send (answer.send), how it’s read (answer.interpretation), whether it applies always or only conditionally (answer.applies, appliesWhen), the answers with their meanings, where to look, the outcomes with next steps, the escalations, the attempt limit, the request limits, and input.jsonSchema, the exact request format.
2. Ask for a decision
curl -s https://api.felspar.ai/v0/jobs/review-claim/decisions \
-H "Authorization: Bearer $FELSPAR_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"mode": "facts",
"executionId": "3f2a6c1e-8b7d-4e0a-9c55-1d2e3f4a5b6c",
"jobId": "review-claim",
"entityId": "AST-5520",
"facts": {
"claim_kind": { "text": "Cuts onboarding time in half for every customer.",
"source": { "class": "campaign-asset", "id": "AST-5520", "locator": "AST-5520#headline", "observedAt": "2026-10-21T09:00:00Z" } }
}
}'
| Field | Meaning |
|---|---|
mode |
"facts": you send what sources say; Felspar decides the values |
executionId |
A new unique ID (a UUID) for each decision. Resend the same ID with the same body to retry safely; you get the original result. |
jobId |
The job, as in the path |
entityId |
The case’s ID, as the brief’s subject.send says: an asset ID, a ticket number, a contract ID, a domain |
related |
Only for questions about a related record: that record’s ID under its relationship name |
facts |
One entry per question key: an excerpt, a list of up to three, or for number and date questions a typed { value, source } |
expectedReleaseDigest |
Optional. Hold a specific release; refused with release_changed if it isn’t the one Felspar would use |
Send every question you have evidence for in one request, including conditional ones. A conditional question that doesn’t apply is never classified and doesn’t change the outcome. If one passage answers several questions, send the same text under each; those questions are classified together, faster.
See Decision result for the response.
3. Verify before acting
curl -s https://api.felspar.ai/v0/executions/$EXECUTION_OBJECT_ID/verify \
-H "Authorization: Bearer $FELSPAR_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{ "receipt": <result.receipt>, "expectedReceiptDigest": "<result.receipt.receiptDigest>" }'
Act only when status is reproduced and decided names the job, entity and an outcome that allows the action. When decided.escalation is present, route the case by its id instead of acting. See Verify receipts.
n8n
In n8n, use HTTP Request nodes:
- Credentials: create a Header Auth credential named
Felsparwith headerAuthorizationand valueBearer <agent key>. - Brief: an HTTP Request node,
GET, URLhttps://api.felspar.ai/v0/jobs/review-claim/brief, authenticationFelspar. Run it once and keep the question keys. - Gather evidence: your own nodes: fetch a page, read a CRM record. Map the exact text into the facts shape.
- Decide: an HTTP Request node,
POST, URLhttps://api.felspar.ai/v0/jobs/review-claim/decisions, JSON body as above, withexecutionIdset to a fresh UUID expression such as{{ $uuid() }}or your record’s own unique ID. - Branch: a Switch node on
result.escalation.idfirst (each escalation your workflow handles: a review queue, a message to the owner), then onresult.outcome. Treat anulloutcome as “not decided”: followresult.attempts.next. - Verify: before any node that acts, an HTTP Request node to the verify URL with the receipt; continue only on
reproduced.
n8n’s MCP Client node can also connect to https://mcp.felspar.ai/mcp with the same header, for n8n AI agents.
Handling errors
- 400 with
error,path,issues[]: the request was malformed. Each issue has apathand afix. Fix them all and resend; nothing was decided. - 403
forbidden: this key can’t run this job, or the release isn’t available to it. - 409
execution_id_reused: this execution ID was used for a different request. Use a new ID, or resend the original request unchanged. - 409
release_changed: read the brief again and resend. - 429
rate_limited: waitretryAfterSeconds(60) and resend the same request with the same execution ID.
All codes: Refusal codes.
Batch runs
Decide each entity in its own request, with all its questions together. Spread large runs over time to stay within rate limits, and hold one release for the whole run with expectedReleaseDigest, so a release mid-run doesn’t mix results. For runs of thousands of entities, talk to the Felspar team.