Approach · Developer Docs

Integrate with Approach

Every way a company can connect to Approach today: a REST Partner API, signed order webhooks, a supplier contract for digital products, store catalogue sync, links and feeds, payment links and the business tools. Pick the method that fits your system; we issue the keys.

Partner API v1 Updated 5 Nov 2026 Format REST · JSON · HTTPS Market Kuwait · KWD

Ways to integrate

Approach is a Kuwait marketplace for services, shops, food, tickets, travel and Premium. You can connect in any of the ways below. API methods need a key from us; link and feed methods work with no key at all.

MethodWho it is forWhat it doesStatusHow to start
Premium provisioning APITelecom operators, banks, employers, loyalty programs Turn Approach Premium on or off for your customers by Kuwait mobile number. Billed to you monthly. LiveAPI key
Availability sync APIBusinesses on Approach with their own booking calendar Push your closed days to Approach so customers cannot book them. LiveAPI key bound to your business
Order webhooksBusinesses on Approach with their own system Approach posts signed order.paid, order.cancelled and order.updated events to your server. LiveSend us your https URL
Digital supplier contracteSIM, voucher, booking code and policy suppliers Approach reads your catalogue, places orders on your API and receives your delivery webhooks. LiveShare your API docs and a key
Code stock filesSuppliers without an API Hand us a CSV of codes; each paid order takes the next code automatically. LiveSend a CSV
Store catalogue syncOnline stores on Shopify, WooCommerce, MNASATI or Bilbayt Your website's products are pulled into Approach and their prices and stock kept in step. LiveSend us your store address
Assisted onboardingAny business Send a menu, price list or spreadsheet with photos; our team builds your catalogue. LiveContact us
Links and deep linksWebsites, apps, marketing teams Link to any business, product, package or landing page. Phones with the app open it in the app. LiveNo key needed
Referral tagPartner websites sending customers to Approach Order links that carry your ref code, so the orders that follow are counted for you. On requestAsk for a code
Product feeds, sitemap, structured dataSearch engines, comparison sites, aggregators Public product feeds in Google Merchant format, an XML sitemap and schema.org data on every page. LiveNo key needed
Payment linksBusinesses selling outside the app A branded link for any amount; the customer pays by KNET, card or Apple Pay. On requestContact us
Web checkoutCustomers without the app Shops and services can be ordered and paid on tryapproach.net with no app and no login. LiveNothing to set up
Business app and dashboardEvery business on Approach Accept orders, manage packages and calendars, get push and WhatsApp alerts, read reports. LiveApply as a business
Visa providers and event organizersVisa offices, clubs, venues Receive visa applications with travellers' documents; sell tickets and scan them at the gate. LiveContact us

Get API keys

This page is public; your credentials are not. Each partner gets its own key (and, for webhooks, its own signing secret), issued privately and shown to you once. Tell us which method you need, your company name, your technical contact, and, if you want it, the list of server IP addresses your calls will come from.

✦

Get API keys: [email protected] · +965 9000 3470 (calls and WhatsApp)


Base URL and conventions

Partner API calls go over HTTPS to:

Production base URL
https://api.tryapproach.net
  • Every path below is relative to this base. There is no /api or version prefix.
  • Request and response bodies are JSON. Send Content-Type: application/json on POST and PUT.
  • Money is in Kuwaiti dinars (KWD, three decimals). Times are ISO 8601. Calendar dates are Kuwait dates written YYYY-MM-DD with no time zone.
  • Every JSON response carries success (true or false). Treat it as the source of truth.

Authentication

Send your secret key in the X-Api-Key header on every request. We store only a hash of it, so we cannot show it to you again; if it is lost we rotate it and the old key stops working at once.

Header on every request
X-Api-Key: apk_your_secret_key_here
i

Your key can be locked to a fixed list of server IP addresses. When that is on, a call from any other address is refused with 403.

A key belongs to one of two kinds of partner. A subscription partner (for example a telecom operator) uses the Premium endpoints. A business partner is bound to one business on Approach and uses the availability endpoints and order webhooks. A key only ever sees its own data.

Errors

Errors use normal HTTP status codes and a JSON body with success: false, a readable message, and the HTTP status repeated as a number in status. Premium endpoints also add a machine readable code (see result codes).

