Skip to content

Pipedream and any HTTP tool

Anything that can send an HTTP request can use Curva: Pipedream, Power Automate, Retool, Airtable automations, a webhook in your own app. There is one call to make and one to send feedback.

POST {base}/v1/decide Authorization: Bearer curva_… Content-Type: application/json
{"state": <any JSON>, "questions": {<key>: <question>}, "project": "…"}
→ {"id": "dec_…", "answers": {<key>: {"choice" | "score" | "noul" | "selected", "confidence", "abstain", …}}}
POST {base}/v1/feedback {"decision_id": "dec_…", "question": <key>, "label": <true answer>}

Question types, options and every response field are in the HTTP API reference. The OpenAPI spec at GET /openapi.json describes it for tools that import one.

Every tool has some branch step (Paths, Router, Switch, If). Branch in this order:

  1. answers.<key>.abstain is true → a human task. It is set only when the question has min_confidence, so set it on any question that routes work.
  2. answers.<key>.choice equals an option key → that route. none_of_these is a possible choice (the escape option) unless the question sets "escape": false; send it to a human too.
  3. A Noul answer is P(yes): compare answers.<key>.noul with a threshold (for example > 0.9).

Keep id next to what you created; it is how feedback finds the decision later.

In a workflow, add a Node.js code step after the trigger. Put the server URL and key in environment variables (CURVA_BASE_URL, CURVA_API_KEY):

export default defineComponent({
async run({ steps, $ }) {
const res = await fetch(`${process.env.CURVA_BASE_URL}/v1/decide`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.CURVA_API_KEY}` },
body: JSON.stringify({
project: "support",
state: { ticket: steps.trigger.event.body.text },
questions: {
department: { type: "choice", instructions: "Which team should handle this",
options: { billing: "Payments, refunds", technical: "Bugs" }, min_confidence: 0.8 }
}
})
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.type}: ${data.error.message}`);
return data;
}
});

Later steps read steps.curva.$return_value.answers.department.choice (name the step curva). Branch with If/Else or Switch on it, following the routing pattern above. Feedback is the same fetch to /v1/feedback.

  • Use the tool’s HTTP or webhook action with method POST, a raw JSON body and the two headers.
  • Build the body with the tool’s JSON helper (or a code step) rather than pasting mapped text into a JSON template: quotes and newlines in the text would break it.
  • A 429 carries Retry-After (seconds); retry after it. A 502 means no model could answer; retry later. Other 4xx errors name the problem in error.message.

© 2026 Tarkova Private Limited.