Graine AI
API referenceWorkflows

Create a workflow

A new workflow: a draft (empty, or the definition you send), its callback URL and signing secret, and a trigger URL that stays off until it is turned on.

A new workflow: a draft (empty, or the definition you send), its callback URL and signing secret, and a trigger URL that stays off until it is turned on.

Rate limit: 2000 requests per minute per organization, counted together with every endpoint that has no stricter limit of its own. Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.

POST
/v2/workflows
/v2/workflows

The Authorization access token

Authorization

Authorization
Required
Bearer <token>

Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.

In: header

Request Body

application/jsonRequired

nameName

Its name (a sample's name when omitted).

Maximum length: 120

descriptionDescription

What it is for.

Maximum length: 1000

definitionDefinition

Steps to start the draft with.

sampleSample

Start from a sample instead (GET /v2/workflow-samples): its id.

Maximum length: 64

agent_idAgent Id

With a sample: the agent for every one of its call steps.

Maximum length: 128

Response Body

201

The new workflow, with its draft.

id
Required
Id

The workflow's id.

name
Required
Name

Its name.

description
Required
Description

What it is for.

versions
Required
Versions

How many versions were published.

latest_versionLatest Version | null

The newest version's number.

agent_ids
Required
Agent Ids

The agents it calls with.

draft_revision
Required
Draft Revision

The draft's revision.

draft_saved_atDraft Saved At | null

When the draft was saved.

trigger_enabled
Required
Trigger Enabled

Whether its trigger URL is on.

created_byCreated By | null

Who created it.

created_atCreated At | null

When.

updated_atUpdated At | null

When it last changed.

published_atPublished At | null

When the newest version was published.

draft
Required
WorkflowDraft

The workflow's editable copy.

trigger
Required
WorkflowTrigger

The URL your system posts a contact to, to start a run.

call_triggerAny properties in WorkflowCallTrigger

app_startAny properties in WorkflowAppStart

callback_urlCallback Url | null

The workflow's callback URL: your system posts here and the body names the contact (only to a key that may edit and run).

signing_secretSigning Secret | null

Signs requests to the trigger and callback URLs (only to a key that may edit and run).

publishedPublished | null

Its versions, newest first (on a read of the workflow).

401

1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented instead of an API key.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

403

1102 — the key is valid but lacks the scope this endpoint requires, or names another organization. GET /v2/scopes reports what a key holds.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

404

1200 — no such resource in your organization. A resource belonging to another organization answers 404, never 403.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

422

1001 — the body or query failed validation; the message names the first offending field.

error
Required
integer

Stable integer code from the error table. Branch on this, not on the message.

message
Required
string

One human-readable sentence. Wording may change; the code will not.

429

1300 — the per-organization request rate or concurrent-call limit was reached. Carries Retry-After.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

curl -X POST "https://api.graine.ai/v2/workflows" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "New leads",
    "description": "Call every new lead within a minute.",
    "definition": {
      "entry_node_id": "start",
      "on_no_match": "unreached",
      "nodes": [
        {
          "id": "start",
          "type": "start",
          "config": {
            "fields": [
              {
                "name": "plan",
                "type": "string"
              }
            ]
          },
          "cases": [
            {
              "when": {
                "always": true
              },
              "then": {
                "to": "call"
              }
            }
          ]
        },
        {
          "id": "call",
          "type": "agent",
          "config": {
            "agent_id": "agt_0123",
            "timeout_s": 1800
          },
          "cases": [
            {
              "when": {
                "cmp": "==",
                "left": {
                  "var": "call.status"
                },
                "right": {
                  "const": "completed"
                }
              },
              "then": {
                "to": "done"
              }
            }
          ]
        },
        {
          "id": "done",
          "type": "end",
          "config": {
            "label": "reached",
            "outcome": "success"
          }
        },
        {
          "id": "unreached",
          "type": "end",
          "config": {
            "label": "unreached",
            "outcome": "failure"
          }
        }
      ]
    },
    "sample": "lead_qualification",
    "agent_id": "agt_0123"
  }'

The new workflow, with its draft.

{
  "id": "owf_8a1d4e7c2b90f1a2b3c4d5e6",
  "name": "New leads",
  "description": "Call every new lead within a minute.",
  "versions": 2,
  "latest_version": 2,
  "agent_ids": [
    "agt_0123"
  ],
  "draft_revision": 3,
  "draft_saved_at": "2026-10-25T09:30:00+00:00",
  "trigger_enabled": false,
  "created_by": "member-live-1a2b3c",
  "created_at": "2026-10-20T08:00:00+00:00",
  "updated_at": "2026-10-25T09:31:00+00:00",
  "published_at": "2026-10-25T09:31:00+00:00",
  "draft": {
    "definition": {
      "entry_node_id": "start",
      "on_no_match": "unreached",
      "nodes": [
        {
          "id": "start",
          "type": "start",
          "config": {
            "fields": [
              {
                "name": "plan",
                "type": "string"
              }
            ]
          },
          "cases": [
            {
              "when": {
                "always": true
              },
              "then": {
                "to": "call"
              }
            }
          ]
        },
        {
          "id": "call",
          "type": "agent",
          "config": {
            "agent_id": "agt_0123",
            "timeout_s": 1800
          },
          "cases": [
            {
              "when": {
                "cmp": "==",
                "left": {
                  "var": "call.status"
                },
                "right": {
                  "const": "completed"
                }
              },
              "then": {
                "to": "done"
              }
            }
          ]
        },
        {
          "id": "done",
          "type": "end",
          "config": {
            "label": "reached",
            "outcome": "success"
          }
        },
        {
          "id": "unreached",
          "type": "end",
          "config": {
            "label": "unreached",
            "outcome": "failure"
          }
        }
      ]
    },
    "revision": 3,
    "saved_at": "2026-10-25T09:30:00+00:00",
    "saved_by": "member-live-1a2b3c"
  },
  "trigger": {
    "enabled": false,
    "require_signature": true,
    "version": 2,
    "url": "https://api.graine.ai/v2/workflow-triggers/tk_example_trigger"
  },
  "call_trigger": {
    "enabled": true,
    "agent_ids": [
      "agt_0123"
    ],
    "statuses": [
      "no_answer",
      "busy"
    ],
    "directions": [
      "inbound",
      "app"
    ],
    "channels": [
      "call",
      "chat"
    ],
    "version": 2
  },
  "app_start": {
    "enabled": false,
    "fields": [
      "plan",
      "preferred_time"
    ],
    "version": 2
  },
  "callback_url": "https://api.graine.ai/v2/workflow-callbacks/cb_example_workflow",
  "signing_secret": "whsec_example_signing_secret",
  "published": []
}