HOCO B2B
SRSAPI reference

Promotions, banners & packs

Banners per placement, promotions and daily offers with their eligible products, and V2 profitable packs — targeted server-side to the caller, open to guests without prices.

What the reseller app and web show under « Promotions » and in the carousels (cahier §4.6, §5.5, reference screen 7): banners, daily offers with a countdown, scheduled promotions and — in V2 — profitable packs. Built in SRV-19 (packs: SRV-31); consumed by MRA-06, WEB-05 and, for promotions.*, by the delegate app (visit report « promotions présentées » and first-order assistance).

  • Targeting is applied on the server. A promotion or banner targets everyone, wilayas, segments, customer types, brands or volumes (PRM-02); the caller only ever receives what targets them, and the audience rules themselves are never returned. A promotion that does not target the caller is 404 NOT_FOUND.
  • Guests welcome, without prices. These operations are optional: guests see the promotions and banners open to all resellers, with price: null and no amounts that would reveal a price (AUTH-10).
  • Applied by the cart. What is shown here is applied automatically by the cart engine — dates, cap and target included (PRM-04); there is no coupon to enter in V1.
  • No stock numbers. A promotion's quantity cap is shown as a status (capStatus), never as a remaining quantity (STK-07).
MethodPathOperationAccessAppsRelease
GET/bannersbanners.list
Active banners for a placement, targeted to the caller — guests allowed, without prices
guest or sessionRA · RWV1
GET/promotionspromotions.list
Promotions and daily offers available to the caller — guests allowed, without prices
guest or sessionRA · RW · DAV1
GET/promotions/{promotionId}promotions.get
Promotion detail: conditions, dates, remaining stock cap, eligible products — guests allowed, without prices
guest or sessionRA · RW · DAV1
GET/packspacks.list
Packs available to the caller (V2) — guests allowed, without prices
guest or sessionRA · RWV2
GET/packs/{packId}packs.get
Pack detail (V2) — guests allowed, without prices
guest or sessionRA · RWV2

Every operation can also answer 426 UPGRADE_REQUIRED, 429 RATE_LIMITED, 500 INTERNAL_ERROR and 503 MAINTENANCE; with a session also 401 UNAUTHENTICATED and 403 ACCOUNT_SUSPENDED — see the error registry.

Reference screen 7 — daily offer with countdown, profitable packs (V2), loyalty points and level (V2), rewards (V2).
Reference screen 7 — daily offer with countdown, profitable packs (V2), loyalty points and level (V2), rewards (V2). — client reference (cahier des charges)

Who sees what

CallerPromotions and banners returnedAmounts
GuestActive items whose audience is every resellerprice: null; value hidden (null) for AMOUNT_OFF and FIXED_PRICE; percentages shown (« -30 % »)
ResellerActive items whose audience matches the reseller (wilaya, segment, customer type, volume rules)Prices for the reseller's customer type
Delegate (promotions.* only)With resellerId: what that reseller sees, with their prices. Without: promotions open to all resellers or targeting a wilaya of the delegate's zones, without pricesAs for the reseller, or none

Active means status ACTIVE, startsAt ≤ now < endsAt, cap not reached — the engine re-checks the dates itself (promotion lifecycle).

Schemas

interface Banner {
  id: Uuid;
  placement: "HOME_CAROUSEL" | "CATALOG_TOP";
  eyebrow: string | null;             // "OFFRE DU JOUR"
  title: string;
  subtitle: string | null;
  imageUrl: string;                   // public CDN, 1200 × 600 WebP (mobile crops to 2:1)
  imageAlt: string;
  theme: "DARK" | "LIGHT";            // text colour over the image
  cta: { label: string; target: BannerTarget } | null;
  countdownEndsAt: Iso | null;        // « Se termine dans 12 h 45 m 30 s »
  startsAt: Iso;
  endsAt: Iso | null;
  sortOrder: number;
}

type BannerTarget =
  | { type: "PROMOTION"; promotionId: Uuid }
  | { type: "PRODUCT"; productId: Uuid }
  | { type: "CATEGORY"; categoryId: Uuid }
  | { type: "BRAND"; brandId: Uuid }
  | { type: "PACK"; packId: Uuid }      // V2
  | { type: "URL"; url: string };       // https only, hoco.dz domains

