Optimiciti Developer PortalOptimiciti Developer Portal
  • Pricing
  • Documentation
  • API Reference
  • Back to Optimiciti
Information
Problem
    Submit an optimization runpostPoll a run's status (never its routes)getCancel the optimization run identified by the problemId parameterpost
Utilities
    Health Checkget
Billing
    This month's task usagegetList public plansget
History
    Get User RunspostGet Run IdspostGet Run SummariespostList Example ScenariospostGet Run ResultspostGet a published example scenariogetUpdate Run NamepostDelete Runpost
Data-processing
    Calculate a cost matrix for the given locationspost
Optimization
    Get Run StatuspostCancel Runpost
System
    Read Rootget
Schemas
powered by Zuplo
Optimiciti API Specification

Optimiciti API Specification

Optimiciti API

Optimiciti turns a real-world routing problem — vehicles, stops, time windows, capacities, and costs — into an optimized plan: who goes where, in what order, and at what time. This API gives you direct, programmatic access to the same solvers that power the Optimiciti app. It's a good fit for scheduling deliveries, field service, home visits, or any fleet that has to visit many places efficiently.

Beta. Endpoints and fields may still change. Using the API requires accepting our terms of service.

How it works

A real optimization can take longer than a single request should wait, so solving is asynchronous — you submit, then poll:

  1. Get travel costs (choose one). Every solve needs the cost of travelling between your locations, and POST /problem does not compute them for you. Either (a) call POST /cost_matrix and pass its travelCostResponses as problemData.travelCosts — it computes them from coordinates by default (autoCalculate* defaults to true, geo method, no road-network call) — or (b) supply your own travelCosts. (There is no costSettings on /problem itself; auto-calculation lives on /cost_matrix.) An all-zero matrix is fine — it solves with every stop assigned. The trap is a null cost or duration on a pair: the solver reads either as unreachable. A matrix with no usable pair at all is rejected up front with 400 UNCOSTED_TRAVEL_MATRIX, and an absent or empty one with MISSING_TRAVEL_COSTS. A matrix that is only partly filled is accepted, and the run succeeded with the stops behind the empty pairs left unassigned and no error. So read how many stops were assigned, not only the status.
  2. Submit the problem. POST /problem with your locations, vehicles, and constraints. You get an id back right away (the response calls it run_id); the solver runs in the background.
  3. Poll for status. GET /problem/{problemId} — the same id — or POST /run_status, until the run reaches a terminal state: succeeded, failed, or cancelled. Poll every 2 to 5 seconds: a tight loop gains nothing and will run into the gateway's rate limit (429). A status response stays small: it carries status and any error — never the routes (a progress key is present but always null).
  4. Fetch the results. Once the run is succeeded, get the optimized routes with POST /run_results_by_run_id. Results are a separate call on purpose — route payloads are large, and polling is frequent.

(problemId in the path and run_id in responses are the same identifier — the two names refer to one run.)

Your runs stay available afterwards: list them, re-open their results, and rename or delete them at any time — see the History section. Saving and editing scenarios is part of the Optimiciti web app, not of this API.

Authentication

There are two ways to authenticate, and which one you use depends on where the request comes from. For programmatic access — scripts, servers, SDKs, anything without a browser — use an API key.

Send the key as a bearer credential in the Authorization header on every request:

Code
Authorization: Bearer <your-api-key>

For example:

Code
curl https://api.optimiciti.com/user_runs \ -X POST -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" -d '{"user_id": "me"}'

Your API key, not this field, decides whose runs are returned.

An API key replaces the Clerk token for server-to-server calls — you do not send both. The gateway resolves the key to your account and derives your identity from it, so, exactly as with a token, your identity is taken from the credential and never from a userId in the request body. During the beta, keys are issued by us and are not self-service yet. To request one, email [email protected]. Once you have a key, the header above is all you need: there is nothing to activate.

The browser app authenticates differently: it sends a Clerk-issued JSON Web Token (Authorization: Bearer <token>), verified on each call for signature, expiry, and issuer. You only need this if you are calling the API from a signed-in Optimiciti web session; direct API integrations should use an API key.

One thing that trips people up: api.optimiciti.com sits behind a gateway, and a request that arrives with no Origin header (a curl call, a script, or any server-to-server request) must carry an API key. Without one it gets a 401 on authenticated tiers — that is expected, not a broken credential.

