Assisted orders
The delegate's first-order assistance: a draft priced with the visited reseller's customer-type prices, sent for the reseller's (or the administration's) confirmation, then confirmed by the back-office like every order — plus the read-only orders of the delegate's resellers.
An assisted order (commande assistée) is an order a delegate prepares with the reseller during a visit — typically the first one (cahier §4.4, §6.7, ORD-08). It identifies the source delegate for ever (BR-73) and passes two confirmations: the reseller confirms it in the app or the web (or the administration confirms it on their behalf after a phone call), and then, like every order, a back-office user confirms it before preparation — no order is ever confirmed automatically (ORD-14, BR-24, BR-72). The state machine is owned by Lifecycles — Order and AssistedConfirmation.

Pricing and stock (team decisions of 17 Oct 2026). Every price is the visited reseller's price: the variant's price for that reseller's customerType (SUPER_GROS, DEMI_GROS or DETAIL, stored HT, TTC derived), then promotions — never the delegate's own view, never a purchase price (PRC-02, BR-07, BR-62). Stock is shown as availability only (IN_STOCK / OUT_OF_STOCK), never as a quantity (STK-07). The amounts follow exactly the cart computation and the controls are the checkout's (BR-71).
Offline behaviour. An assisted order is the one delegate flow that needs the network to finish. Offline, the app lets the delegate build the basket locally from its cached catalog (products, last known availability, the last prices received for this reseller, marked « prix estimés »); create and update are called as soon as a connection exists and return the authoritative prices, promotions and issues; submit always requires the network because prices, availability, minimum amount and credit are re-checked at that moment. None of these operations is replayed through sync.batch (NOT_BATCHABLE).
Scope. A delegate prepares assisted orders only for resellers in their delegate scope that are not SUSPENDED; a prospect still pending validation is allowed — the order then waits for the account approval (BR-70). The order lists show the orders of the delegate's assigned resellers plus every order the delegate prepared (sourceDelegateId = caller), read-only and without purchase prices (permissions matrix). Drafts are visible only to the delegate who created them.
| Method | Path | Operation | Access | Apps | Release |
|---|---|---|---|---|---|
| POST | /delegate/assisted-orders | delegate.assisted.createStart an assisted order for a reseller in my scope (draft, priced) | delegateIdempotency-Key | DA | V1 |
| PATCH | /delegate/assisted-orders/{orderId} | delegate.assisted.updateEdit draft lines, address and note; returns re-priced totals and issues | delegateIdempotency-Key | DA | V1 |
| POST | /delegate/assisted-orders/{orderId}/submit | delegate.assisted.submitSend for confirmation (reseller in app, or administration); same controls as a normal order | delegateIdempotency-Key | DA | V1 |
| DELETE | /delegate/assisted-orders/{orderId} | delegate.assisted.discardDiscard a draft assisted order | delegate | DA | V1 |
| GET | /delegate/orders | delegate.orders.listOrders of resellers in my scope (assisted and direct), read-only | delegate | DA | V1 |
| GET | /delegate/orders/{orderId} | delegate.orders.getOrder detail (read-only, no purchase prices) | delegate | DA | V1 |
Conventions on this page
- Caller: delegate session; mobile headers on every call. Mutations require
Idempotency-Key(everydelegate.*mutation, includingdiscard). - Errors common to every operation, not repeated:
400 VALIDATION_FAILED,400 IDEMPOTENCY_KEY_REQUIRED(mutation without the header),401 UNAUTHENTICATED,403 ACCOUNT_SUSPENDED,403 PERMISSION_DENIED,404 NOT_FOUND,409 IDEMPOTENCY_KEY_REUSED,409 IDEMPOTENCY_IN_PROGRESS,426 UPGRADE_REQUIRED,429 RATE_LIMITED,500 INTERNAL_ERROR,503 MAINTENANCE. - Settings:
orders.assistedConfirmationHours(72),orders.minAmount(1 000 000 = 10 000,00 DA, merchandise TTC after promotions),delivery.feePolicy(FREE),credit.overLimitPolicy(BLOCK) — settings catalogue.
Shared shapes of this page
Lines, totals and promotions reuse the shapes of Cart & checkout (CartLine, LineTotals, PromotionApplied, AppliedPromotion, DisplayTotals) and the shared Totals, Issue, Address, StatusChange.
type OrderStatus = "DRAFT" | "SUBMITTED" | "PENDING" | "VALIDATED" | "REFUSED" | "PREPARING" | "READY"
| "SHIPPED" | "DELIVERED" | "CANCELLED" | "RETURNED";
type AssistedConfirmation = "AWAITING_RESELLER" | "CONFIRMED_BY_RESELLER" | "CONFIRMED_BY_ADMIN" | "REJECTED_BY_RESELLER" | "EXPIRED";
type PaymentMethod = "CASH_ON_DELIVERY" | "BANK_TRANSFER" | "CCP" | "BARIDIMOB" | "CREDIT";
interface AssistedOrderView {
id: Uuid;
number: string | null; // CMD-YYYY-NNNNNN, allocated when sent for confirmation
status: OrderStatus; // DRAFT, then PENDING, then SUBMITTED …
channel: "DELEGATE_ASSISTED";
reseller: ResellerSummary;
pricing: {
customerType: "SUPER_GROS" | "DEMI_GROS" | "DETAIL"; // the tier used for every line
customerTypeConfirmed: boolean; // false while only proposed at sign-up (AUTH-11)
};
sourceDelegate: UserSummary;
visitId: Uuid | null;
lines: CartLine[]; // same shape as the reseller's cart lines; availability only
totals: Totals;
displayTotals: DisplayTotals;
appliedPromotions: AppliedPromotion[];
minimumOrder: { amountTtc: Money; met: boolean; missingTtc: Money };
address: Address | null;
note: string | null; // ≤ 500
paymentMethod: PaymentMethod;
issues: Issue[]; // order-level; line issues are in lines[].issues
canSubmit: boolean; // DRAFT, ≥ 1 line, no BLOCKING issue anywhere
confirmationMode: "RESELLER_APP" | "ADMIN";
assistedConfirmation: AssistedConfirmation | null; // null while DRAFT
expiresAt: Iso | null; // set when sent: + orders.assistedConfirmationHours
awaitingConfirmation: "RESELLER" | "ADMINISTRATION" | "BACK_OFFICE" | null;
isFirstOrder: boolean; // forecast while DRAFT/PENDING; frozen when the order reaches SUBMITTED
createdAt: Iso;
updatedAt: Iso;
submittedAt: Iso | null; // when sent for confirmation
confirmedAt: Iso | null; // reseller or administration confirmation
version: number;
}Order-level issues specific to assisted orders (in addition to the cart issues PRICE_CHANGED, PROMOTION_ENDED, PRODUCT_UNAVAILABLE, STOCK_INSUFFICIENT, QUANTITY_NOT_ALLOWED, ORDER_MIN_AMOUNT_NOT_MET, RESELLER_SUSPENDED):
| Code | Severity | Raised when |
|---|---|---|
CUSTOMER_TYPE_UNCONFIRMED | WARNING | The reseller's customer type is only proposed (record pending validation) or unknown (DETAIL used): « Prix calculés sur le type Détail proposé — confirmé à la validation du compte ». The order is re-priced at confirmation with the confirmed type |
RESELLER_NOT_VALIDATED | WARNING | The point of sale is still PENDING validation: the order will wait for the account approval before the back-office can confirm it |
ADDRESS_REQUIRED | BLOCKING | No delivery address chosen and the reseller has none |
ASSISTED_ORDER_ALREADY_PENDING | BLOCKING | Another assisted order of this reseller is awaiting confirmation (BR-74) — details.orderId, details.number |
POST /delegate/assisted-orders
delegate.assisted.create · Access session, delegate scope (reseller in scope, not SUSPENDED) · Apps DA · Idempotency-Key required · Offline-capable no — the basket is kept locally offline and this call is made when the network returns · Release V1 · Requirements ORD-08
Purpose. Steps 1–2 of « Aide à la 1ère commande » (« Choisir produits », « Remplir panier »): create the draft with its lines and get it priced for the visited reseller.
Request. Body:
interface CreateAssistedOrderRequest {
resellerId: Uuid;
visitId?: Uuid | null; // the visit in progress, for reports
lines: Array<{ variantId: Uuid; qty: number }>; // 1–100 lines, one per variant
addressId?: Uuid | null; // one of the reseller's addresses; default address when omitted
address?: { // or a new address, saved to the reseller's address book
label?: string | null;
recipientName: string;
phone: string;
wilayaCode: string;
communeId: Uuid;
addressLine: string;
landmark?: string | null;
location?: GeoPoint | null;
} | null;
note?: string | null; // ≤ 500
paymentMethod?: PaymentMethod; // default CASH_ON_DELIVERY
}{
"resellerId": "0192d1aa-3b4c-7d5e-8f60-718293a4b315",
"visitId": "0193a2f0-5b6c-7e8d-9f01-23456789ab14",
"lines": [
{ "variantId": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "qty": 10 },
{ "variantId": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "qty": 10 }
],
"addressId": null,
"note": "Première commande — livraison le matin de préférence.",
"paymentMethod": "CASH_ON_DELIVERY"
}Response 201 Created — AssistedOrderView (DRAFT).
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e01",
"number": null,
"status": "DRAFT",
"channel": "DELEGATE_ASSISTED",
"reseller": {
"id": "0192d1aa-3b4c-7d5e-8f60-718293a4b315",
"number": "REV-000315",
"storeName": "Alpha Market",
"ownerName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"communeName": "Es Senia",
"status": "ACCOUNT_CREATED"
},
"pricing": { "customerType": "DETAIL", "customerTypeConfirmed": true },
"sourceDelegate": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9f01", "displayName": "Yacine Belkacem" },
"visitId": "0193a2f0-5b6c-7e8d-9f01-23456789ab14",
"lines": [
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e11",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e10", "name": "HOCO Z46A Chargeur voiture double port USB", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/z46a/z46a-black-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "sku": "Z46A_BLACK", "label": "Noir" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 200 },
"price": { "ht": 72000, "ttc": 85680, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 720000, "discountHt": 0, "totalHt": 720000, "vat": 136800, "totalTtc": 856800 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
},
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e12",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e20", "name": "HOCO X89 Câble USB-C vers Lightning", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/x89/x89-white-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "sku": "X89_LIGHTNING_WHITE_1M", "label": "Blanc · 1 m" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 300 },
"price": { "ht": 55000, "ttc": 65450, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 550000, "discountHt": 0, "totalHt": 550000, "vat": 104500, "totalTtc": 654500 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
}
],
"totals": { "subtotalHt": 1270000, "discountTotal": 0, "deliveryFee": 0, "vatTotal": 241300, "totalTtc": 1511300, "currency": "DZD" },
"displayTotals": { "itemsTtc": 1511300, "discountTtc": 0, "deliveryFeeTtc": 0, "totalTtc": 1511300 },
"appliedPromotions": [],
"minimumOrder": { "amountTtc": 1000000, "met": true, "missingTtc": 0 },
"address": {
"id": "0192d1ab-4c5d-7e6f-8a70-b1c2d3e4f515",
"label": "Magasin",
"recipientName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"wilayaName": "Oran",
"communeId": "0192b7c0-31aa-7a00-8b00-000000310007",
"communeName": "Es Senia",
"addressLine": "Route de l'aéroport, cité El Amel",
"landmark": "À côté de la station Naftal",
"location": { "lat": 35.6491, "lng": -0.6202 },
"isDefault": true
},
"note": "Première commande — livraison le matin de préférence.",
"paymentMethod": "CASH_ON_DELIVERY",
"issues": [],
"canSubmit": true,
"confirmationMode": "RESELLER_APP",
"assistedConfirmation": null,
"expiresAt": null,
"awaitingConfirmation": null,
"isFirstOrder": true,
"createdAt": "2026-11-03T13:15:00Z",
"updatedAt": "2026-11-03T13:15:00Z",
"submittedAt": null,
"confirmedAt": null,
"version": 1
}Field notes. « 850,00 DA — En stock » on the reference = price.ttc and availability of the reseller's type (here DETAIL: 856,80 DA TTC from 720,00 DA HT); « Articles sélectionnés » = lines; « Total estimé » = displayTotals.totalTtc. The reference total (2 350,00 DA for 3 units) would be refused by the minimum amount; the example orders ten of each. The « Revendeur accompagné » badge = sourceDelegate.
Errors
| Status | Code | When |
|---|---|---|
| 400 | VALIDATION_FAILED | No line or more than 100; duplicate variantId; qty < 1; both addressId and address; unknown address (UNKNOWN_ADDRESS) |
| 403 | OUT_OF_SCOPE | Reseller not in the caller's scope any more |
| 403 | RESELLER_SUSPENDED | ResellerStatus SUSPENDED |
Line problems (unavailable product, quantity rule, insufficient stock, minimum not met) never fail the creation: they come back as issues and canSubmit = false, so the delegate can fix the basket with the reseller.
Rules & side effects
- Prices: for each line, the variant's price for the reseller's
customerType(HT;ttc = round(ht × (1 + vatRate/10 000))), then the best promotion the reseller is eligible to, then line and order totals exactly as in the cart. A reseller without a confirmed type is priced with the proposed type, orDETAILwhen none, with the warningCUSTOMER_TYPE_UNCONFIRMED. confirmationMode=RESELLER_APPwhen the reseller has a user account with AccountStatusACTIVE(they will confirm in the app or the web), elseADMIN(the administration will confirm after calling them).- The draft has no number, is invisible to the reseller and has no stock effect (lifecycles). No event.
Used by DA-17.
PATCH /delegate/assisted-orders/{orderId}
delegate.assisted.update · Access session — the delegate who created the draft · Apps DA · Idempotency-Key required · Offline-capable no — local edits are sent when online · Release V1 · Requirements ORD-08, ORD-02
Purpose. Edit the draft (lines, address, note, payment method) and get it re-priced with its issues — step 3 « Vérifier adresse » included.
Request. Body — omitted fields unchanged; lines, when present, replaces all lines:
interface UpdateAssistedOrderRequest {
version: number;
lines?: Array<{ variantId: Uuid; qty: number }>;
addressId?: Uuid;
address?: CreateAssistedOrderRequest["address"];
note?: string | null;
paymentMethod?: PaymentMethod;
}{
"version": 1,
"lines": [
{ "variantId": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "qty": 10 },
{ "variantId": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "qty": 10 },
{ "variantId": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e31", "qty": 5 }
]
}Response 200 OK — the re-priced AssistedOrderView. Here the earphones added are out of stock, so the order cannot be sent until that line is removed:
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e01",
"number": null,
"status": "DRAFT",
"channel": "DELEGATE_ASSISTED",
"reseller": {
"id": "0192d1aa-3b4c-7d5e-8f60-718293a4b315",
"number": "REV-000315",
"storeName": "Alpha Market",
"ownerName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"communeName": "Es Senia",
"status": "ACCOUNT_CREATED"
},
"pricing": { "customerType": "DETAIL", "customerTypeConfirmed": true },
"sourceDelegate": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9f01", "displayName": "Yacine Belkacem" },
"visitId": "0193a2f0-5b6c-7e8d-9f01-23456789ab14",
"lines": [
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e11",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e10", "name": "HOCO Z46A Chargeur voiture double port USB", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/z46a/z46a-black-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "sku": "Z46A_BLACK", "label": "Noir" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 200 },
"price": { "ht": 72000, "ttc": 85680, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 720000, "discountHt": 0, "totalHt": 720000, "vat": 136800, "totalTtc": 856800 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
},
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e12",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e20", "name": "HOCO X89 Câble USB-C vers Lightning", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/x89/x89-white-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "sku": "X89_LIGHTNING_WHITE_1M", "label": "Blanc · 1 m" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 300 },
"price": { "ht": 55000, "ttc": 65450, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 550000, "discountHt": 0, "totalHt": 550000, "vat": 104500, "totalTtc": 654500 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
},
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e13",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e30", "name": "HOCO M1 Pro Écouteurs filaires avec micro", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/m1pro/m1pro-white-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e31", "sku": "M1PRO_WHITE", "label": "Blanc" },
"qty": 5,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 100 },
"price": { "ht": 80000, "ttc": 95200, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 400000, "discountHt": 0, "totalHt": 400000, "vat": 76000, "totalTtc": 476000 },
"availability": "OUT_OF_STOCK",
"addedAt": "2026-11-03T13:18:00Z",
"issues": [
{ "code": "STOCK_INSUFFICIENT", "severity": "BLOCKING", "lineId": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e13", "message": "Produit en rupture — retirez-le ou attendez le réassort.", "details": { "availability": "OUT_OF_STOCK" } }
]
}
],
"totals": { "subtotalHt": 1670000, "discountTotal": 0, "deliveryFee": 0, "vatTotal": 317300, "totalTtc": 1987300, "currency": "DZD" },
"displayTotals": { "itemsTtc": 1987300, "discountTtc": 0, "deliveryFeeTtc": 0, "totalTtc": 1987300 },
"appliedPromotions": [],
"minimumOrder": { "amountTtc": 1000000, "met": true, "missingTtc": 0 },
"address": {
"id": "0192d1ab-4c5d-7e6f-8a70-b1c2d3e4f515",
"label": "Magasin",
"recipientName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"wilayaName": "Oran",
"communeId": "0192b7c0-31aa-7a00-8b00-000000310007",
"communeName": "Es Senia",
"addressLine": "Route de l'aéroport, cité El Amel",
"landmark": "À côté de la station Naftal",
"location": { "lat": 35.6491, "lng": -0.6202 },
"isDefault": true
},
"note": "Première commande — livraison le matin de préférence.",
"paymentMethod": "CASH_ON_DELIVERY",
"issues": [],
"canSubmit": false,
"confirmationMode": "RESELLER_APP",
"assistedConfirmation": null,
"expiresAt": null,
"awaitingConfirmation": null,
"isFirstOrder": true,
"createdAt": "2026-11-03T13:15:00Z",
"updatedAt": "2026-11-03T13:18:00Z",
"submittedAt": null,
"confirmedAt": null,
"version": 2
}The delegate then sends lines without the earphones (version: 2); the draft is back to 15 113,00 DA, canSubmit: true, version: 3.
Errors — 403 OUT_OF_SCOPE · 404 NOT_FOUND (not the caller's draft) · 409 ORDER_TRANSITION_NOT_ALLOWED (not DRAFT any more; details: { status }) · 409 VERSION_CONFLICT (details.current: AssistedOrderView).
Rules & side effects. Re-priced and re-controlled on every change (BR-71); PRICE_CHANGED warnings appear when a price moved since the line was added (for instance the back-office confirmed another customer type); version increments. No event.
Used by DA-17.
POST /delegate/assisted-orders/{orderId}/submit
delegate.assisted.submit · Access session — the delegate who created the draft · Apps DA · Idempotency-Key required (one key per tap on « Passer la 1ère commande », reused on retries) · Offline-capable no — requires the network: prices, availability, minimum and credit are re-checked now · Release V1 · Requirements ORD-08, ORD-09
Purpose. Step 4 « Valider commande »: send the order for confirmation (cahier §6.7 « Demander la confirmation du revendeur »).
Request. Body:
interface SubmitAssistedOrderRequest {
version: number;
expectedTotalTtc: Money; // the total shown to the reseller
}{ "version": 3, "expectedTotalTtc": 1511300 }Response 200 OK — AssistedOrderView now PENDING, awaiting the reseller (lines as in the creation example).
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e01",
"number": "CMD-2026-000163",
"status": "PENDING",
"channel": "DELEGATE_ASSISTED",
"reseller": {
"id": "0192d1aa-3b4c-7d5e-8f60-718293a4b315",
"number": "REV-000315",
"storeName": "Alpha Market",
"ownerName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"communeName": "Es Senia",
"status": "ACCOUNT_CREATED"
},
"pricing": { "customerType": "DETAIL", "customerTypeConfirmed": true },
"sourceDelegate": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9f01", "displayName": "Yacine Belkacem" },
"visitId": "0193a2f0-5b6c-7e8d-9f01-23456789ab14",
"lines": [
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e11",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e10", "name": "HOCO Z46A Chargeur voiture double port USB", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/z46a/z46a-black-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "sku": "Z46A_BLACK", "label": "Noir" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 200 },
"price": { "ht": 72000, "ttc": 85680, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 720000, "discountHt": 0, "totalHt": 720000, "vat": 136800, "totalTtc": 856800 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
},
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e12",
"kind": "VARIANT",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e20", "name": "HOCO X89 Câble USB-C vers Lightning", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/x89/x89-white-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "sku": "X89_LIGHTNING_WHITE_1M", "label": "Blanc · 1 m" },
"qty": 10,
"limits": { "minQty": 1, "qtyStep": 1, "maxQtyPerOrder": 300 },
"price": { "ht": 55000, "ttc": 65450, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 550000, "discountHt": 0, "totalHt": 550000, "vat": 104500, "totalTtc": 654500 },
"availability": "IN_STOCK",
"addedAt": "2026-11-03T13:15:00Z",
"issues": []
}
],
"totals": { "subtotalHt": 1270000, "discountTotal": 0, "deliveryFee": 0, "vatTotal": 241300, "totalTtc": 1511300, "currency": "DZD" },
"displayTotals": { "itemsTtc": 1511300, "discountTtc": 0, "deliveryFeeTtc": 0, "totalTtc": 1511300 },
"appliedPromotions": [],
"minimumOrder": { "amountTtc": 1000000, "met": true, "missingTtc": 0 },
"address": {
"id": "0192d1ab-4c5d-7e6f-8a70-b1c2d3e4f515",
"label": "Magasin",
"recipientName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"wilayaName": "Oran",
"communeId": "0192b7c0-31aa-7a00-8b00-000000310007",
"communeName": "Es Senia",
"addressLine": "Route de l'aéroport, cité El Amel",
"landmark": "À côté de la station Naftal",
"location": { "lat": 35.6491, "lng": -0.6202 },
"isDefault": true
},
"note": "Première commande — livraison le matin de préférence.",
"paymentMethod": "CASH_ON_DELIVERY",
"issues": [],
"canSubmit": false,
"confirmationMode": "RESELLER_APP",
"assistedConfirmation": "AWAITING_RESELLER",
"expiresAt": "2026-11-06T13:22:00Z",
"awaitingConfirmation": "RESELLER",
"isFirstOrder": true,
"createdAt": "2026-11-03T13:15:00Z",
"updatedAt": "2026-11-03T13:22:00Z",
"submittedAt": "2026-11-03T13:22:00Z",
"confirmedAt": null,
"version": 4
}Errors — checked in this order; the first failing check answers.
| Status | Code | When |
|---|---|---|
| 403 | OUT_OF_SCOPE · RESELLER_SUSPENDED | Reseller left the scope · reseller suspended |
| 404 | NOT_FOUND | Not the caller's draft |
| 409 | ORDER_TRANSITION_NOT_ALLOWED | Status is not DRAFT (details: { from, to: "PENDING", allowed }) |
| 409 | VERSION_CONFLICT | version is stale |
| 409 | ASSISTED_ORDER_ALREADY_PENDING | Another assisted order of the reseller awaits confirmation (details: { orderId, number }) |
| 422 | PRODUCT_UNAVAILABLE · QUANTITY_NOT_ALLOWED · STOCK_INSUFFICIENT · ORDER_MIN_AMOUNT_NOT_MET · ADDRESS_REQUIRED | First blocking issue; details: { issues: Issue[], order: AssistedOrderView } — the app renders details.order at once. Stock details carry availability only, never a quantity |
| 422 | ADDRESS_NOT_DELIVERABLE | Wilaya of the address not served |
| 422 | PAYMENT_METHOD_NOT_ALLOWED | Method disabled, or CREDIT without an open credit line (details.reason) |
| 422 | CREDIT_LIMIT_EXCEEDED | CREDIT and over the limit under policy BLOCK (details: { required } — the reseller's limit and balance are not disclosed to the delegate) |
| 409 | CART_CHANGED | The re-validated total differs from expectedTotalTtc (details: { expectedTotalTtc, actualTotalTtc, order: AssistedOrderView }); nothing is sent — show the new total to the reseller and submit again with a new key |
Rules & side effects
DRAFT→PENDINGwith AssistedConfirmationAWAITING_RESELLERin one transaction: numberCMD-YYYY-NNNNNNallocated; lines, prices, promotions and address snapshotted;sourceDelegateId= caller and channelDELEGATE_ASSISTEDfor ever (BR-73);assistedExpiresAt= now +orders.assistedConfirmationHours(72 h);OrderStatusChangeDRAFT → PENDINGwith the delegate as actor. No stock is reserved (reservation happens at the back-office confirmation,stock.reserveOn = VALIDATED).- Who confirms.
confirmationMode = RESELLER_APP: the reseller receivesassisted_order.awaiting_confirmation(in-app, push, SMS, and live onGET /events) with a deep link to RA-23 / RW-09, and confirms withorders.confirmAssistedor rejects withorders.rejectAssisted— often on the spot, with the delegate.confirmationMode = ADMIN(no active account yet): the order appears in the back-office queue BO-41; a user withorders.validatecalls the reseller and confirms on their behalf with a note (admin.orders.confirmAssisted). In both modes the status staysAWAITING_RESELLERuntil one of them acts; a reminder goes 24 h beforeexpiresAt; after it the joborders.expireAssistedcancels the order (EXPIRED). - Confirmation is not acceptance. On confirmation the order is re-priced and re-controlled, becomes
SUBMITTEDand joins the back-office queue « Commandes à confirmer » (admin.orders.toConfirm); only an explicitadmin.orders.validatemoves it toVALIDATED(ORD-14). A point of sale still pending validation is putPENDING(RESELLER_NOT_VALIDATED) until the account is approved. - First order (ORD-09, BR-27): when the order reaches
SUBMITTEDand the reseller has no earlier order that is notREFUSEDorCANCELLED,isFirstOrderis frozentrue, the ResellerStatus moves toFIRST_ORDER, the invitation stepFIRST_ORDERis recorded, and the order counts in the source delegate'sFIRST_ORDERSobjective; it counts inORDERSandREVENUEonce the back-office confirms it. - Events: outbox
order.assisted_sent→ back-office SSEorder.created(BO-41) and the reseller notifications above. The delegate later receivesassisted_order.confirmed,assisted_order.rejectedorassisted_order.expired(FIELD, push and in-app) and everyorder.status_changedof this order on their live stream while the app is open.
DELETE /delegate/assisted-orders/{orderId}
delegate.assisted.discard · Access session — the delegate who created the draft · Apps DA · Idempotency-Key required (every delegate.* mutation) · Offline-capable no · Release V1 · Requirements ORD-08
Purpose. Throw away a draft that will not be sent.
Request. Path orderId; no body.
Response 204 No Content.
Errors — 404 NOT_FOUND (not the caller's draft, or already discarded — a replay with the same key returns the original 204) · 409 ORDER_TRANSITION_NOT_ALLOWED (no longer DRAFT: once sent, only the reseller can reject it and the back-office cancel it).
Rules & side effects. Hard delete of the draft and its lines; an AuditLog entry is kept (lifecycles). No number was allocated, so no gap appears in the CMD- sequence. Drafts untouched for 7 days are purged by the same rule (Assumption — housekeeping job to confirm on the jobs page).
GET /delegate/orders
delegate.orders.list · Access session, delegate scope — orders of resellers assigned to the caller, plus orders whose sourceDelegateId is the caller; the caller's own drafts · Apps DA · Idempotency-Key — · Offline-capable no — the last page is cached · Release V1 · Requirements ORD-08, ACL-03
Purpose. « Commandes »: assisted orders and their confirmation state, and the direct orders of the delegate's resellers, read-only.
Request. Query parameters: status (repeatable OrderStatus), channel (DELEGATE_ASSISTED · RESELLER_APP · RESELLER_WEB · BACK_OFFICE), resellerId, awaiting (RESELLER · BACK_OFFICE — orders waiting for a confirmation), from, to (YYYY-MM-DD, creation date), q (CMD- number or store name), cursor, limit. Sorted by updatedAt descending.
Response 200 OK
interface DelegateOrderListItem {
id: Uuid;
number: string | null; // null for drafts
status: OrderStatus;
channel: "DELEGATE_ASSISTED" | "RESELLER_APP" | "RESELLER_WEB" | "BACK_OFFICE";
assistedConfirmation: AssistedConfirmation | null;
awaitingConfirmation: "RESELLER" | "ADMINISTRATION" | "BACK_OFFICE" | null;
expiresAt: Iso | null;
reseller: ResellerSummary;
itemsCount: number;
totalTtc: Money;
isFirstOrder: boolean;
preparedByMe: boolean;
createdAt: Iso;
submittedAt: Iso | null;
updatedAt: Iso;
}{
"items": [
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e01",
"number": "CMD-2026-000163",
"status": "VALIDATED",
"channel": "DELEGATE_ASSISTED",
"assistedConfirmation": "CONFIRMED_BY_RESELLER",
"awaitingConfirmation": null,
"expiresAt": null,
"reseller": { "id": "0192d1aa-3b4c-7d5e-8f60-718293a4b315", "number": "REV-000315", "storeName": "Alpha Market", "ownerName": "Amina Kaddour", "phone": "+213550982214", "wilayaCode": "31", "communeName": "Es Senia", "status": "FIRST_ORDER" },
"itemsCount": 2,
"totalTtc": 1511300,
"isFirstOrder": true,
"preparedByMe": true,
"createdAt": "2026-11-03T13:15:00Z",
"submittedAt": "2026-11-03T13:22:00Z",
"updatedAt": "2026-11-03T15:02:00Z"
},
{
"id": "0193a2a8-6e7f-7a80-9b91-0c1d2e3f4a60",
"number": "CMD-2026-000160",
"status": "VALIDATED",
"channel": "RESELLER_APP",
"assistedConfirmation": null,
"awaitingConfirmation": null,
"expiresAt": null,
"reseller": { "id": "0192d1aa-3b4c-7d5e-8f60-718293a4b123", "number": "REV-000123", "storeName": "Magasin El Wafa", "ownerName": "Karim Belkacem", "phone": "+213555123456", "wilayaCode": "31", "communeName": "Bir El Djir", "status": "ACTIVE" },
"itemsCount": 6,
"totalTtc": 11000000,
"isFirstOrder": false,
"preparedByMe": false,
"createdAt": "2026-11-03T08:52:00Z",
"submittedAt": "2026-11-03T08:52:00Z",
"updatedAt": "2026-11-03T10:40:00Z"
},
{
"id": "0193a35e-2f30-7a41-8b52-6c7d8e9f0a71",
"number": null,
"status": "DRAFT",
"channel": "DELEGATE_ASSISTED",
"assistedConfirmation": null,
"awaitingConfirmation": null,
"expiresAt": null,
"reseller": { "id": "0192d1aa-3b4c-7d5e-8f60-718293a4b287", "number": "REV-000287", "storeName": "Electro Plus", "ownerName": "Sofiane Medjahed", "phone": "+213661457812", "wilayaCode": "31", "communeName": "Bir El Djir", "status": "APP_INSTALLED" },
"itemsCount": 3,
"totalTtc": 2142000,
"isFirstOrder": true,
"preparedByMe": true,
"createdAt": "2026-11-03T09:50:00Z",
"submittedAt": null,
"updatedAt": "2026-11-03T09:55:00Z"
}
],
"nextCursor": null
}Errors — 400 VALIDATION_FAILED (malformed filters).
Rules & side effects. Read-only. Orders of a reseller reassigned away stay listed only if the caller prepared them. Amounts are the reseller's TTC totals; no margin, purchase price or credit information is ever returned (ACL-04).
Used by DA-18, DA-09 (orders of one store).
GET /delegate/orders/{orderId}
delegate.orders.get · Access session, delegate scope (as the list) · Apps DA · Idempotency-Key — · Offline-capable no — cached once opened · Release V1 · Requirements ORD-08
Purpose. Order detail for the delegate: lines, totals, confirmation state, status history and delivery progress — to answer the reseller's questions in the field.
Request. Path orderId. A draft of the caller is returned as its AssistedOrderView (same as create).
Response 200 OK
interface DelegateOrderView {
id: Uuid;
number: string;
status: OrderStatus;
channel: "DELEGATE_ASSISTED" | "RESELLER_APP" | "RESELLER_WEB" | "BACK_OFFICE";
isFirstOrder: boolean;
reseller: ResellerSummary;
sourceDelegate: UserSummary | null;
attributedToMe: boolean; // BR-49 snapshot taken at submission
createdAt: Iso;
submittedAt: Iso | null;
validatedAt: Iso | null;
updatedAt: Iso;
currency: "DZD";
lines: Array<Pick<CartLine, "id" | "product" | "variant" | "qty" | "price" | "promotionApplied" | "lineTotals">>;
totals: Totals;
displayTotals: DisplayTotals;
address: Address;
note: string | null;
paymentMethod: PaymentMethod;
delivery: { status: string | null; mode: "OWN_FLEET" | "CARRIER" | "PICKUP" | null; carrierName: string | null; trackingNumber: string | null; shippedAt: Iso | null; deliveredAt: Iso | null };
assisted: { confirmationMode: "RESELLER_APP" | "ADMIN"; confirmation: AssistedConfirmation; expiresAt: Iso; confirmedAt: Iso | null; confirmedBy: UserSummary | null; rejectionReason: string | null } | null;
awaitingConfirmation: "RESELLER" | "ADMINISTRATION" | "BACK_OFFICE" | null;
refusal: { reasonCode: string; comment: string | null; at: Iso } | null;
cancellation: { reasonCode: string; comment: string | null; at: Iso; by: "RESELLER" | "BACK_OFFICE" | "SYSTEM" } | null;
statusHistory: StatusChange[];
}{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e01",
"number": "CMD-2026-000163",
"status": "VALIDATED",
"channel": "DELEGATE_ASSISTED",
"isFirstOrder": true,
"reseller": { "id": "0192d1aa-3b4c-7d5e-8f60-718293a4b315", "number": "REV-000315", "storeName": "Alpha Market", "ownerName": "Amina Kaddour", "phone": "+213550982214", "wilayaCode": "31", "communeName": "Es Senia", "status": "FIRST_ORDER" },
"sourceDelegate": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9f01", "displayName": "Yacine Belkacem" },
"attributedToMe": true,
"createdAt": "2026-11-03T13:15:00Z",
"submittedAt": "2026-11-03T13:22:00Z",
"validatedAt": "2026-11-03T15:02:00Z",
"updatedAt": "2026-11-03T15:02:00Z",
"currency": "DZD",
"lines": [
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e11",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e10", "name": "HOCO Z46A Chargeur voiture double port USB", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/z46a/z46a-black-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e11", "sku": "Z46A_BLACK", "label": "Noir" },
"qty": 10,
"price": { "ht": 72000, "ttc": 85680, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 720000, "discountHt": 0, "totalHt": 720000, "vat": 136800, "totalTtc": 856800 }
},
{
"id": "0193a3f0-1b2c-7d3e-8f40-5a6b7c8d9e12",
"product": { "id": "0192a3f0-0a1b-7c2d-8e3f-4a5b6c7d8e20", "name": "HOCO X89 Câble USB-C vers Lightning", "brandName": "HOCO", "imageUrl": "https://cdn.hoco.dz/products/x89/x89-white-1-240.webp" },
"variant": { "id": "0192a3f1-0a1b-7c2d-8e3f-4a5b6c7d8e21", "sku": "X89_LIGHTNING_WHITE_1M", "label": "Blanc · 1 m" },
"qty": 10,
"price": { "ht": 55000, "ttc": 65450, "vatRate": 1900 },
"promotionApplied": null,
"lineTotals": { "subtotalHt": 550000, "discountHt": 0, "totalHt": 550000, "vat": 104500, "totalTtc": 654500 }
}
],
"totals": { "subtotalHt": 1270000, "discountTotal": 0, "deliveryFee": 0, "vatTotal": 241300, "totalTtc": 1511300, "currency": "DZD" },
"displayTotals": { "itemsTtc": 1511300, "discountTtc": 0, "deliveryFeeTtc": 0, "totalTtc": 1511300 },
"address": {
"id": "0192d1ab-4c5d-7e6f-8a70-b1c2d3e4f515",
"label": "Magasin",
"recipientName": "Amina Kaddour",
"phone": "+213550982214",
"wilayaCode": "31",
"wilayaName": "Oran",
"communeId": "0192b7c0-31aa-7a00-8b00-000000310007",
"communeName": "Es Senia",
"addressLine": "Route de l'aéroport, cité El Amel",
"landmark": "À côté de la station Naftal",
"location": { "lat": 35.6491, "lng": -0.6202 },
"isDefault": true
},
"note": "Première commande — livraison le matin de préférence.",
"paymentMethod": "CASH_ON_DELIVERY",
"delivery": { "status": "TO_PREPARE", "mode": null, "carrierName": null, "trackingNumber": null, "shippedAt": null, "deliveredAt": null },
"assisted": {
"confirmationMode": "RESELLER_APP",
"confirmation": "CONFIRMED_BY_RESELLER",
"expiresAt": "2026-11-06T13:22:00Z",
"confirmedAt": "2026-11-03T13:35:00Z",
"confirmedBy": { "id": "0192e011-2a3b-7c4d-8e5f-6a7b8c9d0e15", "displayName": "Amina Kaddour" },
"rejectionReason": null
},
"awaitingConfirmation": null,
"refusal": null,
"cancellation": null,
"statusHistory": [
{ "from": "DRAFT", "to": "PENDING", "at": "2026-11-03T13:22:00Z", "actor": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9f01", "displayName": "Yacine Belkacem" } },
{ "from": "PENDING", "to": "SUBMITTED", "at": "2026-11-03T13:35:00Z", "actor": { "id": "0192e011-2a3b-7c4d-8e5f-6a7b8c9d0e15", "displayName": "Amina Kaddour" }, "reason": "Confirmée par le revendeur" },
{ "from": "SUBMITTED", "to": "VALIDATED", "at": "2026-11-03T15:02:00Z", "actor": { "id": "0192f0a1-7c3e-7b10-9a4e-5d2c1b0a9e22", "displayName": "Service commandes HOCO" } }
]
}Field notes. The back-office actor is shown by display name only. Invoices and delivery notes are not exposed to delegates (financial documents); the reseller downloads them from their own app.
Errors — 404 NOT_FOUND (outside the list scope).
Rules & side effects. Read-only; refreshed live by order.status_changed events on the delegate's stream for orders they prepared.
Used by DA-18.
Prospects, points of sale, follow-ups & invitations
The delegate's CRM in the field — scoped list and map of points of sale, duplicate check, offline prospect creation, point-of-sale sheet and edits, notes and photos, invitations with activation tracking, and follow-up tasks.
Offline sync & location
How the offline-first delegate app talks to the server: ordered replay of queued mutations with per-item results, the delta feed of its offline scopes with tombstones, and batched location pings during a tour.