API reference

NL EN

Try everything here, with this token

Every call below has a button that really makes it. What comes back is from the server itself, not from an example in the text — including the errors.

Test environment
rQIj1a8DGUng23lCAUKHKZpSzhsDv5l1zPvd9UCiqhF45ojk

This token is replaced as soon as you reload this page, and it cannot place orders. So do not build anything with it: turn on dropshipping in your own account for a token that stays.

You can look but not change — it is one account for everyone looking at it.

Authentication

Every call carries your API token as a Bearer header. You will find that token in the dropship panel under API.

curl -H "Authorization: Bearer JOUW_TOKEN" https://api.l33d.be/api/dropship/status
  • Amounts are in cents, VAT included.
  • With a test token everything goes to the test environment: nothing is really ordered or paid. GET /status tells you where you are in environment.
  • Errors come back as JSON with error: 401 invalid token, 404 not found or not yours, 422 invalid input, 429 too many requests, 503 maintenance (retry after Retry-After).

Endpoints

https://api.l33d.be/api/dropship

Account and catalogue

GET /status

Test your token: your account, your balance, whether invoice and credit are allowed, and live or test.

GET /products

All active products with prices in cents, the full quantity scale, the photo and the engraving area.

GET /addresses

Your address book of end customers.

Design

POST /position-sessions

Creates a session for a product and returns a white label link to the full editor.

GET /position-sessions/{token}

The result: status, the full layout and a preview.

POST /preview

A preview without ordering. Valid for an hour.

Orders

POST /orders

Place an order.

GET /orders

Your orders with status, end customer and tracking.

GET /orders/{number}

One order: lines, discounts, shipping, total, payment and can_cancel.

POST /orders/{number}/cancel

Cancel while can_cancel is true. Reason is optional.

{"reason":"Klant annuleerde"}

Credit

GET /credits

Your balance, whether you may use credit, and the last 100 transactions.

POST /credits/topup

Top up: returns a code and the url where payment happens.

GET /credits/topup/{code}

The state of that top-up and your new balance.

Address book and prices

POST /addresses

Add an address to your address book.

{"label":"Bakkerij","first_name":"Jan","last_name":"Peeters","street":"Kerkstraat","house_number":"12","postal_code":"3500","city":"Hasselt","country":"BE"}

PUT /addresses/{id}

Change an address, with the same fields.

DELETE /addresses/{id}

Delete an address.

PUT /products/{id}/price

Your own retail price for one product; null resets it to your markup.

{"price_cents":1299}

PUT /markup

Your markup in percent, for everything without its own price.

{"markup_percent":40}

Rather not build an editor yourself? That is the recommended route. See Positioning logos

Placing an order

The price in the response is what you pay us: quantity scale, your discount, surcharges, VAT and shipping to the end customer's address. What you charge your own customer is separate from that. You do not need to recalculate anything.

By default it comes off your credits and production starts immediately. If your balance is too low, or you ask for a payment link or an invoice, the order waits for payment.

Option A — through a confirmed positioning session. Supports everything: multiple texts, multiple logos, two sides.

curl -X POST https://api.l33d.be/api/dropship/orders \
  -H "Authorization: Bearer JOUW_TOKEN" -H "Content-Type: application/json" \
  -d '{
    "reference": "WC-1042",
    "payment": "credits",
    "address": { "first_name": "Jan", "last_name": "Peeters",
      "street": "Kerkstraat", "house_number": "12",
      "postal_code": "3500", "city": "Hasselt", "country": "BE" },
    "items": [
      { "quantity": 2, "position_session_token": "..." }
    ]
  }'

Option B — text and one logo, straight in the call.

{
  "items": [
    { "product_id": 23, "quantity": 2, "text": "Voor opa" },
    { "product_id": 23, "quantity": 1,
      "logo_url": "https://jouwsite.be/logo.png",
      "logo_position": { "cx": 0.5, "cy": 0.5, "w": 0.4, "angle": 90 } }
  ]
}
  • payment: credits (default), link (the response contains pay_url) or invoice (if invoicing is enabled for you).
  • The same reference within a day returns the existing order with already_known: true. Retrying after a timeout is safe.
  • We fetch a logo_url ourselves, or send logo_base64. PNG, JPG or WebP, up to 5 MB. Without logo_position we centre it in the engraving area.
  • If a product has colours (colors in GET products), send color_id. Without color_id we use the default colour.
  • The response (201) contains order_number, total_cents, paid, insufficient_credits, credit_balance_cents, pay_url and track_url. Instead of a full address you may also send address_id from your address book.

One order: lines, totals and payment. Cancelling works while can_cancel is true; credits are not refunded automatically.

GET  https://api.l33d.be/api/dropship/orders/{number}
POST https://api.l33d.be/api/dropship/orders/{number}/cancel
     { "reason": "Klant annuleerde" }

< { "ok": true, "status": "cancelled", "order": { ... } }

Topping up credit

Request a code, open the url in the browser, then poll the state. It is only paid when this call says so.

# 1. code aanvragen
POST https://api.l33d.be/api/dropship/credits/topup
{ "amount_cents": 5000 }
< { "ok": true, "code": "…", "url": "https://l33d.be/dropshipping/opwaarderen/…", "status": "open", "test": false }

# 2. url openen in de browser: daar wordt betaald

# 3. de stand opvragen tot betaald of mislukt
GET https://api.l33d.be/api/dropship/credits/topup/{code}
< { "ok": true, "status": "betaald", "balance_cents": 12500 }

status: open, betalen (paying), betaald (paid), mislukt (failed) or verlopen (expired). A code is valid for two hours. In the test environment the payment is simulated on that page.

Webhooks

Set a webhook URL in the dropship panel. We send a JSON message on every status change and as soon as tracking is available.

Verify the sender with the X-L33D-Signature header: a sha256 HMAC over the raw body, keyed with your API token.

$body = file_get_contents('php://input');
$sig  = $_SERVER['HTTP_X_L33D_SIGNATURE'] ?? '';
if (!hash_equals(hash_hmac('sha256', $body, 'JOUW_TOKEN'), $sig)) {
    http_response_code(401); exit;
}
$event = json_decode($body, true);
// X-L33D-Event / event: order.status_changed | order.tracking_added | test
// data: order_number, status, total_cents, tracking_code, tracking_url, end_customer