Open Application Platform Docs

Async jobs

Track a long-running solve and collect its result.

platform.jobs Stable free

How to call it

REST

GET /v1/jobs

GET /v1/jobs/{jobId}

POST /v1/jobs/{jobId}/cancel

GET /v1/jobs/{jobId}/deliveries

POST /v1/jobs/{jobId}/deliveries/{deliveryId}/replay

GET /v1/jobs/{jobId}/result

POST /v1/webhooks/verify

GraphQL

query openJob

query openJobs

query openJobResult

query openJobDeliveries

mutation openJobCancel

mutation openJobDeliveryReplay

mutation openWebhookVerify

MCP

open_job_cancel

Cancel a queued or running job. A job that has already finished cannot be cancelled and its charge stands.

open_job_deliveries

Every webhook delivery attempt for one job — endpoint, outcome, attempt count and error. The first thing to check when a result never arrived. Free.

open_job_delivery_replay

Re-drive one webhook delivery by hand — the answer to a receiver that was down all afternoon. Free, and only for the caller's own deliveries.

open_job_get

Status and progress of one asynchronous job. Free — you have already paid for the work; asking whether it finished is not a second charge.

open_job_list

Recent asynchronous jobs for this client. Free.

open_job_result

Collect a finished job's result. Free, and available for 24 hours after the job completes.

open_webhook_verify

Run the challenge handshake against a callback URL so jobs may deliver to it. Must succeed before the URL can be used — a typo fails here rather than after an expensive solve. Free.

Request schema

Generated from the same validation rules the endpoint runs, so a field cannot be documented without being validated.

POST /v1/webhooks/verify

{
    "type": "object",
    "properties": {
        "secret": {
            "type": [
                "string",
                "null"
            ],
            "maxLength": 255
        },
        "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
        }
    },
    "additionalProperties": false,
    "required": [
        "url"
    ]
}

Request example

{
    "url": "https://hooks.example.com/superroute",
    "secret": "whsec_0123456789abcdef"
}

Response

What a successful call returns: the schema of `data` and `meta`, with a description of each field, followed by an example response from a real call.

GET /v1/jobs

Response schema

{
    "description": "Recent jobs of this client, newest first.",
    "data": {
        "type": "object",
        "properties": {
            "jobs": {
                "type": "array",
                "items": {
                    "type": "object",
                    "description": "A job. Fields without a value are left out.",
                    "properties": {
                        "id": {
                            "type": "string",
                            "description": "The job id, `job_...`."
                        },
                        "status": {
                            "type": "string",
                            "enum": [
                                "queued",
                                "running",
                                "succeeded",
                                "failed",
                                "cancelled",
                                "expired"
                            ]
                        },
                        "capability": {
                            "type": "string",
                            "description": "The capability the job runs."
                        },
                        "progress": {
                            "type": "integer",
                            "description": "Percent complete, 0-100."
                        },
                        "stage": {
                            "type": "string",
                            "description": "What the job is doing: `queued`, `solving`, an engine stage while it runs, then `done`, `failed` or `cancelled`."
                        },
                        "created_at": {
                            "type": "string",
                            "description": "ISO 8601 with offset."
                        },
                        "started_at": {
                            "type": "string",
                            "description": "ISO 8601 with offset. Absent until the job starts."
                        },
                        "finished_at": {
                            "type": "string",
                            "description": "ISO 8601 with offset. Absent until the job ends."
                        },
                        "result_url": {
                            "type": "string",
                            "description": "Where to collect the result. Present only once the job has succeeded."
                        },
                        "result_expires_at": {
                            "type": "string",
                            "description": "After this the result is deleted; collect it before then. ISO 8601 with offset."
                        },
                        "error": {
                            "type": "object",
                            "description": "Present only when the job failed.",
                            "properties": {
                                "code": {
                                    "type": "string",
                                    "description": "An error code from the error catalog."
                                },
                                "message": {
                                    "type": [
                                        "string",
                                        "null"
                                    ],
                                    "description": "What went wrong."
                                }
                            }
                        }
                    },
                    "required": [
                        "id",
                        "status"
                    ]
                }
            }
        }
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "jobs": [
            {
                "id": "job_01k8zq4a6c8e0g2j4l6n8q0s2u",
                "status": "succeeded",
                "capability": "routing.optimize",
                "progress": 100,
                "stage": "done",
                "created_at": "2026-10-23T09:27:40-04:00",
                "started_at": "2026-10-23T09:27:40-04:00",
                "finished_at": "2026-10-23T09:27:40-04:00",
                "result_url": "/v1/jobs/job_01k8zq4a6c8e0g2j4l6n8q0s2u/result",
                "result_expires_at": "2026-10-24T09:27:40-04:00"
            }
        ]
    }
}

