API v1.0

API Reference

Integrate Formict with your existing systems using the Public API. Manage jobs, customers, vehicles, locations, and shifts programmatically.

Base URL
https://api.formict.com/v1/public

Overview

The Formict Public API lets you integrate your existing systems — ERPs, CRMs, dispatch platforms, or custom workflows — with Formict. You can create and manage jobs, customers, vehicles, locations, and shifts programmatically.

Requirements

  • Plan: Pro or Enterprise (API access is not available on Free or Starter plans)
  • API Key: Generate one from Settings → API Keys in the Formict dashboard

Interactive playground

A live interactive API playground is available at api.formict.com/v1/public/docs. You can browse endpoints, fill in parameters, paste your API key, and send real requests directly from the browser.

Authentication

All API requests must include your API key in the Authorization header using the Bearer scheme:

Authorization: Bearer fmct_live_xxxxxxxxxxxxxxxxxxxxxxxx

API key format

API keys follow the format fmct_live_ followed by a random string. The fmct_live_ prefix is the public identifier visible in the dashboard. The full key is shown only once at creation — store it securely.

Scopes

Each API key is created with one or more scopes that determine what it can do:

Scope Permissions
read Read resources (GET requests)
write Create and update resources (POST, PATCH, DELETE requests)
admin Full access including team and settings

A request will fail with 403 Forbidden if the API key lacks the required scope.

Security best practices

  • Never expose API keys in client-side code or public repositories
  • Use the minimum required scope for each integration
  • Set an expiration date for keys that don't need permanent access
  • Regenerate keys immediately if you suspect they've been compromised
  • Use separate keys for different integrations to isolate access

Request Format

Base URL

https://api.formict.com/v1/public

Content type

All request bodies must be JSON with the Content-Type header:

Content-Type: application/json

Example request

curl -X GET "https://api.formict.com/v1/public/jobs?page=1&limit=20" \
  -H "Authorization: Bearer fmct_live_xxxxxxxx" \
  -H "Content-Type: application/json"

Response Format

All responses are JSON. Successful responses wrap data in a data envelope:

{
  "data": {
    "jobs": [...],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 42,
      "totalPages": 3
    }
  },
  "message": "Success"
}

Single-resource responses follow the same pattern:

{
  "data": {
    "job": {
      "id": "clx1234...",
      "title": "AC Maintenance",
      "status": "CREATED",
      ...
    }
  },
  "message": "Success"
}

HTTP status codes

Status Meaning
200Success
201Resource created
400Bad request (validation error)
401Unauthorized (missing or invalid API key)
403Forbidden (insufficient scope)
404Resource not found
422Unprocessable entity (business logic error)
429Rate limit exceeded
500Internal server error

Error Handling

Error responses include an error field with a human-readable message and optionally a machine-readable code:

{
  "error": "Job not found",
  "code": "NOT_FOUND"
}

Common error codes

Code Description
NOT_FOUNDThe requested resource does not exist or was deleted
VALIDATION_ERRORRequest body failed validation (missing or invalid fields)
TERMINAL_STATECannot modify a job in COMPLETED or CANCELLED status
JOB_IN_PROGRESSCannot delete a job that is currently in progress
FORBIDDENAPI key lacks the required scope for this operation
RATE_LIMITEDToo many requests — wait and retry

Pagination

List endpoints support cursor-based pagination with page and limit query parameters:

Parameter Type Default Description
page number 1 Page number (1-indexed)
limit number 20 Items per page (max 100)

The response includes a pagination object:

"pagination": {
  "page": 1,
  "limit": 20,
  "total": 42,
  "totalPages": 3
}

Rate Limits

API keys have configurable rate limits set at creation time (requests per minute). When you exceed the rate limit, the API returns 429 Too Many Requests.

The response includes headers indicating your current rate limit status:

Header Description
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetSeconds until the rate limit resets

Jobs

Jobs are field service work items — deliveries, maintenance calls, inspections, or any task performed at a customer's location.

GET /jobs

Returns a paginated list of jobs in your organization. Requires read scope.

Query parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
statusstringFilter by status: CREATED, ASSIGNED, IN_PROGRESS, COMPLETED, CANCELLED
customerIdstringFilter by customer ID
locationIdstringFilter by location ID
prioritystringFilter by priority: LOW, NORMAL, HIGH
targetDatestringFilter by date (YYYY-MM-DD) — returns jobs with time windows overlapping this date

Example request

curl "https://api.formict.com/v1/public/jobs?status=CREATED&limit=10" \
  -H "Authorization: Bearer fmct_live_xxxxxxxx"

Example response

