Skip to content
TRAXOAPI documentation
FR

API · Integrations

Send your orders to TRAXO

Your website, Zapier, Make or n8n sends each order to a receiving URL. TRAXO creates the request, and your customer gets a link to say where to deliver.

HTTPS · JSONOne POST request per order.
No codeWooCommerce, FedaPay, Zapier, Make, n8n, Excel.
Nothing billed on receiptNothing is billed until the request becomes a delivery.

Get started

First steps

  1. 1
    In TRAXO: Settings › Integrations › Add a source.
  2. 2
    Choose Zapier, Make, n8n or your website.
  3. 3
    Copy the receiving URL (with its token) and the signing secret. They are shown only once.
  4. 4
    Send a test ("test": true), then open the Log.

WooCommerce store or FedaPay payment links: no code needed, see WooCommerce and FedaPay.

TRAXO format

Send an order

POSThttps://app.gettraxo.app/api/in/src_…/whk_…

Header Content-Type: application/json · 512 KB at most

curl -X POST "$TRAXO_URL" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "CMD-1042",
    "customer": { "name": "Awa Dossou", "phone": "+229 01 95 12 34 56" },
    "address": { "neighborhood": "Fidjrossè" },
    "cash_to_collect": 15000
  }'

$TRAXO_URL: the full URL copied from TRAXO. Keep it in your server or automation tool, never in a public web page.

Full example

{
  "reference": "CMD-1042",
  "customer": {
    "name": "Awa Dossou",
    "phone": "+229 01 95 12 34 56",
    "email": "[email protected]"
  },
  "address": {
    "neighborhood": "Fidjrossè",
    "landmark": "Behind the pharmacy"
  },
  "cash_to_collect": 15000,
  "delivery_fee": 1500,
  "items": [{ "name": "Pagne wax", "qty": 2, "unit_price": 6750 }],
  "window": { "from": "2026-11-10T10:00:00+01:00", "to": "2026-11-10T13:00:00+01:00" },
  "note": "Call before arriving"
}

TRAXO format

Fields

Required: customer.phone or customer.email. Everything else is optional.

FieldTypeDescription
referencetext, 80 charsYour order number. A reference creates only one request; it is also used to cancel. Also: order_id, id.
customer.nametextCustomer name. Also: customer_name.
customer.phonetextPhone number, preferably in international format (+229 …). Also: customer_phone.
customer.phone_countrycountry codeCountry of a number written without its calling code (BJ, TG, CI…). Default: your company’s country.
customer.emailtextEmail: TRAXO can send the customer’s link there. Also: customer_email.
address.neighborhoodtextNeighbourhood or area. Also: address.zone, address.district or address as text.
address.landmarktextLandmark.
cash_to_collectinteger, CFA francsAmount to collect on delivery, fee included.
delivery_feeinteger, CFA francsDelivery fee, included in cash_to_collect.
amountinteger, CFA francsAmount of an order already paid: nothing to collect.
items[]list, 20 at mostItems: name, qty (1 to 999), unit_price.
package_descriptiontextParcel contents, if you do not send items.
windowobject or textPreferred time slot: from and to in ISO 8601, or text.
notetextDelivery instruction, visible to the customer.
testbooleantrue: test, no request created.
cancelbooleantrue with reference: cancels the order. Also: "status": "cancelled".

Amounts in whole CFA francs; 15000, "15 000 F" or "15000.00" are accepted.

TRAXO format

Authentication

MethodURL and headersUse
Token in the URLhttps://app.gettraxo.app/api/in/src_…/whk_…Simplest: Zapier, Make, n8n.
Token in a headerhttps://app.gettraxo.app/api/in/src_…
X-Traxo-Token: whk_…
or Authorization: Bearer whk_…
The URL no longer contains the token.
Signaturehttps://app.gettraxo.app/api/in/src_…
headers webhook-*
Recommended for a website. Sign a request.

With a token only, your team approves each request confirmed by the customer before a rider is sent (“To check”), and the link is not emailed unless you turn it on. A signed request is approved as soon as the customer confirms.

TRAXO format

Sign a request

Format Standard Webhooks: libraries for this format produce the same headers.

ItemValue
Secretwhsec_…, shown once when the source is created.
Signed content{webhook-id}.{webhook-timestamp}.{body}
AlgorithmHMAC-SHA256, key = secret without whsec_, base64-decoded; result in base64.
webhook-idUnique ID of the request.
webhook-timestampUnix seconds; at most 5 minutes off.
webhook-signaturev1,<signature>
const crypto = require('crypto');

const secret = process.env.TRAXO_SECRET;     // whsec_…
const url = process.env.TRAXO_SOURCE_URL;    // https://app.gettraxo.app/api/in/src_…
const body = JSON.stringify(order);
const id = `msg_${crypto.randomUUID()}`;
const timestamp = Math.floor(Date.now() / 1000).toString();
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
const signature = crypto.createHmac('sha256', key)
  .update(`${id}.${timestamp}.${body}`)
  .digest('base64');

await fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'webhook-id': id,
    'webhook-timestamp': timestamp,
    'webhook-signature': `v1,${signature}`,
  },
  body,
});
import base64, hashlib, hmac, json, os, time, uuid, urllib.request

