> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bodhveda.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send notification

> Start sending notifications through Bodhveda API.

Send a **direct** notification to a specific recipient or send a **broadcast** to all recipients subscribed to a `target`.

* **Direct**: If `recipient_id` is set, `target` is optional.
* **Broadcast**: If `recipient_id` is null, `target` is required.

A send must carry **at least one content block** — `payload` for in-app, `email` for email. Omitting both returns a `400`, since such a send names no medium.

<Note>
  Sending is **asynchronous**. A direct send returns as soon as the notification is accepted — the response carries the notification `id` with `status: "enqueued"`. Preference gating, quota, and email are all resolved by a background worker. Read the resolved outcome back with [retrieve a notification](/api-reference/endpoint/notifications/get-notification).
</Note>

## Delivering email

Include the optional typed `email` block (`subject`, `html`, `text`) to also send an **email**. Its presence is your "email is eligible" signal — omit it and no email is sent (there is no fallback that derives an email from `payload`). See [mediums](/docs/concepts/mediums) for the full model.

* **Direct sends only.** An `email` block on a broadcast returns `400`.
* **No templating.** You render the subject/HTML/text yourself (e.g. with `@react-email`) and pass the result. `text` is optional and derived from `html` when omitted.
* Email fires only when the `(target, email)` pair is cataloged, the recipient's email preference is enabled, and the recipient has a **primary email** [contact](/api-reference/endpoint/recipients/contacts/create-contact). Otherwise the send still succeeds and the email is skipped.
* The email is delivered by a background worker, so its outcome is **not** on the send response. Read it back on the notification's `email` field via [retrieve a notification](/api-reference/endpoint/notifications/get-notification).

## Email without an in-app notification

On a **direct** send, `payload` is optional. Omit it and Bodhveda sends the email **without** creating an in-app notification — useful when the two mediums want different timing (an instant in-app row per event, but one debounced email covering several).

```json theme={null}
{
    "recipient_id": "recipient_123",
    "target": { "channel": "conversation", "topic": "thread_7", "event": "reply" },
    "email": {
        "subject": "3 new messages on your thread",
        "html": "<p>Vikram and 2 others replied.</p>"
    }
}
```

The notification is still created and still returns an `id` — you need one to read the email outcome back — but its `status` is `not_requested` and it is excluded from the recipient's [feed](/api-reference/endpoint/recipients/notifications/list-notifications), their [unread count](/api-reference/endpoint/recipients/notifications/unread-count), and mark-all-read. The recipient's **in-app** preference does not apply to it; the email gates above still do.

An explicit `"payload": null` is treated the same as omitting it. `payload` remains **required on a broadcast**.


## OpenAPI

````yaml POST /notifications/send
openapi: 3.0.3
info:
  title: Bodhveda Notifications API
  version: '1.0'
  description: API for sending notifications to recipients or broadcasting to all.
servers: []
security: []
paths:
  /notifications/send:
    post:
      tags:
        - Notifications
      summary: Send a notification (direct or broadcast)
      description: Start sending notifications through Bodhveda API.
      operationId: sendNotification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendNotificationPayload'
      responses:
        '200':
          description: Notification response
          content:
            application/json:
              examples:
                Direct notification:
                  summary: Direct Notification Response
                  value:
                    message: >-
                      Direct notification queued for delivery to recipient
                      recipient_123.
                    data:
                      notification:
                        id: 42069
                        recipient_id: recipient_123
                        payload:
                          title: Elon, Zuck and others commented on your post.
                          post_url: /posts/post_id_123#comments
                        broadcast_id: null
                        target:
                          channel: posts
                          topic: post_id_123
                          event: new_comment
                        read: false
                        opened: false
                        created_at: '2025-11-07T05:31:56Z'
                        updated_at: '2025-11-07T05:31:56Z'
                        status: enqueued
                      broadcast: null
                Broadcast notification:
                  summary: Broadcast Notification Response
                  value:
                    message: >-
                      Broadcast notification sent successfully. It will be
                      delivered to all elligible recipients.
                    data:
                      notification: null
                      broadcast:
                        id: 42069
                        target:
                          channel: announcements
                          topic: product
                          event: new_feature
                        payload:
                          title: Big News!
                          message: We just launched a new feature.
                        created_at: '2025-08-11T20:54:25.039856+05:30'
                        updated_at: '2025-08-11T20:54:25.039856+05:30'
                Direct notification rejected:
                  summary: Rejected Notification Based on Preferences
                  value:
                    message: >-
                      No notification was sent. Recipient's preferences do not
                      allow delivery.
                    data:
                      notification: null
                      broadcast: null
                Direct notification with email:
                  summary: Direct Notification Fanned Out to Inbox + Email
                  value:
                    message: >-
                      Direct notification sent successfully to recipient
                      recipient_123.
                    data:
                      notification:
                        id: 42070
                        recipient_id: recipient_123
                        payload:
                          title: Your daily digest is ready.
                        broadcast_id: null
                        target:
                          channel: digest
                          topic: none
                          event: sent
                        read: false
                        opened: false
                        created_at: '2025-11-07T05:31:56Z'
                        updated_at: '2025-11-07T05:31:56Z'
                      broadcast: null
                      deliveries:
                        - medium: email
                          status: pending
                          address: alice@example.com
                          created_at: '2025-11-07T05:31:56Z'
                          updated_at: '2025-11-07T05:31:56Z'
      security:
        - BearerAuthWithAPIKeyWithFullAcessScope: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST https://api.bodhveda.com/notifications/send \
              -H "Authorization: Bearer bv_xxxxxxxxx" \
              -H "Content-Type: application/json" \
              -d '{
                "recipient_id": "recipient_123",
                "target": {
                  "channel": "posts",
                  "topic": "post_id_123",
                  "event": "new_comment"
                },
                "payload": {
                  "title": "Elon, Zuck and others commented on your post.",
                  "post_url": "/posts/post_id_123#comments"
                }
              }' 
        - lang: curl
          label: cURL — with email
          source: |-
            # Direct send fanned out to inbox + email.
            # The `email` block makes email eligible (direct sends only).
            curl -X POST https://api.bodhveda.com/notifications/send \
              -H "Authorization: Bearer bv_xxxxxxxxx" \
              -H "Content-Type: application/json" \
              -d '{
                "recipient_id": "recipient_123",
                "target": {
                  "channel": "digest",
                  "topic": "none",
                  "event": "sent"
                },
                "payload": {
                  "title": "Your daily digest is ready."
                },
                "email": {
                  "subject": "Your daily digest",
                  "html": "<h1>Your daily digest</h1><p>3 new follow-ups today.</p>",
                  "text": "Your daily digest\n3 new follow-ups today."
                }
              }' 
        - lang: javascript
          label: JavaScript
          source: >-
            import { Bodhveda } from "@bodhveda/js";


            const bodhveda = new Bodhveda("bv_xxxxxxxxx");


            const res = await bodhveda.notifications.send({
                recipient_id: "recipient_123",
                target: { channel: "posts", topic: "post_id_123", event: "new_comment" },
                payload: {
                    title: "Elon, Zuck and others commented on your post.",
                    post_url: "/posts/post_id_123#comments",
                },
            });

            // res.notification (direct) or res.broadcast, plus res.deliveries
            for email.
        - lang: go
          label: Go
          source: >-
            import (
                "context"
                "encoding/json"

                bodhveda "github.com/MudgalLabs/bodhveda/sdk/go"
            )


            ctx := context.Background()

            client := bodhveda.NewClient("bv_xxxxxxxxx", nil)


            recipientID := "recipient_123"

            payload, _ := json.Marshal(map[string]any{
                "title":    "Elon, Zuck and others commented on your post.",
                "post_url": "/posts/post_id_123#comments",
            })

            res, _ := client.Notifications.Send(ctx,
            &bodhveda.SendNotificationRequest{
                RecipientID: &recipientID,
                Target:      &bodhveda.Target{Channel: "posts", Topic: "post_id_123", Event: "new_comment"},
                Payload:     payload,
            })

            // res.Notification (direct) or res.Broadcast, plus res.Deliveries
            for email.
