HOCO B2B
SRSAPI referenceBack-office endpoints

Support & communication

Back-office support and messaging — ticket queue, replies and internal notes, after-sales resolutions, announcements with targeting, the notification log, templates and the event-to-channel rules.

These operations handle reseller requests and claims (cahier §2.1 « demandes SAV et réclamations ») and back-office messaging (cahier §6.1 « messages », §8 notifications): the ticket queue and detail (BO-55, BO-56) including after-sales claims (ticket type AFTER_SALES, V1 since 17 Oct 2026 — SUP-04), announcements (BO-57) and notification templates and rules (BO-58). Ticket statuses: Lifecycles › Ticket; events, channels and copy: notifications matrix; after-sales rules: BR-81, BR-82.

Who uses it. Support agents and the Administrateur commercial handle tickets; resolving after-sales claims needs support.validate; announcements are sent by holders of communication.validate; templates and rules are administered by the Super administrateur.

PermissionUnlocks on this page
support.view · support.updateTickets read · reply, internal notes, assign, status, priority
support.validateAfter-sales resolutions
communication.view · create · update · deleteAnnouncements and the notification log · create · edit · delete
communication.validateSending (or scheduling) an announcement
communication.administerTemplates and rules

Audit. CREATE on internal notes and announcements, UPDATE/STATUS_CHANGE on tickets, VALIDATE/REJECT on resolutions, UPDATE on templates and rules (before/after). Public replies are not audit rows (they are the conversation).

Conventions: lists return Page<T> = { items, total, page, pageSize } (responses); attachments are uploaded with files.createUpload (purpose TICKET_ATTACHMENT); editable records carry version. 401, 429 and 500 apply everywhere and are not repeated.

MethodPathOperationAccessAppsRelease
GET/admin/ticketsadmin.tickets.list
Tickets queue with filters
support.viewBOV1
GET/admin/tickets/{ticketId}admin.tickets.get
Ticket with public and internal messages
support.viewBOV1
POST/admin/tickets/{ticketId}/messagesadmin.tickets.reply
Reply or add an internal note
support.updateBOV1
PATCH/admin/tickets/{ticketId}admin.tickets.update
Assign, change status or priority
support.updateBOV1
POST/admin/tickets/{ticketId}/resolutionadmin.tickets.resolve
Resolve an after-sales claim: REPLACEMENT (creates a free order), RETURN (creates a return), CREDIT_NOTE, REPAIR or REJECTED with reason
support.validateBOV1
GET · POST · PATCH · DELETE/admin/announcements[/{announcementId}]admin.announcements.crud
Announcements with targeting and schedule
communication.*BOV1
POST/admin/announcements/{announcementId}/sendadmin.announcements.send
Publish now (push + inbox)
communication.validateBOV1
GET/admin/notifications/logadmin.notifications.log
Delivery log per channel (sent, failed)
communication.viewBOV1
GET · PUT/admin/notification-templates[/{eventKey}]admin.notifications.templates
Templates per event, channel and locale
communication.administerBOV1
GET · PUT/admin/notification-rulesadmin.notifications.rules
Event → channels → recipients matrix
communication.administerBOV1

Schemas

Ticket

interface Ticket {
  id: Uuid;
  number: string;                     // TKT-2026-000045
  type: TicketType;                   // AFTER_SALES, ORDER_ISSUE, DELIVERY_ISSUE, BILLING, QUESTION, OTHER
  status: TicketStatus;               // OPEN, IN_PROGRESS, WAITING_RESELLER, RESOLVED, REJECTED, CLOSED
  priority: "LOW" | "NORMAL" | "HIGH" | "URGENT";   // TicketPriority (not in enums.json)
  subject: string;
  reseller: ResellerSummary;
  order?: { id: Uuid; number: string; deliveredAt?: Iso };
  items?: { orderLineId: Uuid; sku: string; productName: string; quantity: number; issue: AfterSalesIssue }[];   // TicketItem — AFTER_SALES only
  assignee?: UserSummary;
  resolution?: { kind: AfterSalesResolution; note?: string; reason?: string; by: UserSummary; at: Iso;
                 orderId?: Uuid; returnId?: Uuid; creditNoteId?: Uuid; repairDate?: string };
  createdAt: Iso; lastMessageAt: Iso; firstResponseAt?: Iso; resolvedAt?: Iso; closedAt?: Iso;
  unreadForStaff: boolean;
  messagesCount: number;
  rating?: number;                    // 1–5 given by the reseller at closing
  version: number;
}