interface PromotionSummary {
  id: Uuid;
  label: string;                      // "Offre flash -30 %"
  description: string | null;
  type: "PERCENT_OFF" | "AMOUNT_OFF" | "FIXED_PRICE" | "FREE_DELIVERY";
  value: number | null;               // PERCENT_OFF: basis points · AMOUNT_OFF: HT centimes off per unit ·
                                      // FIXED_PRICE: unit price HT · FREE_DELIVERY: null · null for guests on AMOUNT_OFF / FIXED_PRICE
  badge: string;                      // ready-to-show: "-30 %", "Prix spécial", "Livraison offerte"
  isDailyOffer: boolean;
  startsAt: Iso;
  endsAt: Iso;
  imageUrl: string | null;
  scope: { kind: "ALL" | "PRODUCTS" | "CATEGORIES" | "BRANDS" | "MIXED"; summary: string; productCount: number };
  conditions: { minQtyPerLine: number | null; minOrderAmountTtc: Money | null };
  capStatus: "NONE" | "AVAILABLE" | "ALMOST_GONE";   // ALMOST_GONE from 80 % of the cap consumed
  stackable: boolean;                 // combinable with other promotions (PRM-03)
}

interface PromotionDetail extends PromotionSummary {
  terms: string[];                    // conditions in plain language, shown as a list
  eligibleProducts: { items: ProductCard[]; nextCursor: string | null };
}

interface PackSummary {               // V2
  id: Uuid;
  name: string;                       // "Pack Charge & Câble"
  description: string;                // "Chargeur rapide HOCO + Câble USB-C"
  imageUrl: string;
  price: Price | null;                // pack price for the caller's customer type; null for guests
  itemsValueTtc: Money | null;        // the items at the caller's unit prices
  savingTtc: Money | null;
  savingRate: BasisPoints;            // « Économisez 20 % » — shown to guests too
  availability: "IN_STOCK" | "OUT_OF_STOCK";   // OUT_OF_STOCK when any item is
  maxPacksPerOrder: number | null;
  endsAt: Iso | null;
}

interface PackDetail extends PackSummary {
  items: { product: ProductCard; variantId: Uuid; sku: string; variantLabel: string; qty: number }[];
  terms: string[];
}

BannerPlacement (HOME_CAROUSEL, CATALOG_TOP), BannerTarget.type and capStatus are not yet in enums.json (to add).

Operations

GET /banners

banners.list · Access optional — guest or reseller · Apps RA, RW · Idempotency-Key — · Release V1 · Requirements PRM-05, PRM-02

Purpose. The active banners of one placement for the caller, in display order — the home carousel (also embedded in catalog.home) and the strip on top of the catalog.

Request

QueryTypeRequiredNotes
placementHOME_CAROUSEL | CATALOG_TOPyes
GET /v1/banners?placement=CATALOG_TOP

Response — 200 OK, Cache-Control: private, max-age=60: { items: Banner[] }, at most 6, not paginated.

{
  "items": [
    {
      "id": "01a19d02-aa40-73d1-8f56-e60bbab760fc",
      "placement": "CATALOG_TOP",
      "eyebrow": "OFFRE FLASH",
      "title": "Jusqu'à -30 % sur une sélection HOCO",
      "subtitle": "Aujourd'hui seulement",
      "imageUrl": "https://cdn.hoco.dz/banners/2026/11/flash-hoco-30-strip.webp",
      "imageAlt": "Chargeur, câble et écouteurs HOCO avec le badge -30 %",
      "theme": "DARK",
      "cta": { "label": "Voir l'offre", "target": { "type": "PROMOTION", "promotionId": "01a19cfd-2c00-78b5-80c8-b4b9fb167f17" } },
      "countdownEndsAt": "2026-11-03T22:59:59Z",
      "startsAt": "2026-11-03T07:00:00Z",
      "endsAt": "2026-11-03T22:59:59Z",
      "sortOrder": 1
    }
  ]
}

Errors

StatusCodeWhen
400VALIDATION_FAILEDplacement missing or unknown.

