workwing-io Integrations API

Running configured integrations and receiving their callbacks

Operations 3

POST /v1/integrations/execute Run a configured integration #
POST /v1/integrations/callback/{token} Receive an asynchronous integration callback #
GET /v1/integrations/executions/{queueId} Get the result of an enqueued integration execution #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/workwing-io:workwing-io-integrations-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

workwing-io-integrations-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: WorkWing Integrations API
  description: 'REST API for WorkWing field service management. Designed as an **integration point** for CRM, ERP, and dispatch systems. Admin configuration (webhooks, roles, job types, integrations) is managed via the web dashboard. Every resource is documented under its own section in the sidebar. ## Authentication


    Send your API key as a bearer token on every request:


    ```

    Authorization: Bearer ww_sk_live_. ```


    ### Scopes


    An API key carries a list of `action:resource` scopes. Every operation publishes the ones it requires as `x-required-scopes`, an array on the operation object; a key must hold all of them, or the wildcard scope `*`, and one that does not is refused with `403 E_AP_1102`. The two operations that declare `security: []` need no key at all: the health check, and the integration callback, which authenticates with the signed token in its own path. ## Querying collections


    List endpoints (jobs, customers, resources, and so on) accept query parameters for filtering, sorting, field selection, and pagination:


    - `?status=eq.T_PENDING` - filter by exact match

    - `?priority=in.(T_HIGH,T_URGENT)` - match any of several values

    - `?created_at=gte.2024-01-01` - range comparisons (`gt`, `gte`, `lt`, `lte`)

    - `?select=id,status,customer:customers(name)` - choose columns and embed related records. Only the resources listed here, the assignments and users they reference, and the foreign keys between them can be embedded; anything else is refused with `E_AP_6003`

    - `?order=created_at.desc` - sort (append `.asc` / `.desc`)

    - `?limit=25&offset=50` - paginate (maximum 1000 rows per page)


    ### Columns not available over the API


    Some columns are never returned: `tenant_id` on every resource (a key is bound to one tenant), `internal_notes` on jobs (staff-only; it can be set with `PATCH`, and a job''s note timeline is at `GET /v1/jobs/{jobId}/notes`), and the raw PostGIS geography columns `customers.location`, `locations.location` and `resources.current_location`. Read a position from `latitude`/`longitude` on locations and `current_latitude`/`current_longitude` on resources instead. `select=*`, at the top level or inside an embed, returns every other column. Naming one of these columns in `select`, a filter or `order` is refused with `E_AP_6003`. To read, update or delete one record, address it by id: `GET`, `PATCH` or `DELETE /v1/jobs/{jobId}` (likewise customers, resources and locations). `PATCH` and `DELETE` on a collection change every row matching its filters, e.g. `PATCH /v1/jobs?status=eq.T_PENDING`; they are listed under Workflows. ### Counting and paging


    Send `Prefer: count=exact` on a list request to get the total row count back in the `Content-Range` response header (`0-24/312`). `count=planned` and `count=estimated` are cheaper approximations for large tables. ## Idempotency


    **Guarantee.** Within 24 hours, a write sent with a given `Idempotency-Key` is applied at most once. If you did not receive a response, retrying with the same key and the same request is always safe. **Core rule.** A key is consumed only when the write is actually applied. The key and the write commit in the same database transaction, so they succeed or fail together. Every write request (`POST`, `PATCH`, `PUT`, `DELETE`) must send an `Idempotency-Key` header. | Situation | Response | Write applied?'
  version: 1.0.0
servers:
- url: https://api.workwing.io
  description: Production
security:
- bearerAuth: []
tags:
- name: Integrations
  description: Running configured integrations and receiving their callbacks
