awaiting_approval, exactly as Approve on the panel does: what you approve is what runs. You can change a step first — a message’s wording, a note, an amount — in the fields its editable lists; each edit is checked again as if the agent had planned it. Steps that were due run now; later ones when they fall due.
Needs the
agents.plans:write scope.Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
plan_id | integer | Yes | The plan’s id. |
Body
| Field | Type | Required | Notes |
|---|---|---|---|
steps | array | No | Edits: { "id": <step id>, <field>: <new value> } for steps still pending. Fields a step doesn’t list in editable are ignored. |
note | string | No | A note kept with the decision. Up to 1,000 characters. |
Request
curl -X POST "https://api.fireflo.au/v1/agents/plans/4812/approve" \
-H "Authorization: Bearer $OMNI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: approve-4812" \
-d '{
"steps": [
{
"id": 20931,
"body": "Hi Neha, for 40 units we can do ₹6,350 each, delivered to Ludhiana within 10 days. Shall I send the revised quote?"
}
],
"note": "Fine — keep delivery at 10 days."
}'
import os
import requests
response = requests.post(
"https://api.fireflo.au/v1/agents/plans/4812/approve",
headers={
"Authorization": f"Bearer {os.environ['OMNI_API_KEY']}",
"Idempotency-Key": "approve-4812",
},
json={
"steps": [
{
"id": 20931,
"body": "Hi Neha, for 40 units we can do ₹6,350 each, delivered to Ludhiana within 10 days. Shall I send the revised quote?"
}
],
"note": "Fine — keep delivery at 10 days."
},
)
print(response.status_code, response.json())
const response = await fetch("https://api.fireflo.au/v1/agents/plans/4812/approve", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OMNI_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "approve-4812",
},
body: JSON.stringify({
"steps": [
{
"id": 20931,
"body": "Hi Neha, for 40 units we can do ₹6,350 each, delivered to Ludhiana within 10 days. Shall I send the revised quote?"
}
],
"note": "Fine — keep delivery at 10 days."
}),
});
console.log(response.status, await response.json());
Response
200 OK — the plan, now scheduled, with your edits.
{
"id": 4812,
"agent": {
"id": 7,
"name": "Arjun",
"role": "sales"
},
"scope": "contact",
"campaign_id": null,
"contact": {
"id": 90417,
"uuid": "3f6b2a1e-8c4d-4e2a-9b7f-5d1c0e8a9f42",
"name": "Neha Arora",
"msisdn": "+919876500102"
},
"deal": {
"id": 3318,
"title": "Arora Traders — 40 inverters",
"stage": "Quoted"
},
"pipeline": {
"id": 2,
"name": "B2B sales"
},
"trigger": "inbound_message",
"trigger_excerpt": "Can you do ₹6,200 per unit if we take 40?",
"goal": "Answer Neha's price question and keep the quote moving",
"rationale": "She asked for a lower unit price on a large order. The playbook allows up to 5% off above 25 units, so offer ₹6,350 and note it on the deal.",
"status": "scheduled",
"approval_mode": "plan",
"approval_reasons": [
"Send a message needs approval"
],
"created": "2026-10-06T10:14:22+05:30",
"expires_at": null,
"next_run_at": "2026-10-06T10:21:05+05:30",
"tokens": 2310,
"model": "gpt-4o-mini",
"decided_by": null,
"decision_note": "Fine — keep delivery at 10 days.",
"last_error": null,
"steps": [
{
"id": 20931,
"order": 1,
"action": "send_message",
"title": "Send WhatsApp message",
"body": "Hi Neha, for 40 units we can do ₹6,350 each, delivered to Ludhiana within 10 days. Shall I send the revised quote?",
"detail": "WhatsApp",
"reason": "Answer the price question while she is online.",
"run_at": "2026-10-06T10:21:05+05:30",
"requires_approval": true,
"status": "scheduled",
"result": null,
"editable": [
"body"
],
"params": {
"channel": "whatsapp",
"body": "Hi Neha, for 40 units we can do ₹6,350 each, delivered to Ludhiana within 10 days. Shall I send the revised quote?",
"channel_locked": true
}
},
{
"id": 20932,
"order": 2,
"action": "add_note",
"title": "Add note",
"body": "Offered ₹6,350/unit for 40 units (5% off list).",
"detail": null,
"reason": "Keep the team aware of the offer.",
"run_at": "2026-10-06T10:21:05+05:30",
"requires_approval": false,
"status": "scheduled",
"result": null,
"editable": [
"body"
],
"params": {
"body": "Offered ₹6,350/unit for 40 units (5% off list)."
}
},
{
"id": 20933,
"order": 3,
"action": "follow_up",
"title": "Follow up",
"body": null,
"detail": "Check whether Neha accepts the revised price",
"reason": "No reply by tomorrow means the quote needs a nudge.",
"run_at": "2026-10-07T11:00:00+05:30",
"requires_approval": false,
"status": "scheduled",
"result": null,
"editable": [],
"params": {
"goal": "Check whether Neha accepts the revised price"
}
}
],
"audience": null,
"story_id": null
}
Errors
Every refusal is{"error": {"code", "message", "field"}}; field is there when one input is at fault.
| Status | Error code | When |
|---|---|---|
| 400 | invalid_request | steps isn’t a list, or note is too long; field names it. |
| 404 | not_found | No plan of this account’s has that id. |
| 409 | invalid_state | The plan isn’t waiting for approval, or an edit isn’t allowed — the message names the step. |
| 404 | module_off | The account doesn’t have AI agents on: they aren’t in its plan, or are switched off for it. |
| 403 | scope_missing | The key doesn’t have the agents.plans:write scope. |
key_required, invalid_key, account_suspended, plan_excludes_api, address_not_allowed, rate_limited); see the overview.