Rules & side effects

  1. A banner is returned when it is active (dates, not paused, never a DRAFT), targets the caller, and its linked promotion (if any) is active — a banner of an ended or paused promotion disappears at once (lifecycle). Targeting (SRV-42): wilayas, segments, customer types and named resellers, kinds ANDed and values ORed; a guest gets the banners marked for guests (audience.guests).
  2. Images are public CDN files managed in BO-51 (admin.banners.crud); the client prefetches them. A mobile app (X-App-Platform android or ios) gets the banner's mobile image (imageMobile) when it has one.
  3. Countdowns run on countdownEndsAt minus the server time (catalog.home → serverTime, or the Date response header). countdownEndsAt is set when the banner has countdown on (by default, a banner of a daily offer).

Used by — carousel of RA-09 and RW-02 (through catalog.home), catalog strip of RA-12 and RW-03, top of RA-24.

GET /promotions

promotions.list · Access optional — guest, reseller, or delegate (resellerId optional) · Apps RA, RW, DA · Idempotency-Key — · Release V1 · Requirements PRM-01, PRM-02

Contract 1.1.0 (SRV-41): brandId (repeatable) keeps the offers that apply to at least one product of these brands visible to the caller (an ALL scope counts).

Purpose. « Promotions » and « Offres du jour »: the promotions active for the caller, daily offers first, then by end date.

Request

QueryTypeRequiredDefaultNotes
dailyOnlybooleannofalseOnly isDailyOffer promotions (the « Offres du jour » carousel)
typePromotionType, repeatableno—
resellerIdUuidno—Delegates only; scope-checked
cursor, limit—nolimit 20Max 100

Response — 200 OK, Cache-Control: private, max-age=60: { items: PromotionSummary[], nextCursor }.

{
  "items": [
    {
      "id": "01a19cfd-2c00-78b5-80c8-b4b9fb167f17",
      "label": "Offre flash -30 %",
      "description": "Jusqu'à -30 % sur une sélection de produits HOCO, aujourd'hui seulement.",
      "type": "PERCENT_OFF",
      "value": 3000,
      "badge": "-30 %",
      "isDailyOffer": true,
      "startsAt": "2026-11-03T07:00:00Z",
      "endsAt": "2026-11-03T22:59:59Z",
      "imageUrl": "https://cdn.hoco.dz/promotions/2026/11/flash-hoco-30.webp",
      "scope": { "kind": "PRODUCTS", "summary": "6 produits HOCO", "productCount": 6 },
      "conditions": { "minQtyPerLine": null, "minOrderAmountTtc": null },
      "capStatus": "AVAILABLE",
      "stackable": false
    },
    {
      "id": "01a17249-c680-746a-84fd-f70a4efea668",
      "label": "-10 % sur les câbles ACEFAST",
      "description": "Tous les câbles ACEFAST à -10 %, dès 10 pièces par référence.",
      "type": "PERCENT_OFF",
      "value": 1000,
      "badge": "-10 %",
      "isDailyOffer": false,
      "startsAt": "2026-10-25T23:00:00Z",
      "endsAt": "2026-11-15T22:59:59Z",
      "imageUrl": "https://cdn.hoco.dz/promotions/2026/10/acefast-cables.webp",
      "scope": { "kind": "MIXED", "summary": "Câbles ACEFAST", "productCount": 14 },
      "conditions": { "minQtyPerLine": 10, "minOrderAmountTtc": null },
      "capStatus": "NONE",
      "stackable": false
    },
    {
      "id": "01a181bc-da80-7da6-9f6e-161582e00776",
      "label": "Z36 à 1 880 DA",
      "description": "Le chargeur voiture HOCO Z36 38W à prix spécial, dans la limite du stock promotionnel.",
      "type": "FIXED_PRICE",
      "value": 157983,
      "badge": "Prix spécial",
      "isDailyOffer": false,
      "startsAt": "2026-10-28T08:00:00Z",
      "endsAt": "2026-11-10T22:59:59Z",
      "imageUrl": "https://cdn.hoco.dz/promotions/2026/10/z36-prix-special.webp",
      "scope": { "kind": "PRODUCTS", "summary": "HOCO Z36 Chargeur voiture 38W", "productCount": 1 },
      "conditions": { "minQtyPerLine": null, "minOrderAmountTtc": null },
      "capStatus": "ALMOST_GONE",
      "stackable": false
    }
  ],
  "nextCursor": null
}