paths:
  /v1/integrations/execute:
    post:
      operationId: executeIntegration
      summary: Run a configured integration
      tags:
      - Integrations
      description: 'Enqueues the integration and answers 202 with a `queueId`. Add `?wait=true` to hold the connection until the run finishes and receive its result instead: the same fields `GET /v1/integrations/executions/{queueId}` returns, plus `result` with the run''s `executionId`, `status`, `output` and `cacheHit`. For an asynchronous integration the wait ends once the request is sent, so read the outcome back by `queueId`.


        Under `?wait=true` a run that fails answers 422 with `E_AP_7003 INTEGRATION_ERROR`, carrying the `queueId` and `executionId` in `error.details`; the provider''s own error text is recorded server-side and not returned. A run still going after the wait window answers 408 with `E_AP_7002`. Either way, read the run back with `GET /v1/integrations/executions/{queueId}` rather than executing again.


        A `jobId` or `customerId` must belong to the key''s brand: one in another brand, or one that does not exist, answers 404.


        Scope: `execute:integrations`. No `Idempotency-Key` is required on this endpoint.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                integrationId:
                  type: string
                  format: uuid
                  pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                inputData:
                  default: {}
                  type: object
                  additionalProperties: {}
                jobId:
                  type: string
                  format: uuid
                  pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                customerId:
                  type: string
                  format: uuid
                  pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              required:
              - integrationId
      parameters:
      - schema:
          type: string
          enum:
          - '0'
          - '1'
          - 'true'
          - 'false'
        in: query
        name: wait
        required: false
      security:
      - bearerAuth: []
      x-required-scopes:
      - execute:integrations
      responses:
        '200':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      queueId:
                        type: string
                        format: uuid
                        pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                      status:
                        type: string
                      executionId:
                        type:
                        - string
                        - 'null'
                        format: uuid
                        pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                      executionStatus:
                        type:
                        - string
                        - 'null'
                      output: {}
                      completedAt:
                        type:
                        - string
                        - 'null'
                        format: date-time
                        pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$
                      result:
                        type: object
                        properties:
                          executionId:
                            type:
                            - string
                            - 'null'
                            format: uuid
                            pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                          status:
                            type:
                            - string
                            - 'null'
                          output: {}
                          cacheHit:
                            type: boolean
                        required:
                        - executionId
                        - status
                        - output
                        - cacheHit
                    required:
                    - queueId
                    - status
                    - executionId
                    - executionStatus
                    - output
                    - completedAt
                    - result
                  meta:
                    type: object
                    properties:
                      request_id:
                        type: string
                      timestamp:
                        type: string
                        format: date-time
        '202':
          description: Queued. Read the outcome back with `GET /v1/integrations/executions/{queueId}`.
          content:
            application/json:
              schema:
                description: Queued. Read the outcome back with `GET /v1/integrations/executions/{queueId}`.
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: object
                    required:
                    - queueId
                    - status
                    - message
                    properties:
                      queueId:
                        type: string
                        format: uuid
                      status:
                        type: string
                        enum:
                        - T_PENDING
                      message:
                        type: string
                  meta:
                    type: object
                    required:
                    - request_id
                    - timestamp
                    properties:
                      request_id:
                        type: string
                      timestamp:
                        type: string
                        format: date-time
  /v1/integrations/callback/{token}:
    post:
      operationId: receiveIntegrationCallback
      summary: Receive an asynchronous integration callback
      tags:
      - Integrations
      description: 'Called by the external service, not by API clients: authorisation is the signed token in the path, so no API key is sent. A token that does not match the execution named by `execution_id`, or an `execution_id` that does not exist, answers 401 alike. The body is stored as received; it must be a JSON object of at most 50 top-level keys and 512KB serialised.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: {}
      parameters:
      - schema:
          type: string
          format: uuid
          pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
        in: query
        name: execution_id
        required: true
      - schema:
          type: string
        in: path
        name: token
        required: true
      security: []
      responses:
        '200':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: object
                    required:
                    - status
                    - execution_id
                    - callback_count
                    properties:
                      status:
                        type: string
                        enum:
                        - accepted
                      execution_id:
                        type: string
                        format: uuid
                      callback_count:
                        type: integer
                        description: Callbacks this execution has received, including this one. At most 10 are accepted.
                  meta:
                    type: object
                    required:
                    - request_id
                    - timestamp
                    properties:
                      request_id:
                        type: string
                      timestamp:
                        type: string
                        format: date-time
  /v1/integrations/executions/{queueId}:
    get:
      operationId: getIntegrationExecution
      summary: Get the result of an enqueued integration execution
      tags:
      - Integrations
      description: 'Returns the status and transformed output of an execution enqueued by `POST /v1/integrations/execute`, using the `queueId` that call returned. Poll this after a 202, or after a 408 from `?wait=true` - the run usually completes regardless, and re-executing repeats the integration''s side effects.


        `status` is the queue entry''s own status (`T_PENDING`, `T_RUNNING`, `T_COMPLETED`, `T_FAILED`). `executionStatus` is the integration''s. For an asynchronous integration the queue entry is `T_COMPLETED` as soon as the request is sent, and `executionStatus` stays `T_PENDING` until the third party calls back, then becomes `T_COMPLETED`, `T_FAILED` or `T_EXPIRED` with `output` filled from that callback. A failed run answers 200 with `status: "T_FAILED"`; the provider''s error text is recorded server-side and not returned.


        Scope: `read:integrations`.'
      parameters:
      - schema:
          type: string
          format: uuid
          pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
        in: path
        name: queueId
        required: true
      security:
      - bearerAuth: []
      x-required-scopes:
      - read:integrations
      responses:
        '200':
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      queueId:
                        type: string
                        format: uuid
                        pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                      status:
                        type: string
                      executionId:
                        type:
                        - string
                        - 'null'
                        format: uuid
                        pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                      executionStatus:
                        type:
                        - string
                        - 'null'
                      output: {}
                      completedAt:
                        type:
                        - string
                        - 'null'
                        format: date-time
                        pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$
                    required:
                    - queueId
                    - status
                    - executionId
                    - executionStatus
                    - output
                    - completedAt
                  meta:
                    type: object
                    properties:
                      request_id:
                        type: string
                      timestamp:
                        type: string
                        format: date-time
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: 'Use your WorkWing API key (format: `ww_sk_live_<tokenId>.<secret>`). The scopes an operation requires are published on it as `x-required-scopes`.'