fragtrDansk · English

Fragtr API

The API lets your own system (warehouse, ERP, webshop) get rates, book shipments, download labels and follow tracking directly in fragtr. Prices are exactly the same as in the portal.

Getting startedEndpointsRates and bookingWebhooksErrors and limitsClaude (MCP)Custom order system →Connect your carrier →

Connect your own carrier agreement

Do you have your own agreement with UPS, DHL, GLS, PostNord, Bring or DAO? Then you can connect it yourself under Backend and get your own rates in fragtr. We have written a simple step-by-step guide for each carrier.

See the guides →

Getting started

  1. Log in to fragtr and go to Backend → API keys → Create key. Choose Read only or Read and book.
  2. Copy the key (fk_…). It is shown only once – store it like a password.
  3. Send the key with every request: Authorization: Bearer fk_…

Base URL: https://fragtr.dk/api/v1 · All amounts are DKK excl. VAT · JSON in and out · Dates as YYYY-MM-DD.

curl https://fragtr.dk/api/v1/me \
  -H "Authorization: Bearer fk_YOUR_KEY"

A customer's key always works on the customer's own account. An organization's key can work on the organization's customers (specify account_no) or as its own shipment ("account_no": "own").

Endpoints

MethodPathWhatAccess
GET/meWho the key belongs toRead
GET/accountsAccounts the key can work on (?q= searches)Read
POST/quotesGet rates – returns quote_id and offers (valid for 30 min.)Read
POST/bookingsBook an offerBook
GET/bookingsList – ?from=&to=&status=&q=&account_no=&limit=Read
GET/bookings/{nr}A single booking (e.g. CL-2026-00012). ?refresh=1 fetches the latest statusRead
GET/bookings/{nr}/labelThe label as PDFRead
POST/bookings/{nr}/cancelCancel (only before pickup)Book
GET/statsKey figures for a period – ?from=&to=Read

Booking status: booked, handling (handled manually), failed, error (can be retried), cancelled. The carrier's own status is in carrier_status.

Rates and booking

1. Get rates

POST /api/v1/quotes
{
  "direction": "export",                  // export (from DK) · import (to DK) · cross (between two other countries)
  "origin":      {"country": "DK", "zip": "2600", "city": "Glostrup", "street": "Industrivej 4"},
  "destination": {"country": "NO", "zip": "0162", "city": "Oslo", "street": "Karl Johans gate 12"},
  "packages": [{"qty": 2, "kg": 4.5, "l": 40, "w": 30, "h": 30}],
  "pickup_date": "2026-10-27",            // optional – defaults to the next business day
  "incoterm": "DAP"                       // optional
}
{
  "quote_id": "4f1c…", "valid_minutes": 30,
  "offers": [
    {"offer_id": "ntg:42", "carrier": "UPS", "product_label": "UPS · Standard", "sell_dkk": 215.32,
     "transit_hint": "Levering senest fre. kl. 23:30"}
  ]
}

2. Book

POST /api/v1/bookings
{
  "quote_id": "4f1c…",
  "offer_id": "ntg:42",
  "sender":   {"name": "Nordlys Lager", "contact": "Pia", "street": "Industrivej 4", "phone": "+45 12 34 56 78",
               "email": "lager@nordlys.dk"},
  "receiver": {"name": "Bergen Interiør AS", "contact": "Ola", "street": "Karl Johans gate 12",
               "phone": "+47 22 33 44 55", "email": "ola@bergen.no"},
  "goods_description": "Bordlamper i messing",    // required – what is in the package
  "reference": "ORD-1001",                        // optional
  "commodity_value": 4800                         // only for shipments subject to customs (e.g. Norway, UK, USA)
}

Postal code, city and country are taken from the quote. A phone number is required for both sender and receiver. For import and cross trade, the sender's email must be filled in (the label is sent there). The response contains the booking with no, tracking_number and has_label.

3. Label

curl -o label.pdf https://fragtr.dk/api/v1/bookings/CL-2026-00012/label -H "Authorization: Bearer fk_…"

Webhooks

Under Backend → Webhook you enter an https URL. Fragtr then sends a POST with JSON whenever something happens:

POST https://jeres-system.dk/fragtr/webhook
X-Fragtr-Event: booking.updated
X-Fragtr-Timestamp: 1792700000
X-Fragtr-Signature: sha256=5d1c…

{"event": "booking.updated", "sent_at": "2026-10-23T09:12:00+00:00",
 "data": {"booking": {"no": "CL-2026-00012", "status": "booked", "tracking_number": "1Z…",
                      "carrier_status": {"code": "IN_TRANSIT", "label": "Undervejs", …}, …}}}

Verify the signature

The signature is HMAC-SHA256 of "{timestamp}.{body}" using your signing secret (whsec_…, shown once). Reject messages where the signature does not match or the timestamp is more than 5 minutes old.

# Python
import hmac, hashlib, time
def ok(secret, ts, body, signature):
    expected = "sha256=" + hmac.new(secret.encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature) and abs(time.time() - int(ts)) < 300
// Node.js
const crypto = require("crypto");
function ok(secret, ts, body, signature) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(`${ts}.${body}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature)) && Math.abs(Date.now()/1000 - ts) < 300;
}

Respond with 2xx within 6 seconds. Use Send test in Backend to test the connection.

Errors and limits

Errors are returned as {"error": "Explanation"} with an HTTP status: 400 invalid data, 401 missing/invalid key, 403 no access (e.g. a read-only key trying to book), 404 not found, 429 too many requests, 502 the carrier system did not respond – try again.

Send the header Accept-Language: en to get error messages in English (default is Danish).

At most 120 requests per minute per key. Delete a key under Backend if it has fallen into the wrong hands – it stops working immediately.

Claude (MCP)

Clovr and organizations can connect Claude to fragtr and ask about revenue, margin, bookings and invoices – or let Claude get rates and book. Claude only sees what the user can see, and asks before changing anything.

  1. In Claude: Settings → Connectors → Add custom connector.
  2. URL: https://fragtr.dk/mcp → Connect → log in with your fragtr login → Allow access.

Claude Code and other MCP clients can also use an API key:

claude mcp add --transport http fragtr https://fragtr.dk/mcp \
  --header "Authorization: Bearer fk_YOUR_KEY"