For a guest, the Z36 item comes back with "value": null (a fixed price is a price) while the two percentages stay visible.

FieldNotes
valueInterpreted with type; FIXED_PRICE and AMOUNT_OFF are HT amounts like every stored price — the product cards carry the resulting TTC price (ProductCard.promotion.price).
scope.summaryHuman summary written by the back-office (« 6 produits HOCO »); the products themselves come from promotions.get.
capStatusALMOST_GONE shows « Bientôt épuisée »; a promotion whose cap is reached is ENDED and no longer listed.
conditions.minQtyPerLineThe cart applies the promotion only to lines reaching this quantity.

Errors

StatusCodeWhen
403OUT_OF_SCOPEDelegate's resellerId outside scope.

Rules & side effects — read-only; delegates use the list to record « promotions présentées » in the visit report (delegate.visits.report).

Used by — RA-24 (« Promotions »), RW-10, visit report DA-12, DA-17.

GET /promotions/{promotionId}

promotions.get · Access optional — guest, reseller, or delegate (resellerId optional) · Apps RA, RW, DA · Idempotency-Key — · Release V1 · Requirements PRM-01, PRM-04

Purpose. « Détail de l'offre »: conditions, dates, cap status and the eligible products (as product cards, with the promotional price for the caller).

Request

Path / queryTypeRequiredNotes
promotionIdUuidyes
cursor, limit—noPaging of eligibleProducts (limit default 20, max 100)
resellerIdUuidnoDelegates only

Response — 200 OK: a PromotionDetail.

{
  "id": "01a19cfd-2c00-78b5-80c8-b4b9fb167f17",
  "label": "Offre flash -30 %",
  "description": "Jusqu'à -30 % sur une sélection de produits HOCO, aujourd'hui seulement.",
  "type": "PERCENT_OFF",
  "value": 3000,
  "badge": "-30 %",
  "isDailyOffer": true,
  "startsAt": "2026-11-03T07:00:00Z",
  "endsAt": "2026-11-03T22:59:59Z",
  "imageUrl": "https://cdn.hoco.dz/promotions/2026/11/flash-hoco-30.webp",
  "scope": { "kind": "PRODUCTS", "summary": "6 produits HOCO", "productCount": 6 },
  "conditions": { "minQtyPerLine": null, "minOrderAmountTtc": null },
  "capStatus": "AVAILABLE",
  "stackable": false,
  "terms": [
    "Remise de 30 % sur le prix revendeur des produits listés.",
    "Valable jusqu'à 23h59 aujourd'hui, dans la limite du stock promotionnel.",
    "Non cumulable avec une autre promotion."
  ],
  "eligibleProducts": {
    "items": [
      {
        "id": "01a15889-fa80-7ff3-b294-f863a2ee34a6",
        "name": "HOCO J86A Power Bank 10000mAh",
        "brand": { "id": "01a05bfb-7000-73a7-ac3c-c71515d5e3b3", "name": "HOCO" },
        "category": { "id": "01a05c04-ab48-7b23-9612-4a7450cd39ef", "name": "Power banks", "parentId": null },
        "imageUrl": "https://cdn.hoco.dz/products/j86a/j86a-black-1-480.webp",
        "defaultVariantId": "01a15889-fe68-733d-8056-75eec8b226f5",
        "price": { "ht": 302521, "ttc": 360000, "vatRate": 1900 },
        "priceLocked": false,
        "recommendedPrice": 450000,
        "availability": "IN_STOCK",
        "promotion": { "id": "01a19cfd-2c00-78b5-80c8-b4b9fb167f17", "label": "Offre flash -30 %", "price": { "ht": 211765, "ttc": 252000, "vatRate": 1900 } },
        "isNew": true,
        "isFavorite": false
      },
      {
        "id": "01a094d8-5280-7779-b2fc-bf0e216609a3",
        "name": "HOCO EW41 Écouteurs TWS",
        "brand": { "id": "01a05bfb-7000-73a7-ac3c-c71515d5e3b3", "name": "HOCO" },
        "category": { "id": "01a05c04-a760-7afa-a91b-ad281947800e", "name": "Écouteurs", "parentId": null },
        "imageUrl": "https://cdn.hoco.dz/products/ew41/ew41-white-1-480.webp",
        "defaultVariantId": "01a094d8-5668-7b74-a958-fc54830e96a2",
        "price": { "ht": 579832, "ttc": 690000, "vatRate": 1900 },
        "priceLocked": false,
        "recommendedPrice": 850000,
        "availability": "IN_STOCK",
        "promotion": { "id": "01a19cfd-2c00-78b5-80c8-b4b9fb167f17", "label": "Offre flash -30 %", "price": { "ht": 405882, "ttc": 483000, "vatRate": 1900 } },
        "isNew": false,
        "isFavorite": false
      }
    ],
    "nextCursor": "eyJpIjoiMDFhMDk0ZDgifQ"
  }
}

