Yalidine (Guepex) Delivery Integration
Yalidine is Algeria's largest courier network. Its API is exposed under the
brand name Guepex (base URL api.guepex.app, dashboard guepex.app) —
same company, same API, same webhooks. Treat "Yalidine" and "Guepex" as the
same integration.
This skill gives a coding agent everything needed to wire a platform up to
Yalidine end-to-end: creating parcels, looking up delivery zones, calculating
fees, and reacting to delivery-status changes via webhooks — without ever
needing to see the user's real API credentials.
Before you write any code
Read the reference file(s) that match what you're building. Don't load both
up front if the task only needs one — this keeps context lean.
- references/api-reference.md — every REST endpoint (parcels, wilayas,
communes, centers, fees, histories): params, filters, fields, full request
and response shapes.
- references/webhooks-reference.md — event types, payload formats, CRC
challenge validation, HMAC signature verification, retry policy.
- references/human-only-steps.md — the dashboard actions only the
account owner can do. Read this first if the user hasn't mentioned having
credentials yet.
- references/troubleshooting.md — check here before improvising a fix
when a call fails, a webhook doesn't fire, or a signature check rejects a
real delivery. Most "weird" failures map to a known cause.
assets/.env.example — copy this into the project as a starting point for
the required environment variables.
Two ready-to-adapt implementations are in scripts/:
scripts/yalidine-client.ts — typed API client (fetch-based, no
dependencies) covering all endpoints, pagination, and rate-limit headers.
scripts/webhook-handler.ts — a Supabase Edge Function (Deno) implementing
CRC validation + signature verification + event routing. Adapt the
request/response wrapper for Express/Next.js/etc. if the project isn't on
Supabase — the validation and security logic underneath is identical.
The integration workflow
Confirm the user has generated credentials. You cannot get an API ID,
API TOKEN, or webhook secret key yourself — these only exist inside the
user's own Guepex Developer Dashboard and Webhooks Dashboard. If they
haven't mentioned having them, point them to references/human-only-steps.md
and wait. Never ask them to paste a screenshot of their dashboard or the
raw key values into chat — have them put the values straight into an env
file instead (see Security below).
Set up configuration, not hardcoded values:
YALIDINE_API_ID=...
YALIDINE_API_TOKEN=...
YALIDINE_BASE_URL=https://api.guepex.app/v1/
YALIDINE_WEBHOOK_SECRET=... # only needed if implementing webhooks
Add these to .env.example with empty values so the user knows what to
fill in, and to the project's actual env file (gitignored) if the user
gives you the real values directly (not via screenshot).
Build the API client layer first using
references/api-reference.md — start with whichever endpoints the
feature needs (usually: wilayas/communes for address forms, fees for a
checkout price preview, parcels for order creation, histories for
tracking pages).
Cache static lookup data. Wilayas, communes, and centers change
rarely. Don't call these endpoints on every request — fetch once, store
in the app's DB or a cache with a daily/weekly refresh, and read from
there. This also protects the user's rate-limit quota (see below).
Build the webhook endpoint last, once parcel creation works, using
references/webhooks-reference.md. The endpoint must exist and pass CRC
validation before the user can create the webhook in their dashboard —
tell them the order of operations if they ask you to "just set up the
webhook."
Tell the user what to do in the dashboard once your code is ready —
see references/human-only-steps.md for the exact list, in order.
Non-negotiable security rules
- Never put
YALIDINE_API_TOKEN in front-end/client-side code (browser
JS, mobile app bundles). It's a backend-only secret — every Yalidine call
must go through the user's own server or edge function, never directly
from a browser.
- Always verify the
X-YALIDINE-SIGNATURE header (HMAC-SHA256 of the
raw request body, keyed with the webhook secret) before trusting any
webhook payload. Reject anything that doesn't match with a 400 — see
references/webhooks-reference.md for the exact algorithm.
- Always keep the CRC challenge-response check (
?subscribe=...&crc_token=...
→ echo crc_token back, 200 status) live in the webhook endpoint
permanently. Yalidine re-validates it periodically; if it ever fails, the
webhook is auto-disabled and the user stops getting delivery updates
silently.
- Never write real API IDs, tokens, secret keys, webhook URLs, or alert
emails into code comments, example files, or documentation you generate —
use env var references only, even in "here's an example" snippets.
- The webhook endpoint must respond within 10 seconds. If the user's
business logic (sending SMS, updating other systems, etc.) might be slow,
have the endpoint just persist the raw payload and return 200 immediately,
then process it in a background job/queue.
Key domain gotchas (read before generating parcel-creation code)
- Addresses are matched by name, not ID, when creating/editing a parcel.
from_wilaya_name and to_wilaya_name/to_commune_name must exactly
match a name from the wilayas/communes endpoints. Validate against your
cached list before sending — a typo fails the whole parcel.
- Personal data comes back masked (
firstname, familyname,
contact_phone, address, and the phone segment of qr_text) on every
GET and PATCH response — e.g. "M*****d". This is intentional privacy
protection on Yalidine's side. Never overwrite your own stored values with
these masked ones. POST (creation) responses are not masked.
- Stop-desk deliveries require a real
stopdesk_id. Look it up from the
centers endpoint (filter by wilaya_id/commune_id) — don't let a user
type one in freely.
- Edit and delete only work while the parcel's
last_status is "En
préparation." Once Yalidine picks it up, both PATCH and DELETE fail.
Surface this constraint in the UI rather than letting users hit an API
error.
- Exchange parcels: if
has_exchange is true, product_to_collect is
required.
- Oversize fee applies past 5kg billable weight, where billable weight =
max(actual_weight, length*width*height*0.0002). Formula and worked
examples are in references/api-reference.md under Fees.
- Rate limits (default): 5/sec, 50/min, 1000/hour, 10000/day. Every
response includes
x-second-quota-left, x-minute-quota-left,
x-hour-quota-left, x-day-quota-left headers — read them, and back off
before hitting 429. Repeated 429s extend the ban period.
- Bulk creation:
POST /v1/parcels takes an array of parcels, even
for one. The response is keyed by order_id, and partial failure is
normal — some parcels in a batch can fail while others succeed. Always
check each entry's success field individually rather than assuming an
all-or-nothing result.
If something looks like it needs a dashboard action mid-build
Stop and tell the user — don't guess or fabricate a credential/URL/ID to
keep going. Point them at references/human-only-steps.md.
If a call or a webhook doesn't behave as expected
Check references/troubleshooting.md before improvising — most failures
(401s, rejected commune names, signature mismatches, silently-stopped
webhooks) have a known cause and fix there rather than needing a guess.
Definition of done — verify before calling the integration finished
Don't declare the integration complete on "the code compiles." Actually
run these checks, and tell the user which ones you could/couldn't verify
yourself (some need their real credentials or a live deployment):
1---2name: yalidine-integration3description: Integrate the Yalidine (Guepex) Algerian delivery/courier API and webhooks into any codebase — creating and tracking parcels, looking up wilayas/communes/stop-desk centers, calculating delivery fees, and receiving real-time delivery-status webhooks. Use this whenever the user asks to integrate Yalidine, Guepex, or an Algerian shipping/courier API, add cash-on-delivery parcel creation, stop-desk/home delivery, parcel tracking, or delivery-status webhooks to their app — even if they just say "add Yalidine" or "hook up shipping" without more detail.4---56# Yalidine (Guepex) Delivery Integration78Yalidine is Algeria's largest courier network. Its API is exposed under the9brand name **Guepex** (base URL `api.guepex.app`, dashboard `guepex.app`) —10same company, same API, same webhooks. Treat "Yalidine" and "Guepex" as the11same integration.1213This skill gives a coding agent everything needed to wire a platform up to14Yalidine end-to-end: creating parcels, looking up delivery zones, calculating15fees, and reacting to delivery-status changes via webhooks — without ever16needing to see the user's real API credentials.1718## Before you write any code1920Read the reference file(s) that match what you're building. Don't load both21up front if the task only needs one — this keeps context lean.2223- **references/api-reference.md** — every REST endpoint (parcels, wilayas,24 communes, centers, fees, histories): params, filters, fields, full request25 and response shapes.26- **references/webhooks-reference.md** — event types, payload formats, CRC27 challenge validation, HMAC signature verification, retry policy.28- **references/human-only-steps.md** — the dashboard actions only the29 account owner can do. Read this first if the user hasn't mentioned having30 credentials yet.31- **references/troubleshooting.md** — check here before improvising a fix32 when a call fails, a webhook doesn't fire, or a signature check rejects a33 real delivery. Most "weird" failures map to a known cause.3435`assets/.env.example` — copy this into the project as a starting point for36the required environment variables.3738Two ready-to-adapt implementations are in `scripts/`:39- `scripts/yalidine-client.ts` — typed API client (fetch-based, no40 dependencies) covering all endpoints, pagination, and rate-limit headers.41- `scripts/webhook-handler.ts` — a Supabase Edge Function (Deno) implementing42 CRC validation + signature verification + event routing. Adapt the43 request/response wrapper for Express/Next.js/etc. if the project isn't on44 Supabase — the validation and security logic underneath is identical.4546## The integration workflow47481. **Confirm the user has generated credentials.** You cannot get an API ID,49 API TOKEN, or webhook secret key yourself — these only exist inside the50 user's own Guepex Developer Dashboard and Webhooks Dashboard. If they51 haven't mentioned having them, point them to `references/human-only-steps.md`52 and wait. Never ask them to paste a screenshot of their dashboard or the53 raw key values into chat — have them put the values straight into an env54 file instead (see Security below).55562. **Set up configuration**, not hardcoded values:57 ```58 YALIDINE_API_ID=...59 YALIDINE_API_TOKEN=...60 YALIDINE_BASE_URL=https://api.guepex.app/v1/61 YALIDINE_WEBHOOK_SECRET=... # only needed if implementing webhooks62 ```63 Add these to `.env.example` with empty values so the user knows what to64 fill in, and to the project's actual env file (gitignored) if the user65 gives you the real values directly (not via screenshot).66673. **Build the API client layer first** using68 `references/api-reference.md` — start with whichever endpoints the69 feature needs (usually: wilayas/communes for address forms, fees for a70 checkout price preview, parcels for order creation, histories for71 tracking pages).72734. **Cache static lookup data.** Wilayas, communes, and centers change74 rarely. Don't call these endpoints on every request — fetch once, store75 in the app's DB or a cache with a daily/weekly refresh, and read from76 there. This also protects the user's rate-limit quota (see below).77785. **Build the webhook endpoint last**, once parcel creation works, using79 `references/webhooks-reference.md`. The endpoint must exist and pass CRC80 validation *before* the user can create the webhook in their dashboard —81 tell them the order of operations if they ask you to "just set up the82 webhook."83846. **Tell the user what to do in the dashboard** once your code is ready —85 see `references/human-only-steps.md` for the exact list, in order.8687## Non-negotiable security rules8889- **Never** put `YALIDINE_API_TOKEN` in front-end/client-side code (browser90 JS, mobile app bundles). It's a backend-only secret — every Yalidine call91 must go through the user's own server or edge function, never directly92 from a browser.93- **Always** verify the `X-YALIDINE-SIGNATURE` header (HMAC-SHA256 of the94 raw request body, keyed with the webhook secret) before trusting any95 webhook payload. Reject anything that doesn't match with a 400 — see96 `references/webhooks-reference.md` for the exact algorithm.97- **Always** keep the CRC challenge-response check (`?subscribe=...&crc_token=...`98 → echo `crc_token` back, 200 status) live in the webhook endpoint99 permanently. Yalidine re-validates it periodically; if it ever fails, the100 webhook is auto-disabled and the user stops getting delivery updates101 silently.102- **Never** write real API IDs, tokens, secret keys, webhook URLs, or alert103 emails into code comments, example files, or documentation you generate —104 use env var references only, even in "here's an example" snippets.105- The webhook endpoint must respond within 10 seconds. If the user's106 business logic (sending SMS, updating other systems, etc.) might be slow,107 have the endpoint just persist the raw payload and return 200 immediately,108 then process it in a background job/queue.109110## Key domain gotchas (read before generating parcel-creation code)111112- **Addresses are matched by name, not ID, when creating/editing a parcel.**113 `from_wilaya_name` and `to_wilaya_name`/`to_commune_name` must exactly114 match a name from the wilayas/communes endpoints. Validate against your115 cached list before sending — a typo fails the whole parcel.116- **Personal data comes back masked** (`firstname`, `familyname`,117 `contact_phone`, `address`, and the phone segment of `qr_text`) on every118 GET and PATCH response — e.g. `"M*****d"`. This is intentional privacy119 protection on Yalidine's side. Never overwrite your own stored values with120 these masked ones. POST (creation) responses are not masked.121- **Stop-desk deliveries require a real `stopdesk_id`.** Look it up from the122 `centers` endpoint (filter by `wilaya_id`/`commune_id`) — don't let a user123 type one in freely.124- **Edit and delete only work while the parcel's `last_status` is "En125 préparation."** Once Yalidine picks it up, both `PATCH` and `DELETE` fail.126 Surface this constraint in the UI rather than letting users hit an API127 error.128- **Exchange parcels**: if `has_exchange` is `true`, `product_to_collect` is129 required.130- **Oversize fee** applies past 5kg billable weight, where billable weight =131 `max(actual_weight, length*width*height*0.0002)`. Formula and worked132 examples are in `references/api-reference.md` under Fees.133- **Rate limits** (default): 5/sec, 50/min, 1000/hour, 10000/day. Every134 response includes `x-second-quota-left`, `x-minute-quota-left`,135 `x-hour-quota-left`, `x-day-quota-left` headers — read them, and back off136 before hitting 429. Repeated 429s extend the ban period.137- **Bulk creation**: `POST /v1/parcels` takes an *array* of parcels, even138 for one. The response is keyed by `order_id`, and partial failure is139 normal — some parcels in a batch can fail while others succeed. Always140 check each entry's `success` field individually rather than assuming an141 all-or-nothing result.142143## If something looks like it needs a dashboard action mid-build144145Stop and tell the user — don't guess or fabricate a credential/URL/ID to146keep going. Point them at `references/human-only-steps.md`.147148## If a call or a webhook doesn't behave as expected149150Check `references/troubleshooting.md` before improvising — most failures151(401s, rejected commune names, signature mismatches, silently-stopped152webhooks) have a known cause and fix there rather than needing a guess.153154## Definition of done — verify before calling the integration finished155156Don't declare the integration complete on "the code compiles." Actually157run these checks, and tell the user which ones you could/couldn't verify158yourself (some need their real credentials or a live deployment):159160- [ ] A real call to `GET /v1/wilayas` succeeds with the user's credentials161 (proves auth is wired correctly).162- [ ] Wilaya/commune names used in parcel creation are validated against a163 cached lookup, not typed freely.164- [ ] Stop-desk flows resolve `stopdesk_id` from `/v1/centers`, never from165 free user input.166- [ ] Parcel creation handles **partial batch failure** — each entry's167 `success` field is checked individually, not just the HTTP status.168- [ ] The API token/ID never appear in any client-side/browser-reachable169 code path — grep the frontend bundle for the env var names if unsure.170- [ ] If webhooks are in scope: the CRC endpoint returns the exact token171 for a manual `curl "<url>?subscribe=1&crc_token=test123"` check, and172 this logic has no code path that could ever be removed by mistake.173- [ ] If webhooks are in scope: signature verification uses the **raw**174 request body, not re-serialized JSON, and rejects on mismatch.175- [ ] If webhooks are in scope: the endpoint returns `200` well under 10176 seconds even under real processing load (heavy logic deferred to a177 queue/background job).178- [ ] Event `event_id` values are deduplicated before side effects run179 (e.g. don't send a "your parcel shipped" SMS twice for a retried180 delivery).