Requests and responses

Every response uses the same envelope. On success:

Code
{ "success": true, "data": { "...": "..." } }

On failure:

Code
{ "success": false, "error": { "code": "PLAN_LIMIT_EXCEEDED", "message": "A human-readable reason." } }

Branch on error.code (stable), not the message text (which may change).

One exception, at the gateway: a request to api.optimiciti.com with a missing or invalid API key is rejected by the gateway before it reaches the API, so a 401 (or 403) there is an RFC 7807 application/problem+json object (type/title/status/detail), not this { success, error } envelope. Once a request reaches the API, every response uses the envelope above.

Plans and limits

Your plan sets how large a problem can be, how many runs you can have in flight at once, and which premium features (such as road-network travel costs) you can use. See API access plans. When a request exceeds your plan, you get a 4xx with one of the codes below — each tells you exactly what to change.

What counts as a task. API plans include a number of optimization tasks per UTC calendar month. A task is one stop (vehicle-routing) or one trip (pickup-delivery) served by a solve that reached succeeded. Stops and trips the solver could not serve are free, and so are failed and cancelled runs, polling, and POST /cost_matrix. Every 202 from POST /problem carries data.usage (tasksUsed, tasksIncluded, resetsAt), and GET /usage returns the same object. The check at submission uses tasks already counted, not a guess of what the new run will use, so you can exceed the allowance by at most one run before MONTHLY_TASKS_EXHAUSTED stops the next submission.

Common error codes

CodeMeaningWhat to do
CONCURRENCY_LIMIT (429)Too many runs in flight for your plan.Wait for one to finish, or cancel it, then retry.
PLAN_LIMIT_EXCEEDEDThe request uses a feature or size your plan doesn't include (error.details.feature names it).Reduce the problem.
PROBLEM_TOO_LARGEThe problem exceeds your plan's size cap.Use fewer locations or vehicles.
PAYLOAD_TOO_LARGE (413)The request body is too large to accept.Send fewer locations, or a smaller travel-cost table.
UNKNOWN_FIELD (400)A POST /problem or POST /cost_matrix body contains a field the API does not recognise -- misplaced (for example timeSettings inside problemData), misspelt, or from the other endpoint. It is refused rather than silently ignored, because an ignored field is a request that does not mean what you think.error.details.unknownFields lists every one with its path and what to do: where the field belongs, or what it probably should be.
RUN_NOT_FOUND / RESULTS_NOT_FOUNDThat run, or its results, doesn't exist yet.Check the id; results appear once a run succeeds.
MISSING_TRAVEL_COSTS (400)POST /problem received no problemData.travelCosts; it does not compute them.Build a matrix with POST /cost_matrix and pass its travelCostResponses, or supply your own, then resubmit.
MONTHLY_TASKS_EXHAUSTED (429)Your plan's optimization tasks for this UTC month are used up (error.details carries tasksUsed, tasksIncluded, resetsAt).Wait for the reset, or email [email protected] to raise the allowance.
ANONYMOUS_LANE_BUSY (429)Only signed-out web sessions can receive this: the capacity reserved for signed-out use is busy. A request carrying an API key never gets it.Try again in a moment, or sign in.
NON_FINITE_NUMBER (400)The JSON body contains NaN, Infinity or -Infinity, which JSON does not define (error.details.paths lists where).Send a finite number, or null for an unknown value.

Transient 429, 502, 503, and 504 responses are safe to retry with backoff.

Links

  • Optimiciti homepage
  • API access plans
  • Questions: [email protected]
Tags
Problem
Submit an optimization problem and follow it to completion. This is the core of the API - build your problem, submit it, poll for status, then read the optimized routes.
Utilities
Health check - confirm the API is up and answering.
Billing
Plans and limits - the public plan tiers, each with its limits and feature flags.
History
Past runs and published examples - list a user's previous optimization runs, re-open their results, rename or delete them, and browse the example scenarios.
Data-processing
Prepare travel data - build the travel-cost matrix (durations and distances between your locations) that a problem needs.
Optimization
Run control by run id - check a run's status, or cancel it.
System
Service root - a one-line banner confirming the service is reachable.
Apache 2.0Terms of Service
Contact[email protected]
Servers
https://api.optimiciti.com
JSON
JSON