Skip to content
Felspar
Esc
↑↓navigate↵open⌘Jpreview
On this page

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:

  1. Credentials: create a Header Auth credential named Felspar with header Authorization and value Bearer <agent key>.
  2. Brief: an HTTP Request node, GET, URL https://api.felspar.ai/v0/jobs/review-claim/brief, authentication Felspar. Run it once and keep the question keys.
  3. Gather evidence: your own nodes: fetch a page, read a CRM record. Map the exact text into the facts shape.
  4. Decide: an HTTP Request node, POST, URL https://api.felspar.ai/v0/jobs/review-claim/decisions, JSON body as above, with executionId set to a fresh UUID expression such as {{ $uuid() }} or your record’s own unique ID.
  5. Branch: a Switch node on result.escalation.id first (each escalation your workflow handles: a review queue, a message to the owner), then on result.outcome. Treat a null outcome as “not decided”: follow result.attempts.next.
  6. 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 a path and a fix. 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: wait retryAfterSeconds (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.

Was this page helpful?