HOCO B2B
SRSAPI referenceBack-office endpoints

Administration, settings & audit

Back-office administration — users, sessions, roles and permissions with guard rails, the activity journal, business settings, reference lists, app versions, support regions, data imports and global search.

These operations administer the platform (cahier §3.1, §8, §10, §13.2): staff users and their roles (BO-61), the roles × permissions matrix (BO-62), the activity journal (BO-63), business settings (BO-64), reference lists (BO-65), mobile app versions (BO-66), data imports (BO-67), support regions and WhatsApp numbers (BO-70) and the global search of the app shell (BO-03). Authorisation model: permissions matrix.

Who uses it. The Super administrateur (cahier §3: « paramétrage global, rôles, permissions et audit »); managers holding users.* for their teams.

PermissionUnlocks on this page
users.view · users.create · users.update · users.administerUsers read · create · edit, status, password reset · sessions
roles.view · roles.administerRoles and permission catalogue · editing permission sets
audit.view · audit.exportActivity journal · its export
settings.view · settings.administerSettings, reference lists, app versions, support regions (read) · their changes and data imports

Re-authentication for sensitive actions (roles, user status, settings) is an open decision (auth.reauthMinutes, default 15 min): when enabled, such calls answer 403 REAUTH_REQUIRED if the session's last password entry is older — see the decision register.

Audit. Everything here is journaled: CREATE/UPDATE/STATUS_CHANGE on users, PERMISSION_CHANGE on roles and user roles, UPDATE per setting key (before/after), IMPORT on apply, LOGOUT for revoked sessions.

MethodPathOperationAccessAppsRelease
GET/admin/usersadmin.users.list
Staff and delegate users
users.viewBOV1
POST/admin/usersadmin.users.create
Create a user with roles (invitation SMS/email with temporary password)
users.createBOV1
GET/admin/users/{userId}admin.users.get
A staff or delegate user (detail page, global search)
users.viewBOV1
PATCH/admin/users/{userId}admin.users.update
Edit user, roles
users.updateBOV1
POST/admin/users/{userId}/statusadmin.users.setStatus
Suspend, reactivate or disable (sessions revoked; history kept)
users.updateBOV1
POST/admin/users/{userId}/reset-passwordadmin.users.resetPassword
Send a reset code / temporary password
users.updateBOV1
GET · DELETE/admin/users/{userId}/sessions[/{sessionId}]admin.users.sessions
List or revoke a user's sessions
users.administerBOV1
GET/admin/staff/assignableadmin.staff.assignable
Active staff for assignee pickers (name and roles only)
crm.viewBOV1
GET/admin/rolesadmin.roles.list
Roles with their permissions
roles.viewBOV1
PUT/admin/roles/{roleKey}/permissionsadmin.roles.updatePermissions
Replace a role's permission set (super admin; system guard rails)
roles.administerBOV1
GET/admin/permissionsadmin.permissions.list
Permission catalogue (module × action)
roles.viewBOV1
GET/admin/audit-logsadmin.audit.list
Activity journal with filters (actor, action, entity, app, dates)
audit.viewBOV1
GET/admin/settingsadmin.settings.get
Business parameters grouped by domain
settings.viewBOV1
PATCH/admin/settingsadmin.settings.update
Update parameters (validated, audited)
settings.administerBOV1
GET · POST · PATCH/admin/reference-lists/{listKey}[/{itemId}]admin.referenceLists.crud
Edit reference list items (deactivate, never delete in use)
settings.administerBOV1
GET · PUT/admin/app-versions[/{app}/{platform}]admin.appVersions.crud
Version policy per app and platform; maintenance mode
settings.administerBOV1
GET · POST · PATCH · DELETE/admin/support-regions[/{regionId}]admin.supportRegions.crud
Support regions: wilayas covered, WhatsApp number, hours
settings.administerBOV1
POST/admin/imports/{type}admin.imports.create
Import resellers, users or stock from Excel/CSV (dry-run then apply)
settings.administerBOV1
GET/admin/imports/{importId}admin.imports.get
Import job status and row-level report
settings.administerBOV1
GET/admin/importsadmin.imports.list
Import history (jobs without their row report), newest first
settings.administerBOV1
GET/admin/imports/{type}/templateadmin.imports.template
Download the template of an import type (XLSX or CSV with the expected columns)
settings.administerBOV1
GET/admin/searchadmin.search
Global search across resellers, orders, products, invoices (permission-filtered)
anyBOV1

