Skip to content

SmsAddTrigger

POST sms/trigger

Subscribes a platform event to templates: when the event fires on the bus, the module renders every enabled template of this trigger and queues the messages.

merge renames event fields into placeholder names. Without it every event schema change would require editing the templates instead of one trigger.

arguments decides whether this trigger reacts to a given event at all — see Matching below.

Access Control

Allowed role: admin. The trigger belongs to the brand of the caller unless global is set.

Request

POST https://{broker_domain}/sms/trigger
{
  "event": "customer.password_reset.delivery_requested",
  "merge": {
    "client.msisdn": "phone"
  },
  "arguments": {
    "match": { "delivery_route": "customer-recovery" }
  },
  "type": "PRIVATE",
  "status": "ENABLED"
}
{
  "command": "SmsAddTrigger",
  "extID": "1",
  "data": {
    "event": "customer.password_reset.delivery_requested",
    "merge": {
      "client.msisdn": "phone"
    },
    "arguments": {
      "match": { "delivery_route": "customer-recovery" }
    },
    "type": "PRIVATE",
    "status": "ENABLED"
  }
}
const res = await platform.SmsAddTrigger({
  event: "customer.password_reset.delivery_requested",
  merge: {
    "client.msisdn": "phone"
  },
  arguments: {
    match: { delivery_route: "customer-recovery" }
  },
  type: "PRIVATE",
  status: "ENABLED"
});

Request Data

Field Type Required Description
event string Yes Bus event name to subscribe to, for example crm.customer.deposit
description string No Free-form note
merge object No Rename event fields for templates, { "client.msisdn": "phone" }
arguments object No Firing condition, { "match": { "delivery_route": "customer-recovery" } } — see Matching
type enum No PRIVATE (default) or PUBLIC
status enum No ENABLED (default) or DISABLED
global bool No true — the trigger works for every brand

Matching

One platform event reaches every subscriber: the delivery channel is a field of the payload (delivery_route), not the number of the receiver. arguments is how a trigger claims only the events meant for it:

{ "match": { "delivery_route": "customer-recovery" } }
  • the value is one string or a list of allowed values;
  • the key is a path into the payload, so { "customer.brand": "sct" } works;
  • comparison is done on strings, so 1 and "1" are the same value;
  • a field missing from the event does not match;
  • all listed fields must match;
  • without arguments the trigger fires on every event with this name.

The same mechanism fans a single event out to several channels: the mailer subscribes to the same event with its own trigger, and each module delivers in its own channel. The platform cannot split channels by emitting two events — one request emits exactly one.

Behavior

  • The module subscribes to the exact event names of its enabled triggers, and the subscription is what the platform reads from Moleculer INFO before it sends anything. A trigger that exists in the database but is not live yet receives nothing.
  • Subscriptions are refreshed from the database by a cron, so a new trigger starts working without restarting the module. SmsGetTriggerSubscriptions shows what is live right now.
  • Repeated delivery of one event does not send two messages: the deduplication key uses event_id, request_id or idempotencyKey from the payload, and falls back to the recipient number within dedupeWindowMin when the event carries none.
  • The event payload must resolve to a phone number after merge; an event without one is counted as an error rather than sent to a blank recipient.
  • The recipient may also come from enrichment: an event that carries only a customer_id or a login is resolved against the platform before templates are picked, and the account, customer and margin values it returns become placeholders. See Platform event enrichment.
  • merge is applied before and after enrichment, so it renames both the fields of the event and the fields added from the platform (approved_time_utc → value_datetime_utc).
  • Service events are never subscribed to: an event whose name starts with $, journal., analytics. or sms. (the events of this module itself, which would loop) is accepted by this method but stays out of the subscription. SmsGetTriggerSubscriptions shows it as subscribed: false.
  • A global trigger fires for every brand — use it for platform-wide notifications, not for brand campaigns.

Response Data

{
  "id": 2,
  "brand": "default",
  "event": "crm.customer.deposit",
  "description": null,
  "merge": { "client.msisdn": "phone", "payment.sum": "amount" },
  "arguments": null,
  "type": "PRIVATE",
  "global": false,
  "status": "ENABLED",
  "createdAt": "2026-08-24 13:18:02"
}

Errors

Code Error Description
400 VALIDATION_ERROR Missing event name
500 INTERNAL_ERROR Storage error