HOCO B2B
SRSAPI reference

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.

First-order assistance in 4 steps: choose products, fill the cart, check the address, submit — « Passer la 1ère commande ».
First-order assistance in 4 steps: choose products, fill the cart, check the address, submit — « Passer la 1ère commande ». — client reference (cahier des charges)

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.

MethodPathOperationAccessAppsRelease
POST/delegate/assisted-ordersdelegate.assisted.create
Start an assisted order for a reseller in my scope (draft, priced)
delegate
Idempotency-Key
DAV1
PATCH/delegate/assisted-orders/{orderId}delegate.assisted.update
Edit draft lines, address and note; returns re-priced totals and issues
delegate
Idempotency-Key
DAV1
POST/delegate/assisted-orders/{orderId}/submitdelegate.assisted.submit
Send for confirmation (reseller in app, or administration); same controls as a normal order
delegate
Idempotency-Key
DAV1
DELETE/delegate/assisted-orders/{orderId}delegate.assisted.discard
Discard a draft assisted order
delegateDAV1
GET/delegate/ordersdelegate.orders.list
Orders of resellers in my scope (assisted and direct), read-only
delegateDAV1
GET/delegate/orders/{orderId}delegate.orders.get
Order detail (read-only, no purchase prices)
delegateDAV1

Conventions on this page

  • Caller: delegate session; mobile headers on every call. Mutations require Idempotency-Key (every delegate.* mutation, including discard).
  • 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):

CodeSeverityRaised when
CUSTOMER_TYPE_UNCONFIRMEDWARNINGThe 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_VALIDATEDWARNINGThe point of sale is still PENDING validation: the order will wait for the account approval before the back-office can confirm it
ADDRESS_REQUIREDBLOCKINGNo delivery address chosen and the reseller has none
ASSISTED_ORDER_ALREADY_PENDINGBLOCKINGAnother 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

StatusCodeWhen
400VALIDATION_FAILEDNo line or more than 100; duplicate variantId; qty < 1; both addressId and address; unknown address (UNKNOWN_ADDRESS)
403OUT_OF_SCOPEReseller not in the caller's scope any more
403RESELLER_SUSPENDEDResellerStatus 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

  1. 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, or DETAIL when none, with the warning CUSTOMER_TYPE_UNCONFIRMED.
  2. confirmationMode = RESELLER_APP when the reseller has a user account with AccountStatus ACTIVE (they will confirm in the app or the web), else ADMIN (the administration will confirm after calling them).
  3. 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.

StatusCodeWhen
403OUT_OF_SCOPE · RESELLER_SUSPENDEDReseller left the scope · reseller suspended
404NOT_FOUNDNot the caller's draft
409ORDER_TRANSITION_NOT_ALLOWEDStatus is not DRAFT (details: { from, to: "PENDING", allowed })
409VERSION_CONFLICTversion is stale
409ASSISTED_ORDER_ALREADY_PENDINGAnother assisted order of the reseller awaits confirmation (details: { orderId, number })
422PRODUCT_UNAVAILABLE · QUANTITY_NOT_ALLOWED · STOCK_INSUFFICIENT · ORDER_MIN_AMOUNT_NOT_MET · ADDRESS_REQUIREDFirst blocking issue; details: { issues: Issue[], order: AssistedOrderView } — the app renders details.order at once. Stock details carry availability only, never a quantity
422ADDRESS_NOT_DELIVERABLEWilaya of the address not served
422PAYMENT_METHOD_NOT_ALLOWEDMethod disabled, or CREDIT without an open credit line (details.reason)
422CREDIT_LIMIT_EXCEEDEDCREDIT and over the limit under policy BLOCK (details: { required } — the reseller's limit and balance are not disclosed to the delegate)
409CART_CHANGEDThe 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

  1. DRAFT → PENDING with AssistedConfirmation AWAITING_RESELLER in one transaction: number CMD-YYYY-NNNNNN allocated; lines, prices, promotions and address snapshotted; sourceDelegateId = caller and channel DELEGATE_ASSISTED for ever (BR-73); assistedExpiresAt = now + orders.assistedConfirmationHours (72 h); OrderStatusChange DRAFT → PENDING with the delegate as actor. No stock is reserved (reservation happens at the back-office confirmation, stock.reserveOn = VALIDATED).
  2. Who confirms. confirmationMode = RESELLER_APP: the reseller receives assisted_order.awaiting_confirmation (in-app, push, SMS, and live on GET /events) with a deep link to RA-23 / RW-09, and confirms with orders.confirmAssisted or rejects with orders.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 with orders.validate calls the reseller and confirms on their behalf with a note (admin.orders.confirmAssisted). In both modes the status stays AWAITING_RESELLER until one of them acts; a reminder goes 24 h before expiresAt; after it the job orders.expireAssisted cancels the order (EXPIRED).
  3. Confirmation is not acceptance. On confirmation the order is re-priced and re-controlled, becomes SUBMITTED and joins the back-office queue « Commandes à confirmer » (admin.orders.toConfirm); only an explicit admin.orders.validate moves it to VALIDATED (ORD-14). A point of sale still pending validation is put PENDING (RESELLER_NOT_VALIDATED) until the account is approved.
  4. First order (ORD-09, BR-27): when the order reaches SUBMITTED and the reseller has no earlier order that is not REFUSED or CANCELLED, isFirstOrder is frozen true, the ResellerStatus moves to FIRST_ORDER, the invitation step FIRST_ORDER is recorded, and the order counts in the source delegate's FIRST_ORDERS objective; it counts in ORDERS and REVENUE once the back-office confirms it.
  5. Events: outbox order.assisted_sent → back-office SSE order.created (BO-41) and the reseller notifications above. The delegate later receives assisted_order.confirmed, assisted_order.rejected or assisted_order.expired (FIELD, push and in-app) and every order.status_changed of this order on their live stream while the app is open.

Used by DA-17, DA-18.

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).

Used by DA-17, DA-18.

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.

On this page