Schemas

AuditLog

interface AuditLog {
  id: Uuid;
  at: Iso;
  actor: UserSummary | null;          // null = SYSTEM (jobs)
  actorRoles: string[];               // RoleKey[] at the time
  app: ClientApp;                     // DASHBOARD | RESELLER_APP | RESELLER_WEB | DELEGATE_APP | SYSTEM
  action: AuditAction;                // LOGIN … OVERRIDE
  entityType: string;                 // Prisma model name: "Order", "Reseller", "Setting"…
  entityId: Uuid | null;
  entityLabel?: string;               // "CMD-2026-000158", "stock.deductOn"
  summary: string;                    // French sentence built server-side
  changes?: { field: string; before: unknown; after: unknown }[];   // secrets never logged; purchase prices masked without pricing.view
  reason?: string;
  context: { ip: string; userAgent: string; requestId: string; sessionId?: Uuid; deviceId?: string };
}

ImportJob

interface ImportJob {
  id: Uuid;
  type: "PRODUCTS" | "RESELLERS" | "USERS" | "STOCK";   // ImportType
  mode: "DRY_RUN" | "APPLY";                           // ImportMode
  status: JobStatus;
  file: FileRef;                                        // IMPORT_FILE: XLSX (first sheet) or CSV UTF-8, ≤ 10 MB
  options: Record<string, unknown>;
  dryRunId?: Uuid;
  summary?: { totalRows: number; validRows: number; warningRows: number; errorRows: number; toCreate: number; toUpdate: number; unchanged: number; applied?: number; skipped?: number };
  rows?: { items: { row: number; status: "VALID" | "WARNING" | "ERROR" | "APPLIED" | "SKIPPED"; action: "CREATE" | "UPDATE" | "UNCHANGED"; key: string; messages: { column: string; code: string; message: string }[] }[]; total: number; page: number; pageSize: number };
  createdBy: UserSummary; createdAt: Iso; finishedAt?: Iso;
  expiresAt?: Iso;                                      // dry runs: + 24 h
}

Flow: POST { fileId, mode: "DRY_RUN" } → 202 → poll admin.imports.get → POST { mode: "APPLY", dryRunId } → applies VALID and WARNING rows, re-validated (rows invalid by then become SKIPPED).

Users

GET /admin/users

admin.users.list · Permission users.view · Apps BO · Release V1 · Requirements ADM-01

Purpose. Staff and delegate users (reseller logins are managed from the CRM).

Request — type[] (STAFF, DELEGATE), role[] (RoleKey), status[] (AccountStatus), q (name, email, phone), sort (lastName, lastSignInAt, createdAt), page / pageSize.

Response 200 OK