components:
  schemas:
    SendNotificationPayload:
      type: object
      properties:
        recipient_id:
          type: string
          nullable: true
          description: |-
            The `id` of a recipient.
            - If null → this is treated as a **broadcast** notification.
            - If set → this is a **direct** notification to that recipient. 

             💡 If no recipient exists with the `recipient_id`, Bodhveda will create a new recipient with that `recipient_id`.
        target:
          $ref: '#/components/schemas/Target'
        payload:
          type: object
          description: >-
            Arbitrary JSON payload for the notification. This is the **in-app**
            content block — its presence is what makes the notification eligible
            for in-app delivery.


            **Optional on a direct send.** Omit it to deliver on email *without*
            creating an in-app notification (an *email-only* send) — the `email`
            block then stands alone. An explicit `null` counts as omitted.


            **Required on a broadcast**, which is in-app only.


            ⚠️ A send must carry at least one content block. Omitting both
            `payload` and `email` is a `400` — such a send names no medium.
          nullable: true
        email:
          $ref: '#/components/schemas/EmailContent'
    Target:
      type: object
      description: >-
        A **target** is the structure used to describe _who should get a
        notification_ and _how it should be categorized_.
      properties:
        channel:
          type: string
          description: Broad category for a notification (e.g., "posts").
        topic:
          type: string
          description: >-
            Subcategory inside the channel (e.g., "post_id_123"). 

            - `any` and `none` have special meaning. 

            - `any` means **all topics under this channel/event**. 

            - `none` means **only the base channel/event**. 

            - `any` is **not** a valid `topic` when sending a notification, but
            both are valid for preferences. 

             A preference with the target `posts:any:new_comment` will match a notification with target `posts:post_id_123:new_comment` but a preference with the target `posts:none:new_comment` will **only** match a notification with target `posts:none:new_comment`.
        event:
          type: string
          description: Event that triggered this notification (e.g., "new_comment").
      required:
        - channel
        - topic
        - event
    EmailContent:
      type: object
      description: >-
        Optional typed **email** content block. Its **presence** is your signal
        that email is eligible for this send (content-block-implies-intent).
        Absence ⇒ no email — there is **no** fallback that derives email from
        `payload`.


        - **Direct sends only.** Including an `email` block on a broadcast
        returns `400` (email is never sent on broadcasts).

        - Bodhveda does **no** templating in v1 — you render your own
        subject/HTML/text (e.g. with `@react-email`) and pass the result.

        - Email still fires only if the `(target, email)` pair is in the project
        catalog, the recipient's email preference is enabled, and the recipient
        has a primary email contact.
      properties:
        subject:
          type: string
          description: The email subject line. Required when an `email` block is present.
        html:
          type: string
          description: >-
            Rendered HTML body. At least one of `html` or `text` must be
            provided.
        text:
          type: string
          description: >-
            Plain-text body. Recommended for deliverability. If omitted, it is
            derived from `html`.
      required:
        - subject
  securitySchemes:
    BearerAuthWithAPIKeyWithFullAcessScope:
      type: http
      scheme: bearer
      bearerFormat: APIKey
      description: >-
        Bearer authentication header of the form `Bearer bv_xxxxxxxxx`, where
        `bv_xxxxxxxxx` is your **API Key** with `Full access` scope.

````