Developer platform

FuelSync API

Quote, place, track and cancel fuel orders from your own POS system, ERP connector, or dispatch software — the same pricing and order pipeline the FuelSync app itself runs on.

Pricing

Developer-friendly pricing built for rapid integration.

Build on FuelSync. Fuel. EV. Roadside. Fleet energy. Procurement. One API.

Loading plans…

Every plan includes full sandbox access with no request limit — build and test for free, upgrade only once you're ready for production traffic.

Authentication

Every request needs an Authorization header with an API key. Keys are self-service — sign in to any FuelSync account and generate one from the developer settings page.

Authorization: Bearer fs_live_8a3b21e9c4f6d05a17b2e4c8f9012ab3

# fs_test_... keys run against the sandbox environment — they never
# create real orders, so they're safe for integration testing.

Sandbox vs production

A key's environment is fixed at creation. fs_test_... keys return realistic pricing but never write a real order — order-creation responses are clearly marked "simulated": true and their IDs can't be looked up afterwards. fs_live_... keys place real orders that get dispatched to a real runner or driver.

Endpoints

POST/api/v1/fuel/quotescope: fuel:quote

Get current fuel price and delivery-fee estimate. Side-effect free — never creates anything.

Request body

{
  "product": "diesel_50ppm",
  "quantity_litres": 500,
  "province": "GP",
  "distance_km": 12
}

Response

{
  "data": {
    "quote_id": "quote_...",
    "product": "diesel_50ppm",
    "fuel_cost_cents": 1105000,
    "delivery_fee": { "total_cents": 45000, "...": "..." },
    "expires_at": "2026-01-01T12:15:00Z"
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
POST/api/v1/fuel/ordersscope: fuel:orders:create

Create a fuel order on behalf of your own customer. Requires a delivery address and GPS coordinates.

Request body

{
  "product": "diesel_50ppm",
  "quantity_litres": 500,
  "province": "GP",
  "delivery_address": "1 Example St, Sandton",
  "delivery_location": { "latitude": -26.1076, "longitude": 28.0567 },
  "payment_type": "cash",
  "external_customer_ref": "your-internal-customer-id"
}

Response

{
  "data": {
    "order_id": "...",
    "status": "pending",
    "total_cents": 1150000,
    "simulated": false
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/fuel/orders/:idscope: fuel:orders:read

Read an order's current status, driver, and totals. Only orders your own key created are visible.

Response

{
  "data": {
    "order_id": "...",
    "status": "dispatched",
    "driver_name": "T. Nkosi",
    "total_cents": 1150000,
    "external_customer_ref": "your-internal-customer-id"
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
POST/api/v1/fuel/orders/:id/cancelscope: fuel:orders:cancel

Cancel an order you created, before it's completed. Orders that are already completed, cancelled, or refunded return 409.

Request body

{ "reason": "Customer changed their mind" }

Response

{
  "data": { "order_id": "...", "status": "cancelled" },
  "meta": { "request_id": "req_...", "environment": "production" }
}

Fleet & demand intelligence

The fleet:read scope is not granted by default — it requires an admin to link your API partner account to a specific FuelSync fleet (partner_accounts row) first. /api/v1/vehicles/* and /api/v1/fleet/* only ever return data for vehicles/runners that are active members of that one linked fleet — every other id, including a real vehicle belonging to a different fleet, returns 404 rather than 403, so a probing request can't confirm it exists.

GET/api/v1/vehicles/:id/capabilitiesscope: fleet:read

A vehicle's Vehicle Capability Profile — configuration (dedicated / multi_compartment / service_only), fuel types carried, total capacity, and per-compartment breakdown.

Response

{
  "data": {
    "vehicle_id": "...",
    "configuration": "multi_compartment",
    "fuel_types": ["diesel_50ppm", "petrol_95"],
    "capacity_l": 4000,
    "compartment_count": 3,
    "compartments": [
      { "position": 1, "product": "diesel_50ppm", "capacity_l": 2500, "current_volume_l": 2200 },
      { "position": 2, "product": "petrol_95", "capacity_l": 1000, "current_volume_l": 900 }
    ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/vehicles/:id/inventoryscope: fleet:read

A vehicle's real current load — distinct from capability. Capable of carrying diesel is not the same fact as currently carrying enough of it.

Response

{
  "data": {
    "vehicle_id": "...",
    "total_capacity_l": 4000,
    "total_current_load_l": 3100,
    "available_headroom_l": 900,
    "compartments": [
      { "position": 1, "product": "diesel_50ppm", "capacity_l": 2500, "current_volume_l": 2200, "available_headroom_l": 300 }
    ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/vehicles/:id/opportunitiesscope: fleet:read

Real nearby demand this vehicle can act on, ranked by the same opportunity_score the mobile Opportunity Map uses. Requires ?lat=&lng= (the vehicle's current position — this API has no live GPS feed to fall back to); optional &radius_km= (default 20).

Response

{
  "data": {
    "vehicle_id": "...",
    "opportunities": [
      { "order_id": "...", "fuel_type": "diesel_50ppm", "litres": 200, "distance_km": 2.1, "fulfillability": "fulfillable", "opportunity_score": 0.91 }
    ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/demand/nearbyscope: fleet:read

Real network-wide demand near a point — not fleet-scoped. Requires ?lat=&lng=; optional &radius_km= (default 20) and &product= to filter the breakdown to one fuel type.

Response

{
  "data": {
    "window_days": 7,
    "radius_km": 20,
    "by_product": [
      { "fuel_type": "diesel_50ppm", "order_count": 12, "total_litres": 9800, "open_count": 4 }
    ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/fleet/:id/inventoryscope: fleet:read

:id is your linked fleet's own id — aggregate real capacity and current load across every active vehicle in it.

Response

{
  "data": {
    "fleet_id": "...",
    "vehicle_count": 6,
    "total_capacity_l": 14000,
    "total_current_load_l": 9200,
    "vehicles": [ { "vehicle_id": "...", "fuel_types": ["diesel_50ppm"], "capacity_l": 2000, "current_load_l": 1240, "configuration": "dedicated" } ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}
GET/api/v1/fleet/:id/demandscope: fleet:read

Real nearby demand centered on your fleet's own registered address. Optional ?radius_km= (default 20). Returns 409 if the fleet has no registered lat/lng yet.

Response

{
  "data": {
    "fleet_id": "...",
    "window_days": 7,
    "radius_km": 20,
    "by_product": [ { "fuel_type": "diesel_50ppm", "order_count": 5, "total_litres": 4200, "open_count": 2 } ]
  },
  "meta": { "request_id": "req_...", "environment": "production" }
}

Webhooks

Configure a webhook URL from the developer settings page to get notified on order.created and order.cancelled. Every delivery is signed:

X-Webhook-Timestamp: 1735689600
X-Webhook-Id: <delivery id>
X-Webhook-Signature: sha256=<hex(hmac_sha256(secret, `${timestamp}.${id}.${rawBody}`))>

Errors

Every error follows the same shape:

{
  "error": {
    "code": "MISSING_SCOPE",
    "message": "This API key does not have the 'fuel:orders:create' scope.",
    "request_id": "req_...",
    "details": { "required_scope": "fuel:orders:create", "granted_scopes": ["fuel:quote"] }
  }
}

429 RATE_LIMIT_EXCEEDED is returned once you exceed your plan's requests-per-minute limit (visible on your developer settings page).

Scopes

Self-service keys are granted the core order-lifecycle scopes automatically. Other scopes below are part of the platform but not yet self-service — contact FuelSync if your integration needs one of them.

Loading…