GET /v1/jobs/{jobId}

Response schema

{
    "description": "One job and where it has got to. Poll this until `status` is terminal (succeeded, failed, cancelled or expired), then collect `result_url`. `?wait=<seconds>` holds the request until the job ends or the wait runs out.",
    "data": {
        "type": "object",
        "description": "A job. Fields without a value are left out.",
        "properties": {
            "id": {
                "type": "string",
                "description": "The job id, `job_...`."
            },
            "status": {
                "type": "string",
                "enum": [
                    "queued",
                    "running",
                    "succeeded",
                    "failed",
                    "cancelled",
                    "expired"
                ]
            },
            "capability": {
                "type": "string",
                "description": "The capability the job runs."
            },
            "progress": {
                "type": "integer",
                "description": "Percent complete, 0-100."
            },
            "stage": {
                "type": "string",
                "description": "What the job is doing: `queued`, `solving`, an engine stage while it runs, then `done`, `failed` or `cancelled`."
            },
            "created_at": {
                "type": "string",
                "description": "ISO 8601 with offset."
            },
            "started_at": {
                "type": "string",
                "description": "ISO 8601 with offset. Absent until the job starts."
            },
            "finished_at": {
                "type": "string",
                "description": "ISO 8601 with offset. Absent until the job ends."
            },
            "result_url": {
                "type": "string",
                "description": "Where to collect the result. Present only once the job has succeeded."
            },
            "result_expires_at": {
                "type": "string",
                "description": "After this the result is deleted; collect it before then. ISO 8601 with offset."
            },
            "error": {
                "type": "object",
                "description": "Present only when the job failed.",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "An error code from the error catalog."
                    },
                    "message": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "What went wrong."
                    }
                }
            }
        },
        "required": [
            "id",
            "status"
        ]
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "id": "job_01k8zq4a6c8e0g2j4l6n8q0s2u",
        "status": "succeeded",
        "capability": "routing.optimize",
        "progress": 100,
        "stage": "done",
        "created_at": "2026-10-23T09:27:40-04:00",
        "started_at": "2026-10-23T09:27:40-04:00",
        "finished_at": "2026-10-23T09:27:40-04:00",
        "result_url": "/v1/jobs/job_01k8zq4a6c8e0g2j4l6n8q0s2u/result",
        "result_expires_at": "2026-10-24T09:27:40-04:00"
    }
}

POST /v1/jobs/{jobId}/cancel

Response schema

{
    "description": "The job after the cancel. Cancelling a job that has already ended changes nothing and answers the job as it is.",
    "data": {
        "type": "object",
        "description": "A job. Fields without a value are left out.",
        "properties": {
            "id": {
                "type": "string",
                "description": "The job id, `job_...`."
            },
            "status": {
                "type": "string",
                "enum": [
                    "queued",
                    "running",
                    "succeeded",
                    "failed",
                    "cancelled",
                    "expired"
                ]
            },
            "capability": {
                "type": "string",
                "description": "The capability the job runs."
            },
            "progress": {
                "type": "integer",
                "description": "Percent complete, 0-100."
            },
            "stage": {
                "type": "string",
                "description": "What the job is doing: `queued`, `solving`, an engine stage while it runs, then `done`, `failed` or `cancelled`."
            },
            "created_at": {
                "type": "string",
                "description": "ISO 8601 with offset."
            },
            "started_at": {
                "type": "string",
                "description": "ISO 8601 with offset. Absent until the job starts."
            },
            "finished_at": {
                "type": "string",
                "description": "ISO 8601 with offset. Absent until the job ends."
            },
            "result_url": {
                "type": "string",
                "description": "Where to collect the result. Present only once the job has succeeded."
            },
            "result_expires_at": {
                "type": "string",
                "description": "After this the result is deleted; collect it before then. ISO 8601 with offset."
            },
            "error": {
                "type": "object",
                "description": "Present only when the job failed.",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "An error code from the error catalog."
                    },
                    "message": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "What went wrong."
                    }
                }
            }
        },
        "required": [
            "id",
            "status"
        ]
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "id": "job_01k8zq4a6c8e0g2j4l6n8q0s2u",
        "status": "succeeded",
        "capability": "routing.optimize",
        "progress": 100,
        "stage": "done",
        "created_at": "2026-10-23T09:27:40-04:00",
        "started_at": "2026-10-23T09:27:40-04:00",
        "finished_at": "2026-10-23T09:27:40-04:00",
        "result_url": "/v1/jobs/job_01k8zq4a6c8e0g2j4l6n8q0s2u/result",
        "result_expires_at": "2026-10-24T09:27:40-04:00"
    }
}