{
  "data": {
    "jobs": [
      {
        "id": "clx1abc...",
        "title": "AC Maintenance",
        "description": "Annual AC unit service",
        "status": "CREATED",
        "priority": "NORMAL",
        "customerId": "clx2def...",
        "locationId": "clx3ghi...",
        "jobLatitude": "-6.2088",
        "jobLongitude": "106.8456",
        "serviceDuration": 3600,
        "timeWindowType": "HARD",
        "earliestStart": "2025-03-15T08:00:00.000Z",
        "latestEnd": "2025-03-15T12:00:00.000Z",
        "scheduledStart": null,
        "scheduledEnd": null,
        "assignedUserId": null,
        "startedAt": null,
        "completedAt": null,
        "createdAt": "2025-03-14T10:00:00.000Z",
        "updatedAt": "2025-03-14T10:00:00.000Z",
        "customer": { "id": "clx2def...", "name": "PT Sejahtera" },
        "assignedUser": null,
        "location": { "id": "clx3ghi...", "name": "Jakarta Office" }
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    }
  },
  "message": "Success"
}

GET /jobs/:id

Returns a single job with full details including customer, assigned worker, tags, and capacity demands. Requires read scope.

Path parameters

ParameterTypeDescription
idstringJob ID

Example response

{
  "data": {
    "job": {
      "id": "clx1abc...",
      "title": "AC Maintenance",
      "description": "Annual AC unit service",
      "status": "CREATED",
      "priority": "NORMAL",
      "customerId": "clx2def...",
      "locationId": "clx3ghi...",
      "jobLatitude": "-6.2088",
      "jobLongitude": "106.8456",
      "serviceDuration": 3600,
      "timeWindowType": "HARD",
      "earliestStart": "2025-03-15T08:00:00.000Z",
      "latestEnd": "2025-03-15T12:00:00.000Z",
      "scheduledStart": null,
      "scheduledEnd": null,
      "assignedUserId": null,
      "shiftId": null,
      "startedAt": null,
      "completedAt": null,
      "actualDuration": null,
      "createdAt": "2025-03-14T10:00:00.000Z",
      "updatedAt": "2025-03-14T10:00:00.000Z",
      "customer": {
        "id": "clx2def...",
        "name": "PT Sejahtera",
        "address": "Jl. Sudirman 100",
        "latitude": "-6.2088",
        "longitude": "106.8456"
      },
      "assignedUser": null,
      "location": { "id": "clx3ghi...", "name": "Jakarta Office" },
      "tags": [
        { "tag": { "id": "clx4jkl...", "name": "HVAC" } }
      ],
      "demands": [
        {
          "capacityDimension": { "id": "clx5mno...", "key": "weight", "label": "Weight" },
          "requiredValue": 50
        }
      ]
    }
  },
  "message": "Success"
}

POST /jobs

Creates a new job. Requires write scope. Returns 201 Created.

Request body

FieldTypeRequiredDescription
titlestringYesJob title (min 1 character)
customerIdstringNoCustomer ID
locationIdstringNoLocation/depot ID
descriptionstringNoDetailed description
jobLatitudenumberNoJob site latitude
jobLongitudenumberNoJob site longitude
prioritystringNoLOW, NORMAL, or HIGH
serviceDurationnumberNoDuration in seconds (default: 900)
timeWindowTypestringNoHARD or SOFT (default: HARD)
earliestStartstringNoISO 8601 datetime
latestEndstringNoISO 8601 datetime (must be after earliestStart)

Example request

curl -X POST "https://api.formict.com/v1/public/jobs" \
  -H "Authorization: Bearer fmct_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "AC Maintenance",
    "customerId": "clx2def...",
    "description": "Annual AC unit service",
    "priority": "NORMAL",
    "serviceDuration": 3600,
    "timeWindowType": "HARD",
    "earliestStart": "2025-03-15T08:00:00.000Z",
    "latestEnd": "2025-03-15T12:00:00.000Z"
  }'

Error cases

  • 400 — Missing required title field
  • 400earliestStart is after latestEnd
  • 400 — Customer or location ID not found in your organization

PATCH /jobs/:id

Updates an existing job. Only include the fields you want to change. Requires write scope.

Path parameters

ParameterTypeDescription
idstringJob ID

Request body

Same fields as POST /jobs, all optional. Only include fields you want to change.

Example request

curl -X PATCH "https://api.formict.com/v1/public/jobs/clx1abc..." \
  -H "Authorization: Bearer fmct_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "priority": "HIGH", "serviceDuration": 7200 }'

Error cases

  • 404 — Job not found
  • 422 — Cannot update a job in COMPLETED or CANCELLED status

DELETE /jobs/:id