{
  "items": [
    { "id": "01929e55-2c3d-7e4f-9a1b-2c3d4e5f6a7b", "type": "STAFF", "firstName": "Nadia", "lastName": "Belkacem", "displayName": "Nadia Belkacem", "email": "n.belkacem@hoco.dz", "phone": "+213661001122", "roles": ["COMMERCIAL_ADMIN"], "status": "ACTIVE", "locale": "fr", "mustChangePassword": false, "lastSignInAt": "2026-11-04T07:31:00Z", "activeSessions": 2, "createdAt": "2026-10-20T09:00:00Z", "version": 3 }
  ],
  "total": 19, "page": 1, "pageSize": 25
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks users.view

Rules & side effects

  1. Read-only. There is no single-user GET in endpoints.json; the list row carries every field of the edit drawer (gap noted).

Used by BO-61

POST /admin/users

admin.users.create · Permission users.create · Apps BO · Release V1 · Requirements ADM-01

Purpose. Creates a staff user with roles; a temporary password is sent by email or SMS.

Request

{ "firstName": "Walid", "lastName": "Rahmani", "email": "w.rahmani@hoco.dz", "phone": "0550 44 55 66", "roles": ["STOCK_MANAGER"], "locale": "fr", "sendInvitation": "EMAIL" }

Response 201 Created — the user (status ACTIVE, mustChangePassword: true). The password is never returned.

Errors

StatusCodeWhen
400VALIDATION_FAILEDNo role, staff without email, unknown role
403PERMISSION_DENIEDCaller lacks users.create
403PERMISSION_ESCALATIONA role grants permissions the caller does not hold — details: { permissions }
409EMAIL_ALREADY_EXISTS · PHONE_ALREADY_EXISTSLogin taken
422DELEGATE_PROFILE_REQUIREDRole DELEGATE — use admin.delegates.crud

Rules & side effects

  1. Audit CREATE + PERMISSION_CHANGE. Notification user.invited (email for staff).

Used by BO-61

GET /admin/users/{userId}

admin.users.get · Permission users.view · Apps BO · Release V1 · Requirements ADM-01 · Added in contract 1.1.0 (SRV-41)

Purpose. One staff or delegate user — the user detail page that the users list and the global search link to.

Response 200 OK — the user, same shape as an item of admin.users.list:

{ "id": "0192f0a1-…", "type": "STAFF", "firstName": "Walid", "lastName": "Rahmani", "displayName": "Walid Rahmani", "email": "w.rahmani@hoco.dz", "phone": "+213550445566", "roles": ["STOCK_MANAGER"], "status": "ACTIVE", "locale": "fr", "mustChangePassword": false, "lastSignInAt": "2026-10-19T08:12:00Z", "activeSessions": 2, "createdAt": "2026-09-01T09:00:00Z", "version": 1760860000000 }

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks users.view
404NOT_FOUNDUnknown id, or a reseller account (managed from the CRM)

Used by BO-61, global search

PATCH /admin/users/{userId}

admin.users.update · Permission users.update · Apps BO · Release V1 · Requirements ADM-01

Purpose. Edits a user and their roles. Request — { firstName?, lastName?, email?, phone?, roles?, locale?, version }. Response 200 OK — the user.

Errors

StatusCodeWhen
403PERMISSION_ESCALATIONGranting a role with permissions the caller lacks
403SELF_MODIFICATION_FORBIDDENChanging one's own roles
404NOT_FOUNDUnknown user
409LAST_SUPER_ADMINRemoving SUPER_ADMIN from the last active super administrator
409EMAIL_ALREADY_EXISTS · PHONE_ALREADY_EXISTS · VERSION_CONFLICT

Rules & side effects

  1. Role changes apply at the next request (permission cache evicted); SSE me.permissions_changed to the user. Audit PERMISSION_CHANGE.

Used by BO-61

POST /admin/users/{userId}/status

admin.users.setStatus · Permission users.update · Apps BO · Release V1 · Requirements ADM-01 · SEC-06

Purpose. Suspends, reactivates or disables an account without deleting its history (cahier §10).

Request — { "status": "SUSPENDED", "reason": "Départ de l'entreprise — accès coupé en attendant la clôture.", "version": 3 }.

Response 200 OK — the user with status, statusReason, revokedSessions: 2.

Errors

StatusCodeWhen
403SELF_MODIFICATION_FORBIDDENActing on oneself
409LAST_SUPER_ADMINLast active super administrator
409DELEGATE_HAS_OPEN_TOURSDisabling a delegate with open tours
409USER_TRANSITION_NOT_ALLOWEDDISABLED → anything (terminal)
422REASON_REQUIREDEmpty reason

Rules & side effects

  1. Transitions of AccountStatus: sessions revoked and push tokens removed on SUSPENDED/DISABLED; a delegate's tour IN_PROGRESS is suspended. Audit STATUS_CHANGE. Notification account.suspended (SMS + in-app).

Used by BO-61

POST /admin/users/{userId}/reset-password

admin.users.resetPassword · Permission users.update · Apps BO · Release V1 · Requirements ADM-01

Purpose. Sends a temporary password (change forced at next sign-in). Request — { "channel": "SMS", "revokeSessions": true }. Response 200 OK — { "sentTo": "+213 55• •• •5 66", "revokedSessions": 1 }.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown user
429RATE_LIMITEDMore than 3 resets per hour for the user

Rules & side effects

  1. Audit UPDATE (no secret logged). Notification security.password_changed.

Used by BO-61

GET /admin/users/{userId}/sessions

admin.users.sessions (list) · Permission users.administer · Apps BO · Release V1 · Requirements AUTH-06

Purpose. A user's active sessions. Response 200 OK — { "items": [{ "id": "01931f00-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "app": "DASHBOARD", "deviceLabel": "Chrome 130 · Windows", "ip": "41.111.22.33", "createdAt": "2026-11-01T07:30:00Z", "lastActivityAt": "2026-11-04T10:02:00Z", "expiresAt": "2026-11-11T10:02:00Z" }] }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks users.administer

Rules & side effects

  1. Read-only.

Used by BO-61

DELETE /admin/users/{userId}/sessions/{sessionId}

admin.users.sessions (revoke one) · Permission users.administer · Apps BO · Release V1 · Requirements AUTH-06

Purpose. Revokes one session. Response 204 No Content.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown session

Rules & side effects

  1. The device gets 401 UNAUTHENTICATED at its next call. Audit LOGOUT (actor = admin).

Used by BO-61

DELETE /admin/users/{userId}/sessions

admin.users.sessions (revoke all) · Permission users.administer · Apps BO · Release V1 · Requirements AUTH-06

Purpose. Revokes every session of the user. Response 200 OK — { "revoked": 3 }.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown user

Rules & side effects

  1. Audit LOGOUT; push tokens removed.

Used by BO-61

GET /admin/staff/assignable

admin.staff.assignable · Permission crm.view or support.view · Apps BO · Release V1 · Requirements ADM-01 · Added in contract 1.1.0 (SRV-41)

Purpose. The active staff for the assignee pickers of CRM tasks and tickets, without users.view: only the name and the roles (no e-mail, phone, status or sessions).

Request — q (name contains), role (RoleKey[], repeatable).

Response 200 OK — { "items": [ { "id": "01929e77-…", "displayName": "Lamia Kaci", "roles": ["COMMERCIAL_ADMIN"] } ] }, sorted by name, at most 500.

Errors

StatusCodeWhen
403PERMISSION_DENIEDNeither crm.view nor support.view

Used by BO-14 · BO-55 · BO-56

Roles and permissions

GET /admin/roles

admin.roles.list · Permission roles.view · Apps BO · Release V1 · Requirements ADM-02

Purpose. The eight system roles with their permission sets. Response 200 OK — { "items": [{ "key": "FINANCE_MANAGER", "permissions": ["dashboard.view", "finance.view", "finance.create", "finance.update", "finance.validate", "finance.export", "finance.administer", "reports.view", "reports.export", "crm.view", "orders.view"], "userCount": 2, "editable": true }, { "key": "SUPER_ADMIN", "permissions": ["*"], "userCount": 1, "editable": false }] }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks roles.view

Rules & side effects

  1. Read-only; defaults are the role × permission matrix.

Used by BO-62

PUT /admin/roles/{roleKey}/permissions

admin.roles.updatePermissions · Permission roles.administer · Apps BO · Release V1 · Requirements ADM-02 · ACL-02

Purpose. Replaces a role's permission set (cahier §3.1).

Request — { "permissions": ["dashboard.view", "orders.view", "orders.validate", "delivery.view", "delivery.update"], "reason": "Le responsable livraison confirme aussi les commandes en V1.", "version": 4 }.

Response 200 OK — the role with the stored set (implied .view keys added) and affectedUsers.

Errors

StatusCodeWhen
400VALIDATION_FAILEDUnknown permission key
403PERMISSION_ESCALATIONGranting a key the caller does not hold — details: { permissions }
409ROLE_PROTECTEDSUPER_ADMIN (always everything), DELEGATE and RESELLER (scope-based roles)
409VERSION_CONFLICTStale version

Rules & side effects

  1. Guard rails of the permissions matrix: any non-view action implies the module's .view; roles.administer always remains with SUPER_ADMIN.
  2. Audit PERMISSION_CHANGE with added/removed keys and reason; SSE me.permissions_changed to the role's connected users.

Used by BO-62

GET /admin/permissions

admin.permissions.list · Permission roles.view · Apps BO · Release V1 · Requirements ACL-02

Purpose. The permission catalogue (module × action). Response 200 OK — { "items": [{ "key": "pricing.view", "module": "pricing", "action": "VIEW", "sensitive": true }, { "key": "orders.validate", "module": "orders", "action": "VALIDATE", "sensitive": false, "implies": ["orders.view"] }] } — the valid keys are those of the catalogue.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks roles.view

Rules & side effects

  1. Read-only.

Used by BO-62

Activity journal

GET /admin/audit-logs

admin.audit.list · Permission audit.view · Apps BO · Release V1 · Requirements AUD-01 · AUD-03

Purpose. The activity journal of cahier §10 (« connexions, créations, modifications, validations, exports et suppressions »).

Request — actorId[], action[] (AuditAction), entityType[], entityId, app[] (ClientApp), from / to (timestamps), q (summary, entity label), page / pageSize (sorted by at desc).

Response 200 OK — Page<AuditLog>

{
  "items": [
    { "id": "01930171-5e6f-7a7b-8c8d-9e0f1a2b3c4d", "at": "2026-11-03T09:52:30Z", "actor": { "id": "01929e66-3d4e-7f5a-8b6c-7d8e9f0a1b2c", "displayName": "Sofiane Hamdi" }, "actorRoles": ["SUPER_ADMIN"], "app": "DASHBOARD", "action": "OVERRIDE", "entityType": "Order", "entityId": "0193016e-4b2a-7c11-9d8e-7f6a5b4c3d2e", "entityLabel": "CMD-2026-000158", "summary": "Dérogation stock à la validation de CMD-2026-000158", "changes": [{ "field": "controls.stock", "before": "INSUFFICIENT", "after": "OVERRIDDEN" }], "reason": "Réassort ACEFAST reçu demain matin.", "context": { "ip": "41.111.22.33", "userAgent": "Mozilla/5.0", "requestId": "req_01J9Z6B2C3", "sessionId": "01931f00-2b3c-7d4e-9f5a-6b7c8d9e0f1a" } }
  ],
  "total": 5821, "page": 1, "pageSize": 25
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks audit.view

Rules & side effects

  1. Read-only, append-only journal; retention per BR-84. Export with admin.exports.create (audit-logs, audit.export).

Used by BO-63

Settings

Settings keys

The binding list of keys, types, defaults and allowed values is the settings catalogue (orders, returns and after-sales, stock, catalog, pricing, credit, payments, billing, promotions, delivery, field, CRM, invitations, auth, support, notifications, exports, numbering, V2 loyalty). The API pages reference those keys verbatim. Keys these pages use that are not yet in the catalogue (proposed): orders.confirmationReminderHours (4 working hours, from the notifications matrix), stock.multiWarehouse, catalog.newProductDays, delivery.proofPhotoRequired, delivery.shippingSlaHours.

GET /admin/settings

admin.settings.get · Permission settings.view · Apps BO · Release V1 · Requirements ADM-03

Purpose. Business parameters grouped by domain.

Response 200 OK

{
  "groups": [
    { "domain": "stock", "settings": [
      { "key": "stock.reserveOn", "type": "ENUM", "value": "VALIDATED", "default": "VALIDATED", "allowed": ["SUBMITTED", "VALIDATED"], "public": false, "updatedAt": "2026-10-20T08:00:00Z", "updatedBy": null },
      { "key": "stock.deductOn", "type": "ENUM", "value": "SHIPPED", "default": "SHIPPED", "allowed": ["READY", "SHIPPED", "DELIVERED"], "public": false, "updatedAt": "2026-10-20T08:00:00Z", "updatedBy": null }
    ] }
  ],
  "version": 12
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks settings.view

Rules & side effects

  1. Read-only; public settings are also exposed to the apps through appConfig.get.

Used by BO-64

PATCH /admin/settings

admin.settings.update · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-03

Purpose. Updates one or several parameters, validated per key, all-or-nothing.

Request — { "values": { "credit.overLimitPolicy": "REQUIRE_APPROVAL", "returns.windowDays": 10 }, "reason": "Décision comité commercial du 2 novembre.", "version": 12 }.

Response 200 OK — the updated groups (version 13).

Errors

StatusCodeWhen
400VALIDATION_FAILEDUnknown key, wrong type or value outside the allowed range — details.fields[{ path: "returns.windowDays", code: "OUT_OF_RANGE" }]
403PERMISSION_DENIEDCaller lacks settings.administer
409VERSION_CONFLICTStale version

Rules & side effects

  1. Settings caches evicted; new values apply to events from now on (no retroactive stock movement or re-pricing). Changes of public settings reach the apps at their next appConfig.get; field settings through sync.delta.
  2. Audit one UPDATE row per key (before/after, reason).

Used by BO-64

Reference lists

Lists of ReferenceItem by listKey: BUSINESS_TYPE, PERSON_ROLE, VISIT_NOT_DONE_REASON, VISIT_ISSUE_TAG, TOUR_SUSPEND_REASON, ORDER_REFUSAL_REASON, ORDER_CANCEL_REASON, PAYMENT_REJECT_REASON. Item: { id, listKey, code (UPPER_SNAKE, immutable), labels: { fr, ar?, en? }, active, sortOrder, requiresComment, system (locked), usageCount, version }.

GET /admin/reference-lists/{listKey}

admin.referenceLists.crud (list) · Permission settings.view · Apps BO · Release V1 · Requirements ADM-05

Purpose. Items of a list, inactive ones included. Response 200 OK — { "listKey": "ORDER_REFUSAL_REASON", "items": [{ "id": "01928d01-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "code": "DUPLICATE_ORDER", "labels": { "fr": "Commande en double" }, "active": true, "sortOrder": 3, "requiresComment": false, "system": false, "usageCount": 4, "version": 1 }] }.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown listKey

Rules & side effects

  1. Read-only (the apps read active items through reference.lists).

Used by BO-65

GET /admin/reference-lists/{listKey}/{itemId}

admin.referenceLists.crud (get) · Permission settings.view · Apps BO · Release V1 · Requirements ADM-05

Purpose. One item. Response 200 OK — the item.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown list or item

Rules & side effects

  1. Read-only.

Used by BO-65

POST /admin/reference-lists/{listKey}

admin.referenceLists.crud (create) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-05

Purpose. Adds an item. Request — { "code": "STORE_MOVED", "labels": { "fr": "Magasin déménagé" }, "requiresComment": false }. Response 201 Created — the item.

Errors

StatusCodeWhen
409DUPLICATE_VALUECode already in the list

Rules & side effects

  1. Audit CREATE; caches (ETag) refreshed.

Used by BO-65

PATCH /admin/reference-lists/{listKey}/{itemId}

admin.referenceLists.crud (update) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-05

Purpose. Edits labels or order, or deactivates an item (never deleted when used). Response 200 OK — the item.

Errors

StatusCodeWhen
409ROLE_PROTECTEDDeactivating a system item (e.g. « Délai de confirmation expiré »)
409VERSION_CONFLICTStale version

Rules & side effects

  1. Audit UPDATE.

Used by BO-65

App versions

GET /admin/app-versions

admin.appVersions.crud (list) · Permission settings.view · Apps BO · Release V1 · Requirements ADM-07

Purpose. Version policy per app and platform. Response 200 OK — { "items": [{ "app": "DELEGATE_APP", "platform": "android", "minVersion": "1.0.2", "latestVersion": "1.0.3", "storeUrl": "https://play.google.com/store/apps/details?id=dz.hoco.delegate", "maintenance": { "enabled": false }, "updatedAt": "2026-11-01T08:00:00Z", "version": 3 }] }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks settings.view

Rules & side effects

  1. Read-only.

Used by BO-66

PUT /admin/app-versions/{app}/{platform}

admin.appVersions.crud (update) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-07

Purpose. Sets minimum and latest versions, release notes and maintenance mode (app: RESELLER_APP, DELEGATE_APP, RESELLER_WEB; platform: android, ios, web).

Request — { "minVersion": "1.0.3", "latestVersion": "1.0.3", "releaseNotes": { "fr": "Correction de la synchronisation des photos." }, "maintenance": { "enabled": false }, "version": 3 }.

Response 200 OK — the policy.

Errors

StatusCodeWhen
400VALIDATION_FAILEDNot semver, minVersion above latestVersion
404NOT_FOUNDUnknown app/platform pair

Rules & side effects

  1. Clients below minVersion get 426 UPGRADE_REQUIRED; maintenance answers 503 MAINTENANCE (details.until) to that app. Audit UPDATE.

Used by BO-66

Support regions

Regions group wilayas and carry the WhatsApp support number and hours used by the WhatsApp button (BR-83, SUP-05, ADM-08); read by support.whatsapp. SupportRegion { id, name, whatsappNumber (E.164), phone?, hours: [{ weekdays: number[], from: "HH:mm", to: "HH:mm" }], wilayaCodes: string[], isDefault, active, version }; a wilaya belongs to one region at most; the default region serves unresolved locations, and support.defaultWhatsappNumber is the last fallback.

GET /admin/support-regions

admin.supportRegions.crud (list) · Permission settings.view · Apps BO · Release V1 · Requirements ADM-08

Purpose. Lists regions. Response 200 OK — { "items": [{ "id": "01928d10-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "name": "Ouest", "whatsappNumber": "+213770900100", "hours": [{ "weekdays": [0, 1, 2, 3, 4], "from": "08:30", "to": "17:00" }], "wilayaCodes": ["31", "46", "13", "29", "22", "27"], "isDefault": false, "active": true, "version": 2 }], "total": 4, "unassignedWilayas": ["11", "33"] }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks settings.view

Rules & side effects

  1. Read-only.

Used by BO-70

GET /admin/support-regions/{regionId}

admin.supportRegions.crud (get) · Permission settings.view · Apps BO · Release V1 · Requirements ADM-08

Purpose. One region. Response 200 OK — the region.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown region

Rules & side effects

  1. Read-only.

Used by BO-70

POST /admin/support-regions

admin.supportRegions.crud (create) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-08 · SUP-05

Purpose. Creates a region. Request — { "name": "Est", "whatsappNumber": "0770 90 02 00", "hours": [{ "weekdays": [0, 1, 2, 3, 4], "from": "08:30", "to": "17:00" }], "wilayaCodes": ["25", "19", "23"], "isDefault": false }. Response 201 Created — the region (number in E.164).

Errors

StatusCodeWhen
400VALIDATION_FAILEDInvalid number, overlapping hours, unknown wilaya
409DUPLICATE_VALUEName taken
409SUPPORT_REGION_OVERLAPA wilaya already belongs to another region — details: { wilayas: [{ wilayaCode, regionId }] }

Rules & side effects

  1. isDefault: true moves the default flag from the previous default region. Audit CREATE.

Used by BO-70

PATCH /admin/support-regions/{regionId}

admin.supportRegions.crud (update) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-08

Purpose. Edits number, hours, wilayas, default flag or deactivates a region. Response 200 OK — the region.

Errors

StatusCodeWhen
409SUPPORT_REGION_OVERLAP · VERSION_CONFLICT
409DEFAULT_REGION_REQUIREDUnsetting or deactivating the only default region

Rules & side effects

  1. Applies at the next support.whatsapp read. Audit UPDATE.

Used by BO-70

DELETE /admin/support-regions/{regionId}

admin.supportRegions.crud (delete) · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-08

Purpose. Deletes a non-default region; its wilayas fall back to the default region. Response 204 No Content.

Errors

StatusCodeWhen
409DEFAULT_REGION_REQUIREDIt is the default region

Rules & side effects

  1. Audit DELETE.

Used by BO-70

POST /admin/imports/{type}

admin.imports.create · Permission settings.administer · Apps BO · Release V1 · Requirements ADM-06

Purpose. Initial imports of cahier §13.2 — resellers, users or stock — dry run then apply (type: resellers, users, stock; products: admin.products.import).

Request — { "mode": "DRY_RUN", "fileId": "01931f10-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "options": { "stockMode": "SET" } } or { "mode": "APPLY", "dryRunId": "…" }.

TypeTemplate columns (* required)
resellersstore_name, owner_name, phone, whatsapp, email, wilaya_code, commune* (name or code), address_line, landmark, lat, lng, business_type, customer_type (SUPER_GROS/DEMI_GROS/DETAIL), potential, delegate_code, status (default NEW_PROSPECT; existing buyers ACTIVE), segments, rc, nif, note — no login is created; owners claim their record at sign-up
usersfirst_name, last_name, email (staff*), phone (delegates*), roles* (RoleKey list), delegate_code, zones, send_invitation (SMS/EMAIL/NONE)
stocksku* (or barcode), warehouse_code, quantity, alert_threshold — option stockMode: SET (ADJUSTMENT movements to reach the quantity) or ADD (RECEIPT movements)

Response 202 Accepted — an ImportJob.

Errors

StatusCodeWhen
403PERMISSION_DENIED · PERMISSION_ESCALATIONMissing settings.administer · user rows granting roles beyond the caller's
404NOT_FOUNDUnknown type, file or dry run
409IMPORT_DRY_RUN_EXPIRED · IMPORT_ALREADY_APPLIED
422IMPORT_FILE_INVALID · IMPORT_DRY_RUN_REQUIRED · FILE_NOT_READYMissing columns or over 20 000 rows · dry run not succeeded · upload incomplete

Rules & side effects

  1. Reseller rows follow the creation rules (unique phone BR-04, source IMPORT, ValidationStatus APPROVED, assignment BR-47). Audit IMPORT; notification and SSE import.finished to the requester.

Used by BO-67

GET /admin/imports/{importId}

admin.imports.get · Permission settings.administer (or catalog.administer for product imports) · Apps BO · Release V1 · Requirements ADM-06 · CAT-06

Purpose. Import job status and row-level report (?rowStatus=ERROR&page=1&pageSize=100).

Response 200 OK — an ImportJob with summary and rows, e.g. { "id": "01931f11-…", "type": "RESELLERS", "mode": "DRY_RUN", "status": "SUCCEEDED", "summary": { "totalRows": 412, "validRows": 398, "warningRows": 6, "errorRows": 8, "toCreate": 404, "toUpdate": 0, "unchanged": 0 }, "rows": { "items": [{ "row": 17, "status": "ERROR", "action": "CREATE", "key": "+213555123456", "messages": [{ "column": "phone", "code": "PHONE_ALREADY_EXISTS", "message": "Numéro déjà utilisé par REV-000123." }] }], "total": 8, "page": 1, "pageSize": 100 }, "expiresAt": "2026-11-05T08:00:00Z" }.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown import

Rules & side effects

  1. Read-only.

Used by BO-67 · BO-32

GET /admin/imports

admin.imports.list · Permission settings.administer (with catalog.administer alone: product imports only) · Apps BO · Release V1 · Requirements ADM-06 · CAT-06 · Added in contract 1.1.0 (SRV-41)

Purpose. The import history of BO-67 and BO-32: past dry runs and applications with their summaries, newest first.

Request — type (ImportType[]: PRODUCTS, RESELLERS, USERS, STOCK), status (JobStatus[]), mode (DRY_RUN | APPLY), page, pageSize (25, max 200), order (desc by default, on createdAt).

Response 200 OK — { items, total, page, pageSize } of ImportJob without rows (the row report is read with admin.imports.get).

Errors

StatusCodeWhen
403PERMISSION_DENIEDNeither settings.administer nor catalog.administer

Used by BO-67 · BO-32

GET /admin/imports/{type}/template

admin.imports.template · Permission settings.administer (catalog.administer for products) · Apps BO · Release V1 · Requirements ADM-06 · CAT-06 · Added in contract 1.1.0 (SRV-41)

Purpose. « Télécharger le modèle »: generates the template of an import type with the columns its import reads — the required ones first, highlighted in XLSX, with an Aide sheet describing every column.

Request

Path / queryTypeNotes
typestringresellers | users | stock | products
formatstringXLSX (default) | CSV (UTF-8 with BOM, ; separator)
categoryIdUuidproducts only: adds the attr:<key> columns of the category and its parents (ENUM codes listed in the help)

Response 200 OK

{
  "type": "RESELLERS", "format": "XLSX", "fileName": "modele-import-resellers.xlsx",
  "url": "https://files.hoco.dz/hoco-private/import-templates/resellers.xlsx?X-Amz-…", "expiresAt": "2026-11-04T09:05:00Z",
  "columns": [ { "name": "store_name", "required": true, "description": "Nom du magasin" }, { "name": "whatsapp", "required": false, "description": "Numéro WhatsApp" } ]
}

Errors

StatusCodeWhen
400VALIDATION_FAILEDUnknown type or format; categoryId on another type than products
403PERMISSION_DENIEDMissing the type's permission
404NOT_FOUNDUnknown category

Rules & side effects

  1. The file is regenerated on each call and stored under a fixed key per type (and category); the signed URL is valid 5 minutes. Nothing is audited.

Used by BO-67 · BO-32

GET /admin/search

admin.search · Permission any back-office user (results filtered by permission) · Apps BO · Release V1 · Requirements ACL-05

Purpose. Global search of the app shell across resellers, orders, products, invoices, users, tickets and tours.

Request — q (min 2 chars; business numbers match exactly, phones after normalisation, names by similarity, SKU and barcode exactly), types (subset of RESELLER, ORDER, PRODUCT, INVOICE, USER, TICKET, TOUR, RETURN), limit (per group, 5, max 20).

Response 200 OK

{
  "q": "158",
  "groups": [
    { "type": "ORDER", "total": 1, "items": [{ "id": "0193016e-4b2a-7c11-9d8e-7f6a5b4c3d2e", "title": "CMD-2026-000158", "subtitle": "Phone Store El Bahia · 30 749,60 DA", "status": "VALIDATED" }] },
    { "type": "RESELLER", "total": 0, "items": [] }
  ]
}

Errors

StatusCodeWhen
400VALIDATION_FAILEDq shorter than 2 characters

Rules & side effects

  1. A group is returned only when the caller holds its module's .view (orders, crm, catalog, finance, users, support, field); the client routes from type and id. Not audited; rate-limited 60 / min.

Used by BO-03

On this page