Orders API (generic connection)

The HTTP endpoint that records an order — or a cart someone has started to pay for — from any tool. Exact contract, field reference, responses, the 422 error catalogue and which contact level each payload creates.

View .md Updated 2026-09-11
On this page

The «Conexión genérica» (generic connection) is a single HTTP endpoint that turns an order from any tool — Zapier, Make, a webhooks module or your own code — into a recorded conversion and, when the phone number is recognisable, into a contact with its consent level.

You will find your exact URL in the app, under «Ajustes → Integraciones → Conexión genérica» (settings → integrations → generic connection).

The endpoint

POST https://app.konverda.com/webhooks/orders/<tu-token>
Content-Type: application/json

Payload

Only order_ref is required. Everything else is optional and improves what the platform can do with the order.

{
  "order_ref": "pedido-1234",
  "status": "paid",
  "occurred_at": "2026-07-12T10:00:00Z",
  "total": 49.9,
  "currency": "EUR",
  "customer": {
    "phone": "+34 612 345 678",
    "name": "Ana Pérez",
    "email": "[email protected]"
  },
  "consent": true,
  "items": [
    { "id": "SKU-9", "name": "Curso X", "quantity": 1, "total": 49.9 }
  ],
  "tags": ["cliente"]
}

Field reference

FieldTypeDescription
order_reftext or number · requiredUnique reference of the order in your platform (max. 120 characters). It is the deduplication key: resending the same order_ref never duplicates the sale.
status'paid' | 'refunded'Defaults to 'paid'. 'refunded' records a refund of the same order.
occurred_atISO 8601 date · optionalWhen it happened. Without it, the moment of receipt is used.
totalnumber · optionalTotal amount of the order. Numeric text is also accepted ("49.90").
currency3 letters · optionalDefaults to EUR.
customerobject · optionalContainer for the customer’s data: phone, name, email.
customer.phonetext · optionalThe customer’s WhatsApp phone number. Without it (or if it is not recognisable) the sale is recorded all the same, but with NO contact — it shows up under «Conversiones sin contacto» (conversions with no contact).
customer.nametext · optionalThe customer’s name.
customer.emailtext · optionalAccepted but NEVER stored — email lives in your email tool. It is also scrubbed from the technical log of the request.
consentstrict boolean (true / false) · optionalThe consent checkbox of your checkout. IT DECIDES THE CONTACT’S LEVEL — see Consent. Careful: a quoted "true" or a 1 is NOT accepted here; a non-boolean value returns 422 bad_consent.
items[]list · optionalMax. 100 items: { id, name, quantity, total }. Each one needs at least id or name. They feed the catalogue and the per-product automations.
tags[]list of text · optionalMax. 20 tags to apply to the contact.
tokentext · optionalThe wtk parameter that sent links append to the destination URL (max. 64 characters). If the order carries no usable phone number but does carry this token, the sale is linked to the contact who received the link (it shows as «vía enlace» — via link).
cart_reftext or number · optionalOn an order: the cart this payment closes (max. 120 characters) — the same cart_ref you sent when the checkout started. Without it, the order still closes that contact’s open carts. On a cart it is required — see Carts.
event'checkout.started' · optionalWithout it, the payload is an order. With "checkout.started" it is a cart someone has started to pay for — see Carts. Any other value returns 422 bad_event.
recovery_urlhttps or http URL · carts onlyThe link that reopens that cart in your store. Ignored on an order.

Trying it with curl

curl -X POST 'https://app.konverda.com/webhooks/orders/<tu-token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_ref": "prueba-1",
    "total": 49.9,
    "customer": { "phone": "+34612345678", "name": "Ana Pérez" },
    "consent": true,
    "items": [{ "id": "SKU-9", "name": "Curso X", "quantity": 1, "total": 49.9 }]
  }'

A correct response is {"ok":true,"matched":true}. The sale appears under «Ajustes → Integraciones → Catálogo» (settings → integrations → catalogue) and, if the phone number is recognisable, on the contact’s page.

Responses

CodeBodyMeaning
200{"ok":true,"matched":true}Recorded and linked to a contact.
200{"ok":true,"matched":false}Recorded with NO contact (phone number absent or unrecognisable) — visible under «Conversiones sin contacto» (conversions with no contact).
200{"ok":true,"duplicate":true}That order_ref was already recorded. Resending is safe.
200{"ok":true,"recorded":false,"reason":"no_consent"}consent:false and the phone number does not belong to an already registered contact — no profile is created. It is a 200 on purpose: retrying would never change the outcome.
404{"error":"not_found"}Unknown URL or deactivated connection. Both answer the same: a 404 does not reveal whether the token exists.
422{"error":"invalid_payload","details":[…]}Invalid payload; details carries the per-field error codes.
429{"error":"rate_limited"}More than 60 requests per minute per IP — wait and retry.
500{"error":"ingest_error"}Internal error; retry later (deduplication by order_ref makes the retry safe).

The 422 error catalogue

details is a list of codes, one per problem found. The whole request is rejected: nothing is recorded partially.