Soft-deletes a job. The job is marked as deleted but retained in the database for data retention. Requires write scope.

Path parameters

ParameterTypeDescription
idstringJob ID

Example request

curl -X DELETE "https://api.formict.com/v1/public/jobs/clx1abc..." \
  -H "Authorization: Bearer fmct_live_xxxxxxxx"

Error cases

  • 404 — Job not found
  • 422 — Cannot delete a job that is IN_PROGRESS

Customers

Customers represent the people or businesses where field work takes place. Each customer has a service location with GPS coordinates used for route optimization.

GET /customers

Returns a paginated list of customers. Requires read scope.

Query parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 50, max: 100)
searchstringSearch by name or address (case-insensitive)

Example response

{
  "data": {
    "customers": [
      {
        "id": "clx2def...",
        "name": "PT Sejahtera",
        "address": "Jl. Sudirman 100, Jakarta",
        "latitude": "-6.2088",
        "longitude": "106.8456",
        "serviceDuration": 1800,
        "priority": "NORMAL",
        "timeWindowType": "HARD",
        "operationalStart": "08:00",
        "operationalEnd": "17:00",
        "createdAt": "2025-01-10T08:00:00.000Z",
        "updatedAt": "2025-01-10T08:00:00.000Z"
      }
    ],
    "pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
  },
  "message": "Success"
}

GET /customers/:id

Returns a single customer with all fields. Requires read scope.

POST /customers

Creates a new customer. Requires write scope. Returns 201 Created.

Request body

FieldTypeRequiredDescription
namestringYesCustomer name (min 1 character)
latitudenumberYesService location latitude
longitudenumberYesService location longitude
addressstringNoStreet address
serviceDurationnumberNoDefault service time in seconds
prioritystringNoLOW, NORMAL, or HIGH
timeWindowTypestringNoHARD or SOFT
operationalStartstringNoOpening time in HH:MM format
operationalEndstringNoClosing time in HH:MM format

Example request

curl -X POST "https://api.formict.com/v1/public/customers" \
  -H "Authorization: Bearer fmct_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "PT Sejahtera",
    "address": "Jl. Sudirman 100, Jakarta",
    "latitude": -6.2088,
    "longitude": 106.8456,
    "serviceDuration": 1800,
    "operationalStart": "08:00",
    "operationalEnd": "17:00"
  }'

PATCH /customers/:id

Updates an existing customer. Only include the fields you want to change. Requires write scope.

Request body

Same fields as POST /customers, all optional.

Vehicles

Vehicles represent your fleet. Each vehicle is assigned to a location (depot) and has capacity constraints, cost parameters, and capability tags.

GET /vehicles

Returns a paginated list of vehicles with tags and capacity info. Requires read scope.

Query parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 50, max: 100)
locationIdstringFilter by depot/location ID
isActivebooleanFilter by active status

Example response

{
  "data": {
    "vehicles": [
      {
        "id": "clx4jkl...",
        "name": "Van-01",
        "locationId": "clx3ghi...",
        "fixedCost": 50000,
        "costPerKm": 500,
        "costPerHour": 15000,
        "speedFactor": 1.0,
        "startLatitude": null,
        "startLongitude": null,
        "endPolicy": "RETURN_TO_ORIGIN",
        "isActive": true,
        "createdAt": "2025-01-10T08:00:00.000Z",
        "updatedAt": "2025-01-10T08:00:00.000Z",
        "location": { "id": "clx3ghi...", "name": "Jakarta Office" },
        "tags": [
          { "tag": { "id": "clx5mno...", "name": "HVAC" } }
        ],
        "capacities": [
          {
            "capacityDimension": { "id": "clx6pqr...", "key": "weight", "label": "Weight" },
            "maxValue": 1000
          }
        ]
      }
    ],
    "pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
  },
  "message": "Success"
}

GET /vehicles/:id

Returns a single vehicle with tags and capacities. Requires read scope.

Locations

Locations are your operational hubs or depots. Vehicles start and end their routes at their assigned location.

GET /locations

Returns all locations in your organization. Requires read scope.

Query parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 50, max: 100)
isActivebooleanFilter by active status

Example response

{
  "data": {
    "locations": [
      {
        "id": "clx3ghi...",
        "name": "Jakarta Office",
        "code": "JKT",
        "description": "Main headquarters",
        "address": "Jl. Sudirman 1, Jakarta",
        "latitude": "-6.1751",
        "longitude": "106.8272",
        "timezone": "Asia/Jakarta",
        "isPrimary": true,
        "isActive": true,
        "createdAt": "2025-01-01T00:00:00.000Z",
        "updatedAt": "2025-01-01T00:00:00.000Z"
      }
    ],
    "pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
  },
  "message": "Success"
}

