Conversions API

For everything Klibon has no connector for. You tell Klibon a payment happened; Klibon does the attribution and the commission. One endpoint, idempotent on your own event id.

Endpoint

POST https://klibon.com/api/v1/conversions, with a JSON body and an API key in the Authorization header.

Authentication

Create a key on your program's Setup page. It starts with klb_ and is shown once — Klibon only stores a hash of it. Send it as a bearer token: Authorization: Bearer klb_….

A key belongs to a product, not to a program, so a leaked key can only ever write events for that one product. Creating a key also connects the generic processor to your program, which counts against your plan's processors-per-program limit — the same as adding Stripe.

Body

event_idstring · required
Your own id for this event. It is the idempotency key: send it twice and the second call changes nothing.
typesale | renewal | refund · required
What happened. A renewal is a payment from a customer already attributed to a referral.
amountinteger · required
Minor units, never a decimal: 1999 for $19.99, 1999 for ¥1999. On a refund, the amount of that refund alone.
currencystring, 3 letters · required
ISO 4217, case insensitive. USD, EUR, JPY.
program_iduuid · sometimes
Only needed when the product this key belongs to runs more than one program. With a single program it is inferred.
referral_codestring · optional
The code you captured in the browser. The most direct way to attribute a sale.
discount_codestring · optional
The coupon the customer applied. If it is one you assigned to an affiliate in Klibon, the sale is credited to them — with or without a referral code.
customer_idstring · optional
Your own customer id. This is what ties a later renewal or refund back to the sale that came first — send it on every event you can.
customer_emailstring · optional
Stored only as a salted hash, used to match a customer and to detect self-referral.
payment_idstring · on a refund
Your id for the payment. Required on a refund: it is how Klibon finds the commission to reverse. Send it on sales too, or the refund will have nothing to match.
customer_ipstring · optional
Used only for self-referral detection, and hashed before it is stored.
product_idstring · optional
Your own id for what was sold, so the rate you set for that product applies. Leave it out and the payment earns your program default.
itemsarray · optional
For a payment covering several products: [{ product_id, price_id?, amount?, quantity? }]. Each line earns its own rate and the results are summed into one commission. Amounts are minor units; omit them and the payment is split evenly.
subscription_idstring · optional
Your id for the subscription. It is what keeps two subscriptions from one customer running their own durations instead of sharing a counter.

Two combinations are enforced:

  • A refund must carry payment_id.
  • A sale or renewal must carry at least one of referral_code, discount_code, customer_id or customer_email — something to attribute it by.

Example

curl
curl -X POST https://klibon.com/api/v1/conversions \
  -H "Authorization: Bearer klb_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "inv_9f21c4",
    "type": "sale",
    "amount": 1999,
    "currency": "USD",
    "referral_code": "ada",
    "customer_id": "cus_8817",
    "customer_email": "[email protected]",
    "payment_id": "pay_44120"
  }'

A new event answers 201:

201
{
  "received": true,
  "duplicate": false,
  "event_id": "inv_9f21c4",
  "outcome": "commission"
}

The same event_id again answers 200 and does nothing. This is what makes a retry safe:

200
{
  "received": true,
  "duplicate": true,
  "event_id": "inv_9f21c4"
}

Outcomes

outcome says what the event turned into. It is informational — the event is stored either way, and none of these values mean you should send it again.

  • commission — A commission was written.
  • reversed — A refund reduced or reversed an existing commission.
  • duplicate_payment — This payment already reached Klibon through another event.
  • no_attribution — Nothing tied this payment to an affiliate. Most sales are simply not referred.
  • no_commission — Attributed, but nothing earned — a zero amount, terms past their duration, a product you set to earn nothing, or a test-mode payment on a live affiliate. The Events tab says which.
  • deferred — Stored, decided later: a refund that overtook its sale, or a program not activated yet. Nothing is lost, and nothing needs re-sending.

Refunds

Send the amount of that refund, not a running total. Klibon adds up the refunds it has already seen for the payment and reverses the commission in proportion. Two partial refunds of 1000 on a 2000 payment are two calls of 1000, not 1000 then 2000.

json
{
  "event_id": "rfnd_2210",
  "type": "refund",
  "amount": 1999,
  "currency": "USD",
  "payment_id": "pay_44120"
}

A refund that arrives before the sale it reverses is held and retried for three days rather than dropped. A refund on a commission already paid out becomes a negative line on the affiliate's next statement.

Errors

  • 400 — the product runs several programs and the body named none.
  • 401 — the key is missing, unknown or revoked.
  • 404 — that program_id does not belong to this key's product.
  • 409 — the product has no active program.
  • 422 — the body did not validate, or one of the two required combinations above is missing. The message says which.

Every error is safe to retry with the same event_id once you have fixed the cause.

In code

node
async function reportConversion(body) {
  const response = await fetch('https://klibon.com/api/v1/conversions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.KLIBON_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(body)
  })

  // Retry with the SAME event_id. A repeat is ignored; a call never made is a lost commission.
  if (!response.ok) {
    throw new Error(`Klibon ${response.status}: ${await response.text()}`)
  }

  return await response.json()
}

await reportConversion({
  event_id: invoice.id,
  type: 'sale',
  amount: invoice.total_cents,
  currency: invoice.currency,
  referral_code: referralCode,      // window.Klibon.referral(), carried through your checkout
  customer_id: customer.id,
  customer_email: customer.email,
  payment_id: payment.id
})

Call it from the same place you already fulfil an order — your processor's own webhook is usually the right spot, because it is the point where the money is confirmed. Get referral_code there by carrying window.Klibon.referral() through your checkout; see Install the script.