Choicera Integration
Contract v1, as of 14 August 2026

Report the order

We append an identifier to the cart link. If a purchase follows, your shop reports the order to our endpoint and the referral is attributed.

What to do

  1. Tell us which parameter names your shop or your affiliate system expects, and carry the values from the link over into your order. Done when the identifier shows up in your order data after a purchase.
  2. Point the webhook at https://choicera.com/api/webhooks/shopify, for the three events paid, cancelled and refunded. Done when a test order arrives on our side and we confirm receipt to you.
  3. Agree the signing secret with us and sign every request with it. Done when your deliveries get HTTP 200 and no 401.

Identifiers in the link

We pass an affiliate identifier and a sub identifier so a purchase can be attributed both to our account and to the referring party, a gym for example. We agree the names with you.

PurposeExampleNote
Affiliate identifier?ref=choiceraParameter name and value come from you.
Sub identifier&subref=studio-123Differs per cart. Contractually usually to be reported back per line item.
Coupon&coupon=CHOICERAOnly if your shop redeems codes via the URL.
Transaction ID&attributes[choicera_attribution]=…On Shopify. The value lands on the order and comes back in the webhook.

If you work with an affiliate network, we send that network's parameters, for example ?clickref=…&clickref2=… for Awin or the program's own reference for UpPromote. Tell us which system counts.

Without a transaction ID we attribute an order via the email address. It must then match the address in the Choicera account exactly, including case.

Set up the webhook

POST https://choicera.com/api/webhooks/shopify

The field set follows the Shopify order format. Shops without Shopify call the same endpoint with the same contract: same headers, same field names, same signature. In full as a file: order-webhook.openapi.yaml (OpenAPI 3.1).

Events

The reported event is in the x-shopify-topic header. We process three. Others we answer with HTTP 200 and discard.

TopicMeaning
orders/paidPaid order with the order data
orders/cancelledCancellation, reverses the attribution
refunds/createRefund, reports the refunded amount

Headers

HeaderMeaning
x-shopify-topicEvent name, for example orders/paid
x-shopify-hmac-sha256Base64-encoded HMAC-SHA256 signature over the unmodified request body. If it is missing or invalid we answer HTTP 401.
x-shopify-webhook-idUnique delivery ID. The same value on every retry of the same delivery, that is what keeps processing idempotent. A value reused for a different event is treated as a retry. Without the ID we accept the delivery, but it is not protected against double processing.
x-shopify-shop-domainShop domain, optional, helps when tracing errors

The signing secret is agreed during onboarding and applies to your shop only. We verify every delivery against the secret of the shop it came from, identified by the x-shopify-shop-domain header. Without that header, or with a shop domain unknown to us, we answer HTTP 401. We enable the integration before it goes live. Shopify shops create the three events in the Shopify admin under Settings, Notifications, Webhooks, pointing at our URL.

Which fields we evaluate

FieldMeaning
idOrder ID in the shop system
order_numberHuman-readable order number
created_atDate and time per ISO 8601, alternatively processed_at
currencyCurrency, for example EUR
total_price, subtotal_price, total_discountsGross total, subtotal before shipping, sum of discounts
discount_codesRedeemed coupon codes with amount and type
emailCustomer email, alternatively contact_email
note_attributesCarries the transaction ID choicera_attribution from the cart link, if set up. Evaluated for attribution only, not stored.
line_itemsLine items with product_id, variant_id, sku, title, variant_title, quantity as a number and price

For orders/cancelled the order id is enough. For refunds/create we evaluate id, order_id and transactions. We sum transactions with kind = refund as well as entries without kind. So please do not include other transaction kinds.

What we store

We store an order only if it can be attributed to an open Choicera purchase: via the transaction ID from the cart link, valid for 48 hours from handoff, or via the email address of a Choicera account. Each attribution is used once. A second order with the same identifier and no new Choicera cart is discarded.

An HTTP 200 response confirms receipt, not storage. Orders without attribution are discarded. Only the fields listed above are stored. The order data remains with Choicera permanently as the customer's purchase history, there is no time-based deletion. On an erasure request under Art. 17 GDPR, Choicera removes the email address and product details. Invoicing data without product reference remains stored for commission accounting and statutory retention obligations.

For naming this in your privacy policy there is a wording template.

Responses and retries

ResponseMeaning
200Receipt confirmed
400JSON body not readable
401Signature missing or invalid
5xxError on our side. Retry the delivery later with the same x-shopify-webhook-id.

If the endpoint keeps answering webhook_not_configured, the integration is not enabled on our side yet. Contact us via the partner contact instead of retrying further.