Developers
The Flowdexa API is organized around REST. It has predictable, resource-oriented URLs, accepts JSON request bodies, returns JSON responses, and uses standard HTTP status codes and verbs.
Every request goes over HTTPS and authenticates with a project API key sent as a Bearer token — no SDK required, any HTTP client works. Mint and scope keys in Settings → API.
Single records come back wrapped under the resource name ({ "customer": { … } }); lists use a consistent envelope ({ project_id, count, … }).
https://flowdexa.app/api/v1Scopes
read — list and fetch records.
read+write — also create and update (Business plan and up).
Send your key in the Authorization header on every request. Keys are project-scoped — a key only ever sees its own project's data.
curl https://flowdexa.app/api/v1/customers \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"Flowdexa uses conventional HTTP status codes. Every failure returns the same JSON shape — { "error": "<message>" } — so you can branch on the status code and surface the message.
400 Validation failed
{ "error": "name is required" }
401 Missing, invalid, or revoked key
{ "error": "Invalid API key." }
402 Trial lapsed, no card on file
{ "error": "Trial expired. Add a payment method in Settings → Billing to continue using the API." }
403 Read-only key on a write endpoint
{ "error": "This endpoint requires a read+write API key." }
429 Rate limit hit (see Retry-After)
{ "error": "Rate limit exceeded. Retry after 30s." }The people and organizations you do work for. Jobs, locations, and invoices point back to a customer.
/customersread+write keyCreates a customer in the authenticated project. The created record is returned wrapped under “customer”.
Body parameters
namestringRequiredemailstringOptionalphonestringOptionalstatusstringOptionalReturns Returns 201 with the created customer object.
/customerscurl https://flowdexa.app/api/v1/customers \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"email": "ops@acme.com",
"phone": "+66 2 123 4567"
}'{
"customer": {
"id": "8f2a1c40-...",
"name": "Acme Corp",
"email": "ops@acme.com",
"phone": "+66 2 123 4567",
"status": "active",
"created_at": "2026-06-13T09:12:00Z"
}
}/customersread keyLists customers in the project. Returns the standard list envelope: project_id, count, and the resource array.
Query parameters
statusstringOptionalqstringOptionallimitintegerOptionalReturns Returns 200 with the customers array.
/customerscurl "https://flowdexa.app/api/v1/customers?status=active&limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 2,
"customers": [
{
"id": "8f2a1c40-...",
"name": "Acme Corp",
"email": "ops@acme.com",
"phone": "+66 2 123 4567",
"status": "active"
},
{
"id": "3b91e7d2-...",
"name": "Sathorn Mall",
"email": null,
"phone": null,
"status": "active"
}
]
}Scheduled work. A job ties a customer, service, time window, and the resources assigned to do it.
/jobsread+write keySchedules a job. customer_id and service_id must belong to the same project as the key. New jobs start in “draft” unless status is set.
Body parameters
titlestringRequiredcustomer_iduuidRequiredservice_iduuidRequiredscheduled_startISO datetimeRequiredscheduled_endISO datetimeRequiredlocation_iduuidOptionalresource_idsuuid[]OptionalnotesstringOptionalstatusstringOptionalReturns Returns 201 with the created job object.
/jobscurl https://flowdexa.app/api/v1/jobs \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{
"title": "Deep clean — Sathorn Tower lobby",
"customer_id": "acme-corp-uuid",
"service_id": "premium-cleaning-uuid",
"scheduled_start": "2026-06-01T08:30:00+07:00",
"scheduled_end": "2026-06-01T12:30:00+07:00",
"resource_ids": ["team-orchid-uuid", "van-04-uuid"]
}'{
"job": {
"id": "job-uuid",
"title": "Deep clean — Sathorn Tower lobby",
"status": "draft",
"scheduled_start": "2026-06-01T08:30:00+07:00",
"scheduled_end": "2026-06-01T12:30:00+07:00",
"customer_id": "acme-corp-uuid",
"service_id": "premium-cleaning-uuid",
"resource_ids": ["team-orchid-uuid", "van-04-uuid"],
"created_at": "2026-05-29T10:00:00Z"
}
}/jobsread keyLists jobs, newest scheduled first. Filter by one or more statuses.
Query parameters
statusstringOptionallimitintegerOptionalReturns Returns 200 with the jobs array.
/jobscurl "https://flowdexa.app/api/v1/jobs?status=dispatched,in_progress&limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"jobs": [
{
"id": "job-uuid",
"title": "Deep clean — Sathorn Tower lobby",
"status": "dispatched",
"scheduled_start": "2026-06-01T08:30:00+07:00",
"scheduled_end": "2026-06-01T12:30:00+07:00",
"customer_id": "acme-corp-uuid",
"service_id": "premium-cleaning-uuid",
"resource_ids": ["team-orchid-uuid", "van-04-uuid"],
"notes": null,
"created_at": "2026-05-29T10:00:00Z"
}
]
}/jobs/{id}/statusread+write keyAdvances a job through its lifecycle (confirmed → dispatched → in_progress → completed, or cancelled). Side effects like timesheets and stock consumption fire on the matching transitions, exactly as in the app.
Body parameters
statusstringRequiredReturns Returns 200 with the job id and new status.
/jobs/{id}/statuscurl -X PATCH https://flowdexa.app/api/v1/jobs/job-uuid/status \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress" }'{
"job": {
"id": "job-uuid",
"project_id": "9b1c2d3e-...",
"status": "in_progress"
}
}Staff, vehicles, rooms, and equipment that jobs consume. Use this to check what exists before assigning work.
/resourcesread keyLists resources with their type, skills, and current utilization.
Query parameters
typestringOptionallimitintegerOptionalReturns Returns 200 with the resources array.
/resourcescurl "https://flowdexa.app/api/v1/resources?type=Truck&limit=10" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"resources": [
{
"id": "van-04-uuid",
"name": "Van 04",
"resource_type": "Truck",
"amount": 1,
"skills": ["HVAC", "Electrical safety"],
"availability": "All day",
"utilization": 58,
"status": "Available",
"created_at": "2026-04-15T10:00:00Z"
}
]
}The people in your project — staff who get assigned to jobs, with their roles and skills.
/membersread+write keyAdds a member by email and sends them an invite to accept. role defaults to employee — owner cannot be assigned through the API.
Body parameters
emailstringRequiredfull_namestringOptionalrolestringOptionalskillsstring[]OptionalReturns Returns 201 with the member object.
/memberscurl https://flowdexa.app/api/v1/members \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{
"email": "niran@acme.com",
"full_name": "Niran P.",
"role": "operations",
"skills": ["HVAC", "Electrical safety"]
}'{
"member": {
"id": "mem-uuid",
"email": "niran@acme.com",
"full_name": "Niran P.",
"role": "operations",
"status": "invited",
"skills": ["HVAC", "Electrical safety"],
"created_at": "2026-06-13T09:20:00Z"
}
}/membersread keyLists members in the project with their role, status, and skills.
Query parameters
limitintegerOptionalReturns Returns 200 with the members array.
/memberscurl "https://flowdexa.app/api/v1/members?limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"members": [
{
"id": "mem-uuid",
"email": "niran@acme.com",
"full_name": "Niran P.",
"role": "operations",
"status": "active",
"skills": ["HVAC", "Electrical safety"],
"created_at": "2026-06-13T09:20:00Z"
}
]
}Time-off requests and their approval state. List them, then approve or reject from an external HR flow.
/leaveread keyLists leave requests with their dates, type, and approval state.
Query parameters
limitintegerOptionalReturns Returns 200 with the requests array.
/leavecurl "https://flowdexa.app/api/v1/leave?limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"requests": [
{
"id": "leave-uuid",
"employee_email": "niran@acme.com",
"type": "annual",
"dates": "Jun 20 – Jun 22",
"start_date": "2026-06-20",
"end_date": "2026-06-22",
"approval_state": "AwaitingManager",
"coverage": null,
"message": "Family trip",
"attachment_url": null,
"created_at": "2026-06-10T04:00:00Z"
}
]
}/leave/{id}/decisionread+write keyRecords a manager decision on a pending request — useful when an HR system forwards approvals back to Flowdexa.
Body parameters
decisionstringRequirednotestringOptionalcoveragestringOptionalReturns Returns 200 with the updated request.
/leave/{id}/decisioncurl -X POST https://flowdexa.app/api/v1/leave/leave-uuid/decision \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{ "decision": "approve" }'{
"request": {
"id": "leave-uuid",
"employee_email": "niran@acme.com",
"dates": "Jun 20 – Jun 22",
"approval_state": "Approved"
}
}Finalized payroll periods with gross, overtime, and deduction totals — for finance exports.
/payroll-runsread keyLists payroll runs, newest first, with their totals and status.
Query parameters
limitintegerOptionalReturns Returns 200 with the runs array.
/payroll-runscurl "https://flowdexa.app/api/v1/payroll-runs?limit=12" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"runs": [
{
"id": "run-uuid",
"period": "2026-05",
"period_start": "2026-05-01",
"period_end": "2026-05-31",
"gross_pay": 184250,
"overtime": 12400,
"deductions": 9870,
"status": "finalized",
"created_at": "2026-06-01T02:00:00Z"
}
]
}Subscribe an external URL to project events. Flowdexa signs each delivery — verify the signature before trusting it.
/webhooksread+write keyRegisters a delivery URL. The signing secret is returned once on creation — store it; afterward only a prefix is visible.
Body parameters
urlstringRequiredlabelstringOptionaleventsstring[]OptionalReturns Returns 201 with the webhook and the one-time secret.
/webhookscurl https://flowdexa.app/api/v1/webhooks \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-system.example.com/flowdexa-webhook",
"label": "Ops sync",
"events": ["audit.job.update"]
}'{
"webhook": {
"id": "wh-uuid",
"label": "Ops sync",
"url": "https://your-system.example.com/flowdexa-webhook",
"secret_prefix": "whsec_3a4b",
"events": ["audit.job.update"],
"enabled": true,
"created_at": "2026-06-13T09:30:00Z"
},
"secret": "whsec_3a4b5c6d...shown-once",
"note": "Shown once. HMAC-SHA256 the body with this secret and compare to the x-flowdexa-signature header."
}/webhooksread keyLists webhooks with their last delivery status.
Query parameters
limitintegerOptionalReturns Returns 200 with the webhooks array.
/webhookscurl https://flowdexa.app/api/v1/webhooks \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"webhooks": [
{
"id": "wh-uuid",
"label": "Ops sync",
"url": "https://your-system.example.com/flowdexa-webhook",
"secret_prefix": "whsec_3a4b",
"events": ["audit.job.update"],
"enabled": true,
"created_at": "2026-06-13T09:30:00Z",
"last_delivery_at": "2026-06-13T10:00:00Z",
"last_delivery_status": 200
}
]
}/webhooks/{id}read+write keyRemoves a webhook. Future events stop being delivered immediately.
Returns Returns 204 No Content.
/webhooks/{id}curl -X DELETE https://flowdexa.app/api/v1/webhooks/wh-uuid \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"204 No Content/webhooks/{id}/deliveriesread keyShows the recent delivery attempts for a webhook — status code, timing, and the request/response bodies for debugging.
Query parameters
limitintegerOptionalReturns Returns 200 with the deliveries array.
/webhooks/{id}/deliveriescurl https://flowdexa.app/api/v1/webhooks/wh-uuid/deliveries \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"webhook": { "id": "wh-uuid", "label": "Ops sync", "url": "https://…", "enabled": true },
"count": 1,
"deliveries": [
{
"id": "dlv-uuid",
"event_type": "audit.job.update",
"attempted_at": "2026-06-13T10:00:00Z",
"status_code": 200,
"error": null,
"duration_ms": 142,
"request_body": "{ … }",
"response_body": "ok"
}
]
}/webhooks/{id}/deliveries/{delivery_id}/replayread+write keyRe-sends a past delivery to the webhook URL — useful when your endpoint was down. The webhook must be enabled.
Returns Returns 200 confirming the replay.
/webhooks/{id}/deliveries/{delivery_id}/replaycurl -X POST \
https://flowdexa.app/api/v1/webhooks/wh-uuid/deliveries/dlv-uuid/replay \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"replayed": "dlv-uuid",
"event_type": "audit.job.update",
"webhook_id": "wh-uuid"
}Every change in the project — who did what, when. A read-only stream for compliance and monitoring.
/audit-logread keyLists audit-log entries, newest first.
Query parameters
entity_typestringOptionallimitintegerOptionalReturns Returns 200 with the entries array.
/audit-logcurl "https://flowdexa.app/api/v1/audit-log?entity_type=job&limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"entries": [
{
"id": "audit-uuid",
"created_at": "2026-06-13T10:00:00Z",
"actor_email": "api_key:key-uuid",
"action": "update",
"entity_type": "job",
"entity_id": "job-uuid",
"payload": { "from_status": "confirmed", "to_status": "in_progress" }
}
]
}Your project's identity and branding — a read-only snapshot of the workspace behind the key.
/projectread keyReturns the project the API key belongs to.
Returns Returns 200 with the project object.
/projectcurl https://flowdexa.app/api/v1/project \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project": {
"id": "9b1c2d3e-...",
"name": "Acme Operations",
"brand_name": "Acme",
"brand_color": "#1d4ed8",
"logo_url": null,
"created_at": "2026-01-10T08:00:00Z",
"archived_at": null
}
}Your catalog — what the business sells or performs, with its duration, price, and skill/resource requirements.
/servicesread keyLists the service catalog. Active only by default; pass active=all to include inactive, active=false for only inactive.
Query parameters
activestringOptionallimitintegerOptionalReturns Returns 200 with the services array.
/servicescurl "https://flowdexa.app/api/v1/services?limit=50" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"services": [
{
"id": "svc-uuid",
"name": "Premium facility cleaning",
"category": "Cleaning",
"duration": "4h",
"delivery_mode": "on_site",
"unit_price": 4500,
"currency": "THB",
"required_skills": ["HVAC", "Site lead"],
"required_resources": ["Floor machine"],
"buffer_minutes": 15,
"is_active": true,
"description": "Deep clean for commercial lobbies.",
"created_at": "2026-03-01T08:00:00Z"
}
]
}Stock items with on-hand quantity and reorder points. Filter to just what's running low.
/inventoryread keyLists active stock items. Pass low_stock=true to return only items at or below their reorder point.
Query parameters
low_stockbooleanOptionallimitintegerOptionalReturns Returns 200 with the items array.
/inventorycurl "https://flowdexa.app/api/v1/inventory?low_stock=true" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"items": [
{
"id": "stk-uuid",
"name": "Microfiber cloth",
"sku": "MF-200",
"unit": "pack",
"quantity_on_hand": 4,
"reorder_point": 10,
"unit_cost": 120,
"supplier": "CleanCo",
"storage_location": "Shelf B2",
"is_active": true
}
]
}Regular and overtime hours per pay period, generated when jobs complete. The detail behind payroll runs.
/timesheetsread keyLists timesheet rows, newest period first. Filter by status or member.
Query parameters
statusstringOptionalmember_iduuidOptionallimitintegerOptionalReturns Returns 200 with the timesheets array.
/timesheetscurl "https://flowdexa.app/api/v1/timesheets?status=Approved&limit=100" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"timesheets": [
{
"id": "ts-uuid",
"member_id": "mem-uuid",
"resource_id": null,
"job_id": "job-uuid",
"period_start": "2026-05-01",
"period_end": "2026-05-31",
"regular_hours": 168,
"overtime_hours": 6,
"status": "Approved",
"created_at": "2026-06-01T02:00:00Z"
}
]
}Two layers: recurring work schedules (the baseline hours) and one-off windows (booked, leave, maintenance). Combine them to compute free/busy.
/work-schedulesread keyThe recurring weekly hours, days, and breaks a resource or member follows — the base layer of availability.
Query parameters
resource_iduuidOptionallimitintegerOptionalReturns Returns 200 with the work_schedules array.
/work-schedulescurl "https://flowdexa.app/api/v1/work-schedules?resource_id=van-04-uuid" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"work_schedules": [
{
"id": "ws-uuid",
"resource_id": "van-04-uuid",
"member_id": null,
"label": "Weekdays",
"work_days": ["mon", "tue", "wed", "thu", "fri"],
"work_start": "08:00",
"work_end": "17:00",
"breaks": [{ "start": "12:00", "end": "13:00" }],
"effective_from": "2026-01-01",
"effective_until": null,
"is_active": true
}
]
}/availabilityread keyOne-off blocks layered on top of the work schedule: booked, unavailable, maintenance, or leave. Pair with /work-schedules to know what's actually free.
Query parameters
resource_iduuidOptionalstatusstringOptionalfromdateOptionaltodateOptionallimitintegerOptionalReturns Returns 200 with the windows array.
/availabilitycurl "https://flowdexa.app/api/v1/availability?resource_id=van-04-uuid&from=2026-06-01&to=2026-06-30" \
-H "Authorization: Bearer fxa_a1b2c3d4e5f6a1b2c3d4e5f6"{
"project_id": "9b1c2d3e-...",
"count": 1,
"windows": [
{
"id": "win-uuid",
"resource_id": "van-04-uuid",
"starts_at": "2026-06-12T09:00:00+07:00",
"ends_at": "2026-06-12T11:00:00+07:00",
"status": "booked",
"note": "Greenfield HVAC service"
}
]
}Need an endpoint that isn't here yet? Tell us what you're building.