Example error · 401
{
  "success": false,
  "message": "Invalid API key",
  "status": 401
}
StatusWhen
200Success, including safe repeats such as ALREADY_ACTIVE.
400Bad input: an invalid phone number, a missing field, a bad date, an unknown package.
401Missing API key or Invalid API key (unknown, rotated or switched off).
403IP not allowed, or the key is not bound to a business for an availability call.
404Nothing matches, for example cancelling an unknown reference.
5xxA temporary problem on our side. Retry with backoff.

Limits and retries

  • Keep to a steady rate, batch where the API allows (the availability sync takes a full year of dates in one call), and expect a limit to be agreed for high volume.
  • Retry 5xx, 429 and network timeouts with exponential backoff. Do not retry other 4xx answers unchanged; fix the request first.
  • Activation and the availability sync are idempotent, so a retry after an unclear network error is always safe.
  • Webhooks we receive from suppliers are flood guarded per sender IP; a 429 answer carries a Retry-After header in seconds.

Premium provisioning

Grant Approach Premium to your own customers. You identify a customer by Kuwait mobile number; Approach finds that customer's account, or creates one, and turns Premium on. Premium then works everywhere in the Approach app for that number with nothing for the customer to do. Each partner has an agreed plan and price per subscriber and is billed monthly for its active subscribers.

Phone numbers

Send an 8 digit Kuwait number starting with 2, 4, 5, 6 or 9, in any of these forms:

+96550123456
country code with plus
0096550123456
international 00 prefix
96550123456
country code, no plus
50123456
local form

Your reference

Every activation carries your own partnerReference, usually your subscription or order ID. Calling activate again with a reference that is still active changes nothing and answers ALREADY_ACTIVE, so you never create a duplicate. Use the same reference to cancel.

POST /partners/subscriptions/activate

Turns Premium on. Creates the Approach account if the number has none. A new period starts when the customer's current Premium ends, so periods stack and never overlap.

FieldTypeRequiredDescription
msisdnstringrequiredThe customer's Kuwait mobile number.
partnerReferencestringrequiredYour reference for this subscription.
planIdintegeroptionalAnother agreed plan. Leave it out to use your default plan.
cURL
curl -X POST https://api.tryapproach.net/partners/subscriptions/activate \
  -H "X-Api-Key: apk_your_secret_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "msisdn": "+96550123456", "partnerReference": "ACME-SUB-88213" }'
200 OK
{
  "success": true,
  "ok": true,
  "code": "ACTIVATED",
  "userId": 900123,
  "subscriptionId": 6789,
  "status": "active",
  "expiresAt": "2026-12-05T10:15:00.000+03:00",
  "created": true
}

created is true when a new Approach account was made for the number. ok always equals success.

400 · invalid number
{
  "success": false,
  "ok": false,
  "code": "INVALID_MSISDN",
  "message": "Not a valid Kuwait mobile number: 1234",
  "status": 400
}
POST /partners/subscriptions/cancel

Turns Premium off for a subscription you activated. Calling it twice is harmless.

FieldTypeRequiredDescription
partnerReferencestringrequiredThe reference you used to activate.
cURL
curl -X POST https://api.tryapproach.net/partners/subscriptions/cancel \
  -H "X-Api-Key: apk_your_secret_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "partnerReference": "ACME-SUB-88213" }'
200 OK
{
  "success": true,
  "ok": true,
  "code": "CANCELLED",
  "userId": 900123,
  "subscriptionId": 6789,
  "status": "cancelled"
}

An unknown reference answers 404 with code NOT_FOUND.

GET /partners/subscriptions/status?msisdn={number}

Says whether a number has Premium right now. Read only; it never creates an account.

cURL
curl "https://api.tryapproach.net/partners/subscriptions/status?msisdn=%2B96550123456" \
  -H "X-Api-Key: apk_your_secret_key_here"
200 OK
{
  "success": true,
  "ok": true,
  "code": "ACTIVE",
  "userId": 900123,
  "subscriptionId": 6789,
  "status": "active",
  "expiresAt": "2026-12-05T10:15:00.000+03:00"
}

code is ACTIVE, INACTIVE (an account with no live Premium; status is inactive) or NO_ACCOUNT (no account for this number; status is none).

Result codes

CodeEndpointHTTPMeaning
ACTIVATEDactivate200Premium turned on for a new period.
ALREADY_ACTIVEactivate200This reference is already active. Nothing changed.
CANCELLEDcancel200Premium turned off.
ACTIVEstatus200The number has Premium now.
INACTIVEstatus200The account exists; Premium ended or was cancelled.
NO_ACCOUNTstatus200No Approach account for this number.
INVALID_MSISDNactivate, status400Not a valid Kuwait mobile number.
MISSING_REFactivate400partnerReference is missing.
PLAN_NOT_FOUNDactivate400The planId you sent does not exist.
BLOCKEDactivate400This number is blocked from partner activation.
NOT_FOUNDcancel404No subscription has that reference.