Errors

StatusCodeWhen
403OUT_OF_SCOPEDelegate's resellerId outside scope.
404NOT_FOUNDUnknown, not active, or not targeting the caller (a guest asking for a targeted promotion gets 404 too).

Rules & side effects — eligible products follow the catalog rules (visibility, availability, no quantity); out-of-stock products are listed after the others. « Ajouter » on a card calls cart.items.add; the promotion then appears on the cart line.

Used by — RA-25 (« Détail de l'offre »), RW-10, DA-17; banner and daily-offer taps.

GET /packs

packs.list · Access optional — guest or reseller · Apps RA, RW · Idempotency-Key — · Release V2 · Requirements PRM-06

Purpose. « Packs rentables » (reference screen 7): bundles of several references at a pack price, added to the cart as a unit (cart.packs.add). Specified with the V2 contract (SRV-29); baseline below.

Request — cursor, limit (default 20, max 100).

Response — 200 OK: { items: PackSummary[], nextCursor }.

{
  "items": [
    {
      "id": "01a49fbf-a000-7f4e-99b1-a4afd2a3a603",
      "name": "Pack Charge & Câble",
      "description": "Chargeur rapide HOCO N32 + Câble USB-C X89",
      "imageUrl": "https://cdn.hoco.dz/packs/charge-cable.webp",
      "price": { "ht": 1588235, "ttc": 1890000, "vatRate": 1900 },
      "itemsValueTtc": 2369000,
      "savingTtc": 479000,
      "savingRate": 2022,
      "availability": "IN_STOCK",
      "maxPacksPerOrder": 5,
      "endsAt": null
    },
    {
      "id": "01a49fbf-a3e8-7f5f-8e92-6670b3d624d4",
      "name": "Pack Audio HOCO",
      "description": "Écouteurs TWS HOCO + Étui de protection",
      "imageUrl": "https://cdn.hoco.dz/packs/audio.webp",
      "price": { "ht": 1344538, "ttc": 1600000, "vatRate": 1900 },
      "itemsValueTtc": 1880000,
      "savingTtc": 280000,
      "savingRate": 1489,
      "availability": "IN_STOCK",
      "maxPacksPerOrder": 5,
      "endsAt": "2027-06-30T22:59:59Z"
    },
    {
      "id": "01a49fbf-a7d0-7e57-8d53-52398557acea",
      "name": "Pack Voiture HOCO",
      "description": "Support voiture HOCO + Chargeur voiture Z36",
      "imageUrl": "https://cdn.hoco.dz/packs/voiture.webp",
      "price": { "ht": 1252101, "ttc": 1490000, "vatRate": 1900 },
      "itemsValueTtc": 1817000,
      "savingTtc": 327000,
      "savingRate": 1800,
      "availability": "OUT_OF_STOCK",
      "maxPacksPerOrder": 3,
      "endsAt": null
    }
  ],
  "nextCursor": null
}

Guests receive the same packs (those open to all resellers) with price, itemsValueTtc and savingTtc set to null; savingRate stays (« Économisez 20 % »).

Errors

StatusCodeWhen
403FEATURE_DISABLEDPacks are switched off (packs.enabled = false, details.feature = "packs").

Rules & side effects — assumption (V2): a pack has one price per customer type, like a variant; itemsValueTtc uses the caller's unit prices, so the saving shown is the caller's real saving. Targeting and visibility as for promotions; a pack is OUT_OF_STOCK as soon as one item is.

Used by — RA-37, RW-15.

GET /packs/{packId}

packs.get · Access optional — guest or reseller · Apps RA, RW · Idempotency-Key — · Release V2 · Requirements PRM-06

Purpose. A pack with its items and quantities.

Request — path packId.

Response — 200 OK: a PackDetail.

{
  "id": "01a49fbf-a000-7f4e-99b1-a4afd2a3a603",
  "name": "Pack Charge & Câble",
  "description": "Chargeur rapide HOCO N32 + Câble USB-C X89",
  "imageUrl": "https://cdn.hoco.dz/packs/charge-cable.webp",
  "price": { "ht": 1588235, "ttc": 1890000, "vatRate": 1900 },
  "itemsValueTtc": 2369000,
  "savingTtc": 479000,
  "savingRate": 2022,
  "availability": "IN_STOCK",
  "maxPacksPerOrder": 5,
  "endsAt": null,
  "items": [
    {
      "product": {
        "id": "01a08ac2-8900-7f6d-937c-c81b37e89a5b",
        "name": "HOCO N32 Chargeur rapide 30W (USB-C + USB-A)",
        "brand": { "id": "01a05bfb-7000-73a7-ac3c-c71515d5e3b3", "name": "HOCO" },
        "category": { "id": "01a05c04-9ba8-779f-8030-3262210b2afb", "name": "Chargeurs muraux", "parentId": "01a05c04-97c0-76c5-9c89-9cf30f53d5b0" },
        "imageUrl": "https://cdn.hoco.dz/products/n32/n32-black-1-480.webp",
        "defaultVariantId": "01a08ac2-8ce8-7069-8328-28fd7158a572",
        "price": { "ht": 209244, "ttc": 249000, "vatRate": 1900 },
        "priceLocked": false,
        "recommendedPrice": 320000,
        "availability": "IN_STOCK",
        "isNew": false,
        "isFavorite": true
      },
      "variantId": "01a08ac2-8ce8-7069-8328-28fd7158a572",
      "sku": "N32_BLACK_EU",
      "variantLabel": "Noir",
      "qty": 6
    },
    {
      "product": {
        "id": "01a08ac7-1ce0-7b52-8b6a-3ec2aaccb8fb",
        "name": "HOCO X89 Câble USB-C",
        "brand": { "id": "01a05bfb-7000-73a7-ac3c-c71515d5e3b3", "name": "HOCO" },
        "category": { "id": "01a05c04-a378-7a15-a596-11824871a56b", "name": "Câbles", "parentId": null },
        "imageUrl": "https://cdn.hoco.dz/products/x89/x89-black-1-480.webp",
        "defaultVariantId": "01a08ac7-20c8-70bf-b753-d181dfe71ff6",
        "price": { "ht": 105042, "ttc": 125000, "vatRate": 1900 },
        "priceLocked": false,
        "recommendedPrice": 160000,
        "availability": "IN_STOCK",
        "isNew": false,
        "isFavorite": true
      },
      "variantId": "01a08ac7-20c8-70bf-b753-d181dfe71ff6",
      "sku": "X89_BLACK_1M",
      "variantLabel": "Noir · 1 m",
      "qty": 7
    }
  ],
  "terms": [
    "6 chargeurs HOCO N32 noirs et 7 câbles HOCO X89 noirs (1 m) au prix du pack.",
    "Non cumulable avec les promotions en cours sur ces produits.",
    "5 packs maximum par commande."
  ]
}

Errors

StatusCodeWhen
403FEATURE_DISABLEDPacks switched off.
404NOT_FOUNDUnknown, inactive, or not targeting the caller.

Rules & side effects — items are fixed (no substitution in V1 of packs); itemsValueTtc = 6 × 2 490,00 + 7 × 1 250,00 = 23 690,00 DA for a Demi-gros reseller, saving 4 790,00 DA.

Used by — pack detail of RA-37 and RW-15.

On this page