secret = os.environ["TRAXO_SECRET"]          # whsec_…
url = os.environ["TRAXO_SOURCE_URL"]         # https://app.gettraxo.app/api/in/src_…
body = json.dumps(order).encode()
msg_id = f"msg_{uuid.uuid4().hex}"
timestamp = str(int(time.time()))
key = base64.b64decode(secret.removeprefix("whsec_"))
signed = f"{msg_id}.{timestamp}.".encode() + body
signature = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()

request = urllib.request.Request(url, data=body, method="POST", headers={
    "Content-Type": "application/json",
    "webhook-id": msg_id,
    "webhook-timestamp": timestamp,
    "webhook-signature": f"v1,{signature}",
})
urllib.request.urlopen(request)

Sign exactly the bytes you send: do not reformat the JSON after signing.

TRAXO format

Responses

CodeMeaning
200
{ "ok": true }
Notification received and verified. The outcome (request created, duplicate, ignored, set aside) shows in the Log. Do not resend.
401Unknown source, invalid token or signature, or signature older than 5 minutes.
413Body larger than 512 KB.
429Too many requests: 120 per minute per source. Try again later.
503Receiving is temporarily closed. Try again later.

Only retry after a 429, a 503 or a network error, spacing out attempts. The same body sent twice is recorded once.

TRAXO format

Test

{
  "test": true,
  "reference": "ESSAI-1",
  "customer": { "name": "Test", "phone": "+229 01 95 12 34 56" }
}

Response 200. The Log shows “Ignored · Test received” with the name and phone it read. No request is created.

TRAXO format

Cancel

{ "reference": "CMD-1042", "cancel": true }

As long as the delivery is not created, the request becomes “Declined”. After that, nothing changes automatically: the Log flags it for your team.

No code

WooCommerce

  1. 1
    TRAXO: Add a source › WooCommerce. Copy the delivery URL and the secret.
  2. 2
    WordPress: WooCommerce › Settings › Advanced › Webhooks › Add webhook.
  3. 3
    Name: TRAXO · Status: Active · Topic: Order created · copied URL and secret · API: WP REST API v3.
  4. 4
    Add a second identical webhook, topic Order updated.
OrderIn TRAXO
Processing (paid), or cash on deliveryRequest created
Not paid yet, local pickup, older than the connectionIgnored
Cancelled, refunded, failed or deletedRequest declined

Amounts: total minus shipping = items; shipping = delivery fee. Cash on delivery: the total is to be collected.

No code

FedaPay

  1. 1
    TRAXO: Add a source › FedaPay. Copy the webhook URL.
  2. 2
    FedaPay: Webhooks › Create a webhook with this URL and the transaction.approved event.
  3. 3
    Paste into TRAXO the secret key shown by FedaPay.

Each approved payment creates a request that is already paid: nothing to collect. Details read: the FedaPay customer (name, phone, email) and the quartier / neighborhood, repere / landmark metadata.

You also take payments with no delivery? Set a keyword in the source settings: only payments whose description contains it create a request.

No code

Excel or CSV import

Excel (.xlsx) or CSV, up to 2 MB and 500 rows; the first row holds the headers. Templates: Settings › Integrations › Import a file.

DataRecognized headers (examples)
ReferenceRéférence, Commande, N° commande, Order
NameNom, Nom du client, Client, Destinataire, Name
Phone or emailTéléphone, Tel, Numéro, Mobile, WhatsApp, Phone · E-mail, Mail, Courriel
NeighbourhoodQuartier, Zone, Adresse, Lieu, Ville, Commune, Address
LandmarkRepère, Point de repère, Indications, Précisions, Landmark
NoteNote, Commentaire, Remarque, Instructions, Message
Amount to collectMontant à encaisser, Montant, Total, Prix, Cash
Delivery feeFrais de livraison, Livraison, Frais, Shipping
ItemsArticles, Produits, Colis, Contenu, Description, Items

Case, accents and punctuation do not matter. Rows to fix are shown before importing; a reference already imported is not created again.

Monitor

Rules and limits

  • A reference creates a single request; the same body sent twice is recorded once.
  • Limit per source: 100 requests per 24 hours by default, adjustable from 1 to 1,000. Beyond it, the notification is set aside: raise the limit, then replay it from the Log.
  • 10 sources at most per company; 120 requests per minute per source.
  • The customer’s link stays valid for 7 days.
  • Email to the customer: at most 2 per address per 24 hours, 300 per company. Otherwise the link waits in “To send”, with a WhatsApp button.
  • Notification content kept 7 days; log kept 30 days.

Monitor

Log

Settings › Integrations › Log: the last 50 notifications, filtered by source and outcome.

OutcomeMeaning
Request createdThe request awaits the customer’s confirmation.
Already receivedThis reference already exists.
IgnoredNothing to deliver: test, order not paid yet, local pickup, unreadable content…
Set asideLimit reached, source paused, customer with no phone or email, suspended workspace. Can be replayed.
FailedProcessing error after several attempts. Can be replayed.

Monitor

Security

  • Secrets and tokens are shown only once, at creation. After that, neither the screen, the API nor the logs show them.
  • Signing secrets are encrypted (AES-256-GCM); tokens are kept only as a hash (SHA-256).
  • Lost or exposed? Source settings › New secret: the old one stops working at once.
  • The company is always the source’s: no field you send can target another company.
  • TRAXO never asks you for a secret by email or WhatsApp.