If you send no planId and no default plan is set for you, or you cancel without a partnerReference, the answer is 400 with a message and no code.

Availability sync

For a business on Approach that runs its own booking calendar. Your system tells Approach which days are closed; the Approach app then greys those days out and refuses orders for them. Your key is bound to your business, so you can only ever read and write your own calendars. Days that our team or you close by hand in Approach are never touched by the API.

GET /partners/availability/packages

The packages you can sync: each bookable package of your business that has a calendar.

200 OK
{
  "success": true,
  "data": {
    "businessUserId": 900001,
    "packages": [
      { "packageId": 77001, "settingId": 4101, "serviceId": 8, "categoryId": 62,
        "title": "Breakfast tray for 10", "titleAr": "صينية فطور لعشرة أشخاص" }
    ]
  }
}
GET /partners/availability/dates

Closed days from today on, per package. source is api for days you set through the API and manual for days closed by hand in Approach.

200 OK
{
  "success": true,
  "data": { "packages": [
    { "packageId": 77001, "closedDates": [
      { "date": "2026-11-20", "source": "api" },
      { "date": "2026-11-27", "source": "manual" }
    ] }
  ] }
}
PUT /partners/availability/dates

Send the full list of closed days every time. Days in the list are closed; days you set before and leave out are opened again. Past days are ignored. Repeating the same call changes nothing.

FieldTypeRequiredDescription
datesstring[]requiredKuwait dates as YYYY-MM-DD, at most 366. An empty list opens every day you closed.
packageIdsinteger[]optionalOnly these packages. Leave it out to apply the list to all your packages.
cURL
curl -X PUT https://api.tryapproach.net/partners/availability/dates \
  -H "X-Api-Key: apk_your_secret_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "dates": ["2026-11-20", "2026-11-21"], "packageIds": [77001] }'
200 OK
{
  "success": true,
  "message": "Availability synced",
  "data": {
    "packagesUpdated": [77001],
    "closedDates": ["2026-11-20", "2026-11-21"],
    "overridesCreated": 2,
    "overridesRemoved": 0
  }
}

Errors: 400 for a date that is not YYYY-MM-DD, more than 366 dates, an empty packageIds list or a package that is not yours; 403 when the key is not bound to a business.

Order webhooks

For a business partner with its own system. When one of your orders is paid, cancelled after payment, or has its date or time changed, Approach posts a signed JSON event to your https URL. You only ever hear about money that landed: unpaid orders are never sent.

EventWhenevent_id
order.paidThe customer paid the order.evt_paid_{orderId}
order.cancelledA paid order was cancelled or rejected (refunds included).evt_cancelled_{orderId}
order.updatedA paid order's date or time was changed.evt_updated_{orderId}_{unixTime}

Request

Headers
Content-Type: application/json
X-Approach-Event: order.paid
X-Approach-Event-Id: evt_paid_48213
X-Approach-Timestamp: 1793865164
X-Approach-Signature: sha256=5f0c9a...e41b
Body
{
  "event": "order.paid",
  "event_id": "evt_paid_48213",
  "payloadVersion": 2,
  "orderId": 48213,
  "businessUserId": 900001,
  "serviceId": 8,
  "packageId": 77001,
  "date": "2026-11-20",
  "time": "18:00",
  "customer": { "name": "Sara", "phone": "96550123456", "email": "[email protected]" },
  "address": { "governorate": "Hawalli", "area": "Salmiya", "areaId": 12, "block": "4",
               "street": "Salem Al Mubarak", "addressLine": "Salmiya, block 4, Salem Al Mubarak" },
  "options": [ { "labelEn": "Extra persons", "labelAr": "عدد الأشخاص", "valueEn": null, "valueAr": null, "count": 5 } ],
  "extraGuests": 5,
  "totalAmount": 185.5,
  "currency": "KWD",
  "occurredAt": "2026-11-05T09:12:44.120Z"
}

date (YYYY-MM-DD), time (HH:mm, 24 hour, Kuwait time), packageId, address and totalAmount are filled for package bookings and are null when an order type does not have them. Any detail we cannot read is sent as null rather than holding the event back.

Verify the signature

