Sign in
Developers

Loader4D API

Call load optimisation from inside your own ERP, WMS or transport management system. The same placement engine that runs in the browser, behind a single HTTP request.

The API is live

A test key gives you 25 calls a month: the real engine, a real plan, and no credits spent. Verify your integration before paying, then pick a plan to go live.

What you can do

Optimisation endpoint

Send your spaces and item list as JSON and get the placement plan back with the coordinates of every piece. Axle loads and items that could not be placed are in the response too.

The result is never lost

An optimisation takes seconds. In a synchronous design a dropped connection destroys the result; here you come back with the job id and collect it, so you never pay for the same computation twice.

A bill you can predict

Credits are banded, not per piece. The engine spends the same search budget on a small shipment as on a large one, so per-piece pricing would penalise small calls and make your bill impossible to forecast.

Build without burning quota

Test keys return real results and spend no credits; they are capped at 25 calls a month. Keep testing until your integration is done — going live only means swapping the key.

Endpoints

Authentication uses a bearer header carrying your key. Keys are never accepted in a query string.

Authorization: Bearer l4d_live_...
Call What it does
POST /api/v1/pack Opens a placement job; returns 202 and a job id.
GET /api/v1/jobs/{id} Returns the state of the job, and its result once finished.
GET /api/v1/usage Returns your quota for the period and the credits left.

Example request

Lengths are centimetres and weights are kilograms. There is no per-request unit setting; convert on your side. A request sent in inches loads a lorry ten times too long.

POST /api/v1/pack
Authorization: Bearer l4d_test_...
Content-Type: application/json
Idempotency-Key: 7f3c1a9e4b6d4c2f

{
  "reference": "SO-2026-4417",
  "spaces": [
    { "id": "sp1", "name": "40HC", "type": "container",
      "length": 1200, "width": 235, "height": 269,
      "max_weight": 26000, "available": 2 }
  ],
  "items": [
    { "id": "A1", "name": "Karton", "length": 120, "width": 100, "height": 40,
      "weight": 8, "quantity": 24, "group": "Siparis-1",
      "constraints": { "no_tilt": true } },
    { "id": "B1", "name": "Varil", "shape": "cylinder",
      "diameter": 58, "length": 88, "weight": 190, "quantity": 12,
      "constraints": { "floor_only": true } }
  ],
  "strategy": { "group_items": true, "balance_load": true }
}

The response comes back immediately; you poll the job id for the result.

HTTP/1.1 202 Accepted
Location: /api/v1/jobs/ba7189d3b1824da3806ca3ee973b2294

{ "id": "ba7189d3...", "status": "queued", "progress": 0,
  "reference": "SO-2026-4417", "credits": 1 }

When the job finishes, every piece arrives with its coordinates. The origin is the front-left-bottom corner of the space, and the value given is that corner of the piece, not its centre.

{ "id": "ba7189d3...", "status": "succeeded", "credits": 1,
  "result": {
    "summary": { "spaces_used": 1, "pieces_requested": 36,
                 "pieces_packed": 36, "weight": 2472,
                 "volume_utilization": 0.7431 },
    "spaces": [
      { "space_id": "sp1", "name": "40HC",
        "placements": [
          { "item_id": "A1", "sequence": 1,
            "x": 0, "y": 0, "z": 0,
            "length": 120, "width": 100, "height": 40, "weight": 8 }
        ],
        "axle_loads": [] }
    ],
    "unpacked": []
  } }

See the API reference for the full list of fields and constraints, the error codes and the OpenAPI document

Credits and limits

Credits are deducted when a job is accepted, not when it finishes. Otherwise a hundred calls arriving at once would all pass the quota check before a single one had been counted.

Total pieces in the request Credits
1 – 1001
101 – 1 0005
1 001 – 10 00025
10 001 and above100

These limits exist so that one call cannot occupy the service for minutes. If your workload needs more, split it or get in touch.

Frequently asked

Which language can I integrate with?

Any language that can make an HTTP request. You can also download our OpenAPI 3.0 document and generate a typed client in most languages; that is the difference between an integration that takes hours and one that takes days.

Download openapi/v1.json

How does pricing work?

The API is part of the paid plans; live calls require a credit pack, which renews each period. Unused credits do not carry over. Trying it out needs no credits: a test key allows 25 calls a month.

Refund Policy

How are my keys protected?

A key is shown once, when it is created; only an encrypted digest is kept in the database. Keys belong to the team rather than to a person, so your integration keeps working even if whoever set it up leaves. Give each integration its own key; then if one is exposed you revoke only that one and the others keep running.

Privacy Policy

What if I send the same request twice by accident?

Send an Idempotency-Key header with a value you generate per logical request. A retry with the same key and the same body returns the original job instead of opening a second one. Using the same key with a different body is rejected: silently returning the earlier answer would leave you waiting for work that was never queued.

Does an interrupted job resume where it stopped?

No, and it is right to say so plainly. The search is a single computation and no intermediate state is kept; a failed job runs from the start. What the job id gives you is not continuity but the fact that the result is not lost.

Can I also see the results in the interface?

Jobs opened through the API are independent and are not added to your project list; the result comes back in the response. API calls spend credits rather than seats, so they do not affect the seats of team members using the interface.