GET /v1/jobs/{jobId}/deliveries

Response schema

{
    "description": "Every callback delivery of the job, with the last attempt's outcome.",
    "data": {
        "type": "object",
        "properties": {
            "deliveries": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "delivery_id": {
                            "type": "string",
                            "description": "The delivery id, `dlv_...`. Also sent in the `X-Open-Delivery` header."
                        },
                        "event": {
                            "type": "string",
                            "enum": [
                                "job.queued",
                                "job.progress",
                                "job.succeeded",
                                "job.failed",
                                "job.cancelled",
                                "job.expired"
                            ],
                            "description": "The event delivered."
                        },
                        "status": {
                            "type": "string",
                            "enum": [
                                "pending",
                                "delivering",
                                "retrying",
                                "delivered",
                                "dead_letter"
                            ],
                            "description": "`dead_letter` means every retry failed; replay it once the endpoint is fixed."
                        },
                        "endpoint_host": {
                            "type": "string",
                            "description": "The host the callback was sent to."
                        },
                        "attempt_count": {
                            "type": "integer",
                            "description": "Attempts made so far."
                        },
                        "http_status": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "description": "The status your endpoint answered on the last attempt."
                        },
                        "response_time_ms": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "description": "How long your endpoint took on the last attempt."
                        },
                        "error_code": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "description": "Why the last attempt failed, when it did."
                        },
                        "error_message": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "description": "Detail of `error_code`."
                        },
                        "last_attempt_at": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "description": "ISO 8601 with offset."
                        },
                        "next_attempt_at": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "description": "When the next retry is due. ISO 8601 with offset."
                        },
                        "delivered_at": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "description": "When your endpoint accepted it. ISO 8601 with offset."
                        }
                    }
                }
            }
        }
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "deliveries": [
            {
                "delivery_id": "dlv_01k8zq4h2k4m6p8r0t2w4y6a8c",
                "event": "job.succeeded",
                "status": "delivered",
                "endpoint_host": "hooks.example.com",
                "attempt_count": 1,
                "http_status": 200,
                "response_time_ms": 0,
                "error_code": null,
                "error_message": null,
                "last_attempt_at": "2026-10-23T09:27:40-04:00",
                "next_attempt_at": null,
                "delivered_at": "2026-10-23T09:27:40-04:00"
            }
        ]
    }
}

POST /v1/jobs/{jobId}/deliveries/{deliveryId}/replay

Response schema

{
    "description": "The delivery is queued to be sent again, with its original payload and a new attempt count.",
    "data": {
        "type": "object",
        "properties": {
            "delivery_id": {
                "type": "string",
                "description": "The delivery that was queued again."
            },
            "status": {
                "type": "string",
                "enum": [
                    "pending"
                ],
                "description": "The delivery is queued and is sent by the next delivery run."
            }
        }
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "delivery_id": "dlv_01k8zq4h2k4m6p8r0t2w4y6a8c",
        "status": "pending"
    }
}

GET /v1/jobs/{jobId}/result

Response schema