The signature is the hex HMAC SHA256 of timestamp + "." + rawBody with your signing secret. It is computed fresh on every attempt. Reject events whose timestamp is more than a few minutes old.

Node.js
const crypto = require("crypto");

function verifyApproach(headers, rawBody, secret) {
  const ts = headers["x-approach-timestamp"];
  const got = String(headers["x-approach-signature"] || "").replace(/^sha256=/, "");
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const want = crypto.createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex");
  return got.length === want.length &&
    crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}

Answering and retries

  • Answer any 2xx within 10 seconds to accept the event.
  • 429, 5xx, timeouts and network errors are retried: up to 6 attempts with exponential backoff starting at 60 seconds.
  • Any other 4xx (for example 409 or 422) is treated as your final answer and is not retried.
  • Redirects are not followed, so give us the exact final URL.
  • The same occurrence keeps the same event_id across retries. Store it and answer repeats with the result you gave the first time.

Digital product suppliers

For suppliers of eSIMs, vouchers, booking codes or insurance policies. This contract runs the other way: you host the API and Approach calls it. When a customer pays, Approach places the order on your API and delivers the result (QR code, activation code, file) to the customer in the app, by e-mail and on a delivery page. If your API already exists in another shape, send us its documentation; we build an adapter for well known platforms instead of asking you to change.

Approach sends your key as Authorization: Bearer <key>, with JSON bodies, and waits up to 12 seconds per call. We call a sandbox base URL first and switch to your live base URL after a test order.

Your endpointApproach uses it to
GET /packagesRead your catalogue (on a schedule, to keep costs in step).
POST /ordersBuy one unit after the customer paid.
GET /orders/{ref}Read the state of an order.
POST /orders/{ref}/cancelCancel an order and learn whether it was refunded.
GET /packages · your answer
{ "data": [
  { "sku": "TR-7D-5GB", "name": "Turkey 5 GB, 7 days", "countries": ["TR"],
    "data_mb": 5120, "validity_days": 7, "cost": 3.250, "currency": "KWD", "retail": 4.500 }
] }
POST /orders · our request
{
  "sku": "TR-7D-5GB",
  "qty": 1,
  "idempotency_key": "a91c3e0f7b...",
  "customer_ref": "48213-1",
  "email": "[email protected]",
  "start_date": "2026-12-01",
  "end_date": "2026-12-08",
  "destination_country": "TR",
  "documents": [ { "kind": "passport", "url": "https://..." } ]
}

start_date and end_date are sent when the order carries trip dates, and destination_country (ISO 3166 alpha 2) when known. documents (passport, civil_id) is sent only to suppliers who need them, as signed links valid for at most 24 hours.

POST /orders · your answer
{ "data": {
  "status": "ready",
  "ref": "ORD-991",
  "lpa": "LPA:1$smdp.example.com$ABC123",
  "activation_code": "ABC123",
  "smdp_address": "smdp.example.com",
  "iccid": "8990000000000000001",
  "confirmation_code": null,
  "file_url": null,
  "install_url": "https://..."
} }
  • Answer "status": "pending" when delivery takes time, then send order.completed to our webhook.
  • You must treat idempotency_key as unique: a repeated key returns the first order and never buys twice. We retry after timeouts and 5xx, so this is what keeps a customer from being charged twice by you.
  • Answer 429 or 5xx for temporary problems (we retry) and other 4xx for a final no.
  • GET /orders/{ref} answers { "data": { "status", "activation_status", "usage_mb" } }; cancel answers { "refunded": true } or false.

Supplier webhooks to Approach

We give you a webhook URL that ends in /webhooks/digital/{partnerKey} and a shared signing secret. Send X-Timestamp (unix seconds) and X-Signature, the hex HMAC SHA256 of timestamp + "." + rawBody (a sha256= prefix is accepted). Events older than 5 minutes are refused. A GET or HEAD on the URL answers 200 for your opt in check.

Body
{
  "id": "evt_10023",
  "type": "order.completed",
  "data": { "ref": "ORD-991", "lpa": "LPA:1$smdp.example.com$ABC123", "iccid": "8990000000000000001",
            "install_url": "https://...", "install_url_android": "https://..." }
}
typeEffect in Approach
order.completedA pending order is delivered to the customer (fields as in the order answer).
order.failedThe order is marked failed and the customer's money is handled by Approach.
esim.installed · esim.activated · esim.expiredThe eSIM state shown to the customer is updated.
usage.updated · usage.thresholdData used is updated from data.usage_mb.
usage.lowThe customer gets one low data notice.
esim.expiringThe customer gets one expiry notice.
Our answerMeaning
200 { "ok": true }Applied. "duplicate": true means we had this id already.
401Bad or missing signature, or an old timestamp.
400The body is not valid JSON.
409 { "code": "unknown_ref" }We do not know this ref yet. Retry shortly.
503Temporary. Retry.

