Send notification
send_notificationSend a notification (POST /send; needs a write-scoped key). Returns { sendId } with HTTP 202: delivery is asynchronous, so check the outcome with get_send_status. Use exactly one mode:
Single:
channelConfigId+recipient.Fan-out:
channelConfigId+targets(1-1000{ recipient, externalUserId? }), one channel, one sendId.Multi-channel:
deliveries(1-10, each with its ownchannelConfigId,recipientandtemplateIdorcontent) for ONE person over several channels; addfeed+externalUserIdfor a single in-app feed entry.Feed-only:
feed(withtitle) +externalUserIdand no channel: an in-app notification only. In modes 1-2 give exactly one oftemplateId(a published template, plusparams) or inlinecontent; in mode 3 that choice is made per delivery. Get channel ids and each recipient shape from list_channels first. PassidempotencyKeywhenever a retry must not deliver twice.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| feed | No | Create exactly ONE in-app feed entry for `externalUserId` (read back with list_feed_notifications). `title`/`description` default to the rendered template text; `title` is required for a feed-only send (mode 4). | |
| params | No | Values for the template's `{{placeholders}}`. Any JSON: strings, numbers, booleans, arrays and nested objects (arrays/objects drive `{{#section}}…{{/section}}` blocks). Missing required params are rejected with a 400 naming them. | |
| content | No | Inline message content, used INSTEAD of `templateId` (give exactly one of the two). Shape by channel kind: ses_email / smtp_email → `{ subject, bodyHtml, bodyText }`; fcm_push → `{ title, body, imageUrl?, data?: { [key]: string } }`; slack_webhook → `{ text }` (Slack mrkdwn); discord_webhook → `{ content }` (max 2000 chars); telegram_bot → `{ text, disableLinkPreview? }` (Telegram HTML subset); generic_webhook → `{ title, body, data?: { [key]: string } }`. `{{name}}` placeholders are filled from `params` and escaped for the channel. | |
| targets | No | Mode 2: fan-out to 1-1000 recipients over ONE channel, sharing one sendId. Mutually exclusive with `recipient`. | |
| logTitle | No | Feed/log title for inline `content` sends only (template sends take it from the template). Placeholders allowed. | |
| priority | No | "high" (default) for transactional messages; "low" for marketing/bulk so it never delays transactional sends. | |
| notBefore | No | Schedule delivery for later: ISO 8601 datetime with offset, e.g. "2026-09-15T09:00:00+08:00". Omit to send now. | |
| recipient | No | Mode 1: the single recipient. Mutually exclusive with `targets`. Channel-specific delivery target. Its shape depends on the kind of the chosen channel (list_channels returns each channel's exact `recipientSchema`): ses_email / smtp_email → `{ email, name?, cc?: [{ email, name? }], bcc?: [...], attachments?: [{ filename, content (base64), contentType?, disposition?: "attachment"|"inline", contentId? }] }`; fcm_push → `{ deviceToken }` OR `{ topic }` (exactly one; Ray keeps no device registry); telegram_bot → `{ chatId }` (numeric id as a string, or "@channelname"); slack_webhook, discord_webhook, generic_webhook → `{}` (the destination is part of the channel config). | |
| campaignId | No | Free-form campaign id used to group click stats across sends. | |
| deliveries | No | Mode 3: the same notification to ONE person over several channels (e.g. push + email), max 10. Each entry has its own channel, recipient and content source. Do not combine with top-level channelConfigId/recipient/targets/templateId/content. | |
| showInFeed | No | Legacy modes 1-2 flag: also add a feed entry for each target that has an externalUserId. Prefer `feed`. Not valid with `deliveries`. | |
| templateId | No | Modes 1-2: a PUBLISHED template to render (see list_templates / publish_template). Exactly one of `templateId` or `content`. Its channelKind must match the channel's `templateKind`. | |
| trackClicks | No | Email channels only: rewrite links in bodyHtml so clicks are counted (read with get_click_stats). Default false. | |
| externalUserId | No | Your own id for the end user. Required with `feed`; keys their in-app feed. | |
| idempotencyKey | No | Sent as the Idempotency-Key header. Retrying with the same key and same arguments returns the original sendId without sending again (24h window); the same key with different arguments fails with 409. Use a fresh unique value (e.g. a UUID) per logical notification. | |
| logDescription | No | Feed/log description for inline `content` sends only. Placeholders allowed. | |
| channelConfigId | No | Modes 1-2: the channel to send through — an `id` from list_channels. Not allowed together with `deliveries`. |