GET /locations/:id

Returns a single location with all fields. Requires read scope.

Shifts

Shifts define when vehicles and workers are available. The route optimizer uses shift time windows as the available operating window for each vehicle.

GET /shifts

Returns a paginated list of shift templates with worker, location, vehicle, and break details. Requires read scope.

Query parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 50, max: 100)
locationIdstringFilter by location ID
userIdstringFilter by worker ID
daystringFilter by day of week (e.g., MONDAY)

Example response

{
  "data": {
    "shifts": [
      {
        "id": "clx7stu...",
        "userId": "clx8vwx...",
        "locationId": "clx3ghi...",
        "vehicleId": "clx4jkl...",
        "day": "MONDAY",
        "startTime": "08:00",
        "endTime": "17:00",
        "isGenerated": false,
        "createdAt": "2025-01-10T08:00:00.000Z",
        "updatedAt": "2025-01-10T08:00:00.000Z",
        "user": { "id": "clx8vwx...", "name": "John", "email": "[email protected]" },
        "location": { "id": "clx3ghi...", "name": "Jakarta Office" },
        "vehicle": { "id": "clx4jkl...", "name": "Van-01" },
        "breaks": [
          { "id": "clx9yza...", "startTime": "12:00", "endTime": "13:00", "isPaid": false }
        ]
      }
    ],
    "pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
  },
  "message": "Success"
}

GET /shifts/:id

Returns a single shift with worker, location, vehicle, and break details. Requires read scope.

Enums & Constants

These are the valid values for enum fields used across the API.

JobStatus

ValueDescription
CREATEDJob exists but is not assigned
ASSIGNEDJob is assigned to a vehicle/worker
IN_PROGRESSWorker has started the job
COMPLETEDJob is done
CANCELLEDJob was cancelled

JobPriority

ValueDescription
LOWLow priority
NORMALNormal priority (default)
HIGHHigh priority — preferred by the optimizer

TimeWindowType

ValueDescription
HARDStrict — job is dropped if it can't fit in the window
SOFTFlexible — solver penalizes but still assigns

VehicleEndPolicy

ValueDescription
RETURN_TO_ORIGINVehicle returns to its route origin after last job
END_AT_LAST_JOBRoute ends wherever the last job is

Day of week

Value
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

Duration format

All duration fields (serviceDuration, etc.) are in seconds. For example, 30 minutes = 1800, 1 hour = 3600.

Datetime format

All datetime fields use ISO 8601 format in UTC: 2025-03-15T08:00:00.000Z

Coordinate format

Latitude and longitude are stored as strings in the database but accepted as numbers in request bodies. Use decimal degrees (e.g., -6.2088 for latitude, 106.8456 for longitude).

Webhooks

Formict can send HTTP POST requests to your server when certain events occur. Webhooks are configured through Automations in the dashboard using the Send Webhook action type.

Setting up a webhook

  1. Go to Settings → Automations
  2. Create a new automation
  3. Select a trigger event (e.g., JOB_COMPLETED)
  4. Choose Send Webhook as the action
  5. Enter your webhook URL
  6. Activate the automation

Webhook payload

The webhook sends a JSON POST request to your URL with the event data:

{
  "event": "JOB_COMPLETED",
  "timestamp": "2025-03-15T14:30:00.000Z",
  "data": {
    "jobId": "clx1abc...",
    "title": "AC Maintenance",
    "status": "COMPLETED",
    "customerId": "clx2def...",
    "assignedUserId": "clx8vwx...",
    "completedAt": "2025-03-15T14:30:00.000Z"
  }
}

Available trigger events

EventDescription
JOB_CREATEDA new job is created
JOB_UPDATEDA job's details are modified
STATUS_CHANGEDA job's status transitions
JOB_ASSIGNEDA job is assigned to a worker
JOB_UNASSIGNEDA job is removed from a worker
JOB_COMPLETEDA job is marked as completed
JOB_CANCELLEDA job is cancelled
FORM_SUBMITTEDA form submission is received

Retry behavior

If your webhook endpoint returns a non-2xx status code, the request is not retried. Check the automation execution logs in the dashboard to see delivery status and any error details.

Changelog

v1.0 — Current

  • Jobs CRUD (list, get, create, update, delete)
  • Customers CRUD (list, get, create, update)
  • Vehicles (list, get) with tags and capacities
  • Locations (list, get)
  • Shifts (list, get) with breaks
  • API key authentication with scopes (read, write, admin)
  • Webhook delivery via automations

Need help? Contact support or check the user documentation for step-by-step guides.