Tickets

GET /admin/tickets

admin.tickets.list · Permission support.view · Apps BO · Release V1 · Requirements SUP-02

Purpose. The tickets queue with filters; after-sales claims have their own tab.

Request

QueryTypeValues / defaultNotes
statusTicketStatus[]default OPEN, IN_PROGRESS, WAITING_RESELLER
typeTicketType[]repeatableAFTER_SALES = SAV tab
prioritystring[]LOW | NORMAL | HIGH | URGENT
assigneeIdUuid[]me, none allowed
resellerId / orderIdUuid
unreadbooleanLast message from the reseller
from / tostring (date)On createdAt
qstringmin 2 charsNumber, subject, store name
sort / order / page / pageSizelastMessageAt (default), createdAt, priority · desc · 1 · 25 (max 200)

Response 200 OK

{
  "items": [
    {
      "id": "01931b30-7c8d-7e9f-8a01-3b4c5d6e7f80", "number": "TKT-2026-000045", "type": "AFTER_SALES", "status": "OPEN", "priority": "NORMAL",
      "subject": "Chargeurs qui chauffent", "reseller": { "id": "0192f4b8-61c2-7a3e-9b10-1f2e3d4c5b6a", "number": "REV-000123", "storeName": "Phone Store El Bahia", "ownerName": "Karim Benali", "phone": "+213555123456", "wilayaCode": "31", "communeName": "Bir El Djir", "status": "ACTIVE" },
      "order": { "id": "0193016e-4b2a-7c11-9d8e-7f6a5b4c3d2e", "number": "CMD-2026-000158", "deliveredAt": "2026-11-06T11:00:00Z" },
      "items": [{ "orderLineId": "0193016e-5a02-7b03-8c04-0d0e0f101113", "sku": "AF-A29-50W-WH", "productName": "Chargeur GaN 50 W 2 ports", "quantity": 2, "issue": "DEFECTIVE" }],
      "createdAt": "2026-11-10T09:12:00Z", "lastMessageAt": "2026-11-10T09:12:00Z", "unreadForStaff": true, "messagesCount": 1, "version": 1
    }
  ],
  "total": 9, "page": 1, "pageSize": 25,
  "counts": { "OPEN": 4, "IN_PROGRESS": 3, "WAITING_RESELLER": 2, "afterSales": 3 }
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks support.view

Rules & side effects

  1. Read-only; new tickets arrive with ticket.created.

Used by BO-55 · BO-69 · BO-11

GET /admin/tickets/{ticketId}

admin.tickets.get · Permission support.view · Apps BO · Release V1 · Requirements SUP-02

Purpose. A ticket with its public and internal messages, claimed items and photos.

Response 200 OK — the Ticket plus messages:

{
  "id": "01931b30-7c8d-7e9f-8a01-3b4c5d6e7f80", "number": "TKT-2026-000045", "type": "AFTER_SALES", "status": "IN_PROGRESS",
  "messages": [
    { "id": "01931b30-8d9e-7fa0-9b12-4c5d6e7f8091", "author": { "id": "0192f4b8-7001-7a02-8b03-0c0d0e0f1011", "displayName": "Karim Benali", "kind": "RESELLER" }, "body": "Deux chargeurs chauffent fortement après 10 minutes.", "isInternal": false, "attachments": [{ "id": "01931b30-9eaf-7b01-8c23-5d6e7f809102", "url": "https://files.hoco.dz/s/tkt45-1.jpg?sig=…", "mimeType": "image/jpeg", "size": 512330, "purpose": "TICKET_ATTACHMENT" }], "createdAt": "2026-11-10T09:12:00Z" },
    { "id": "01931b31-0a1b-7c2d-9e3f-4a5b6c7d8e9f", "author": { "id": "01929e55-2c3d-7e4f-9a1b-2c3d4e5f6a7b", "displayName": "Nadia Belkacem", "kind": "STAFF" }, "body": "Lot 2610 déjà signalé par un autre client — remplacer.", "isInternal": true, "attachments": [], "createdAt": "2026-11-10T10:02:00Z" }
  ],
  "version": 3
}

Errors

StatusCodeWhen
404NOT_FOUNDUnknown ticket

Rules & side effects

  1. Reading marks the ticket read for staff (unreadForStaff: false); not audited.

Used by BO-56

POST /admin/tickets/{ticketId}/messages

admin.tickets.reply · Permission support.update · Apps BO · Release V1 · Requirements SUP-02

Purpose. Replies to the reseller or adds an internal note.

Request

interface TicketReplyBody {
  body: string;                       // 1–4 000
  isInternal: boolean;                // true = internal note, never shown or notified to the reseller
  attachmentFileIds?: Uuid[];         // ≤ 5, TICKET_ATTACHMENT
  asQuestion?: boolean;               // public reply that waits for the reseller → WAITING_RESELLER
}
{ "body": "Bonjour M. Benali, pouvez-vous nous indiquer le numéro de lot inscrit sous le chargeur ?", "isInternal": false, "asQuestion": true }

Response 201 Created — the message, plus ticket: { status, firstResponseAt, version }.

Errors

StatusCodeWhen
400VALIDATION_FAILEDEmpty body, more than 5 attachments, asQuestion on an internal note
403PERMISSION_DENIEDCaller lacks support.update
404NOT_FOUNDUnknown ticket
409TICKET_TRANSITION_NOT_ALLOWEDPublic reply on a CLOSED ticket
422FILE_NOT_READY · FILE_PURPOSE_MISMATCHAttachment not uploaded or wrong purpose

Rules & side effects

  1. First public reply on OPEN → IN_PROGRESS and sets firstResponseAt; asQuestion → WAITING_RESELLER. Internal notes never change the status.
  2. Notifications: public reply → ticket.replied to the reseller (push + in-app; live on the reseller stream). Internal notes notify nobody.

Used by BO-56

PATCH /admin/tickets/{ticketId}

admin.tickets.update · Permission support.update · Apps BO · Release V1 · Requirements SUP-02

Purpose. Assigns, changes the status, priority or type of a ticket.

Request

interface UpdateTicketBody { assigneeId?: Uuid | null; status?: "IN_PROGRESS" | "WAITING_RESELLER" | "RESOLVED" | "CLOSED"; priority?: TicketPriority; type?: TicketType; note?: string; version: number }
{ "assigneeId": "01929e55-2c3d-7e4f-9a1b-2c3d4e5f6a7b", "priority": "HIGH", "version": 1 }

Response 200 OK — the updated Ticket.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks support.update
404NOT_FOUNDUnknown ticket or assignee
409TICKET_TRANSITION_NOT_ALLOWEDMove not in the table; RESOLVED on an AFTER_SALES ticket (use resolve); changing the type of a claim
409VERSION_CONFLICTStale version

Rules & side effects

  1. Assigning an OPEN ticket moves it to IN_PROGRESS. Audit UPDATE / STATUS_CHANGE.
  2. Notifications: ticket.assigned → assignee (in-app; proposed event); ticket.status_changed → reseller for WAITING_RESELLER and RESOLVED.

Used by BO-55 · BO-56

POST /admin/tickets/{ticketId}/resolution

admin.tickets.resolve · Permission support.validate · Apps BO · Release V1 · Requirements SUP-04 · ORD-13

Purpose. Settles an after-sales claim with exactly one resolution (BR-82).

Request

interface ResolveClaimBody {
  resolution: "REPLACEMENT" | "RETURN" | "CREDIT_NOTE" | "REPAIR" | "REJECTED";   // AfterSalesResolution
  items?: { orderLineId: Uuid; quantity: number }[];   // default: the claimed items; quantity ≤ claimed
  creditAmountTtc?: Money;            // CREDIT_NOTE: ≤ claimed lines at snapshot prices (default: that maximum)
  repair?: { note: string; expectedOn?: string };      // REPAIR
  reason?: string;                    // REJECTED: required (out of warranty, misuse…), shown to the reseller
  message?: string;                   // public message posted with the resolution
  version: number;
}
{ "resolution": "REPLACEMENT", "items": [{ "orderLineId": "0193016e-5a02-7b03-8c04-0d0e0f101113", "quantity": 2 }], "message": "Deux chargeurs neufs partent avec votre prochaine livraison.", "version": 3 }

Response 200 OK — the Ticket with status RESOLVED (or REJECTED) and resolution, e.g. { "kind": "REPLACEMENT", "orderId": "01931b40-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "by": { "id": "01929e66-3d4e-7f5a-8b6c-7d8e9f0a1b2c", "displayName": "Sofiane Hamdi" }, "at": "2026-11-10T11:00:00Z" } and createdOrder: { "number": "CMD-2026-000171", "status": "SUBMITTED", "totalTtc": 0 }.

ResolutionEffect
REPLACEMENTA free order (channel BACK_OFFICE, lines isFree, price 0, PaymentMethod none required) is created SUBMITTED for the items; it enters the Commandes à confirmer queue and follows the normal flow (reservation, preparation, shipping)
RETURNA return request is created APPROVED (origin: AFTER_SALES); its reception re-enters stock and issues the credit note
CREDIT_NOTEA CreditNote (AV- number) is issued without physical return, allocated to the order's invoice or kept as an advance (BR-39)
REPAIRRepair note and expected date recorded; no stock or money movement
REJECTEDTicket REJECTED with the reason

Errors

StatusCodeWhen
400VALIDATION_FAILEDItem not claimed, quantity above the claimed one, creditAmountTtc above the maximum, repair missing
403PERMISSION_DENIEDCaller lacks support.validate
404NOT_FOUNDUnknown ticket
409TICKET_NOT_AFTER_SALESTicket type is not AFTER_SALES
409TICKET_TRANSITION_NOT_ALLOWEDAlready RESOLVED, REJECTED or CLOSED
409VERSION_CONFLICTStale version
422REASON_REQUIREDREJECTED without reason

Rules & side effects

  1. One transaction: resolution + created order / return / credit note. Audit VALIDATE (or REJECT) with the resolution, plus CREATE on the created record.
  2. Notifications: ticket.resolved (templates per resolution, e.g. ticket.resolved.credit_note) or ticket.rejected → reseller (push + in-app, live). The replacement order then produces the order events.

Used by BO-56 · BO-69

Announcements

interface Announcement {
  id: Uuid;
  title: string;                      // ≤ 80
  body: string;                       // ≤ 2 000, plain text with line breaks (French)
  bodyAr?: string;                    // ≤ 2 000, shown to Arabic readers instead of `body` (contract 1.1.0)
  image?: FileRef;                    // ANNOUNCEMENT_IMAGE; write `imageFileId` (null clears it) (contract 1.1.0)
  smsText?: string;                   // ≤ 160, required when SMS is a channel
  audience: { roles: ("DELEGATE" | "RESELLER")[]; zoneIds: Uuid[]; wilayaCodes: string[]; segmentIds: Uuid[]; userIds: Uuid[];
              customerTypes: CustomerType[] };   // AND between criteria, OR inside; customerTypes (contract 1.1.0): resellers of these types only, needs the RESELLER role
  target: { productId?; promotionId?; categoryId?; brandId?; fileId? };   // COMMERCIAL_PUSH / NEW_CATALOGUE
  targetNames: { product?: string; promotion?: string; category?: string; brand?: string };   // names of the target ids (contract 1.1.0)
  file?: FileRef;                     // the catalogue PDF of target.fileId, signed (contract 1.1.0)
  channels: ("IN_APP" | "PUSH" | "SMS" | "EMAIL")[];   // IN_APP always included
  status: "DRAFT" | "SCHEDULED" | "SENT" | "CANCELLED";   // AnnouncementStatus (not in enums.json)
  scheduledAt?: Iso;
  sentAt?: Iso;
  expiresAt?: Iso;                    // hidden from 'Messages' afterwards
  stats?: { recipients: number; read: number; pushDelivered: number; smsSent: number };
  createdBy: UserSummary; createdAt: Iso; version: number;
}

GET /admin/announcements

admin.announcements.crud (list) · Permission communication.view · Apps BO · Release V1 · Requirements NOT-07

Purpose. Lists announcements. Request — status[], from / to, q, page / pageSize. Response 200 OK — Page<Announcement>, e.g. { "items": [{ "id": "01931d00-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "title": "Nouveaux chargeurs ACEFAST", "body": "La gamme GaN 65 W arrive le 15 novembre…", "audience": { "roles": ["DELEGATE"], "zoneIds": [], "wilayaCodes": [], "segmentIds": [], "userIds": [] }, "channels": ["IN_APP", "PUSH"], "status": "SENT", "sentAt": "2026-11-03T07:30:00Z", "stats": { "recipients": 11, "read": 9, "pushDelivered": 11, "smsSent": 0 }, "createdBy": { "id": "01929e55-2c3d-7e4f-9a1b-2c3d4e5f6a7b", "displayName": "Nadia Belkacem" }, "createdAt": "2026-11-03T07:20:00Z", "version": 2 }], "total": 7, "page": 1, "pageSize": 25 }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks communication.view

Rules & side effects

  1. Read-only.

Used by BO-57

GET /admin/announcements/{announcementId}

admin.announcements.crud (get) · Permission communication.view · Apps BO · Release V1 · Requirements NOT-07

Purpose. One announcement with its stats and estimatedRecipients (computed from the audience). Response 200 OK — an Announcement.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown announcement

Rules & side effects

  1. Read-only.

Used by BO-57

POST /admin/announcements

admin.announcements.crud (create) · Permission communication.create · Apps BO · Release V1 · Requirements NOT-07

Purpose. Drafts an announcement to delegates and/or resellers.

Request

{ "title": "Fermeture le 1er novembre", "body": "Nos dépôts seront fermés le dimanche 1er novembre. Les commandes reprennent le lundi.", "audience": { "roles": ["RESELLER", "DELEGATE"], "zoneIds": [], "wilayaCodes": ["31", "46"], "segmentIds": [], "userIds": [] }, "channels": ["IN_APP", "PUSH"], "expiresAt": "2026-11-02T23:00:00Z" }

Response 201 Created — the Announcement (DRAFT) with estimatedRecipients.

Errors

StatusCodeWhen
400VALIDATION_FAILEDEmpty audience, SMS without smsText, body too long; SMS or EMAIL on a COMMERCIAL_PUSH or NEW_CATALOGUE (field code CHANNEL_NOT_AVAILABLE)
403PERMISSION_DENIEDCaller lacks communication.create
404NOT_FOUNDAn audience.userIds id is not a user of the chosen roles

Rules & side effects

  1. Audit CREATE.
  2. SRV-42 — every field is stored: smsText, the SMS and EMAIL channels (messages only) and audience.userIds (named users, ANDed with the other criteria). At sending, announcement.published goes through the chosen channels: SMS with smsText through the SMS gateway (D-13 — simulated until it is configured), e-mail (title and body) through SMTP to recipients with an address; both outside the SMS whitelist and on unless the recipient switched the channel off. byChannel of the send answer counts the recipients with a phone (SMS) or an e-mail (EMAIL); stats.smsSent counts the SMS sent.

Used by BO-57

PATCH /admin/announcements/{announcementId}

admin.announcements.crud (update) · Permission communication.update · Apps BO · Release V1 · Requirements NOT-07

Purpose. Edits a draft or scheduled announcement (status: "DRAFT" unschedules). Response 200 OK — the Announcement.

Errors

StatusCodeWhen
409ANNOUNCEMENT_NOT_EDITABLEAlready SENT or CANCELLED
409VERSION_CONFLICTStale version

Rules & side effects

  1. Audit UPDATE.

Used by BO-57

DELETE /admin/announcements/{announcementId}

admin.announcements.crud (delete) · Permission communication.delete · Apps BO · Release V1 · Requirements NOT-07

Purpose. Deletes a draft or cancels a scheduled announcement (SENT ones stay for history). Response 204 No Content.

Errors

StatusCodeWhen
409ANNOUNCEMENT_NOT_EDITABLEAlready SENT

Rules & side effects

  1. Audit DELETE (draft) or STATUS_CHANGE (→ CANCELLED).

Used by BO-57

POST /admin/announcements/{announcementId}/send

admin.announcements.send · Permission communication.validate · Apps BO · Release V1 · Requirements NOT-07

Purpose. Publishes an announcement now, or schedules it.

Request — { "scheduleAt": "2026-10-31T16:00:00Z" } (optional; absent = now).

Response 200 OK — { "id": "…", "status": "SENT", "sentAt": "2026-10-31T16:00:02Z", "recipients": 418, "byChannel": { "IN_APP": 418, "PUSH": 377 } } (or "status": "SCHEDULED").

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks communication.validate
404NOT_FOUNDUnknown announcement
409ANNOUNCEMENT_NOT_EDITABLEAlready SENT or CANCELLED
422ANNOUNCEMENT_NO_RECIPIENTSThe audience resolves to nobody

Rules & side effects

  1. Recipients are resolved at send time; one Notification per user (announcement.published, category ANNOUNCEMENT — respects opt-outs except in-app, and quiet hours for push). AnnouncementRead rows track reads.
  2. Audit STATUS_CHANGE. An Idempotency-Key is recommended (a double click must not send twice).

Used by BO-57

Notifications

GET /admin/notifications/log

admin.notifications.log · Permission communication.view · Apps BO · Release V1 · Requirements NOT-04

Purpose. Delivery log per channel (NotificationDelivery) to diagnose "I did not receive the SMS".

Request — channel[] (NotificationChannel), status[] (QUEUED, SENT, DELIVERED, FAILED, SKIPPED — NotificationDeliveryStatus, not in enums.json), eventKey, userId, from / to, q (masked address suffix), page / pageSize.

Response 200 OK

{
  "items": [
    { "id": "01931e00-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "notificationId": "01931dff-0a1b-7c2d-9e3f-4a5b6c7d8e9f", "eventKey": "account.approved", "channel": "SMS", "recipient": { "id": "0192f4c1-7a01-7b02-8c03-0d0e0f101112", "displayName": "Samir Haddad" }, "address": "+213 66• •• •5 67", "status": "FAILED", "provider": "sms-gateway", "providerMessageId": "a81f22", "error": { "code": "UNREACHABLE", "message": "Destinataire injoignable" }, "attempts": 3, "createdAt": "2026-11-04T09:00:00Z", "lastAttemptAt": "2026-11-04T09:12:00Z" }
  ],
  "total": 1286, "page": 1, "pageSize": 25
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks communication.view

Rules & side effects

  1. Read-only; addresses masked; OTP SMS are never logged with content (notifications matrix).

Used by BO-58

GET /admin/notification-templates

admin.notifications.templates (list) · Permission communication.administer · Apps BO · Release V1 · Requirements NOT-04

Purpose. Lists templates per event × channel × locale with completeness. Response 200 OK — { "items": [{ "eventKey": "order.validated", "channels": { "PUSH": { "fr": true, "ar": false, "en": false }, "IN_APP": { "fr": true, "ar": false, "en": false } }, "updatedAt": "2026-10-30T10:00:00Z" }], "total": 52 }.

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks communication.administer

Rules & side effects

  1. Read-only.

Used by BO-58

GET /admin/notification-templates/{eventKey}

admin.notifications.templates (get) · Permission communication.administer · Apps BO · Release V1 · Requirements NOT-04

Purpose. All templates of one event, with the allowed placeholders.

Response 200 OK

{
  "eventKey": "order.validated",
  "placeholders": ["orderNumber", "totalTtc", "storeName", "deliveryEta"],
  "templates": [
    { "channel": "PUSH", "locale": "fr", "title": "Commande validée", "body": "Votre commande {{orderNumber}} de {{totalTtc}} est validée.", "active": true },
    { "channel": "IN_APP", "locale": "fr", "title": "Commande validée", "body": "La commande {{orderNumber}} a été validée par HOCO. Préparation en cours.", "active": true }
  ],
  "version": 4
}

Errors

StatusCodeWhen
404NOT_FOUNDUnknown event key

Rules & side effects

  1. Read-only.

Used by BO-58

PUT /admin/notification-templates/{eventKey}

admin.notifications.templates (update) · Permission communication.administer · Apps BO · Release V1 · Requirements NOT-04

Purpose. Replaces the templates of an event ({ templates: [...], version }, same shape as the read).

Response 200 OK — the stored templates.

Errors

StatusCodeWhen
400VALIDATION_FAILEDMissing fr for an active channel, SMS over 160 GSM / 70 Unicode characters per segment × 2, EMAIL without subject
409VERSION_CONFLICTStale version
422TEMPLATE_PLACEHOLDER_UNKNOWNPlaceholder not in the event's list — details: { placeholders }

Rules & side effects

  1. Applies to notifications produced from now on; ar and en fall back to fr when absent (BR-59). Audit UPDATE with before/after.

Used by BO-58

GET /admin/notification-rules

admin.notifications.rules (get) · Permission communication.administer · Apps BO · Release V1 · Requirements NOT-04

Purpose. The event → recipients → channels matrix as configured.

Response 200 OK

{
  "rules": [
    { "eventKey": "order.validated", "category": "TRANSACTIONAL", "recipient": "RESELLER", "channels": ["IN_APP", "PUSH"], "enabled": true, "locked": true },
    { "eventKey": "tour.started", "category": "FIELD", "recipient": "holders:field.view", "channels": [], "enabled": true, "locked": false }
  ],
  "version": 7
}

Errors

StatusCodeWhen
403PERMISSION_DENIEDCaller lacks communication.administer

Rules & side effects

  1. Read-only; defaults are the notifications matrix.

Used by BO-58

PUT /admin/notification-rules

admin.notifications.rules (update) · Permission communication.administer · Apps BO · Release V1 · Requirements NOT-04

Purpose. Replaces the rules ({ rules, version }).

Response 200 OK — the stored rules.

Errors

StatusCodeWhen
400VALIDATION_FAILEDUnknown event key, recipient or channel
409VERSION_CONFLICTStale version
422RULE_LOCKEDDisabling or removing IN_APP from a TRANSACTIONAL or SECURITY rule, or editing an OTP rule

Rules & side effects

  1. Effective at once for new events. Audit UPDATE with before/after.

Used by BO-58

On this page