Authentication
Betakom partner endpoints use HMAC-SHA256 request signing — the same scheme Stripe uses for webhooks. You never send your secret over the wire; instead you sign each request with it and Betakom recomputes the signature to verify it. Your partnerId and secret are issued during onboarding (see Get Started).
Umgebung
https://api.betakom.deRequest headers
Every signed request carries these three headers:
| Field | Type | Required | Description |
|---|---|---|---|
x-partner-id | string | required | Your public partner identifier (e.g. "acme"). Selects the credential — and therefore the environment — used to verify the signature. |
x-betakom-timestamp | string | required | Unix seconds at signing time. Must be within ±5 minutes of Betakom server time, otherwise the request is rejected (replay protection). |
x-betakom-signature | string | required | v1=<hex>, where <hex> = HMAC-SHA256(secret, "<timestamp>.<rawBody>"). The bare <hex> form (without the v1= prefix) is also accepted. |
How to sign a request
- Serialize the request body to a string (
payload). You must sign and send the exact same bytes — re-serializing JSON later will break the signature. - Take the current Unix time in seconds (
timestamp). - Compute
signature = HMAC-SHA256(secret, "<timestamp>.<payload>")and hex-encode it. - Send
x-partner-id,x-betakom-timestampandx-betakom-signature: v1=<hex>.
Node.js
import crypto from 'crypto';
const PARTNER_ID = 'acme';
const SECRET = process.env.BETAKOM_PARTNER_SECRET; // shared with Betakom
async function ingestOrder(body) {
const payload = JSON.stringify(body);
const timestamp = Math.floor(Date.now() / 1000).toString();
const signed = `${timestamp}.${payload}`;
const signature = 'v1=' + crypto
.createHmac('sha256', SECRET)
.update(signed)
.digest('hex');
return fetch('https://api.betakom.de/api/v1/partners/orders/ingest', {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-partner-id': PARTNER_ID,
'x-betakom-timestamp': timestamp,
'x-betakom-signature': signature,
},
body: payload, // sign and send the EXACT same bytes
});
}cURL
# 1. Build the body once and sign "<timestamp>.<body>"
TS=$(date +%s)
BODY='{"partnerOrderId":"PO-1001","customer":{"email":"kunde@example.com"},"loading":{"country":"DE","city":"Berlin","postalCode":"10115"},"unloading":{"country":"DE","city":"Muenchen","postalCode":"80331"},"vehicleType":"sprinter","totalPriceEur":480}'
SIG=$(printf '%s' "$TS.$BODY" | openssl dgst -sha256 -hmac "$BETAKOM_PARTNER_SECRET" | awk '{print $2}')
# 2. Send the same bytes you signed
curl -X POST 'https://api.betakom.de/api/v1/partners/orders/ingest' \
-H 'content-type: application/json' \
-H "x-partner-id: acme" \
-H "x-betakom-timestamp: $TS" \
-H "x-betakom-signature: v1=$SIG" \
-d "$BODY"Verification & errors
- Replay protection: the timestamp must be within ±5 minutes of Betakom server time, or the request is rejected with
401. - Signature mismatch / unknown partner: returns
401with a generic message (we don't reveal whether a partner exists or is inactive). - Body limits: the order-ingest endpoint caps bodies at 100 KB (
413) and rate-limits to 60 requests/minute per partner (429).
Other authentication schemes
The Carrier Integration API uses a per-connection token in the URL plus an x-betakom-signature over the raw body. The Tracking API uses a signed per-order share token (the t query parameter). The Pricing API (beta) currently accepts a shared API key in the request body. See each product's reference page for details.