Getting Started

TL;DR

Build a JSON OptimizationRequest with a travel matrix, one resource, and at least one job. POST it to /api/v1/optimize/sync. Read status, routes, and score from the response. That's the whole loop.

What you'll learn
  • How to construct a minimal valid OptimizationRequest
  • How to call POST /api/v1/optimize/sync with curl
  • How to read the resulting OptimizationResponse

Prerequisites

You need access to the FieldGenius API at https://api.fieldgenius.be and a terminal with curl.

Every request needs two headers

Every endpoint under /api/v1/* requires both X-API-Key (your adapter/tenant key) and X-Client-Key (your specific client key, issued as a child of that tenant). Only /health is open with no auth. See Authentication for how these two keys relate.

Walkthrough

  1. Construct a minimal request. Every OptimizationRequest needs a travel block (a distance/time matrix or coordinates to compute one), at least one resource, and at least one job or shipment. The smallest possible request uses three locations (one depot, two job stops) and an explicit 3×3 distance matrix so no matrix computation call is needed:

    {
      "metadata": { "problem_id": "getting-started-01" },
      "travel": {
        "distance_matrix": [
          [0, 3200, 5400],
          [3200, 0, 2600],
          [5400, 2600, 0]
        ],
        "time_matrix": [
          [0, 420, 660],
          [420, 0, 360],
          [660, 360, 0]
        ]
      },
      "resources": [
        { "id": "truck-1", "depot_index": 0, "capacities": 100 }
      ],
      "jobs": [
        { "id": "job-4821", "location_index": 1, "demands": 10, "service_time": 300 },
        { "id": "job-4822", "location_index": 2, "demands": 15, "service_time": 300 }
      ],
      "options": { "time_limit_seconds": 5 }
    }

    Location 0 is the depot (e.g. a depot near Amsterdam Sloterdijk), location 1 is job-4821, and location 2 is job-4822. depot_index on the resource and location_index on each job both refer to rows/columns of the matrices.

  2. POST it to /api/v1/optimize/sync. The sync endpoint blocks until the solver finishes (or time_limit_seconds elapses) and returns the result directly:

    curl -X POST https://api.fieldgenius.be/api/v1/optimize/sync \
      -H "Content-Type: application/json" \
      -H "X-API-Key: your-adapter-key" \
      -H "X-Client-Key: your-client-key" \
      -d '{
        "metadata": { "problem_id": "getting-started-01" },
        "travel": {
          "distance_matrix": [[0, 3200, 5400], [3200, 0, 2600], [5400, 2600, 0]],
          "time_matrix": [[0, 420, 660], [420, 0, 360], [660, 360, 0]]
        },
        "resources": [
          { "id": "truck-1", "depot_index": 0, "capacities": 100 }
        ],
        "jobs": [
          { "id": "job-4821", "location_index": 1, "demands": 10, "service_time": 300 },
          { "id": "job-4822", "location_index": 2, "demands": 15, "service_time": 300 }
        ],
        "options": { "time_limit_seconds": 5 }
      }'
  3. Read the response. Check status first — it must be optimal or feasible for the routes to be usable. Then inspect routes for the per-vehicle stop sequence and summary for totals:

    {
      "status": "optimal",
      "problem_id": "getting-started-01",
      "solve_time_ms": 42,
      "routes": [
        {
          "resource_id": "truck-1",
          "day": 0,
          "activities": [
            { "type": "start", "location_index": 0, "arrival_time": 0, "departure_time": 0 },
            { "type": "service", "job_id": "job-4821", "location_index": 1, "arrival_time": 420, "departure_time": 720, "service_time": 300 },
            { "type": "service", "job_id": "job-4822", "location_index": 2, "arrival_time": 1080, "departure_time": 1380, "service_time": 300 },
            { "type": "end", "location_index": 0, "arrival_time": 2040, "departure_time": 2040 }
          ],
          "summary": { "total_distance": 9020, "total_time": 2040, "jobs_served": 2 },
          "violations": []
        }
      ],
      "unserved": [],
      "score": { "total": 9020 },
      "warnings": []
    }

    Here truck-1 served both jobs, status is optimal, and unserved is empty — nothing was dropped. If unserved is non-empty, each entry includes a reason code explaining why (see Understanding the Response).

Skip the matrix

If you don't have a precomputed distance/time matrix, omit travel.distance_matrix/time_matrix and instead provide lat/lon coordinates on your locations — FG-API computes matrices for you.

Next steps

Next steps
  • User Guide — learn how to build richer jobs, read full responses, and apply constraints.
  • API Reference — every endpoint, every field, every error code.

FieldGenius VRP API documentation. Generated from the engineering source of truth (.tex docs and app/ source).