{
    "description": "The finished result, exactly as the synchronous call would have answered it: `data`, `warnings` and `meta` of the capability that ran (this example is a routing.optimize job). `billing.counted` is false because the call was billed when the job was accepted. A job that has not succeeded answers 409 JOB_NOT_FINISHED.",
    "data": {
        "type": "object",
        "description": "The capability's own `data`; see that capability's reference.",
        "properties": {},
        "additionalProperties": true
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "billing": {
        "unit": "node",
        "quantity": 5,
        "counted": false,
        "breakdown": {
            "nodes": 5,
            "jobs": 3,
            "shipments": 0,
            "shipment_nodes": 0,
            "vehicles": 2,
            "vehicle_nodes": 2
        }
    },
    "data": {
        "routes": [
            {
                "vehicle_id": "van-2",
                "stops": [
                    {
                        "type": "start",
                        "arrival": "2026-11-02T08:31:07-05:00",
                        "arrival_epoch": 1793626267,
                        "distance_meters": 0,
                        "duration_seconds": 0,
                        "load": [
                            6
                        ]
                    },
                    {
                        "type": "job",
                        "arrival": "2026-11-02T08:35:11-05:00",
                        "arrival_epoch": 1793626511,
                        "distance_meters": 1839,
                        "duration_seconds": 244,
                        "leg_distance_meters": 1839,
                        "leg_duration_seconds": 244,
                        "id": "order-1001",
                        "load": [
                            4
                        ]
                    },
                    {
                        "type": "job",
                        "arrival": "2026-11-02T08:47:56-05:00",
                        "arrival_epoch": 1793627276,
                        "distance_meters": 5338,
                        "duration_seconds": 709,
                        "leg_distance_meters": 3499,
                        "leg_duration_seconds": 465,
                        "id": "order-1003",
                        "load": [
                            3
                        ]
                    },
                    {
                        "type": "job",
                        "arrival": "2026-11-02T09:00:00-05:00",
                        "arrival_epoch": 1793628000,
                        "distance_meters": 9220,
                        "duration_seconds": 1193,
                        "leg_distance_meters": 3882,
                        "leg_duration_seconds": 484,
                        "id": "order-1002",
                        "load": [
                            0
                        ]
                    },
                    {
                        "type": "end",
                        "arrival": "2026-11-02T09:08:17-05:00",
                        "arrival_epoch": 1793628497,
                        "distance_meters": 10687,
                        "duration_seconds": 1390,
                        "leg_distance_meters": 1467,
                        "leg_duration_seconds": 197,
                        "load": [
                            0
                        ]
                    }
                ],
                "stop_count": 5,
                "task_count": 3,
                "distance_meters": 10687,
                "duration_seconds": 1390,
                "service_seconds": 840,
                "waiting_seconds": 0,
                "geometry": null
            }
        ],
        "unassigned": [],
        "summary": {
            "routes": 1,
            "assigned": 3,
            "unassigned": 0,
            "distance_meters": 10687,
            "duration_seconds": 1390
        }
    },
    "meta": {
        "engine": "sroute2",
        "engine_version": "1.6.1",
        "solve_id": "e363b370-4113-44a0-8630-1579e1fbc799",
        "capacity_dimensions": [
            "0"
        ]
    }
}

POST /v1/webhooks/verify

Response schema

{
    "description": "Whether the endpoint answered the challenge. A job callback is accepted only for a URL verified this way: the endpoint receives `{\"event\": \"endpoint.verify\", \"challenge\": \"...\"}` and must answer 2xx with `{\"challenge\": \"<the same value>\"}`.",
    "data": {
        "type": "object",
        "properties": {
            "verified": {
                "type": "boolean",
                "description": "The endpoint echoed the challenge."
            },
            "reason": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "Why verification failed; null when verified. `UNSAFE` (not a public HTTPS address), `UNREACHABLE` (no answer within the timeout), `HTTP_<status>` (the status your endpoint answered) or `CHALLENGE_MISMATCH`."
            }
        },
        "required": [
            "verified"
        ]
    }
}

Response example

{
    "request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
    "data": {
        "verified": true,
        "reason": null
    }
}

What it costs

Never billed, and never disable-able.

Every billable response carries a billing block with the unit, the quantity and how the quantity was derived.

Errors it can return

Status Code Description
401 SESSION_EXPIRED The session token is invalid or has expired.
401 TOKEN_INVALID Unknown or revoked API token.
401 TOKEN_MISSING No API token. Send Authorization: Bearer <your token>.
403 CAPABILITY_NOT_ENABLED This capability is not enabled for your account. See :doc to enable it.
403 CAPABILITY_NOT_GRANTED_TO_KEY Your account has this capability, but this API key was not granted it.
403 OPEN_API_DISABLED Open Platform access is not enabled for this account.
404 JOB_NOT_FOUND No such job, or it belongs to another account.
409 JOB_NOT_FINISHED The job has not finished yet. Poll the job, or wait for the callback.
410 JOB_RESULT_EXPIRED The result has expired and is no longer available. Submit the request again.
422 VALIDATION_FAILED The request failed validation. See details.
429 RATE_LIMITED Too many requests. Please retry after the indicated delay.
500 INTERNAL_ERROR An unexpected error occurred. Quote the request_id when contacting support.