{"components":{"parameters":{"IdempotencyKey":{"description":"OPTIONAL — omit it and this operation behaves exactly as it always has. A unique value (a UUID) you choose per request. A retry with the same key and the same method, path and body within 24 hours gets the first response replayed (status and body, with `Idempotent-Replayed: true`) instead of running again; the same key with a different request is refused with 422. A 5xx is not stored, so that retry runs. A one-time credential is never stored: on a replay any `secret` is null, with an `idempotentReplayNote` explaining it.","in":"header","name":"Idempotency-Key","required":false,"schema":{"maxLength":255,"minLength":1,"type":"string"}}},"schemas":{"Actor":{"description":"The person acting in your portal; at least one of name/email","properties":{"email":{"type":"string"},"name":{"type":"string"}},"type":"object"},"Approval":{"properties":{"approver":{"type":"string"},"body":{"type":"string"},"completedAt":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"decidedBy":{"properties":{"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"executionId":{"type":"string"},"expiresAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"reference":{"type":"string"},"response":{"type":"string"},"status":{"enum":["pending","approved","rejected","expired"],"type":"string"},"subject":{"type":"string"},"type":{"enum":["single","group"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","executionId","type","approver","status","subject","createdAt","updatedAt"],"type":"object"},"Branding":{"properties":{"accentColor":{"type":"string"},"brandColor":{"type":"string"},"displayName":{"type":"string"},"favicon":{"type":"string"},"logo":{"description":"data: URL","type":"string"},"logoDark":{"type":"string"},"organisationId":{"type":"string"}},"required":["organisationId","displayName"],"type":"object"},"Client":{"properties":{"createdAt":{"format":"date-time","type":"string"},"environment":{"enum":["cloudOnly","onPremOnly","cloudAndOnPremSeparate","cloudAndOnPremSynced"],"type":"string"},"googleWorkspaceDomains":{"items":{"type":"string"},"type":"array"},"id":{"type":"string"},"integrationMappingIds":{"additionalProperties":{"type":"string"},"description":"The client's id in each client-mapped integration (PSA company, RMM site, …), keyed by that integration's mapping key — e.g. `haloId`, `connectwiseId`, `autotaskId`, `dattoSiteId`. Only keys that are set appear; several ids are joined by commas (no spaces). `{}` when unmapped.","type":"object"},"microsoftDomain":{"type":"string"},"microsoftTenantId":{"type":"string"},"name":{"type":"string"}},"required":["id","name","environment","microsoftTenantId","microsoftDomain","googleWorkspaceDomains","integrationMappingIds","createdAt"],"type":"object"},"CoreCatalogueEntry":{"properties":{"availability":{"type":"string"},"configured":{"type":"boolean"},"kind":{"enum":["provisioning","lookup","other"],"type":"string"},"listedOnHomepage":{"type":"boolean"},"name":{"type":"string"},"publicUrl":{"format":"uri","type":"string"},"slug":{"type":"string"}},"required":["slug","name","kind","configured","listedOnHomepage"],"type":"object"},"CoreConfigResponse":{"properties":{"base":{"$ref":"#/components/schemas/CoreWorkflowConfig"},"client":{"oneOf":[{"$ref":"#/components/schemas/CoreWorkflowConfig"},{"type":"null"}]},"policyQuestions":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"slug":{"type":"string"}},"required":["slug","base","client"],"type":"object"},"CoreConfigWrite":{"description":"Merge semantics: omitted keeps, null clears (formConfig/execConfig), an object replaces the whole section","properties":{"availability":{"description":"inherit is valid on a client override only","enum":["disabled","internal","public","both","inherit"],"type":"string"},"execConfig":{"additionalProperties":true,"nullable":true,"type":"object"},"formConfig":{"additionalProperties":true,"nullable":true,"type":"object"},"listOnHomepage":{"description":"Base only","type":"boolean"}},"type":"object"},"CoreForm":{"properties":{"availability":{"enum":["disabled","internal","public","both"],"type":"string"},"clientOverrides":{"items":{"properties":{"availability":{"nullable":true,"type":"string"},"enabled":{"type":"boolean"},"tenantId":{"type":"string"},"tenantName":{"type":"string"}},"type":"object"},"type":"array"},"embeddable":{"description":"Whether a session can be created for the form: true exactly when public. A client override can still withdraw it for one client (client_not_entitled)","type":"boolean"},"enabled":{"type":"boolean"},"internal":{"type":"boolean"},"listedOnHomepage":{"type":"boolean"},"name":{"type":"string"},"public":{"type":"boolean"},"publicUrl":{"format":"uri","type":"string"},"slug":{"type":"string"}},"required":["slug","name","enabled","availability","internal","public","embeddable","listedOnHomepage","clientOverrides"],"type":"object"},"CoreRequest":{"properties":{"clientId":{"type":"string"},"clientName":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"error":{"type":"string"},"executionId":{"type":"string"},"failedStep":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"source":{"enum":["public","internal","api"],"type":"string"},"status":{"description":"Live execution status when executionId is set; else the status recorded at submit time","type":"string"},"subject":{"type":"string"},"submitter":{"properties":{"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","slug","name","status","source","submitter","createdAt","updatedAt"],"type":"object"},"CoreRequestDetail":{"allOf":[{"$ref":"#/components/schemas/CoreRequest"},{"properties":{"fields":{"items":{"properties":{"label":{"type":"string"},"value":{"type":"string"}},"required":["label","value"],"type":"object"},"type":"array"}},"required":["fields"],"type":"object"}]},"CoreWorkflowConfig":{"properties":{"availability":{"description":"null on a client override = inherits the base","enum":["disabled","internal","public","both",null],"nullable":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"enabled":{"type":"boolean"},"etag":{"description":"Send back as If-Match on a PUT","type":"string"},"execConfig":{"additionalProperties":true,"nullable":true,"type":"object"},"formConfig":{"additionalProperties":true,"nullable":true,"type":"object"},"listOnHomepage":{"type":"boolean"},"updatedAt":{"format":"date-time","type":"string"}},"required":["enabled","availability","listOnHomepage","formConfig","execConfig","etag","createdAt","updatedAt"],"type":"object"},"Error":{"properties":{"error":{"type":"string"}},"required":["error"],"type":"object"},"Execution":{"properties":{"clientId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"status":{"enum":["pending","running","paused","completed","failed"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"workflowId":{"type":"string"},"workflowName":{"type":"string"}},"required":["id","workflowId","workflowName","status","createdAt","updatedAt"],"type":"object"},"ExecutionDetail":{"allOf":[{"$ref":"#/components/schemas/Execution"},{"properties":{"error":{"type":"string"},"failedStep":{"type":"string"},"output":{"additionalProperties":true,"type":"object"},"source":{"description":"core / core_public / core_api for Core-started runs","type":"string"}},"type":"object"}]},"ExecutionStep":{"properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"label":{"type":"string"},"outcome":{"enum":["pending","running","success","error"],"type":"string"},"stepId":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","stepId","label","outcome"],"type":"object"},"Form":{"properties":{"authType":{"enum":["none","password","microsoft","google","internal"],"type":"string"},"embeddable":{"description":"Whether the form can be embedded in a third-party portal through a form session: true for microsoft, google and none; false for password and internal (a session request is refused with form_session_unsupported). Branch on this rather than on authType","type":"boolean"},"id":{"type":"string"},"listedOnHomepage":{"type":"boolean"},"name":{"type":"string"},"shareUrl":{"format":"uri","type":"string"},"updatedAt":{"description":"When the form (including its fields) last changed, through any path","format":"date-time","type":"string"}},"required":["id","name","shareUrl","authType","embeddable","listedOnHomepage","updatedAt"],"type":"object"},"FormSession":{"properties":{"embedUrl":{"format":"uri","type":"string"},"expiresIn":{"description":"Seconds the single-use handle stays redeemable (120). 0 when no handle is issued (provider none). Not the signed-in session's lifetime, which is 30 minutes from mint","type":"integer"},"formSessionHandle":{"description":"Absent only for a none form requested with no user","type":"string"},"provider":{"enum":["microsoft","google","portal","none"],"type":"string"}},"required":["expiresIn","provider","embedUrl"],"type":"object"},"FormSessionRequest":{"properties":{"user":{"properties":{"clientId":{"description":"Alternative to microsoftTenantId: the client the user belongs to (GET /api/v1/clients). For a none form, the client the submission is attributed to","type":"string"},"microsoftTenantId":{"description":"The user's Microsoft tenant ID. Required for microsoft forms unless clientId is given; ignored for google forms","type":"string"},"userIdentifier":{"description":"Microsoft object ID or UPN (microsoft), Google Workspace email (google), or the portal user's identifier, e.g. their email (none — optional)","type":"string"}},"type":"object"}},"type":"object"},"ManualStep":{"properties":{"completedAt":{"format":"date-time","type":"string"},"completedBy":{"properties":{"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"createdAt":{"format":"date-time","type":"string"},"executionId":{"type":"string"},"formId":{"type":"string"},"id":{"type":"string"},"instructions":{"type":"string"},"status":{"description":"cancelled appears only in webhook payloads (a kill closed the step)","enum":["pending","completed","cancelled"],"type":"string"},"title":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","executionId","title","status","createdAt","updatedAt"],"type":"object"},"OptionList":{"properties":{"options":{"items":{"properties":{"default":{"type":"string"},"label":{"type":"string"},"preselect":{"type":"boolean"},"required":{"type":"boolean"},"type":{"type":"string"},"value":{"type":"string"}},"required":["label","value"],"type":"object"},"type":"array"}},"required":["options"],"type":"object"},"RunForm":{"description":"The public projection of an assembled run form (see /api/v1/core/schema for field shapes)","properties":{"approval":{"properties":{"mode":{"enum":["none","internal","external"],"type":"string"}},"type":"object"},"availability":{"type":"string"},"enabled":{"type":"boolean"},"identity":{"additionalProperties":true,"type":"object"},"sections":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"slug":{"type":"string"}},"type":"object"},"SessionError":{"description":"A form-session refusal. `error.code` is from a closed set and each code keeps its HTTP status between releases; branch on the pair. `retryable` is true only when the same request can succeed later. `message` is for an operator, not an end user.\n\n| code | status | retryable | meaning |\n|---|---|---|---|\n| `invalid_request` | 400 | no | The request is malformed or incomplete — e.g. a missing `userIdentifier` or tenant for a microsoft form |\n| `invalid_api_key` | 401 | no | The API key is missing, malformed, revoked or expired |\n| `rate_limited` | 429 | yes | Too many requests for this key — wait `Retry-After` seconds |\n| `form_not_found` | 404 | no | No such form in this organisation (a deleted Studio form is not found) |\n| `form_unpublished` | 400 | no | Core only: the form is not available publicly (disabled or internal-only) |\n| `form_session_unsupported` | 400 | no | The form's authType cannot take a session (`password` or `internal`) |\n| `client_not_found` | 404 | no | `clientId` is not one of this organisation's clients |\n| `client_not_connected` | 404 | no | The client has no Microsoft tenant configured, so a microsoft session cannot be resolved for it |\n| `client_not_entitled` | 400 | no | Core only: the client's override makes the form unavailable publicly for that client |\n| `tenant_not_connected` | 403 | no | The user's Microsoft tenant (or Google Workspace domain) is not a client this organisation manages |\n| `user_not_found` | 404 | no | The user does not exist in that client's directory — invite them, then retry |\n| `invalid_user_identifier` | 400 | no | Microsoft or Google rejected the `userIdentifier` — give an object ID, UPN or Workspace email |\n| `microsoft_permission_denied` | 403 | no | The organisation's Microsoft connection is not permitted to read this user — fix the connection's permissions |\n| `microsoft_unavailable` | 503 | yes | Microsoft is throttling or temporarily unavailable — retry after `Retry-After` seconds |\n| `microsoft_connection_failed` | 500 | no | The organisation's Microsoft connection itself isn't working (not configured, consent lapsed, token refused) — an administrator must reconnect it |\n| `internal_error` | 500 | yes | An unexpected error on Triggr's side |\n| `forbidden` | 403 | no | Catch-all: refused for a reason no specific code covers yet |\n| `not_found` | 404 | no | Catch-all: something the request names was not found |\n| `unavailable` | 503 | yes | Catch-all: a dependency is unavailable |\n| `unknown` | — | no | Catch-all for any other refusal. New causes appear as a new code — the field is never omitted |\n","properties":{"error":{"properties":{"code":{"enum":["invalid_request","invalid_api_key","rate_limited","form_not_found","form_unpublished","form_session_unsupported","client_not_found","client_not_connected","client_not_entitled","tenant_not_connected","user_not_found","invalid_user_identifier","microsoft_permission_denied","microsoft_unavailable","microsoft_connection_failed","internal_error","forbidden","not_found","unavailable","unknown"],"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"],"type":"object"}},"required":["error"],"type":"object"},"Webhook":{"properties":{"active":{"type":"boolean"},"consecutiveFailures":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"disabledReason":{"type":"string"},"events":{"items":{"type":"string"},"type":"array"},"id":{"type":"string"},"lastDeliveryAt":{"format":"date-time","type":"string"},"lastError":{"type":"string"},"url":{"format":"uri","type":"string"}},"required":["id","url","events","active","consecutiveFailures","createdAt"],"type":"object"},"WebhookAttempt":{"description":"The first attempt of a delivery made on demand (test ping or redeliver). `status` pending means that attempt failed and the cron will retry the same row","properties":{"attempts":{"type":"integer"},"deliveryId":{"description":"The DELIVERY ROW id, sent as X-Triggr-Delivery-Id on every attempt and listed by GET …/deliveries — not the event id inside the envelope","type":"string"},"error":{"type":"string"},"status":{"description":"pending = failed this attempt, will be retried","enum":["pending","delivered","failed","unknown"],"type":"string"},"statusCode":{"nullable":true,"type":"integer"}},"required":["deliveryId","status","attempts","statusCode","error"],"type":"object"},"WebhookDelivery":{"properties":{"attempts":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"deliveredAt":{"format":"date-time","type":"string"},"error":{"type":"string"},"event":{"type":"string"},"id":{"description":"Delivery row id — the value sent as X-Triggr-Delivery-Id on every attempt of this delivery. A redelivery of the same event is a new row, with a different one","type":"string"},"nextAttemptAt":{"format":"date-time","type":"string"},"status":{"enum":["pending","delivered","failed"],"type":"string"},"statusCode":{"nullable":true,"type":"integer"}},"required":["id","event","status","attempts","createdAt"],"type":"object"},"WebhookEnvelope":{"description":"The JSON body of every webhook delivery","properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":true,"description":"The event's object: ExecutionDetail, Approval, ManualStep, CoreRequest, Form, Client or CoreForm — or { id, deletedAt } for a *.deleted event","type":"object"},"event":{"type":"string"},"id":{"description":"EVENT id — unchanged across retries and redeliveries, so it is your dedupe key. The delivery row carrying it is named by the X-Triggr-Delivery-Id header instead","type":"string"},"organisationId":{"type":"string"}},"required":["id","event","createdAt","organisationId","data"],"type":"object"},"WebhookRedelivery":{"description":"A redelivery's first attempt plus the NEW delivery row it created — prepend `delivery` to your list rather than reconstructing it","properties":{"attempts":{"type":"integer"},"delivery":{"$ref":"#/components/schemas/WebhookDelivery"},"deliveryId":{"description":"The NEW delivery row's id (also `delivery.id`). The event id inside the re-posted envelope is still the original's","type":"string"},"error":{"type":"string"},"status":{"enum":["pending","delivered","failed","unknown"],"type":"string"},"statusCode":{"nullable":true,"type":"integer"}},"required":["delivery","deliveryId","status","attempts","statusCode","error"],"type":"object"},"Workflow":{"properties":{"active":{"type":"boolean"},"folderPath":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"updatedAt":{"description":"When the workflow or its definition last changed, through any path","format":"date-time","type":"string"}},"required":["id","name","active","folderPath","updatedAt"],"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"bearerFormat":"tpk_…","description":"Organisation API key. Scoped operations carry x-triggr-scope; the scopes themselves are described in x-triggr-scopes.","scheme":"bearer","type":"http"}}},"info":{"description":"The API an MSP's own portal (or a partner acting for it) uses to wrap Triggr: list clients, forms, workflows, executions and Core requests; embed forms as a signed-in user; run Core forms natively; act on approvals and manual steps; configure Core workflows; and receive events by webhook.\n\nAuthentication: every request carries an organisation API key as `Authorization: Bearer tpk_…` (issued on the API Keys settings page; shown once). Every key can read the catalogue and mint form sessions; `core:run`, `core:configure` and `executions:manage` are opt-in scopes chosen when the key is created — see `x-triggr-scopes` and each operation's `x-triggr-scope`.\n\nRate limits: 600 requests/min per key (bursts to 200) for reads and 60/min (bursts to 30) for writes; form-session mints have their own 120/min (bursts to 120). Authenticated responses carry `X-RateLimit-Limit` / `X-RateLimit-Remaining` (exposed to browsers); a 429 carries `Retry-After`.\n\nPaging: lists take `limit` (default 50, max 100) and `offset` and return `total` + `hasMore`; `since` (RFC 3339) is accepted where an operation declares it (executions, Core requests).\n\nIdempotency is OPTIONAL and opt-in: send nothing and every endpoint behaves exactly as before — existing integrations need change nothing. The operations that start or decide something (run a Core form, approve / reject, complete a manual step, cancel / retry an execution, register a webhook) additionally accept an `Idempotency-Key` header (1–255 characters; use a UUID per request). Retry a timed-out call with the same key and the same method, path and body within 24 hours and you get the first response back — status and body — flagged `Idempotent-Replayed: true`, instead of a second run. The same key with a different request is refused with 422; a repeat while the first is still in flight is a 409; a 5xx is never stored, so that retry runs for real. Keys are scoped to the API key that sent them.\n\nOne-time values are the exception, and deliberately so: a webhook signing `secret` and a Core run's `secret` (the new starter's temporary password) are never written to our store, so a REPLAYED response carries `\"secret\": null` and an `idempotentReplayNote` saying where to get a fresh one. Record those from the original response — a replay cannot give them back.\n\nWebhooks: a delivery is a POST carrying `X-Triggr-Signature`, `X-Triggr-Event`, `X-Triggr-Delivery-Id` and `User-Agent: Triggr-Webhooks/1.0`, with a `WebhookEnvelope` body. Mind the two ids: the envelope's `id` names the EVENT and is unchanged across retries and redeliveries, so it is your dedupe key; `X-Triggr-Delivery-Id` names the DELIVERY ROW — the same on every retry of that delivery, new on a redelivery — and matches a row in the Deliveries list. Verify the signature by accepting the header if any `v1` matches your secret — there are two for 24 hours after a rotation.\n\n## Embedding\n\n**Which forms can be embedded.** A form can be embedded in your portal exactly when its `embeddable` field is true (every form in `GET /api/v1/forms`, `GET /api/v1/forms/{formId}` and the Core forms list and detail carries it). By auth type: `microsoft` and `google` — yes, as the signed-in user, through a form session; `none` (public) — yes, through a form session that attributes the submission to your portal user and client, or plainly from `shareUrl` (anonymous); `password` and `internal` — no: a session request is refused with `form_session_unsupported`, and neither can sign a visitor in inside a third-party frame. Core forms are embeddable when `public` (Microsoft sign-in). Branch on `embeddable`, not on your own list of auth types.\n\n**When a session ends.** Inside your frame, the form page tells your page when its embedded session can't be used, with `window.parent.postMessage({ type: \"triggr:form-session\", state }, \"*\")` — exactly those two fields, no token. `state` is `\"error\"` when the handle couldn't be redeemed (already used, expired, or rate-limited past its retry) and `\"expired\"` when the signed-in session lapsed (noticed on reload or submit — and, on a Core form, on a lookup) — at most once per lapse. Nothing is posted when the page isn't framed. Listen for it, check `event.origin` equals your stored embed origin (`formsOrigin` / `coreFormsOrigin`), then mint a fresh session and replace the iframe's `src` with its `embedUrl`; without that, the visitor is left on a \"reopen the form\" message.\n\n**The embed host.** Every `embedUrl` and `shareUrl` begins with the organisation's canonical embed origin: `scheme://host[:port]` — `https`, lower-case host, no path, no trailing slash, no default port. It is the same for every form and session and does not change between releases — only if you change your forms domain — and `GET /api/v1/me` returns it as `formsOrigin` (Studio) and `coreFormsOrigin` (Core). Store that value as your embed host, and before framing a session compare it byte-for-byte with the ORIGIN of the returned `embedUrl` (`new URL(embedUrl).origin`; in .NET `new Uri(embedUrl).GetLeftPart(UriPartial.Authority)`). Worked example — stored embed host `https://forms.acme-msp.com`; `embedUrl` `https://forms.acme-msp.com/forms/org_2Ab3/9c8d…?formSession=3f9a…` → origin `https://forms.acme-msp.com` → match. With no custom forms domain the origin is `https://app.triggr-app.com` (Studio) or `https://core.triggr-app.com` (Core). If you store a bare host instead (`forms.acme-msp.com`), compare it with the URL's host component, lower-cased.\n\nErrors are `{ \"error\": \"…\" }`: 400 your request, 401 the key, 403 scope or not your client, 404 not found, 412 a stale If-Match, 429 rate limit, 503 a dependency such as the on-prem agent. The two form-session endpoints instead answer `{ \"error\": { \"code\", \"message\", \"retryable\" } }` (SessionError). Timestamps are RFC 3339 UTC.","title":"Triggr Public API","version":"1.4.0"},"openapi":"3.0.3","paths":{"/api/v1/approvals":{"get":{"description":"Runs paused for sign-off.","parameters":[{"description":"","in":"query","name":"status","required":false,"schema":{"enum":["pending","approved","rejected","expired"],"type":"string"}},{"description":"Page size, default 50, max 100","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"approvals":[{"approver":"manager@acme.com","body":"Jane Doe leaves on 12 September. Approve to start the offboarding run.","createdAt":"2026-09-07T10:00:30Z","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","expiresAt":"2026-09-09T10:00:00Z","id":"a7c19f02-8d3e-4b61-9f5a-2c8e7d4b1a03","reference":"REQ-4821","status":"pending","subject":"Approve offboarding for Jane Doe","type":"single","updatedAt":"2026-09-07T10:00:30Z"}],"hasMore":false,"total":1},"schema":{"properties":{"approvals":{"items":{"$ref":"#/components/schemas/Approval"},"type":"array"},"hasMore":{"type":"boolean"},"total":{"type":"integer"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List approvals","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/approvals\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/approvals\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/approvals' -Headers $headers"}]}},"/api/v1/approvals/{approvalId}":{"get":{"parameters":[{"in":"path","name":"approvalId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"approval":{"approver":"manager@acme.com","body":"Jane Doe leaves on 12 September. Approve to start the offboarding run.","createdAt":"2026-09-07T10:00:30Z","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","expiresAt":"2026-09-09T10:00:00Z","id":"a7c19f02-8d3e-4b61-9f5a-2c8e7d4b1a03","reference":"REQ-4821","status":"pending","subject":"Approve offboarding for Jane Doe","type":"single","updatedAt":"2026-09-07T10:00:30Z"},"execution":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","createdAt":"2026-09-07T10:00:00Z","id":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","status":"paused","workflowId":"wf_d4e5f6"}},"schema":{"properties":{"approval":{"$ref":"#/components/schemas/Approval"},"execution":{"properties":{"clientId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"status":{"type":"string"},"workflowId":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get an approval","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e' -Headers $headers"}]}},"/api/v1/approvals/{approvalId}/approve":{"post":{"description":"Records `actor` (your signed-in person) on the approval and resumes the run. The key's scope is the authority, and your portal decides which of its people may act. Requires the `executions:manage` key scope.","parameters":[{"in":"path","name":"approvalId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"actor":{"email":"sam@acme-msp.com","name":"Sam Tech"},"response":"Looks good"},"schema":{"properties":{"actor":{"$ref":"#/components/schemas/Actor"},"response":{"description":"Comment; required when rejecting","type":"string"}},"required":["actor"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"approval":{"approver":"manager@acme.com","body":"Jane Doe leaves on 12 September. Approve to start the offboarding run.","completedAt":"2026-09-07T10:05:00Z","createdAt":"2026-09-07T10:00:30Z","decidedBy":{"email":"sam@acme-msp.com","id":"","name":"Sam Tech"},"executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","expiresAt":"2026-09-09T10:00:00Z","id":"a7c19f02-8d3e-4b61-9f5a-2c8e7d4b1a03","reference":"REQ-4821","response":"Looks good","status":"approved","subject":"Approve offboarding for Jane Doe","type":"single","updatedAt":"2026-09-07T10:05:00Z"}},"schema":{"properties":{"approval":{"$ref":"#/components/schemas/Approval"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request or the target's state — a missing actor, a missing `response` on a reject, or an approval or manual step that is no longer pending. The message names which"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Approve","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/approve\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  },\n  \"response\": \"Looks good\"\n}'"},{"label":"Node","lang":"node","source":"// Requires the executions:manage key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/approve\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    \"actor\": {\n      \"name\": \"Sam Tech\",\n      \"email\": \"sam@acme-msp.com\"\n    },\n    \"response\": \"Looks good\"\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\n$body = @'\n{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  },\n  \"response\": \"Looks good\"\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/approve' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"executions:manage"}},"/api/v1/approvals/{approvalId}/reject":{"post":{"description":"A `response` (reason) is required. Same authority rule as approve. Requires the `executions:manage` key scope.","parameters":[{"in":"path","name":"approvalId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"actor":{"email":"sam@acme-msp.com","name":"Sam Tech"},"response":"Start date is wrong"},"schema":{"properties":{"actor":{"$ref":"#/components/schemas/Actor"},"response":{"description":"Comment; required when rejecting","type":"string"}},"required":["actor"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"approval":{"approver":"manager@acme.com","body":"Jane Doe leaves on 12 September. Approve to start the offboarding run.","completedAt":"2026-09-07T10:05:00Z","createdAt":"2026-09-07T10:00:30Z","decidedBy":{"email":"sam@acme-msp.com","id":"","name":"Sam Tech"},"executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","expiresAt":"2026-09-09T10:00:00Z","id":"a7c19f02-8d3e-4b61-9f5a-2c8e7d4b1a03","reference":"REQ-4821","response":"Start date is wrong","status":"rejected","subject":"Approve offboarding for Jane Doe","type":"single","updatedAt":"2026-09-07T10:05:00Z"}},"schema":{"properties":{"approval":{"$ref":"#/components/schemas/Approval"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request or the target's state — a missing actor, a missing `response` on a reject, or an approval or manual step that is no longer pending. The message names which"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Reject","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/reject\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  },\n  \"response\": \"Start date is wrong\"\n}'"},{"label":"Node","lang":"node","source":"// Requires the executions:manage key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/reject\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    \"actor\": {\n      \"name\": \"Sam Tech\",\n      \"email\": \"sam@acme-msp.com\"\n    },\n    \"response\": \"Start date is wrong\"\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\n$body = @'\n{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  },\n  \"response\": \"Start date is wrong\"\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/approvals/\u003capprovalId\u003e/reject' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"executions:manage"}},"/api/v1/branding":{"get":{"responses":{"200":{"content":{"application/json":{"example":{"accentColor":"#F26B3A","brandColor":"#1F3A93","displayName":"Acme MSP","organisationId":"org_2Ab3Cd4Ef5Gh6Ij7Kl"},"schema":{"$ref":"#/components/schemas/Branding"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"The organisation's public branding","tags":["Organisation"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/branding\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/branding\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/branding' -Headers $headers"}]}},"/api/v1/clients":{"get":{"description":"Every client (tenant) with the identifiers you map your own records onto.","responses":{"200":{"content":{"application/json":{"example":{"clients":[{"createdAt":"2026-03-01T09:00:00Z","environment":"cloudOnly","googleWorkspaceDomains":[],"id":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","integrationMappingIds":{"haloId":"42"},"microsoftDomain":"acme.com","microsoftTenantId":"72f988bf-86f1-41af-91ab-2d7cd011db47","name":"Acme Ltd"}]},"schema":{"properties":{"clients":{"items":{"$ref":"#/components/schemas/Client"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List clients","tags":["Organisation"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/clients\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/clients\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/clients' -Headers $headers"}]}},"/api/v1/clients/{clientId}":{"get":{"parameters":[{"in":"path","name":"clientId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"createdAt":"2026-03-01T09:00:00Z","environment":"cloudOnly","googleWorkspaceDomains":[],"id":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","integrationMappingIds":{"haloId":"42"},"microsoftDomain":"acme.com","microsoftTenantId":"72f988bf-86f1-41af-91ab-2d7cd011db47","name":"Acme Ltd"},"schema":{"$ref":"#/components/schemas/Client"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get a client","tags":["Organisation"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/clients/\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/clients/\u003cclientId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/clients/\u003cclientId\u003e' -Headers $headers"}]}},"/api/v1/core/catalogue":{"get":{"description":"Every form the organisation can offer — configured or not — with each entry's configuration state. Use it to present the full menu; GET /api/v1/core/forms lists only what has a base config.","responses":{"200":{"content":{"application/json":{"example":{"forms":[{"availability":"internal","configured":true,"kind":"provisioning","listedOnHomepage":false,"name":"Onboarding","slug":"onboarding"},{"availability":"both","configured":true,"kind":"provisioning","listedOnHomepage":true,"name":"Offboarding","publicUrl":"https://app.triggr-app.com/core/org_2Ab3Cd4Ef5Gh6Ij7Kl/offboarding","slug":"offboarding"},{"configured":false,"kind":"lookup","listedOnHomepage":false,"name":"User Lookup","slug":"user-lookup"}]},"schema":{"properties":{"forms":{"items":{"$ref":"#/components/schemas/CoreCatalogueEntry"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"The Core form catalogue","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/catalogue\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/catalogue\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/catalogue' -Headers $headers"}]}},"/api/v1/core/forms":{"get":{"parameters":[{"description":"Only forms that appear on the public homepage","in":"query","name":"listedOnly","required":false,"schema":{"type":"boolean"}},{"description":"Exactly this availability","in":"query","name":"availability","required":false,"schema":{"enum":["internal","public","both","disabled"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"forms":[{"availability":"both","clientOverrides":[{"availability":"internal","enabled":true,"tenantId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","tenantName":"Acme Ltd"}],"enabled":true,"internal":true,"listedOnHomepage":true,"name":"Offboarding","public":true,"publicUrl":"https://app.triggr-app.com/core/org_2Ab3Cd4Ef5Gh6Ij7Kl/offboarding","slug":"offboarding"}]},"schema":{"properties":{"forms":{"items":{"$ref":"#/components/schemas/CoreForm"},"type":"array"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List configured Core forms with status","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/forms\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/forms' -Headers $headers"}]}},"/api/v1/core/forms/{slug}":{"get":{"parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"availability":"both","clientOverrides":[{"availability":"internal","enabled":true,"tenantId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","tenantName":"Acme Ltd"}],"enabled":true,"internal":true,"listedOnHomepage":true,"name":"Offboarding","public":true,"publicUrl":"https://app.triggr-app.com/core/org_2Ab3Cd4Ef5Gh6Ij7Kl/offboarding","slug":"offboarding"},"schema":{"$ref":"#/components/schemas/CoreForm"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get a Core form's status","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e' -Headers $headers"}]}},"/api/v1/core/forms/{slug}/check-upns":{"post":{"description":"Which candidate UPNs already exist in the client's directory. Requires the `core:run` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"candidates":["jane.doe@acme.com","jdoe@acme.com"],"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f"},"schema":{"properties":{"candidates":{"items":{"type":"string"},"type":"array"},"clientId":{"type":"string"}},"required":["clientId","candidates"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"taken":["jdoe@acme.com"]},"schema":{"properties":{"taken":{"items":{"type":"string"},"type":"array"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Check UPN availability","tags":["Core run"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:run key scope.\ncurl -X POST \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/check-upns\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n  \"candidates\": [\n    \"jane.doe@acme.com\",\n    \"jdoe@acme.com\"\n  ]\n}'"},{"label":"Node","lang":"node","source":"// Requires the core:run key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/check-upns\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n    \"candidates\": [\n      \"jane.doe@acme.com\",\n      \"jdoe@acme.com\"\n    ]\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:run key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\n$body = @'\n{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n  \"candidates\": [\n    \"jane.doe@acme.com\",\n    \"jdoe@acme.com\"\n  ]\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/check-upns' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"core:run"}},"/api/v1/core/forms/{slug}/config":{"get":{"description":"Each row carries an `etag`; the ETag header names the row you asked about (the client override with `clientId`, else the base). Send it back as If-Match on the matching PUT. Requires the `core:configure` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"description":"Also return this client's override","in":"query","name":"clientId","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"base":{"availability":"both","createdAt":"2026-03-01T09:00:00Z","enabled":true,"etag":"\"6b1f0a92c47d3e8514ab27f0\"","execConfig":{"approval":{"mode":"internal"}},"formConfig":{"sections":[{"id":"std-identity","title":"Who is leaving"}]},"listOnHomepage":true,"updatedAt":"2026-09-06T16:41:02Z"},"client":{"availability":null,"createdAt":"2026-03-01T09:00:00Z","enabled":true,"etag":"\"c93de1740b6a2f85e0d4c118\"","execConfig":{"baseAccess":{"groups":["All Staff"],"licenses":["Microsoft 365 Business Premium"],"mailboxes":[]}},"formConfig":{"sections":[{"id":"std-identity","title":"Who is leaving"}]},"listOnHomepage":false,"updatedAt":"2026-09-06T16:41:02Z"},"policyQuestions":[],"slug":"offboarding"},"schema":{"$ref":"#/components/schemas/CoreConfigResponse"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Read a Core form's base config and a client's override","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config' -Headers $headers"}],"x-triggr-scope":"core:configure"},"put":{"description":"Omitted fields keep their value; formConfig / execConfig are replaced as whole units; JSON null clears one. Re-syncs every client's compiled workflow. With If-Match the write is atomic: it is refused (412) if any save happened after the version you read. Requires the `core:configure` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"description":"The etag from the last read","in":"header","name":"If-Match","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"availability":"both","listOnHomepage":true},"schema":{"$ref":"#/components/schemas/CoreConfigWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"base":{"availability":"both","createdAt":"2026-03-01T09:00:00Z","enabled":true,"etag":"\"6b1f0a92c47d3e8514ab27f0\"","execConfig":{"approval":{"mode":"internal"}},"formConfig":{"sections":[{"id":"std-identity","title":"Who is leaving"}]},"listOnHomepage":true,"updatedAt":"2026-09-06T16:41:02Z"},"slug":"offboarding"},"schema":{"properties":{"base":{"$ref":"#/components/schemas/CoreWorkflowConfig"},"slug":{"type":"string"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"412":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"If-Match did not match — the config changed since you read it; re-read and retry"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Write the base config (merge)","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X PUT \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"If-Match: $ETAG\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"availability\": \"both\",\n  \"listOnHomepage\": true\n}'"},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config\", {\n  method: \"PUT\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"If-Match\": etag,\n  },\n  body: JSON.stringify({\n    \"availability\": \"both\",\n    \"listOnHomepage\": true\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'If-Match' = $etag\n}\n$body = @'\n{\n  \"availability\": \"both\",\n  \"listOnHomepage\": true\n}\n'@\nInvoke-RestMethod -Method Put -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/forms/{slug}/config/clients/{clientId}":{"delete":{"description":"Requires the `core:configure` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"in":"path","name":"clientId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"success":true},"schema":{"properties":{"success":{"type":"boolean"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Remove a client's override","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X DELETE \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e\", {\n  method: \"DELETE\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Delete -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e' -Headers $headers"}],"x-triggr-scope":"core:configure"},"put":{"description":"Same merge rules and If-Match atomicity as the base; `\"availability\": \"inherit\"` clears the override. Recompiles that client's workflow. The example only adds base access — a body of `{}` changes nothing. Requires the `core:configure` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"in":"path","name":"clientId","required":true,"schema":{"type":"string"}},{"description":"The etag from the last read","in":"header","name":"If-Match","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"execConfig":{"baseAccess":{"groups":["All Staff"],"licenses":["Microsoft 365 Business Premium"],"mailboxes":[]}}},"schema":{"$ref":"#/components/schemas/CoreConfigWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"client":{"availability":null,"createdAt":"2026-03-01T09:00:00Z","enabled":true,"etag":"\"c93de1740b6a2f85e0d4c118\"","execConfig":{"baseAccess":{"groups":["All Staff"],"licenses":["Microsoft 365 Business Premium"],"mailboxes":[]}},"formConfig":{"sections":[{"id":"std-identity","title":"Who is leaving"}]},"listOnHomepage":false,"updatedAt":"2026-09-06T16:41:02Z"},"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","slug":"offboarding"},"schema":{"properties":{"client":{"$ref":"#/components/schemas/CoreWorkflowConfig"},"clientId":{"type":"string"},"slug":{"type":"string"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"412":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"If-Match did not match — the config changed since you read it; re-read and retry"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Write a client's override (merge)","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X PUT \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"If-Match: $ETAG\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"execConfig\": {\n    \"baseAccess\": {\n      \"licenses\": [\n        \"Microsoft 365 Business Premium\"\n      ],\n      \"groups\": [\n        \"All Staff\"\n      ],\n      \"mailboxes\": []\n    }\n  }\n}'"},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e\", {\n  method: \"PUT\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"If-Match\": etag,\n  },\n  body: JSON.stringify({\n    \"execConfig\": {\n      \"baseAccess\": {\n        \"licenses\": [\n          \"Microsoft 365 Business Premium\"\n        ],\n        \"groups\": [\n          \"All Staff\"\n        ],\n        \"mailboxes\": []\n      }\n    }\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'If-Match' = $etag\n}\n$body = @'\n{\n  \"execConfig\": {\n    \"baseAccess\": {\n      \"licenses\": [\n        \"Microsoft 365 Business Premium\"\n      ],\n      \"groups\": [\n        \"All Staff\"\n      ],\n      \"mailboxes\": []\n    }\n  }\n}\n'@\nInvoke-RestMethod -Method Put -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/config/clients/\u003cclientId\u003e' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/forms/{slug}/fields/{fieldId}/options":{"post":{"description":"Microsoft-sourced, cached, or static options for one field, for the given client. `forceRefresh` bypasses the option cache — leave it off unless the user asked to refresh. Requires the `core:run` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"in":"path","name":"fieldId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f"},"schema":{"properties":{"clientId":{"type":"string"},"forceRefresh":{"type":"boolean"}},"required":["clientId"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"options":[{"label":"All Staff","type":"group","value":"0a5f7c2e-91b4-4d38-8e6a-2c7f1b9d4e50"},{"label":"Sales","type":"group","value":"7e3b1d42-6c8f-4a91-b2d5-3f0a8c6e1b47"}]},"schema":{"$ref":"#/components/schemas/OptionList"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Resolve a dynamic field's options","tags":["Core run"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:run key scope.\ncurl -X POST \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/fields/\u003cfieldId\u003e/options\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n}'"},{"label":"Node","lang":"node","source":"// Requires the core:run key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/fields/\u003cfieldId\u003e/options\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:run key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\n$body = @'\n{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/fields/\u003cfieldId\u003e/options' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"core:run"}},"/api/v1/core/forms/{slug}/preview":{"get":{"description":"Public projection: sections, identity hints, approval mode — never the exec config. Requires the `core:configure` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"description":"Merge this client's overrides; omit for the base","in":"query","name":"clientId","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"form":{"approval":{"mode":"internal"},"availability":"both","enabled":true,"identity":{"upnFormat":"first.last"},"sections":[{"fields":[{"id":"std-upn","label":"User","required":true,"type":"select"}],"id":"std-identity","title":"Who is leaving"}],"slug":"offboarding"},"primaryDomain":"acme.com"},"schema":{"properties":{"form":{"$ref":"#/components/schemas/RunForm"},"primaryDomain":{"type":"string"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Preview the merged run form","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/preview\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/preview\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/preview' -Headers $headers"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/forms/{slug}/run":{"post":{"description":"Provisioning forms only — a lookup-kind form (see the catalogue) has no run to start and is refused with 400. Same approval gate and compiled workflow as the Core app's run page. `submitter` is your signed-in person and is recorded on the request; credential delivery (email / ticket) follows the form's configuration using that email. `secret` — onboarding's one-time credential — is returned once, here only: it is never stored, so an `Idempotency-Key` replay of this call returns `\"secret\": null` with an `idempotentReplayNote`. Requires the `core:run` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","submission":{"std-first":"Jane","std-last":"Doe","std-upn":"jane.doe@acme.com"},"submitter":{"email":"sam@acme-msp.com","name":"Sam Tech"}},"schema":{"properties":{"clientId":{"type":"string"},"display":{"additionalProperties":{"type":"string"},"description":"fieldId → human label for id/code-valued answers","type":"object"},"submission":{"additionalProperties":true,"description":"fieldId → value","type":"object"},"submitter":{"$ref":"#/components/schemas/Actor"}},"required":["clientId","submission","submitter"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","status":"awaiting_approval"},"schema":{"properties":{"executionId":{"type":"string"},"idempotentReplayNote":{"description":"Present only on an Idempotency-Key replay whose original response carried a one-time credential: says that the value is shown only in the original response and how to issue a fresh one","type":"string"},"secret":{"description":"The one-time credential, shown ONCE. null on an Idempotency-Key replay — see idempotentReplayNote","nullable":true,"properties":{"label":{"type":"string"},"value":{"type":"string"}},"type":"object"},"status":{"enum":["running","awaiting_approval"],"type":"string"}},"required":["executionId","status"],"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Submit a Core form as a technician","tags":["Core run"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:run key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n  \"submission\": {\n    \"std-first\": \"Jane\",\n    \"std-last\": \"Doe\",\n    \"std-upn\": \"jane.doe@acme.com\"\n  },\n  \"submitter\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  }\n}'"},{"label":"Node","lang":"node","source":"// Requires the core:run key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n    \"submission\": {\n      \"std-first\": \"Jane\",\n      \"std-last\": \"Doe\",\n      \"std-upn\": \"jane.doe@acme.com\"\n    },\n    \"submitter\": {\n      \"name\": \"Sam Tech\",\n      \"email\": \"sam@acme-msp.com\"\n    }\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:run key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\n$body = @'\n{\n  \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\",\n  \"submission\": {\n    \"std-first\": \"Jane\",\n    \"std-last\": \"Doe\",\n    \"std-upn\": \"jane.doe@acme.com\"\n  },\n  \"submitter\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  }\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"core:run"}},"/api/v1/core/forms/{slug}/run-form":{"get":{"description":"Base + overrides merged, in the public projection, plus the client's primary Microsoft domain for the UPN generator. The form must be available internally. Requires the `core:run` key scope.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"description":"The client to run for","in":"query","name":"clientId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"form":{"approval":{"mode":"internal"},"availability":"both","enabled":true,"identity":{"upnFormat":"first.last"},"sections":[{"fields":[{"id":"std-upn","label":"User","required":true,"type":"select"}],"id":"std-identity","title":"Who is leaving"}],"slug":"offboarding"},"primaryDomain":"acme.com"},"schema":{"properties":{"form":{"$ref":"#/components/schemas/RunForm"},"primaryDomain":{"type":"string"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"The run form for a client","tags":["Core run"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:run key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run-form?clientId=\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:run key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run-form?clientId=\u003cclientId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:run key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/run-form?clientId=\u003cclientId\u003e' -Headers $headers"}],"x-triggr-scope":"core:run"}},"/api/v1/core/forms/{slug}/sessions":{"post":{"description":"Core public forms are Microsoft-only: give the user's object ID or UPN plus their tenant (`microsoftTenantId`, or `clientId`). The form must be public — base availability, and any override for that client — and a form that is not is a 400, not a 403. The handle is single-use and expires after 2 minutes: mint one per page load, server-side. The user must belong to a client this organisation manages — their Microsoft tenant connected, or their Google Workspace domain mapped to a client — otherwise 403. The signed-in session lasts 30 minutes from when you mint it; after that a submit is refused and the page must be reloaded with a fresh handle. Every session is audited against the key that minted it, and a submission — and every workflow it triggers, as `metadata.custom.apiKeyId` — records which key embedded the form. The form's own access rules still apply to the asserted identity.","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"user":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","userIdentifier":"jane.doe@contoso.com"}},"schema":{"$ref":"#/components/schemas/FormSessionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"embedUrl":"https://core.triggr-app.com/telescope/forms/org_2Ab3Cd4Ef5Gh6Ij7Kl/onboarding?formSession=8b1e5d0c93a74f26e1d4c7a2","expiresIn":120,"formSessionHandle":"8b1e5d0c93a74f26e1d4c7a2","provider":"microsoft"},"schema":{"$ref":"#/components/schemas/FormSession"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`invalid_request`, `form_session_unsupported`, `form_unpublished`, `client_not_entitled` or `invalid_user_identifier` — see SessionError"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`invalid_api_key`"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`tenant_not_connected` or `microsoft_permission_denied`"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`form_not_found`, `client_not_found`, `client_not_connected` or `user_not_found` — the code tells them apart"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`rate_limited` — see `Retry-After`"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`microsoft_unavailable` — retry after the `Retry-After` seconds"}},"security":[{"ApiKeyAuth":[]}],"summary":"Start an embedded session for a Core form","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X POST \"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/sessions\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"user\": {\n    \"userIdentifier\": \"jane.doe@contoso.com\",\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n  }\n}'"},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/sessions\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"user\": {\n      \"userIdentifier\": \"jane.doe@contoso.com\",\n      \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n    }\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\n$body = @'\n{\n  \"user\": {\n    \"userIdentifier\": \"jane.doe@contoso.com\",\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n  }\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/core/forms/\u003cslug\u003e/sessions' -Headers $headers -ContentType 'application/json' -Body $body"}]}},"/api/v1/core/options/microsoft":{"get":{"description":"Requires the `core:configure` key scope.","parameters":[{"description":"The client whose tenant to read","in":"query","name":"clientId","required":true,"schema":{"type":"string"}},{"description":"Which data set","in":"query","name":"dataKey","required":true,"schema":{"enum":["groups","users","domains","sharedMailboxes","licenses","licenseSkus","departments","jobTitles"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"options":[{"label":"All Staff","type":"group","value":"0a5f7c2e-91b4-4d38-8e6a-2c7f1b9d4e50"},{"label":"Sales","type":"group","value":"7e3b1d42-6c8f-4a91-b2d5-3f0a8c6e1b47"}]},"schema":{"$ref":"#/components/schemas/OptionList"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Microsoft 365 picker data for a client","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/options/microsoft?clientId=\u003cclientId\u003e\u0026dataKey=\u003cdataKey\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/options/microsoft?clientId=\u003cclientId\u003e\u0026dataKey=\u003cdataKey\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/options/microsoft?clientId=\u003cclientId\u003e\u0026dataKey=\u003cdataKey\u003e' -Headers $headers"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/options/onprem-groups":{"get":{"description":"Requires the `core:configure` key scope.","parameters":[{"description":"The client whose agent to query","in":"query","name":"clientId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"groups":[{"category":"Security","dn":"CN=RDP-Users,OU=Groups,DC=acme,DC=local","name":"RDP Users","samAccountName":"RDP-Users","scope":"Global"}]},"schema":{"properties":{"groups":{"items":{"properties":{"category":{"type":"string"},"dn":{"type":"string"},"name":{"type":"string"},"samAccountName":{"type":"string"},"scope":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A dependency (e.g. the on-prem agent) is unavailable"}},"security":[{"ApiKeyAuth":[]}],"summary":"A synced client's on-prem AD groups","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/options/onprem-groups?clientId=\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/options/onprem-groups?clientId=\u003cclientId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/options/onprem-groups?clientId=\u003cclientId\u003e' -Headers $headers"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/options/onprem-ous":{"get":{"description":"Requires the `core:configure` key scope.","parameters":[{"description":"The client whose agent to query","in":"query","name":"clientId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ous":[{"dn":"OU=Staff,OU=Acme,DC=acme,DC=local","name":"Staff"},{"dn":"OU=Leavers,OU=Acme,DC=acme,DC=local","name":"Leavers"}]},"schema":{"properties":{"ous":{"items":{"properties":{"dn":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A dependency (e.g. the on-prem agent) is unavailable"}},"security":[{"ApiKeyAuth":[]}],"summary":"A synced client's on-prem AD OUs","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/options/onprem-ous?clientId=\u003cclientId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/options/onprem-ous?clientId=\u003cclientId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/options/onprem-ous?clientId=\u003cclientId\u003e' -Headers $headers"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/options/psa":{"get":{"description":"Requires the `core:configure` key scope.","parameters":[{"description":"Which option set","in":"query","name":"dataKey","required":true,"schema":{"enum":["boards","ticketTypes","priorities","statuses","ticketTypeFields","ticketTypeStandardFields","ticketFieldValues"],"type":"string"}},{"description":"halo | connectwise | autotask; default the org's PSA","in":"query","name":"psa","required":false,"schema":{"type":"string"}},{"description":"","in":"query","name":"clientId","required":false,"schema":{"type":"string"}},{"description":"","in":"query","name":"boardId","required":false,"schema":{"type":"string"}},{"description":"","in":"query","name":"ticketTypeId","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"options":[{"label":"Service Desk","type":"board","value":"12"},{"label":"Projects","type":"board","value":"18"}]},"schema":{"$ref":"#/components/schemas/OptionList"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"}},"security":[{"ApiKeyAuth":[]}],"summary":"Option sets from the organisation's PSA","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the core:configure key scope.\ncurl -X GET \"https://api.triggr-app.com/api/v1/core/options/psa?dataKey=\u003cdataKey\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"// Requires the core:configure key scope.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/core/options/psa?dataKey=\u003cdataKey\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the core:configure key scope.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/options/psa?dataKey=\u003cdataKey\u003e' -Headers $headers"}],"x-triggr-scope":"core:configure"}},"/api/v1/core/requests":{"get":{"description":"Every submission made through a Core form — public form, technician, or API — with who asked, for which client, and the live status of the run it started.","parameters":[{"description":"","in":"query","name":"clientId","required":false,"schema":{"type":"string"}},{"description":"","in":"query","name":"slug","required":false,"schema":{"type":"string"}},{"description":"RFC 3339; only rows created at or after it","in":"query","name":"since","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Page size, default 50, max 100","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"hasMore":false,"requests":[{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","clientName":"Acme Ltd","createdAt":"2026-09-07T09:59:50Z","error":"Exchange returned 403: insufficient permissions","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","failedStep":"Convert mailbox to shared","id":"3c9e5a71-2b48-4d0f-9e6c-8a1b7d4f2e50","name":"Offboarding","slug":"offboarding","source":"public","status":"failed","subject":"Offboard Jane Doe","submitter":{"email":"priya@acme.com","name":"Priya Patel"},"updatedAt":"2026-09-07T10:02:14Z"}],"total":1},"schema":{"properties":{"hasMore":{"type":"boolean"},"requests":{"items":{"$ref":"#/components/schemas/CoreRequest"},"type":"array"},"total":{"type":"integer"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List Core requests with live status","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/requests\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/requests\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/requests' -Headers $headers"}]}},"/api/v1/core/requests/{requestId}":{"get":{"parameters":[{"in":"path","name":"requestId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","clientName":"Acme Ltd","createdAt":"2026-09-07T09:59:50Z","error":"Exchange returned 403: insufficient permissions","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","failedStep":"Convert mailbox to shared","fields":[{"label":"User","value":"jane.doe@acme.com"},{"label":"Last day","value":"2026-09-12"},{"label":"Forward mail to","value":"sam.jones@acme.com"}],"id":"3c9e5a71-2b48-4d0f-9e6c-8a1b7d4f2e50","name":"Offboarding","slug":"offboarding","source":"public","status":"failed","subject":"Offboard Jane Doe","submitter":{"email":"priya@acme.com","name":"Priya Patel"},"updatedAt":"2026-09-07T10:02:14Z"},"schema":{"$ref":"#/components/schemas/CoreRequestDetail"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get a Core request with its answers","tags":["Core forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/requests/\u003crequestId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/requests/\u003crequestId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/requests/\u003crequestId\u003e' -Headers $headers"}]}},"/api/v1/core/schema":{"get":{"description":"JSON-Schema-style description of formConfig / execConfig and every enum the validator enforces — render your editor from it.","responses":{"200":{"content":{"application/json":{"example":{"execConfig":{"approval":{"mode":{"enum":["none","internal","external"]}}},"formConfig":{"sections":{"items":{"…":"…"},"type":"array"}}},"schema":{"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"The Core config schema","tags":["Core configuration"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/core/schema\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/core/schema\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/core/schema' -Headers $headers"}]}},"/api/v1/executions":{"get":{"description":"Newest first. `paused` means the run is waiting on a person (approval or manual step).","parameters":[{"description":"","in":"query","name":"workflowId","required":false,"schema":{"type":"string"}},{"description":"","in":"query","name":"clientId","required":false,"schema":{"type":"string"}},{"description":"pending | running | paused | completed | failed","in":"query","name":"status","required":false,"schema":{"enum":["pending","running","paused","completed","failed"],"type":"string"}},{"description":"RFC 3339; only rows created at or after it","in":"query","name":"since","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Page size, default 50, max 100","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"executions":[{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","createdAt":"2026-09-07T10:00:00Z","id":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","status":"failed","updatedAt":"2026-09-07T10:02:14Z","workflowId":"wf_d4e5f6","workflowName":"Offboard User"}],"hasMore":false,"total":1},"schema":{"properties":{"executions":{"items":{"$ref":"#/components/schemas/Execution"},"type":"array"},"hasMore":{"type":"boolean"},"total":{"type":"integer"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List executions","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/executions\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/executions\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/executions' -Headers $headers"}]}},"/api/v1/executions/{executionId}":{"get":{"description":"A failed run reports the step that failed and its last error; a finished run reports the output its author published. Parameters, step context and logs are never included.","parameters":[{"in":"path","name":"executionId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","createdAt":"2026-09-07T10:00:00Z","error":"Exchange returned 403: insufficient permissions","failedStep":"Convert mailbox to shared","id":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","source":"core_public","status":"failed","updatedAt":"2026-09-07T10:02:14Z","workflowId":"wf_d4e5f6","workflowName":"Offboard User"},"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get an execution's status and outcome","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e' -Headers $headers"}]}},"/api/v1/executions/{executionId}/cancel":{"post":{"description":"Stops a pending, running or paused run; its open approvals and manual steps are closed (announced as `approval.expired` / `manual_step.cancelled`). Requires the `executions:manage` key scope.","parameters":[{"in":"path","name":"executionId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"example":{"executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","message":"Execution cancelled"},"schema":{"properties":{"executionId":{"type":"string"},"message":{"type":"string"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Cancel a running execution","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/cancel\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\""},{"label":"Node","lang":"node","source":"// Requires the executions:manage key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/cancel\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/cancel' -Headers $headers"}],"x-triggr-scope":"executions:manage"}},"/api/v1/executions/{executionId}/retry":{"post":{"description":"Starts a new execution from the original's inputs. Only a completed or failed run may be retried — retrying a live one is refused (400) so the same inputs are never provisioned twice concurrently. Requires the `executions:manage` key scope.","parameters":[{"in":"path","name":"executionId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"example":{"message":"Retry started","newExecutionId":"7d2c9f14-6a83-4b57-9e21-0f8b3d5a6c47"},"schema":{"properties":{"message":{"type":"string"},"newExecutionId":{"type":"string"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Retry an execution","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/retry\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\""},{"label":"Node","lang":"node","source":"// Requires the executions:manage key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/retry\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/retry' -Headers $headers"}],"x-triggr-scope":"executions:manage"}},"/api/v1/executions/{executionId}/steps":{"get":{"description":"Labels and outcomes in order, for a progress view — never a step's output or context.","parameters":[{"in":"path","name":"executionId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","status":"failed","steps":[{"createdAt":"2026-09-07T10:00:05Z","id":"3a8c1e07-4b52-4d9f-8a16-7c0e2b5d9f31","label":"Disable the account","outcome":"success","stepId":"disable-account","updatedAt":"2026-09-07T10:00:11Z"},{"createdAt":"2026-09-07T10:00:11Z","id":"b4f7d290-8e31-4c65-9a07-1d3f6b8e2c94","label":"Convert mailbox to shared","outcome":"error","stepId":"shared-mailbox","updatedAt":"2026-09-07T10:02:14Z"}]},"schema":{"properties":{"executionId":{"type":"string"},"status":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/ExecutionStep"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"List an execution's steps","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/steps\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/steps\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/executions/\u003cexecutionId\u003e/steps' -Headers $headers"}]}},"/api/v1/forms":{"get":{"description":"Each with its shareable embed URL. Check `authType` before embedding: only `none` embeds friction-free from `shareUrl`; `microsoft` and `google` forms embed friction-free through a form session; `password` and `internal` forms cannot be embedded as a signed-in user.","parameters":[{"description":"Only forms listed on the homepage","in":"query","name":"listedOnly","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"example":{"forms":[{"authType":"microsoft","id":"9c8d7e6f-5a4b-3c2d-1e0f-a9b8c7d6e5f4","listedOnHomepage":true,"name":"New Starter Request","shareUrl":"https://app.triggr-app.com/telescope/forms/org_2Ab3Cd4Ef5Gh6Ij7Kl/9c8d7e6f-5a4b-3c2d-1e0f-a9b8c7d6e5f4","updatedAt":"2026-09-22T09:41:07Z"}]},"schema":{"properties":{"forms":{"items":{"$ref":"#/components/schemas/Form"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List Studio forms","tags":["Studio forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/forms\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/forms\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/forms' -Headers $headers"}]}},"/api/v1/forms/{formId}":{"get":{"parameters":[{"in":"path","name":"formId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"authType":"microsoft","id":"9c8d7e6f-5a4b-3c2d-1e0f-a9b8c7d6e5f4","listedOnHomepage":true,"name":"New Starter Request","shareUrl":"https://app.triggr-app.com/telescope/forms/org_2Ab3Cd4Ef5Gh6Ij7Kl/9c8d7e6f-5a4b-3c2d-1e0f-a9b8c7d6e5f4","updatedAt":"2026-09-22T09:41:07Z"},"schema":{"$ref":"#/components/schemas/Form"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get a Studio form","tags":["Studio forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e' -Headers $headers"}]}},"/api/v1/forms/{formId}/sessions":{"post":{"description":"Mints a handle asserting the given user into a `microsoft` or `google` authType form and returns the `embedUrl` to iframe: the visitor lands already signed in. For a microsoft form give the user's object ID or UPN plus their tenant (`microsoftTenantId`, or `clientId` and it is looked up); for a google form the Workspace email alone. A `none` (public) form takes a session too: give the portal user's identifier and their `clientId` (or `microsoftTenantId`), and the submission is attributed to them and that client (`provider` `portal`) — nothing is looked up in a directory. With no `user`, a public form returns its plain `embedUrl` (`provider` `none`, no handle) and submits anonymously, as before. `password` and `internal` forms cannot take a session. Refusals carry a SessionError code. The handle is single-use and expires after 2 minutes: mint one per page load, server-side. The user must belong to a client this organisation manages — their Microsoft tenant connected, or their Google Workspace domain mapped to a client — otherwise 403. The signed-in session lasts 30 minutes from when you mint it; after that a submit is refused and the page must be reloaded with a fresh handle. Every session is audited against the key that minted it, and a submission — and every workflow it triggers, as `metadata.custom.apiKeyId` — records which key embedded the form. The form's own access rules still apply to the asserted identity.","parameters":[{"in":"path","name":"formId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"user":{"clientId":"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f","userIdentifier":"jane.doe@contoso.com"}},"schema":{"$ref":"#/components/schemas/FormSessionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"embedUrl":"https://app.triggr-app.com/telescope/forms/org_…/9c8d…?formSession=3f9a…e21c","expiresIn":120,"formSessionHandle":"3f9a…e21c","provider":"microsoft"},"schema":{"$ref":"#/components/schemas/FormSession"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`invalid_request`, `form_session_unsupported`, `form_unpublished`, `client_not_entitled` or `invalid_user_identifier` — see SessionError"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`invalid_api_key`"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`tenant_not_connected` or `microsoft_permission_denied`"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`form_not_found`, `client_not_found`, `client_not_connected` or `user_not_found` — the code tells them apart"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`rate_limited` — see `Retry-After`"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionError"}}},"description":"`microsoft_unavailable` — retry after the `Retry-After` seconds"}},"security":[{"ApiKeyAuth":[]}],"summary":"Start an embedded form session","tags":["Studio forms"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X POST \"https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e/sessions\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"user\": {\n    \"userIdentifier\": \"jane.doe@contoso.com\",\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n  }\n}'"},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e/sessions\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"user\": {\n      \"userIdentifier\": \"jane.doe@contoso.com\",\n      \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n    }\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\n$body = @'\n{\n  \"user\": {\n    \"userIdentifier\": \"jane.doe@contoso.com\",\n    \"clientId\": \"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f\"\n  }\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/forms/\u003cformId\u003e/sessions' -Headers $headers -ContentType 'application/json' -Body $body"}]}},"/api/v1/manual-steps":{"get":{"description":"Runs paused for a human task.","parameters":[{"description":"","in":"query","name":"status","required":false,"schema":{"enum":["pending","completed"],"type":"string"}},{"description":"Page size, default 50, max 100","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"hasMore":false,"manualSteps":[{"createdAt":"2026-09-07T10:01:00Z","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","id":"5b2c8d17-4e93-42af-8c1d-6f0a9b3e7d24","instructions":"Arrange courier collection and log the asset tag.","status":"pending","title":"Collect the laptop","updatedAt":"2026-09-07T10:01:00Z"}],"total":1},"schema":{"properties":{"hasMore":{"type":"boolean"},"manualSteps":{"items":{"$ref":"#/components/schemas/ManualStep"},"type":"array"},"total":{"type":"integer"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List manual steps","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/manual-steps\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/manual-steps\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/manual-steps' -Headers $headers"}]}},"/api/v1/manual-steps/{manualStepId}":{"get":{"parameters":[{"in":"path","name":"manualStepId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"manualStep":{"createdAt":"2026-09-07T10:01:00Z","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","id":"5b2c8d17-4e93-42af-8c1d-6f0a9b3e7d24","instructions":"Arrange courier collection and log the asset tag.","status":"pending","title":"Collect the laptop","updatedAt":"2026-09-07T10:01:00Z"}},"schema":{"properties":{"manualStep":{"$ref":"#/components/schemas/ManualStep"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"}},"security":[{"ApiKeyAuth":[]}],"summary":"Get a manual step","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e' -Headers $headers"}]}},"/api/v1/manual-steps/{manualStepId}/complete":{"post":{"description":"Resumes the run. A step with a form (`formId` set) needs `formSubmissionId` — a submission of that form, in this organisation. Requires the `executions:manage` key scope.","parameters":[{"in":"path","name":"manualStepId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"actor":{"email":"sam@acme-msp.com","name":"Sam Tech"}},"schema":{"properties":{"actor":{"$ref":"#/components/schemas/Actor"},"formSubmissionId":{"type":"string"}},"required":["actor"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"manualStep":{"completedAt":"2026-09-07T11:20:00Z","completedBy":{"email":"sam@acme-msp.com","id":"","name":"Sam Tech"},"createdAt":"2026-09-07T10:01:00Z","executionId":"1b4e28ba-2fa1-11d2-883f-0016d3cca427","id":"5b2c8d17-4e93-42af-8c1d-6f0a9b3e7d24","instructions":"Arrange courier collection and log the asset tag.","status":"completed","title":"Collect the laptop","updatedAt":"2026-09-07T11:20:00Z"}},"schema":{"properties":{"manualStep":{"$ref":"#/components/schemas/ManualStep"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request or the target's state — a missing actor, a missing `response` on a reject, or an approval or manual step that is no longer pending. The message names which"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the required scope, or the target is not managed by this organisation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Complete a manual step","tags":["Approvals \u0026 manual steps"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e/complete\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  }\n}'"},{"label":"Node","lang":"node","source":"// Requires the executions:manage key scope.\n// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e/complete\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    \"actor\": {\n      \"name\": \"Sam Tech\",\n      \"email\": \"sam@acme-msp.com\"\n    }\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Requires the executions:manage key scope.\n# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\n$body = @'\n{\n  \"actor\": {\n    \"name\": \"Sam Tech\",\n    \"email\": \"sam@acme-msp.com\"\n  }\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/manual-steps/\u003cmanualStepId\u003e/complete' -Headers $headers -ContentType 'application/json' -Body $body"}],"x-triggr-scope":"executions:manage"}},"/api/v1/me":{"get":{"description":"Also returns the organisation's canonical embed origins — the exact value to store as your embed host and compare against `new URL(embedUrl).origin` (see Embedding).","responses":{"200":{"content":{"application/json":{"example":{"coreFormsOrigin":"https://core.triggr-app.com","displayName":"Acme MSP","formsOrigin":"https://forms.acme-msp.com","organisationId":"org_2Ab3Cd4Ef5Gh6Ij7Kl"},"schema":{"properties":{"coreFormsOrigin":{"description":"The same for Core forms","format":"uri","type":"string"},"displayName":{"type":"string"},"formsOrigin":{"description":"Canonical origin of every Studio form's shareUrl / embedUrl: scheme://host[:port], lower-case, no path or trailing slash","format":"uri","type":"string"},"organisationId":{"type":"string"}},"required":["organisationId","displayName","formsOrigin","coreFormsOrigin"],"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"The organisation this key belongs to","tags":["Organisation"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/me\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/me\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/me' -Headers $headers"}]}},"/api/v1/openapi.json":{"get":{"description":"The OpenAPI 3.0 description of the public API. No authentication.","responses":{"200":{"content":{"application/json":{"example":{"info":{"title":"Triggr Public API","version":"1.4.0"},"openapi":"3.0.3","paths":{"…":{}}},"schema":{"type":"object"}}},"description":"OK"}},"security":[],"summary":"This document","tags":["Meta"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/openapi.json\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/openapi.json\", {\n  method: \"GET\",\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"Invoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/openapi.json'"}]}},"/api/v1/webhooks":{"get":{"responses":{"200":{"content":{"application/json":{"example":{"events":["execution.completed","execution.failed","approval.requested","approval.decided","approval.expired","manual_step.created","manual_step.completed","manual_step.cancelled","core.request.submitted","form.created","form.updated","form.deleted","core_form.updated","client.created","client.updated","client.deleted"],"webhooks":[{"active":true,"consecutiveFailures":0,"createdAt":"2026-09-01T08:30:00Z","description":"Acme portal","events":["execution.completed","execution.failed","approval.requested"],"id":"e2b7c4d9-1f8a-4c36-b5e0-7a9d2f4c8b13","lastDeliveryAt":"2026-09-07T10:02:20Z","url":"https://portal.example.com/hooks/triggr"}]},"schema":{"properties":{"events":{"items":{"type":"string"},"type":"array"},"webhooks":{"items":{"$ref":"#/components/schemas/Webhook"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List webhooks","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/webhooks\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/webhooks' -Headers $headers"}]},"post":{"description":"An https URL on a public host, for a set of events. The signing secret is returned ONCE — record it now: it is never stored by us, so replaying this call with the same `Idempotency-Key` returns `\"secret\": null` rather than repeating it (rotate the secret if you lost it). Deliveries are POSTed within about a minute and retried on 1m / 5m / 30m / 2h / 12h.\n\nEvery delivery carries four headers: `X-Triggr-Signature` (see below), `X-Triggr-Event` (the event name), `X-Triggr-Delivery-Id` (the delivery row's id) and `User-Agent: Triggr-Webhooks/1.0`. The body is a `WebhookEnvelope`.\n\nTwo ids, and they mean different things. The envelope's `id` identifies the EVENT: it is unchanged across retries and across a redelivery (POST …/redeliver re-posts the original payload bytes), so it is your dedupe key. `X-Triggr-Delivery-Id` identifies the DELIVERY ROW: it is the same on every retry attempt of that delivery (attempts 1 to 5 all carry it), changes on a redelivery, and matches a row in GET …/deliveries — use it to correlate with the delivery history and in support conversations.\n\nVerify `X-Triggr-Signature: t=\u003cunix\u003e,v1=\u003chex HMAC-SHA256(secret, t + \".\" + rawBody)\u003e`, rejecting a `t` older than 5 minutes. The header may carry MORE THAN ONE `v1` — for 24 hours after a secret rotation (POST …/rotate-secret) each delivery is signed with the new secret and the previous one — so accept it if ANY `v1` matches.\n\nA webhook whose deliveries keep exhausting their retries after 25 consecutive failures is disabled (re-enable it with POST …/enable once the endpoint is fixed); revoking the key that registered a webhook disables it too. Delivered and failed history is kept for 30 days. An event is delivered at most once per webhook unless you ask for it again with …/redeliver.\n\n**Catalogue changes** — subscribe to these instead of re-reading the lists: `form.created` / `form.updated` / `form.deleted`, `client.created` / `client.updated` / `client.deleted`, and `core_form.updated`. They fire for a change made in any way — the Triggr app, this API, or Triggr's AI assistant — and are sent typically within 30 seconds of the change (at most about 90 seconds), then retried on the schedule above. `data` is the object exactly as the list endpoint returns it now (`Form`, `Client` or `CoreForm`); for a `*.deleted` event it is `{ \"id\", \"deletedAt\" }`. `form.updated` fires on any change to a form, including its fields (compare `updatedAt`); `client.updated` fires only when something in the `Client` object changed; `core_form.updated` when its enabled / availability / homepage settings or a client override changed. Core forms are a fixed catalogue, so they are never created or deleted. Each form and workflow also carries `updatedAt`, so after an outage longer than the retry schedule one list call tells you what changed.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"events":["execution.completed","execution.failed","approval.requested"],"url":"https://portal.example.com/hooks/triggr"},"schema":{"properties":{"description":{"type":"string"},"events":{"items":{"enum":["*","execution.completed","execution.failed","approval.requested","approval.decided","approval.expired","manual_step.created","manual_step.completed","manual_step.cancelled","core.request.submitted","form.created","form.updated","form.deleted","core_form.updated","client.created","client.updated","client.deleted"],"type":"string"},"type":"array"},"url":{"format":"uri","type":"string"}},"required":["url","events"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"secret":"whsec_3Jd8Kq2mXv7pR4tYw1Zn6Bc5Ha0Sf9Le","signature":"X-Triggr-Signature: t=\u003cunix\u003e,v1=hex(HMAC-SHA256(secret, t + \".\" + body))","webhook":{"active":true,"consecutiveFailures":0,"createdAt":"2026-09-01T08:30:00Z","description":"Acme portal","events":["execution.completed","execution.failed","approval.requested"],"id":"e2b7c4d9-1f8a-4c36-b5e0-7a9d2f4c8b13","lastDeliveryAt":null,"url":"https://portal.example.com/hooks/triggr"}},"schema":{"properties":{"idempotentReplayNote":{"description":"Present only on an Idempotency-Key replay whose original response carried a one-time credential: says that the value is shown only in the original response and how to issue a fresh one","type":"string"},"secret":{"description":"The signing secret, shown ONCE. null on an Idempotency-Key replay — see idempotentReplayNote","nullable":true,"type":"string"},"signature":{"type":"string"},"webhook":{"$ref":"#/components/schemas/Webhook"}},"type":"object"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Register a webhook","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/webhooks\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"url\": \"https://portal.example.com/hooks/triggr\",\n  \"events\": [\n    \"execution.completed\",\n    \"execution.failed\",\n    \"approval.requested\"\n  ]\n}'"},{"label":"Node","lang":"node","source":"// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    \"url\": \"https://portal.example.com/hooks/triggr\",\n    \"events\": [\n      \"execution.completed\",\n      \"execution.failed\",\n      \"approval.requested\"\n    ]\n  }),\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\n$body = @'\n{\n  \"url\": \"https://portal.example.com/hooks/triggr\",\n  \"events\": [\n    \"execution.completed\",\n    \"execution.failed\",\n    \"approval.requested\"\n  ]\n}\n'@\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/webhooks' -Headers $headers -ContentType 'application/json' -Body $body"}]}},"/api/v1/webhooks/{webhookId}":{"delete":{"description":"Also removes its delivery history.","parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"success":true},"schema":{"properties":{"success":{"type":"boolean"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Delete a webhook","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X DELETE \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e\", {\n  method: \"DELETE\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Delete -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e' -Headers $headers"}]}},"/api/v1/webhooks/{webhookId}/deliveries":{"get":{"parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}},{"description":"Page size, default 50, max 100","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Rows to skip","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"deliveries":[{"attempts":1,"createdAt":"2026-09-07T10:02:14Z","deliveredAt":"2026-09-07T10:02:20Z","event":"execution.failed","id":"d1f4a8c2-9b76-4e51-8a3d-0c5f2e9b7a64","status":"delivered","statusCode":200}]},"schema":{"properties":{"deliveries":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List a webhook's recent deliveries","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries' -Headers $headers"}]}},"/api/v1/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver":{"post":{"description":"Creates a NEW delivery row carrying the ORIGINAL payload bytes and attempts it immediately. So the envelope's `id` is unchanged — it names the event, and you should dedupe on it if you already processed it — while `X-Triggr-Delivery-Id` and the returned `deliveryId` are new, naming this new delivery row. The response reports that first attempt AND the new delivery row, so you can prepend it to a list without reconstructing it. The original delivery is left as history. A delivery that is still pending is refused (400): it is already being retried.","parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}},{"in":"path","name":"deliveryId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"example":{"attempts":1,"delivery":{"attempts":1,"createdAt":"2026-09-07T14:10:03Z","deliveredAt":"2026-09-07T14:10:04Z","event":"execution.failed","id":"8c5e0b39-7a24-4f18-9d63-2b1f4e7a0c95","status":"delivered","statusCode":200},"deliveryId":"8c5e0b39-7a24-4f18-9d63-2b1f4e7a0c95","error":"","status":"delivered","statusCode":200},"schema":{"$ref":"#/components/schemas/WebhookRedelivery"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Re-send a past delivery","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries/\u003cdeliveryId\u003e/redeliver\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\""},{"label":"Node","lang":"node","source":"// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries/\u003cdeliveryId\u003e/redeliver\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/deliveries/\u003cdeliveryId\u003e/redeliver' -Headers $headers"}]}},"/api/v1/webhooks/{webhookId}/enable":{"post":{"description":"Clears the failure streak and makes the calling key the registering key. Use after fixing an endpoint that was disabled for repeated failures, or to keep a webhook whose original key was revoked.","parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"webhook":{"active":true,"consecutiveFailures":0,"createdAt":"2026-09-01T08:30:00Z","description":"Acme portal","events":["execution.completed","execution.failed","approval.requested"],"id":"e2b7c4d9-1f8a-4c36-b5e0-7a9d2f4c8b13","lastDeliveryAt":"2026-09-07T10:02:20Z","url":"https://portal.example.com/hooks/triggr"}},"schema":{"properties":{"webhook":{"$ref":"#/components/schemas/Webhook"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Re-enable a disabled webhook","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X POST \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/enable\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/enable\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/enable' -Headers $headers"}]}},"/api/v1/webhooks/{webhookId}/rotate-secret":{"post":{"description":"Issues a new secret (returned ONCE) and keeps the previous one for 24 hours: until `previousSecretValidUntil` every delivery's `X-Triggr-Signature` carries two `v1` values — new secret first, previous second — so switch your receiver whenever convenient inside that window.\n\nRotating again inside that window KEEPS the older secret — the one your receiver is actually verifying with — rather than promoting the current one, so a retried rotation can never leave your endpoint unable to verify anything. The window still runs from the FIRST rotation; it is not extended. Send an `Idempotency-Key` and a retry replays instead of minting another secret.","parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"example":{"previousSecretValidUntil":"2026-09-08T14:12:00Z","secret":"whsec_7Qm4Xt9bZa2vLp6Rk0Yc3Nd8Fe1Ws5Hj","webhook":{"active":true,"consecutiveFailures":0,"createdAt":"2026-09-01T08:30:00Z","description":"Acme portal","events":["execution.completed","execution.failed","approval.requested"],"id":"e2b7c4d9-1f8a-4c36-b5e0-7a9d2f4c8b13","lastDeliveryAt":"2026-09-07T10:02:20Z","url":"https://portal.example.com/hooks/triggr"}},"schema":{"properties":{"idempotentReplayNote":{"description":"Present only on an Idempotency-Key replay whose original response carried a one-time credential: says that the value is shown only in the original response and how to issue a fresh one","type":"string"},"previousSecretValidUntil":{"format":"date-time","type":"string"},"secret":{"description":"The new signing secret, shown ONCE. null on an Idempotency-Key replay — see idempotentReplayNote","nullable":true,"type":"string"},"webhook":{"$ref":"#/components/schemas/Webhook"}},"required":["webhook","secret","previousSecretValidUntil"],"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A request with this Idempotency-Key is still in progress — retry shortly"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Idempotency-Key was already used with a different request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Rotate the signing secret","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"# Idempotency-Key is optional: send one to make a retry safe.\ncurl -X POST \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/rotate-secret\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\""},{"label":"Node","lang":"node","source":"// Idempotency-Key is optional: send one to make a retry safe.\nconst res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/rotate-secret\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n    \"Idempotency-Key\": crypto.randomUUID(),\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"# Idempotency-Key is optional: send one to make a retry safe.\n$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n  'Idempotency-Key' = [guid]::NewGuid().ToString()\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/rotate-secret' -Headers $headers"}]}},"/api/v1/webhooks/{webhookId}/test":{"post":{"description":"Delivered immediately; the response reports the first attempt.","parameters":[{"in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"attempts":1,"deliveryId":"f0a3e6b8-2d17-4c95-8b40-9e6c1a7f3d28","error":"","status":"delivered","statusCode":200},"schema":{"$ref":"#/components/schemas/WebhookAttempt"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request — the message names the problem"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (or belongs to another organisation)"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded for this key — see Retry-After"}},"security":[{"ApiKeyAuth":[]}],"summary":"Send a test (ping) event","tags":["Webhooks"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X POST \"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/test\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/test\", {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Post -Uri 'https://api.triggr-app.com/api/v1/webhooks/\u003cwebhookId\u003e/test' -Headers $headers"}]}},"/api/v1/workflows":{"get":{"responses":{"200":{"content":{"application/json":{"example":{"workflows":[{"active":true,"folderPath":"/Offboarding","id":"wf_d4e5f6","name":"Offboard User","updatedAt":"2026-09-20T14:03:11Z"}]},"schema":{"properties":{"workflows":{"items":{"$ref":"#/components/schemas/Workflow"},"type":"array"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid, revoked, or expired API key"}},"security":[{"ApiKeyAuth":[]}],"summary":"List active Studio workflows","tags":["Workflows \u0026 executions"],"x-codeSamples":[{"label":"curl","lang":"curl","source":"curl -X GET \"https://api.triggr-app.com/api/v1/workflows\" \\\n  -H \"Authorization: Bearer $TRIGGR_API_KEY\""},{"label":"Node","lang":"node","source":"const res = await fetch(\"https://api.triggr-app.com/api/v1/workflows\", {\n  method: \"GET\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.TRIGGR_API_KEY}`,\n  },\n});\nif (!res.ok) throw new Error(`Triggr ${res.status}: ${await res.text()}`);\nconst data = await res.json();"},{"label":"PowerShell","lang":"powershell","source":"$headers = @{\n  Authorization = \"Bearer $env:TRIGGR_API_KEY\"\n}\nInvoke-RestMethod -Method Get -Uri 'https://api.triggr-app.com/api/v1/workflows' -Headers $headers"}]}}},"security":[{"ApiKeyAuth":[]}],"servers":[{"url":"https://api.triggr-app.com"}],"tags":[{"description":"Who this key is, and the clients every other endpoint scopes by.","name":"Organisation"},{"description":"Studio forms with shareable embed URLs, and form sessions that embed a `microsoft` or `google` form as an already-signed-in user. Branch on each form's `embeddable` (see Embedding): `microsoft` and `google` forms embed as the signed-in user, `none` forms embed with a session attributing the submission to your portal user (or plainly from `shareUrl`), and `password` / `internal` forms cannot be embedded.","name":"Studio forms"},{"description":"The Studio workflow catalogue and a status feed of runs: what ran, for which client, how it ended. Outcome only — never parameters, step context or logs.","name":"Workflows \u0026 executions"},{"description":"Core forms (onboarding, offboarding, …) with their configuration status, embedded sessions for the public ones, and every request submitted through them with live status.","name":"Core forms"},{"description":"Render and submit a Core form in your own UI as a technician. Scope `core:run`.","name":"Core run"},{"description":"Read and write Core configuration. A form has one base config and optional per-client overrides; writes merge (omitted keeps, formConfig/execConfig replace as units, null clears, `inherit` clears a client's availability); read the `etag` and send If-Match to write atomically. Scope `core:configure`.","name":"Core configuration"},{"description":"The work waiting for a person. Read with any key; decide with scope `executions:manage`, naming the actor.","name":"Approvals \u0026 manual steps"},{"description":"Signed event delivery to your endpoint, so you don't poll. Register a URL, verify `X-Triggr-Signature` (accept the header if any `v1` matches — there are two for 24 hours after a secret rotation), inspect and re-send deliveries.","name":"Webhooks"},{"description":"This document.","name":"Meta"}],"x-triggr-scopes":[{"description":"Fetch run forms, resolve field options, check UPNs and submit Core forms as a technician from your own UI. Same approval gate as the Core app.","id":"core:run","title":"Run Core forms natively"},{"description":"Read and write Core configuration (base and per-client), preview run forms, and use the Microsoft 365, PSA and on-prem picker lookups. This includes each client's granted groups, licences, mailboxes and handover targets — only grant it to a portal you operate.","id":"core:configure","title":"Configure Core workflows"},{"description":"Approve or reject approvals, complete manual steps, cancel and retry executions — on behalf of a named person in your portal, whose name and email are recorded on the run.","id":"executions:manage","title":"Act on running work"}]}