Quickstart
Goal: a real member in Diller, with a real order against them, in about fifteen minutes. Sandbox only — nothing here touches production.
You need a client id and client secret. Your merchant finds them in Diller under Settings → Our Details → API Details. See Authentication.
Throughout, $STORE_ID is the store you are working against. Step 2 shows
you how to find it.
export DILLER_BASE="https://api.prerelease.dillerapp.com"export CLIENT_ID="your-client-id"export CLIENT_SECRET="your-client-secret"1. Get a token
Section titled “1. Get a token”curl -s -X POST "$DILLER_BASE/connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "scope=api.retailer" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRET"{ "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...", "scope": "api.retailer", "expires_in": 3600, "token_type": "Bearer"}Save it:
export TOKEN="paste-the-access_token-here"Every call from here carries Authorization: Bearer $TOKEN.
2. Find your store id
Section titled “2. Find your store id”Every resource URL needs a store id. Ask the API for the store your credentials belong to:
curl -s "$DILLER_BASE/api/v2.0/stores" \ -H "Authorization: Bearer $TOKEN"[ { "id": "Ab3xK_9pQrLm", "store_name": "Nordmann Sport Oslo", "currency": "NOK", "time_zone": "Europe/Oslo" }]export STORE_ID="Ab3xK_9pQrLm"The array always holds exactly one store, and its id matches your client
id. If the token request failed instead, check you are not mixing sandbox
and production credentials.
3. Find your department id
Section titled “3. Find your department id”curl -s "$DILLER_BASE/api/v2.0/stores/$STORE_ID/departments" \ -H "Authorization: Bearer $TOKEN"[ { "id": "101", "name": "Web" }, { "id": "102", "name": "Oslo" }]Pick the one representing your webshop and keep it. Everything below uses
101.
4. Create a member
Section titled “4. Create a member”This is the ecommerce signup call: you have already collected consent on your own form, so you create the member directly.
curl -s -X POST "$DILLER_BASE/api/v2.0/stores/$STORE_ID/members" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "phone": { "country_code": "+47", "number": "99900001" }, "first_name": "Ola", "last_name": "Nordmann", "email": "ola.nordmann@example.com", "department_ids": ["101"], "consent": { "gdpr_accepted": true, "save_order_history": true, "receive_sms": true, "receive_email": true }, "origin": { "system_id": "my-webshop", "department_id": "101", "channel": "OnlineStore" } }'You get back 200 with the new member. Keep the id — that is the member
id.
Send both receive_sms and receive_email, as above. Leave either one out
and it defaults to true, opting the member in to marketing they never
agreed to — see consent.
{ "id": "m_nsr714RRBEHX", "first_name": "Ola", "last_name": "Nordmann", "email": "ola.nordmann@example.com", "phone": { "country_code": "+47", "number": "99900001" }, "consent": { "gdpr_accepted": true, "save_order_history": true, "receive_sms": true, "receive_email": true }, "membership_detail": { "points": 0.0, "qualification_points": 0.0, "pending_points": 0.0, "remaining_points": 0.0, "level_title": null, "next_level_title": null, "next_level_points": 0.0, "level_expire_date": null }, "department_ids": ["101"], "segments": []}export MEMBER_ID="m_nsr714RRBEHX"5. Look the member up again
Section titled “5. Look the member up again”This is what you will call on every login.
curl -s -G "$DILLER_BASE/api/v2.0/stores/$STORE_ID/members/search" \ --data-urlencode "phone=+4799900001" \ -H "Authorization: Bearer $TOKEN"Returns an array:
[ { "id": "m_nsr714RRBEHX", "first_name": "Ola", "...": "..." } ]6. Post an order
Section titled “6. Post an order”curl -s -X POST "$DILLER_BASE/api/v2.0/stores/$STORE_ID/members/$MEMBER_ID/transactions" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "external_id": "ORDER-1001", "created_at": "2026-09-10T12:30:00Z", "currency": "NOK", "total": 499.00, "total_tax": 99.80, "total_discount": 0, "round_off_amount": 0, "send_email_receipt": false, "payment_details": [ { "payment_method": "Card", "sub_total": 499.00 } ], "department_id": "101", "origin": { "system_id": "my-webshop", "department_id": "101", "channel": "OnlineStore" }, "coupon_codes": [], "details": [ { "product": { "external_id": "SKU-123", "sku": "SKU-123", "name": "T-shirt, large" }, "quantity": 1, "unit_price": 499.00, "tax_percentage": 25, "discount": 0, "total_price": 499.00, "coupon_codes": [] } ] }'{ "is_ok": true, "details": "" }The status is 200 whether or not the order was recorded, so check
is_ok. Run the same request twice and the second one comes back
is_ok: false — we do not record the same order twice.
Fetch the member again and membership_detail.points will have moved.
The one field everyone forgets
Section titled “The one field everyone forgets”origin.channel.
It is optional. It is nullable. And if you leave it out — or misspell it — we silently record the action as point-of-sale. Your merchant’s reporting will show zero online activity while orders quietly pile up in the wrong channel.
"origin": { "channel": "OnlineStore" }The literal string is "OnlineStore". On a transaction, only that exact
value maps to the webshop channel; anything else, including "Online",
"Web" or "Storefront", falls back to POS. Member creation is more
forgiving and recognises some looser spellings, but do not lean on that —
use the one value that works everywhere.
Set it on every call that accepts an origin: member create, member
update, transaction, cancel, refund, coupon reservation.
What you just built
Section titled “What you just built”That is the whole skeleton. The rest of the documentation fills it in: matching existing customers on login, consent, coupons at checkout, and what to do when an order is cancelled.
