Optimiciti Developer PortalOptimiciti Developer Portal
  • Pricing
  • Documentation
  • API Reference
  • Back to Optimiciti
Getting Started
    Overview
powered by Zuplo

Welcome to the Optimiciti Developer Portal

The developer portal is your starting point for accessing our public-facing API. This portal is for developers and users who want to integrate Optimiciti's optimization solvers directly into their own applications and workflows by making requests to our back-end.

Click here to visit our main site, where you can solve problems interactively in your browser without writing any code.

Our API Reference has the most up-to-date endpoint documentation, and you can download the full OpenAPI spec to generate a client or import into Postman/Insomnia.


What is the Optimiciti API?

The Optimiciti API gives you programmatic access to the same optimization engine that powers our web application.

Submit a problem, receive a problemId, then poll for results — all over standard HTTPS requests authenticated with your API key.


Optimization Models

The API currently supports two problem types, specified via the problemType field in your request body.

Vehicle Routing (vehicle-routing)

The classic Vehicle Routing Problem (VRP). One or more vehicles depart from a depot and must visit a set of locations using the lowest-cost routes. Supports:

  • Capacity constraints — assign demand values to locations and enforce vehicle load limits
  • Time windows — restrict arrival times at individual locations
  • Multiple vehicle types — model fleets with different capacities, speeds, or cost profiles
  • Bring your own travel costs — POST /problem never computes travel times or distances; build the matrix with POST /cost_matrix (straight-line by default, road network on the Professional plan) and submit it as problemData.travelCosts. See Submit a problem below.

Pickup & Delivery Routing (pickup-delivery)

An extension of the VRP where locations are paired into trips. Each trip has a pickup location that must be visited before its corresponding delivery location, and both stops must be served by the same vehicle. Useful for:

  • Ride-hailing and shuttle services
  • Courier and last-mile delivery with paired collections
  • Airport and logistics transfer networks

API Workflow

Optimization runs are asynchronous. The typical flow is:

  1. Submit a problem

    POST /problem with a userId and a problem object containing the problemType, locations, vehicles, vehicle types, and time settings. The response is 202 Accepted with a run_id — the solver runs in the background; the call does not wait for it. (run_id and the problemId you poll with are the same value.)

    POST /problem does not compute travel costs, and problemData.travelCosts is required: a complete matrix with a cost for every pair of locations. Build one with POST /cost_matrix, then copy its data.travelCostResponses array into problemData.travelCosts unchanged. In the /cost_matrix request, costSettings.costMetric is required (duration, distance or custom; without it the call returns 422). Set autoCalculateDistance and autoCalculateDuration to true, and set durationMethod explicitly as well as distanceMethod, so every pair gets a duration:

    Code
    { "locations": [...], "costSettings": { "costMetric": "duration", "autoCalculateDistance": true, "autoCalculateDuration": true, "distanceMethod": "geo", "durationMethod": "geo" } }

    You can also supply your own matrix if you already have distance or duration data.

    What happens when the matrix is wrong:

    • Missing or empty travelCosts: rejected with 400 MISSING_TRAVEL_COSTS.
    • An all-zero matrix: solves normally. Every leg is free, so the routes are unlikely to be useful.
    • Pairs with a missing duration or cost: the run can still come back succeeded with 0 stops assigned.

    So don't rely on the run's status: check how many stops were actually assigned (see Fetch results below).

    Code
    { "userId": "your-account-id", "problem": { "problemType": "vehicle-routing", "problemData": { "locations": [...], "vehicles": [...], "vehicleTypes": [...], "travelCosts": [...] } } }
  2. Poll for status

    GET /problem/{problemId} (or POST /run_status) returns the run's status only — queued, running, or a terminal succeeded / failed / cancelled. It does not return the routes. Poll until the status is terminal.

  3. Fetch results

    Once the run has succeeded, POST /run_results_by_run_id returns the plan. Read the route from routeStopsFull, and before trusting the result, compare data.resultSummary.assignmentSummary.locationsAssigned.assigned with the number of stops you submitted, counted from your own request: your locations where isDepot is not true (for pickup-delivery, the distinct pickup and delivery locations of your trips). A succeeded run can still have assigned nothing.

    Also check that data.problemResult.unassignedLocationsFull and data.problemResult.unassignedTripsFull are both empty. The count alone can look right while a location was only partly served, or while a trip was dropped at a location that another trip still visits.

    Don't rely on locationsAssigned.total alone for this. It is computed from the result (assigned plus the unassigned lists), not from your request. For pickup-delivery it adds unassigned trips to assigned locations, and it is null when both are empty.

  4. Cancel if needed

    POST /problem/cancel/{problemId} cancels a queued or running run. It has no effect once the run has reached a terminal state.


