REST API Reference
Apex REST resources shipped with FlowMason. All endpoints sit under ${OrgDomain}/services/apexrest/... and require session auth (the caller must hold the relevant permset).
Authentication
All endpoints honour the calling user's session, FLS, and CRUD via FMSecurityUtil. Two auth flows:
- Standard Salesforce OAuth.
Authorization: Bearer <session_id>. - Connected App. For headless integrations; consumer key/secret + Named Principal user with the required permset.
No API-key auth. Every call is on behalf of a real user.
Base URLs
| Family | Base | Permset |
|---|---|---|
| Pipeline runs | /services/apexrest/api/v1/runs/* | FlowMason_Pipeline_Runner |
| AI chat | /services/apexrest/api/v1/ai/* | FlowMason_Org_Chat_User |
| Templates | /services/apexrest/api/v1/templates/* | FlowMason_Pipeline_Author |
| Settings | /services/apexrest/api/v1/settings/* | FlowMason_Admin |
| Logs | /services/apexrest/api/v1/logs/* | FlowMason_Admin |
| Analytics | /services/apexrest/api/v1/analytics/* | FlowMason_Admin |
| Admin | /services/apexrest/api/v1/admin/* | FlowMason_Admin |
| Signal delivery | /services/apexrest/fm/v1/signal/* | (caller of WaitForSignal) |
Pipeline runs
POST /api/v1/runs/{pipelineId}. Start a pipeline
Body:
{
"input": { "accountId": "001000000000001" },
"executionMode": "sync"
} 200 sync response:
{
"status": "Completed",
"executionId": "uuid",
"output": { "summary": "..." }
} 202 async response:
{
"status": "Enqueued",
"executionId": "uuid",
"asyncJobId": "707..."
} GET /api/v1/runs/{executionId}. Poll a tracked run
{
"status": "Running",
"progress": 60,
"currentStage": "summarise",
"output": null
} GET /api/v1/runs/{executionId}/trace. Full ExecutionTrace
Returns the JSON shape documented in Pipeline JSON Schema § ExecutionTrace.
POST /api/v1/runs/{executionId}/cancel
Best-effort cancel; works on Running / Yielded / Paused.
AI Chat
POST /api/v1/ai/chat. Org Chat turn
{
"message": "show me 5 hot leads",
"conversationId": "uuid",
"surface": "tab",
"pipelineId": null,
"inventoryHint": null,
"objectScopeJson": null
} 200 response:
{
"reply": "Here are 5 hot leads...",
"query": "SELECT Id, Name FROM Lead WHERE Rating='Hot' LIMIT 5",
"records": [...],
"sobjectType": "Lead",
"columns": [...],
"executionId": "uuid",
"latencyMs": 1234,
"toolCalls": 2
} Errors return 200 with errorCode set in body (typed). Non-200 only for auth + transport failures.
POST /api/v1/ai/chat/dml/dryrun
Two-step DML preview. Returns a confirmation key for the apply leg.
POST /api/v1/ai/chat/dml/apply
Apply with confirmationKey. Single use; expires per cache TTL.
Templates / Settings / Logs / Analytics
GET /api/v1/templates— list templatesGET /api/v1/templates/{key}— fetch latest versionPOST /api/v1/templates— create or new versionGET /api/v1/settings/providers— provider list + healthGET /api/v1/settings/config—FM_Config__mdtsnapshotGET /api/v1/settings/models— model registryGET /api/v1/logs/runs?pipelineId=X&limit=50— recentPipelineExecution__cGET /api/v1/logs/stage/{executionId}— per-stage log arrayGET /api/v1/analytics/summary?since=...— aggregates fromFM_Run_Audit__c
Admin
GET /api/v1/admin/health
{
"status": "healthy",
"providers": [...],
"cronJobs": [
{ "name": "FM Org Inventory Nightly", "state": "WAITING", "nextFireTime": "..." }
],
"subscribers": [
{ "trigger": "FlowMasonRunSubscriber", "active": true }
],
"cacheAvailable": true
} Signal delivery
POST /fm/v1/signal/{signalName}. Wake a WaitForSignal stage
{
"executionId": "uuid",
"payload": { "approved": true, "approver": "005..." }
} Inserts a FM_Signal__c row; the runtime resumes the paused pipeline and threads the payload into context. Lets external systems deliver approval / webhook callbacks without a Salesforce SDK.
Error envelope
{
"errorCode": "FM_VALIDATOR_REJECTED",
"errorMessage": "SOQL contains DML keyword",
"executionId": "uuid"
} Typed error codes:
| Code | HTTP | Meaning |
|---|---|---|
FM_PERMSET_DENIED | 403 | Caller lacks required permset |
FM_SURFACE_DISABLED | 403 | Surface token not in orgChatSurfacesEnabled |
FM_OBJECT_NOT_ALLOWLISTED | 403 | SObject not in FM_Org_Chat_Allowlist__mdt |
FM_VALIDATOR_REJECTED | 400 | FMSoqlValidator 8-gate failure |
FM_RATE_LIMITED | 429 | Per-user / per-org cap |
FM_PROVIDER_TIMEOUT | 504 | Provider exceeded providerTimeoutMs |
FM_GOVERNOR_LIMIT | 503 | Hard governor breach |
FM_PIPELINE_NOT_FOUND | 404 | No matching MDT or object row |
FM_PIPELINE_VALIDATION | 400 | PipelineValidator rejected on load |
FM_DML_REFUSED | 403 | One of three DML fail-closed gates blocked |
Rate limits
| Endpoint | Cap | Config key |
|---|---|---|
/ai/chat | 60 / user / min | orgChatMaxTurnsPerMinutePerUser |
/ai/chat/dml/apply | 3 / user / min | orgChatDmlMaxConfirmationsPerMinute |
Salesforce platform also imposes per-org REST limits — typically 1M requests / 24 h on Enterprise.
CORS
Salesforce REST API rejects cross-origin browser calls by default. For LWC / Visualforce in the same org, no CORS needed. For external SPAs, add the origin under Setup → CORS.