Public REST API
Authentication, rate limits, ticket CRUD, comments, attachments, and error handling.
The FlowMingo public API (/api/v1) lets integrations list, create, update, and delete tickets in a workspace using scoped API keys.
Plan: Public API requires Pro or Enterprise (
integrations.public_api). Create keys under Admin → API in the app. Use API Reference → Try It on this docs site to test endpoints interactively.
Getting started in 5 minutes
- Create an API key — App → Admin → API → create key with scopes
tickets:readandtickets:write. Copy the plaintext key (fm…) — it is shown only once. - Verify the key —
GET /mereturns your workspace id/name and key scopes. - List tickets —
GET /tickets?limit=50withAuthorization: Bearer fm…. - Create a ticket —
POST /ticketswithtitle,ticketFormId, and optionaldescription. - Add a reply —
POST /tickets/{id}/commentswith{ "content": "…" }(visible in the ticket chat).
Use a production key (app.flowmingo.io) for Try It on this docs site. Keys from dev/staging use a different server secret and return 401 invalid_api_key on production.
Base URL
https://app.flowmingo.io/api/v1
Your workspace is determined by the API key, not the URL path.
Custom domains (e.g.
support.yourcompany.com) apply to the web app UI. Integrations should always callhttps://app.flowmingo.io/api/v1.
Authentication
Authorization: Bearer fmxxxxxxxxxxxxxxxxxxxxxxxxAll endpoints except GET /health and signed attachment downloads require a Bearer token.
GET /me
GET /meReturns workspace metadata and the credential bound to the key. Works with any valid key (no scope required) — useful to confirm a write-only key before calling POST /tickets.
curl -s -H "Authorization: Bearer fm…" \
"https://app.flowmingo.io/api/v1/me"Scopes
Default-deny. Assign scopes when creating or editing a key in Admin → API.
| Scope | Access |
|---|---|
tickets:read | GET /tickets, GET /tickets/{id}, GET /attachments/{id} |
tickets:write | POST /tickets, PATCH /tickets/{id}, DELETE /tickets/{id}, POST /tickets/{id}/comments |
Rate limits
Enforced per workspace and per API key (Upstash). Exceeded limits return HTTP 429 with JSON code: rate_limit_exceeded and header Retry-After.
| Plan | Workspace / min | API key / min | Workspace / day |
|---|---|---|---|
| Basic | — (API not available) | — | — |
| Pro | 100 | 60 | 15,000 |
| Enterprise | 300 | 120 | 100,000 |
Response headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset. Implement exponential backoff on 429.
Endpoints (v1)
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /health | — | Liveness check |
GET | /me | Bearer | Workspace + credential metadata |
GET | /tickets | tickets:read | Paginated ticket list (limit, cursor) |
POST | /tickets | tickets:write | Create ticket |
GET | /tickets/{id} | tickets:read | Single ticket + attachments[] |
PATCH | /tickets/{id} | tickets:write | Update status, priority, customFieldData |
DELETE | /tickets/{id} | tickets:write | Permanently delete ticket |
POST | /tickets/{id}/comments | tickets:write | Append public message to ticket chat |
GET | /attachments/{id} | tickets:read | Download file by attachment id (Bearer) |
GET | /attachments/download?token=… | Token | Signed URL from ticket JSON (1h TTL) |
Full request/response schemas: API Reference (synced from OpenAPI).
Ticket JSON: status vs workflowStatus
status vs workflowStatusEach ticket has two status concepts:
| Field | Meaning |
|---|---|
status | Legacy lifecycle column: open, in-progress, resolved, closed |
workflowStatus | Custom status from the ticket form (id, name, phase) — what agents see in Inbox/Kanban |
The app stores the custom status id internally as __workflowStatusId in custom_field_data. API responses expose it as enriched workflowStatus (not in customFieldData).
Updating status via API
Option A — legacy status (simple):
curl -X PATCH -H "Authorization: Bearer fm…" \
-H "Content-Type: application/json" \
-d '{"status":"in-progress"}' \
"https://app.flowmingo.io/api/v1/tickets/FTT-4"The API picks the matching workflow status for that phase on the ticket form and syncs __workflowStatusId automatically.
Option B — exact custom status:
curl -X PATCH -H "Authorization: Bearer fm…" \
-H "Content-Type: application/json" \
-d '{"customFieldData":{"__workflowStatusId":"wfs_abc123"}}' \
"https://app.flowmingo.io/api/v1/tickets/FTT-4"Also updates the legacy status column from the workflow phase.
Messages vs description field
- Initial description — set on
POST /ticketsviadescription(creates the first chat message). - New replies — use
POST /tickets/{id}/commentswith{ "content": "…" }. - Do not PATCH
DescriptionincustomFieldData— returns400with a hint to use comments.
Examples
List tickets
curl -s -H "Authorization: Bearer fm…" \
"https://app.flowmingo.io/api/v1/tickets?limit=50"Response: { "tickets": […], "nextCursor": "…", "hasMore": true }. Tickets include enriched ticketForm, category, area, createdBy, assignedTo, and workflowStatus labels.
Create ticket
curl -s -X POST -H "Authorization: Bearer fm…" \
-H "Content-Type: application/json" \
-d '{
"title": "Laptop request",
"ticketFormId": "tf_abc123",
"description": "Need a new device",
"priority": "medium"
}' \
"https://app.flowmingo.io/api/v1/tickets"Returns 201 with { "ticket": { … } }. ticketFormId is the form id from Studio → Ticket forms (must belong to the key's workspace).
Add a public comment
curl -s -X POST -H "Authorization: Bearer fm…" \
-H "Content-Type: application/json" \
-d '{"content":"Customer confirmed the fix."}' \
"https://app.flowmingo.io/api/v1/tickets/FTT-4/comments"Returns 201 with { "comment": { "id", "content", "createdBy", "createdAt", … } }.
Delete ticket
curl -s -X DELETE -H "Authorization: Bearer fm…" \
"https://app.flowmingo.io/api/v1/tickets/FTT-4"Returns { "deleted": true, "id": "FTT-4" }. Deletes messages, history, and storage files. Cannot be undone.
Attachments
GET /tickets/{id} includes an attachments array. File fields in customFieldData also include download metadata.
| Field | Purpose |
|---|---|
id | Stable id for Bearer download (recommended) |
downloadUrl | Signed absolute URL (expires after 1 hour) |
path | Internal storage path (debugging) |
Bearer download (recommended)
curl -H "Authorization: Bearer fm…" \
"https://app.flowmingo.io/api/v1/attachments/{id}" \
--output file.pdfAdd ?inline=1 for inline preview.
Signed URL
Use downloadUrl from the ticket JSON directly (no Bearer). Re-fetch the ticket when the token expires.
Error responses
Errors return JSON: { "error": "…", "code": "…" }.
| HTTP | code | Typical cause |
|---|---|---|
| 400 | validation_error | Invalid body, blocked status transition, protected field |
| 401 | invalid_api_key | Missing/expired/revoked key, wrong environment |
| 403 | insufficient_scope | Key lacks required scope |
| 403 | — | Plan does not include Public API |
| 404 | not_found | Ticket/form not in workspace |
| 429 | rate_limit_exceeded | Plan rate limit — retry after Retry-After |
| 500 | internal_error | Server error |
Pagination
GET /tickets uses cursor pagination:
- First page:
?limit=100(max 200). - If
hasMoreistrue, passnextCursoras thecursorquery param on the next request.
Product guides
- Tickets — creating and managing tickets in the UI
- Quickstart — workspace setup for admins and agents
Interactive Try It for every endpoint: API Reference tab on this site.
Updated about 2 months ago