Code stock files

No API? Give us your codes as a CSV file (UTF 8, up to 5,000 rows and 2 MB per file). Each paid order takes the next free code and delivers it at once. The header row names the columns you use:

CSV
lpa,activation_code,smdp_address,confirmation_code,iccid
LPA:1$smdp.example.com$ABC123,ABC123,smdp.example.com,,8990000000000000001
,,,VOUCHER-7781,

A supplier can also fill each order by hand: the order waits until the code or file is uploaded, then the customer is notified.

Store catalogue sync

For online stores. Give us your store's website and we read its public product list. Supported today: Shopify, WooCommerce, MNASATI and Bilbayt.

  • Auto pull brings in products that are not on Approach yet: name (Arabic too when your site has it), description, price, crossed out price, stock and up to 5 photos. New products wait hidden for review unless you ask for them to go live straight away.
  • Auto sync keeps price, sale price and stock in step on a schedule you choose (every 24, 48, 72 hours or weekly). It never deletes or hides products and never changes photos or names.
  • Safety holds: if your site answer looks wrong (unreachable, much smaller than before, or a price moving below 30% or above 3 times its value), nothing changes for that run.
  • Products whose sizes have different prices are added by hand.

Assisted onboarding

Not on one of those platforms? Send us your menu, price list or spreadsheet with photos. Our team builds your catalogue on Approach, including options and add ons, and you preview it before it goes live.


Feeds and structured data

ResourceWhat it is
https://tryapproach.net/merchant/products-en.xmlShop products in English, Google Merchant format (RSS 2.0), Kuwait, KWD.
https://tryapproach.net/merchant/products-ar.xmlThe same feed in Arabic.
https://tryapproach.net/sitemap.xmlEvery public page in both languages.

The feeds refresh every 30 minutes and list only products that are on sale to the public; each item links to its product page. Product pages carry schema.org Product data with the same price and availability; business pages carry LocalBusiness, category pages CollectionPage, and Premium packages Service.

Payment links and checkout

Payment links

Our team creates a payment link for any amount with a description, in your business's name and logo. The customer opens a secure page on pay.tryapproach.net, picks a payment method and pays; the link expires after the time set for it and can be sent by SMS. Paid links settle to your business like any order.

Web checkout

Shops and services can be ordered and paid on tryapproach.net with no app and no login. After an order, the customer gets a WhatsApp message with a private link to the order page: status, price breakdown and payment. Tickets stay in the app.

Payment methods

KNET, Visa and Mastercard and Apple Pay are processed by UPayments; pay later in instalments is offered through Taly in the app. These are Approach's own payment rails: partners do not integrate with them directly, and card details never reach Approach or you.

Business tools

  • Business account in the Approach app: accept or reject orders, set prices, packages, options, opening hours and closed days, publish stories and offers.
  • Business dashboard: a web login (sent by e-mail when you join) with your orders, packages, calendar, transfers and a printable monthly report.
  • Notifications: push on every new order and status change, a WhatsApp message for new and paid orders, and e-mail for account messages. If a customer has an urgent issue they can send one emergency message per order, which reaches you by WhatsApp.
  • Visa providers: receive each visa application with its travellers and their passport and civil ID copies, download all documents as one ZIP, and move the application through its stages while the customer is kept up to date.
  • Event organizers: we set up the event, seat map and prices; tickets sell in the app, can be transferred between customers, and your gate staff scan them with the Approach app. Sales reports are available during and after the event.

To join as a business, apply at tryapproach.net/en/become-an-approacher.

Security

  • Keep keys and signing secrets on your servers only. Never put them in a mobile app, a web page or a public repository.
  • Always call over HTTPS, and give us an https webhook URL.
  • Send us your outbound IP addresses so we can lock your key to them.
  • Verify every webhook signature and timestamp before you act on it.
  • If a key or secret may have leaked, ask us to rotate it. The old one stops working immediately.

Support and onboarding

To go live we agree the method, test it with you, then issue your live credentials. For the Premium API that includes your plan and price; for suppliers, a test order on your sandbox.

✦

Get API keys and support: [email protected] · +965 9000 3470