Additional Endpoints

EndpointDescription
POST /cost_matrixCalculate a travel time and distance matrix for a set of locations
GET /healthReturns the operational status of the API

Plans & Limits

Access to the API is tied to your subscription plan. The following limits apply to each optimization run.

StarterProfessional
PriceFree$20 / month
Locations per run50250
Trips per run—250
Vehicles per run—50
Vehicle types per run—20
Saved scenarios5Unlimited
API access——
Auto-populate travel times—✓

During the beta, API access is issued directly: email [email protected].

Developer plan coming soon. A dedicated Developer plan will offer bigger limits on problem size, up to 10 API solves per minute, and full REST API access. Join the waitlist to be notified at launch.


Authentication

For programmatic access — scripts, servers, SDKs, anything without a browser — authenticate with an API key. Send it as a bearer credential in the Authorization header on every request:

Code
Authorization: Bearer <your-api-key>

For example, to list your past runs:

TerminalCode
curl https://api.optimiciti.com/user_runs \ -H "Authorization: Bearer $OPTIMICITI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"user_id": "me"}'

The body still needs a user_id field, but its value is ignored: the runs returned are always the ones belonging to the account your key identifies. A few endpoints need no key at all, such as GET /health and GET /plans; the API Reference marks which ones do.

An API key replaces the Clerk token used by the web app — you send one or the other, never both. The gateway resolves your key to your account and takes your identity from it, so (just like a token) your identity comes from the credential and is never read from a userId in the request body. Keys are issued by us during the beta rather than from a self-service page — email [email protected] if you need one, or another for a second environment. Keys are scoped to your account. Rate limits are not counted per key — see Rate Limits below.

Requests with no Origin header — curl, scripts, and any server-to-server call — must carry an API key. Without one, authenticated endpoints return 401. That's expected, not a broken key. Note that a gateway 401/403 is an RFC 7807 problem+json body, not the standard { success, error } envelope the API itself returns.


Rate Limits

Rate limits vary by endpoint, and they are the same on every plan. Solving and other expensive calls (/problem, /cost_matrix, the exports) are limited far more tightly than reads and status polls.

Limits are counted per IP address, not per API key, per user or per plan. Two things follow, and they surprise people in opposite directions:

  • Several servers calling with the same key each get their own allowance, because they are different addresses.
  • Everything behind one address shares an allowance — a NAT'd office, a CI runner, or several services on one host — even with different keys.

A request over the limit gets a 429 Too Many Requests from the gateway, as an RFC 7807 problem+json body rather than the API's { success, error } envelope, with a retry-after header in seconds. Email [email protected] if you need a higher limit for your use case.


Contact

Questions about the API or your subscription? Reach us at [email protected] or visit the terms of service.

Last modified on September 25, 2026
On this page
  • What is the Optimiciti API?
  • Optimization Models
    • Vehicle Routing (vehicle-routing)
    • Pickup & Delivery Routing (pickup-delivery)
  • API Workflow
  • Additional Endpoints
  • Plans & Limits
  • Authentication
  • Rate Limits
  • Contact
JSON
JSON