CodeWhat causes it
missing_order_reforder_ref is missing (or arrives as null).
bad_order_reforder_ref is neither text nor number, is empty, or is longer than 120 characters.
bad_statusstatus is neither 'paid' nor 'refunded'.
bad_occurred_atoccurred_at is not text, or is not an interpretable date.
bad_totaltotal cannot be read as a number.
bad_currencycurrency is not exactly 3 letters.
bad_customercustomer is not an object (it arrived as text or as a list).
bad_consentconsent is not a boolean. "true", "1" and 1 are rejected here on purpose: consent is not guessed.
bad_itemsitems is not a list, is longer than 100, or some item carries neither id nor name (or carries a non-numeric quantity/total).
bad_tagstags is not a list of text, or is longer than 20.
bad_tokentoken is not text, or is longer than 64 characters.

Since 25 August 2026 a contact has TWO possible levels, and the consent field of your payload decides which one.

  • «Marketing» = they agreed to receive messages: campaigns, waves, proactive automations and 1
    templates.
  • «No» = we can only reply to them when they write.

This is not a reporting nuance: a contact at level «No» receives NO message started by us — not even a utility template, not even the welcome automation. The attempt is logged as not_marketing and nothing is sent.

What you sendBasis recordedResulting opt-inWhat they can receive
consent: truecheckbox«Marketing»Everything: campaigns, waves, proactive automations (order.paid included) and 1
templates. And, being an explicit act by the customer themselves, it lifts a previous opt-out.
consent absentpurchase«No»Only replies when the person writes. The order.paid automation is NOT sent. A previous opt-out is always respected.
consent: false— (no registration recorded)UnchangedThe sale is recorded ONLY if the phone number was already a registered contact; if not, no profile is created and the response says so (recorded:false).

Carts: checkout.started

The same URL also records a cart: the moment someone starts to pay in your store. If they do not finish the purchase within the time you set in «Ajustes → Reglas» (settings → rules; 45 minutes unless you change it), Konverda treats the cart as abandoned and the flow you built on the «Carrito abandonado» (abandoned cart) trigger starts. What the customer sees, the consent it requires and the safeguards are in Abandoned cart.

{
  "event": "checkout.started",
  "cart_ref": "carrito-5678",
  "recovery_url": "https://tu-tienda.com/carrito/recuperar/5678",
  "occurred_at": "2026-09-11T10:00:00Z",
  "total": 79.9,
  "currency": "EUR",
  "customer": {
    "phone": "+34 612 345 678",
    "email": "[email protected]"
  },
  "items": [
    { "id": "SKU-9", "name": "Curso X", "quantity": 1, "total": 49.9 },
    { "id": "SKU-12", "name": "Libro del curso", "quantity": 1, "total": 30 }
  ]
}

Cart fields

FieldTypeDescription
event'checkout.started' · requiredWhat turns the payload into a cart.
cart_reftext or number · requiredThe cart’s id in your store (max. 120 characters). Resending the same cart_ref updates that cart and restarts its countdown: it never creates a second cart or a second reminder.
recovery_urlhttps or http URL · requiredThe link that reopens the cart (max. 2048 characters). Konverda never sends it as is: it turns it into a tracked link, with its UTMs.
customer.phonetext · optionalUsed to find the contact. Same format as on orders.
customer.emailtext · optionalUsed to find the contact when the phone is not enough. On a cart with no contact it is kept only while the cart is open — the checkbox can arrive a moment later — and deleted as soon as the cart closes.
items[]list · optionalAs on orders. The first named item and the number of units can go into the message.
totalnumber · optionalThe cart’s value. It can go into the message in your currency’s format («79,90 €»).
currency3 letters · optionalDefaults to EUR.
occurred_atISO 8601 date · optionalWhen the checkout started. The countdown starts when we receive it, not at this date.

status, consent, token and tags are ignored on a cart.

Cart responses

CodeBodyMeaning
200{"ok":true,"matched":true,"armed":true}Cart recorded, contact found, countdown running.
200{"ok":true,"matched":false,"armed":true}Recorded with no contact yet. We look again when the countdown ends; if there is still nobody, the cart closes with no message.
200{"ok":true,"matched":…,"armed":false}That cart was already closed (bought, reminded or dropped). The resend changes nothing.

404, 429 and 500 mean the same as for orders.

Cart errors

CodeWhat causes it
bad_eventevent carries a value other than "checkout.started".
missing_cart_refcart_ref is missing.
bad_cart_refcart_ref is not text or a number, is empty, or is longer than 120 characters.
missing_recovery_urlrecovery_url is missing.
bad_recovery_urlrecovery_url is not a valid https/http address or is longer than 2048 characters.
bad_occurred_atoccurred_at is not a readable date.
bad_totaltotal cannot be read as a number.
bad_currencycurrency is not exactly 3 letters.
bad_customercustomer is not an object.
bad_itemsitems is not a valid list (same rules as on orders).

Closing the cart on payment

When the purchase completes, send the normal order to this same URL. If it carries the cart’s cart_ref, it closes exactly that cart; if not, it closes that contact’s open carts. On top of that, right before sending the reminder, Konverda checks whether the person has bought since the cart started — through any connection, Stripe or WooCommerce included — and if they have, nothing is sent.

Still stuck? Contact support