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

# Email

> Send a message using the email channel.

## Overview

The Create message API allows you to send push notifications, emails, and SMS to your users. This guide is specific for email. See [Push notification](/reference/push-notification) or [SMS](/reference/sms) to send to those channels.

Ensure your [Email setup](/docs/en/email-setup) is complete.

<Note>
  Review the [Sending messages with the OneSignal API](/reference/create-message) guide for details on how to structure your messages.

  * [Select your target audience](/reference/create-message#choose-your-target-audience)
  * [Craft your message](/reference/create-message#craft-your-message)
  * [Schedule & per-user delivery options](/reference/create-message#schedule-%26-per-user-delivery)
</Note>

***


## OpenAPI

````yaml POST /notifications?c=email
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /notifications?c=email:
    post:
      summary: Email
      description: Send a message using the email channel.
      operationId: email
      parameters:
        - name: Authorization
          in: header
          description: >-
            Your App API key with prefix `Key `. See [Keys &
            IDs](/docs/en/keys-and-ids).
          required: true
          schema:
            type: string
            default: Key YOUR_APP_API_KEY
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - app_id
                - email_subject
                - email_body
              properties:
                app_id:
                  type: string
                  description: >-
                    Your OneSignal App ID in UUID v4 format. See [Keys &
                    IDs](/docs/en/keys-and-ids).
                  default: YOUR_APP_ID
                include_aliases:
                  type: object
                  description: >-
                    Target up to 20,000 users by their `external_id`,
                    `onesignal_id`, or your own custom alias. Use with
                    `target_channel` to control the delivery channel. Not
                    compatible with any other targeting parameters like
                    `filters`, `include_subscription_ids`, `included_segments`,
                    or `excluded_segments`. See [Sending messages with the
                    OneSignal API](/reference/create-message#include-aliases).
                  format: json
                  properties:
                    external_id:
                      description: >-
                        An array of external IDs which should be the same as the
                        user ID in your app. This is the recommended method for
                        targeting users. See [Users](/docs/users).
                      type: array
                      items:
                        type: string
                target_channel:
                  type: string
                  description: >-
                    The targeted delivery channel. Required when using
                    `include_aliases`. Accepts `push`, `email`, or `sms`.
                  enum:
                    - push
                    - email
                    - sms
                  default: email
                include_subscription_ids:
                  type: array
                  description: >-
                    Target users' specific [subscriptions](/docs/subscriptions)
                    by ID. Include up to 20,000 `subscription_id` per API call.
                    Not compatible with any other targeting parameters like
                    `filters`, `include_aliases`, `included_segments`, or
                    `excluded_segments`. See [Sending messages with the
                    OneSignal API](/reference/create-message).
                  items:
                    type: string
                email_to:
                  type: array
                  description: >-
                    Send email to specific users by their email address. Include
                    up to 20,000 email addresses per API call. If the email
                    address does not exist within the OneSignal App, then a new
                    email Subscription will be created. Can only be used when
                    sending [Email](/reference/email). Not compatible with any
                    other targeting parameters like `filters`,
                    `include_aliases`, `included_segments`, or
                    `excluded_segments`. See [Sending messages with the
                    OneSignal API](/reference/create-message).
                  items:
                    type: string
                included_segments:
                  type: array
                  description: >-
                    Target predefined [Segments](/docs/segmentation). Users that
                    are in multiple segments will only be sent the message once.
                    Can be combined with `excluded_segments`. Not compatible
                    with any other targeting parameters like `filters`,
                    `include_aliases`, or `include_subscription_ids`. See
                    [Sending messages with the OneSignal
                    API](/reference/create-message).
                  items:
                    type: string
                excluded_segments:
                  type: array
                  description: >-
                    Exclude users in predefined [Segments](/docs/segmentation).
                    Overrides membership in any segment specified in the
                    `included_segments`. Not compatible with any other targeting
                    parameters like `filters`, `include_aliases`, or
                    `include_subscription_ids`. See [Sending messages with the
                    OneSignal API](/reference/create-message).
                  items:
                    type: string
                filters:
                  type: array
                  description: >-
                    Filters define the segment based on user properties like
                    tags, activity, or location using flexible AND/OR logic.
                    Limited to 200 total entries, including fields and `OR`
                    operators. See [Sending messages with the OneSignal
                    API](/reference/create-message#filters).
                  items:
                    oneOf:
                      - title: Filter
                        description: Required. The fitler object.
                        required:
                          - field
                          - relation
                        type: object
                        properties:
                          field:
                            type: string
                            description: The name of the filter to use.
                            enum:
                              - tag
                              - last_session
                              - first_session
                              - session_count
                              - session_time
                              - language
                              - app_version
                              - location
                              - country
                          relation:
                            type: string
                            description: >-
                              Used with most filters. See details on the
                              specific filter.
                            enum:
                              - '='
                              - '!='
                              - '>'
                              - <
                              - exists
                              - not_exists
                              - in_array
                              - not_in_array
                              - time_elapsed_gt
                              - time_elapsed_lt
                          key:
                            type: string
                            description: Used with the `tag` filter. This is the tag `key`.
                          value:
                            type: string
                            description: >-
                              The value of the `field` or tag `key` in which you
                              want to filter with.
                      - title: Operator
                        type: object
                        properties:
                          operator:
                            type: string
                            description: >-
                              Chain filter conditions with implicit `AND` and
                              `OR` logic. Never end your `filters` object with
                              an `operator`. See
                              [filters](/reference/create-message#filters) for
                              more.
                            enum:
                              - AND
                              - OR
                            default: AND
                  minItems: 1
                  maxItems: 200
                email_subject:
                  type: string
                  description: >-
                    The subject of the email. Supports [Message
                    Personalization](/docs/message-personalization).
                  default: This is your email subject.
                email_preheader:
                  type: string
                  description: Preview text displayed after the email subject.
                email_body:
                  type: string
                  description: >-
                    The body of the email in HTML format. Required if
                    `template_id` is not set. Supports [Message
                    Personalization](/docs/message-personalization).
                name:
                  type: string
                  description: >-
                    An internal name you set to help organize and track
                    messages. Not shown to recipients. Maximum 128 characters.
                template_id:
                  type: string
                  description: >-
                    The template ID in UUID v4 format set for the message if
                    applicable. See [Templates](/docs/en/templates).
                custom_data:
                  type: object
                  description: >-
                    Include user or context-specific data (e.g., cart items,
                    OTPs, links) in a message. Use with `template_id`. See
                    [Message Personalization](/docs/message-personalization).
                    Max size: 2KB (Push/SMS), 10KB (Email).
                email_from_name:
                  type: string
                  description: >-
                    The name the email is sent from. Defaults to the 'Sender
                    Name' in the Email Settings of your OneSignal Dashboard. See
                    [Email setup](/docs/email-setup) and
                    [Senders](/docs/senders).
                  default: Your Company
                email_from_address:
                  type: string
                  description: >-
                    The full email address shown in the 'From' field of the
                    email (e.g., `promotions@news.example.com`). This is what
                    recipients see as the sender. If not specified, OneSignal
                    uses the default 'Sender Email' set in your Dashboard's
                    Email Settings. See [Senders](/docs/senders).
                email_sender_domain:
                  type: string
                  description: >-
                    The authenticated sending domain used for email delivery.
                    This domain must be verified in your DNS records and will
                    determine which domain handles the mail transfer. It may not
                    always exactly match the domain in the `email_from_address`
                    (e.g., `email_from_address = news@example.com` while
                    `email_sender_domain = mail.example.com`), but the root
                    domain must align for DMARC compliance. If not specified,
                    OneSignal uses the default sender email's domain configured
                    in your Dashboard. See [Email setup](/docs/email-setup) and
                    [Senders](/docs/senders).
                email_reply_to_address:
                  type: string
                  description: >-
                    The email address users reply to. Defaults to the 'Reply-To'
                    address in the Email Settings of your OneSignal Dashboard.
                    See [Email setup](/docs/email-setup).
                email_bcc:
                  type: array
                  description: >-
                    BCC recipients for the email. Maximum 5 addresses. Only
                    supported when the email service provider is OneSignal
                    Email. For every email sent, an additional billable email is
                    sent to each BCC address.  See [BCC
                    Emails](/docs/en/email-bcc).
                  items:
                    type: string
                include_unsubscribed:
                  type: boolean
                  description: >-
                    Used for important account-related, non-marking emails. If
                    set to `true` it will send the email to unsubscribed email
                    addresses. Defaults to `false`. See [Email unsubscribe links
                    & headers](/docs/unsubscribe-links-email-subscriptions).
                disable_email_click_tracking:
                  type: boolean
                  description: >-
                    If set to `true`, the URLs sent within the email will not
                    include link tracking and will be the same as originally
                    set; otherwise, all the URLs in the email will be tracked.
                    See [Email unsubscribe links &
                    headers](/docs/unsubscribe-links-email-subscriptions).
                    Defaults to `false`.
                send_after:
                  type: string
                  description: >-
                    Schedule delivery for a future date/time (in UTC). The
                    format must be valid per the [ISO
                    8601](https://en.wikipedia.org/wiki/ISO_8601) standard and
                    compatible with [`JavaScript’s Date()
                    parser`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#datestring).
                    Example: `2025-09-24T14:00:00-07:00`
                delayed_option:
                  type: string
                  description: >-
                    Controls how messages are delivered on a per-user basis:
                    `'timezone'` — Sends at the same local time across time
                    zones. `'last-active'` — Delivers based on each user’s most
                    recent session. Not compatible with [Push
                    Throttling](/docs/throttling). If enabled, set
                    `throttle_rate_per_minute` to `0`.
                delivery_time_of_day:
                  type: string
                  description: >-
                    Use with `delayed_option: 'timezone'` to set a consistent
                    local delivery time. Accepted formats: `'9:00AM'` (12-hour),
                    `'21:45'` (24-hour), `'09:45:30'` (HH:mm:ss).
                idempotency_key:
                  type: string
                  description: >-
                    A unique identifier used to prevent duplicate messages from
                    repeat API calls. See [Idempotent notification
                    requests](/reference/idempotent-notification-requests). Any
                    RFC 9562 UUID supported. Valid for 30 days. Previously
                    called `external_id`.
      responses:
        '200':
          description: '200'
          content:
            application/json:
              schema:
                oneOf:
                  - title: Message Sent
                    type: object
                    properties:
                      id:
                        type: string
                        description: >-
                          Notification ID in UUID v4 format. If `id` is an empty
                          string, then the message was not sent.
                        format: uuid
                      external_id:
                        type:
                          - string
                          - 'null'
                        description: >-
                          The `idempotency_key` parameter from the request,
                          echoed back. Null when no idempotency_key was
                          provided. Used to detect duplicate-send attempts — see
                          [Idempotent message
                          requests](/reference/idempotent-notification-requests).
                      errors:
                        type: object
                        description: >-
                          Per-channel listings of invalid identifiers in the
                          request. Only emitted when at least one identifier in
                          the request failed validation. Each listed key is
                          optional; the keys present depend on the channel and
                          request.
                        properties:
                          invalid_email_tokens:
                            type: array
                            items:
                              type: string
                              description: >-
                                The listed email addresses used in the
                                `email_to` parameter that were unsubscribed from
                                the email message channel before the message was
                                sent.
                          invalid_aliases:
                            type: object
                            description: >-
                              The alias label that was used in the
                              `include_aliases` parameter.
                            properties:
                              external_id:
                                type: array
                                items:
                                  type: string
                                  description: >-
                                    The alias IDs associated with the
                                    unsubscribed Subscriptions. The listed
                                    aliases were unsubscribed before the message
                                    was sent. In this example, `user_id_1` has
                                    two unsubscribed Subscriptions while
                                    `user_id_2` has one unsubscribed
                                    Subscription.
                                  example: '["user_id_1", "user_id_1", "user_id_2"]'
                              onesignal_id:
                                type: array
                                items:
                                  type: string
                                  description: >-
                                    The OneSignal ID associated with the
                                    unsubscribed Subscription. The listed
                                    OneSignal IDs were unsubscribed before the
                                    message was sent. In this example, the user
                                    with OneSignal ID
                                    `1589641e-bed1-4325-bce4-d2234e578884` has
                                    three unsubscribed Subscriptions.
                                  example: >-
                                    ["1589641e-bed1-4325-bce4-d2234e578884",
                                    "1589641e-bed1-4325-bce4-d2234e578884",
                                    "1589641e-bed1-4325-bce4-d2234e578884"]
                          invalid_player_ids:
                            type: array
                            items:
                              type: string
                              description: >-
                                The Subscription ID exists in the OneSignal app
                                but is unsubscribed from the message channel. If
                                the Subscription ID did not exist, it will not
                                be reported.
                      warnings:
                        oneOf:
                          - type: object
                            description: Object form.
                            properties:
                              invalid_external_user_ids:
                                type: string
                                description: >-
                                  external_ids whose subscriptions are
                                  unsubscribed.
                            additionalProperties: true
                          - type: array
                            items:
                              type: string
                            description: Array form. Contains non-fatal warning messages.
                        description: >-
                          Non-fatal warnings emitted alongside a successful
                          send.
                    description: >-
                      Notification was accepted and dispatched to one or more
                      subscribers. `errors` (when present) reports per-channel
                      invalid identifiers; `warnings` (when present) reports
                      non-fatal issues such as unsubscribed external IDs.
                      `external_id` echoes the request's `idempotency_key` (or
                      null when not provided).
                    required:
                      - id
                  - title: Message Not Sent
                    type: object
                    properties:
                      id:
                        type: string
                        description: >-
                          If the message `id` is an empty string, then no
                          message was sent. The request appears to be formatted
                          correctly, but there are issues with the aliases,
                          segments, or filters targeted.
                        example: ''
                        enum:
                          - ''
                      errors:
                        type: array
                        items:
                          type: string
                        description: >-
                          Reasons the message was not dispatched. The most
                          common value is `"All included players are not
                          subscribed"`, which means every subscription matched
                          by the segments/aliases/filters was unsubscribed
                          before send time. Per-channel sentinels (e.g., invalid
                          identifiers) may also appear.
                        example:
                          - All included players are not subscribed
                      warnings:
                        oneOf:
                          - type: object
                            description: Object form.
                            properties:
                              invalid_external_user_ids:
                                type: string
                                description: >-
                                  external_ids whose subscriptions are
                                  unsubscribed.
                            additionalProperties: true
                          - type: array
                            items:
                              type: string
                            description: Array form. Contains non-fatal warning messages.
                        description: >-
                          Non-fatal warnings emitted alongside a successful
                          send.
                    description: >-
                      Validation passed but the targeting matched zero
                      subscribers (and the notification is not
                      lightspeed-eligible). HTTP status is 200 even though no
                      message was dispatched. `id` is always the empty string in
                      this branch — use it as the discriminator from the Message
                      Sent variant.
                    required:
                      - id
                      - errors
                description: >-
                  Two variants are possible with HTTP 200, distinguished by the
                  `id` field: a UUID indicates the message was accepted and
                  dispatched (Message Sent); an empty string indicates the
                  request was valid but no subscribers matched (Message Not
                  Sent). Inspect `errors` when `id` is empty.
          headers:
            Idempotent-Replayed:
              description: >-
                Present and set to `true` when this response is a replay of a
                previous successful request that used the same
                `idempotency_key`. Absent on fresh executions. Use this to
                distinguish "new send" from "deduplicated retry" without
                inspecting the body.
              schema:
                type: boolean
                enum:
                  - true
        '400':
          description: '400'
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: array
                    description: The reason for the bad request.
                    items:
                      properties:
                        Message Notifications must have English language content:
                          type: string
                          description: >-
                            Make sure the request or template has English
                            language ('en')content. This is required but can be
                            any language desired.
                        'Incorrect subscription_id format in include_subscription_ids (not a valid UUID):':
                          type: string
                          description: The provided `subscription_id` is not a valid UUID.
                        Platforms You may only send to one delivery channel at a time. Make sure you are only including one of push platforms, Email, or SMS.:
                          type: string
                          description: >-
                            You are attempting to send a message to a
                            Subscription for a different channel. Make sure you
                            are only targeting one channel at a time.
        '403':
          description: >-
            Forbidden. The Authorization key cannot send email for this app, or
            the request targets a feature the app's plan does not enable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - This API is not available for applications on your plan.
        '429':
          description: >-
            Rate limit exceeded. Wait the number of seconds in the `Retry-After`
            header before retrying.
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying the request. Always
                emitted on 429 responses.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - API rate limit exceeded
        '503':
          description: >-
            Service temporarily unavailable. Retry after a short backoff. The
            body may be empty or non-JSON in some failure modes.
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying. Optional — may be
                absent when the response is generated upstream.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - Service temporarily unavailable
      deprecated: false
      x-codeSamples:
        - lang: typescript
          label: Node.js SDK
          source: >-
            import Onesignal from '@onesignal/node-onesignal';

            import { randomUUID } from 'node:crypto';


            const configuration = Onesignal.createConfiguration({
                restApiKey: 'YOUR_REST_API_KEY',
            });

            const apiInstance = new Onesignal.DefaultApi(configuration);


            const notification = new Onesignal.Notification();

            notification.app_id = 'YOUR_APP_ID';

            notification.email_subject = 'Welcome to OneSignal';

            notification.email_body = '<h1>Hello!</h1><p>Thanks for signing
            up.</p>';

            // Target by External ID: alias keys must match the API
            (external_id, not externalId).

            notification.include_aliases = { external_id:
            ['YOUR_USER_EXTERNAL_ID'] };

            notification.target_channel = 'email';

            // Idempotency key: a client-generated UUID that lets you safely
            retry on network failure.

            // If two requests arrive with the same key inside the 30-day
            window, only the first is sent

            // and the second returns the original response. `randomUUID` is
            imported from `node:crypto`

            // (available on Node 14.17+) — DO NOT reuse keys across logically
            distinct sends.

            notification.idempotency_key = randomUUID();


            try {
              const response = await apiInstance.createNotification(notification);
              if (!response.id) {
                console.warn("Notification was not sent:", response.errors);
              } else if (response.errors) {
                console.log("Notification created:", response.id, "(partial failures:", response.errors, ")");
              } else {
                console.log("Notification created:", response.id);
              }
            } catch (e) {
              if (e instanceof Onesignal.ApiException) {
                // `e.errorMessages` flattens any error-envelope shape to a `string[]`;
                // the raw parsed body remains on `e.body`.
                console.error("createNotification failed: HTTP " + e.code, e.errorMessages);
              } else {
                throw e;
              }
            }
        - lang: python
          label: Python SDK
          source: >-
            import uuid

            import onesignal

            from onesignal.api import default_api

            from onesignal.model.notification import Notification


            # See configuration.py for a list of all supported configuration
            parameters.

            # Some of the OneSignal endpoints require ORGANIZATION_API_KEY token
            for authorization, while others require REST_API_KEY.

            # We recommend adding both of them in the configuration page so that
            you will not need to figure it out yourself.

            configuration = onesignal.Configuration(
                rest_api_key = "YOUR_REST_API_KEY", # App REST API key required for most endpoints
                organization_api_key = "YOUR_ORGANIZATION_API_KEY" # Organization key is only required for creating new apps and other top-level endpoints
            )



            with onesignal.ApiClient(configuration) as api_client:
                api_instance = default_api.DefaultApi(api_client)
                notification = Notification(
                    app_id='YOUR_APP_ID',
                    email_subject='Welcome to OneSignal',
                    email_body='<h1>Hello!</h1><p>Thanks for signing up.</p>',
                    include_aliases={'external_id': ['YOUR_USER_EXTERNAL_ID']},
                    target_channel='email',
                    # Idempotency key: a client-generated UUID that lets you safely retry on network
                    # failure. If two requests arrive with the same key inside the 30-day window, only
                    # the first is sent and the second returns the original response. Use uuid.uuid4()
                    # or a similar source of randomness — DO NOT reuse keys across logically distinct
                    # sends.
                    idempotency_key=str(uuid.uuid4()),
                )
                try:
                    api_response = api_instance.create_notification(notification)
                    # `api_response.id` discriminates the two HTTP 200 shapes. A falsy value means no
                    # notification was created (e.g. all targets were unreachable / not subscribed).
                    # `api_response.errors` is polymorphic: a `list[str]` in the no-subscribers case, or
                    # a dict keyed by recipient-identifier type (`invalid_player_ids`,
                    # `invalid_external_user_ids`, `invalid_aliases`, ...) when the notification WAS
                    # created but some recipients were skipped. Access via `.get('errors')` rather than
                    # attribute access — the legacy Python generator's `ModelNormal.__getattr__` raises
                    # `ApiAttributeError` for optional fields that the server omitted, so plain
                    # `api_response.errors` would crash on the pure-success path.
                    response_id = api_response.get('id')
                    response_errors = api_response.get('errors')
                    if not response_id:
                        print('Notification was not sent:', response_errors)
                    elif response_errors:
                        print('Notification created:', response_id, '(partial failures:', response_errors, ')')
                    else:
                        print('Notification created:', response_id)
                except onesignal.ApiException as e:
                    print('Exception when calling DefaultApi->create_notification: %s\n' % e)
                    print('Status Code: %s' % e.status)
                    # `e.error_messages` flattens any error-envelope shape to a list[str];
                    # the raw body remains on `e.body`.
                    print('Error Messages: %s' % e.error_messages)
                    print('Response Body: %s' % e.body)
        - lang: php
          label: PHP SDK
          source: >-
            <?php

            require_once(__DIR__ . '/vendor/autoload.php');



            // Configure Bearer authorization: rest_api_key

            $config = onesignal\client\Configuration::getDefaultConfiguration()
                                                            ->setRestApiKeyToken('YOUR_REST_API_KEY')
                                                            ->setOrganizationApiKeyToken('YOUR_ORGANIZATION_API_KEY');



            $apiInstance = new onesignal\client\Api\DefaultApi(
                new GuzzleHttp\Client(),
                $config
            );


            $notification = new onesignal\client\Model\Notification();

            $notification->setAppId('YOUR_APP_ID');

            $notification->setEmailSubject('Welcome to OneSignal');

            $notification->setEmailBody('<h1>Hello!</h1><p>Thanks for signing
            up.</p>');

            $notification->setIncludeAliases(['external_id' =>
            ['YOUR_USER_EXTERNAL_ID']]);

            $notification->setTargetChannel('email');

            // Idempotency key: a client-generated UUID that lets you safely
            retry on network failure.

            // If two requests arrive with the same key inside the 30-day
            window, only the first is sent

            // and the second returns the original response. Use a strong source
            of randomness — DO NOT

            // reuse keys across logically distinct sends. We use PHP 7+'s
            built-in random_bytes() here

            // so the snippet works against this SDK's declared composer.json
            deps (Guzzle + PSR-7) with

            // no extra install; projects that already pull in ramsey/uuid can
            swap in

            // `\Ramsey\Uuid\Uuid::uuid4()->toString()` instead.

            $idempotencyKeyBytes = random_bytes(16);

            $idempotencyKeyBytes[6] = chr(ord($idempotencyKeyBytes[6]) & 0x0f |
            0x40);

            $idempotencyKeyBytes[8] = chr(ord($idempotencyKeyBytes[8]) & 0x3f |
            0x80);

            $idempotencyKey = vsprintf('%s%s-%s-%s-%s-%s%s%s',
            str_split(bin2hex($idempotencyKeyBytes), 4));

            $notification->setIdempotencyKey($idempotencyKey);


            try {
                $result = $apiInstance->createNotification($notification);
                // `$result->getId()` discriminates the two HTTP 200 shapes. A falsy value (empty
                // string or null) means no notification was created (e.g. all targets were
                // unreachable / not subscribed). `$result->getErrors()` is polymorphic: a `string[]`
                // in the no-subscribers case, or an object keyed by recipient-identifier type
                // (`invalid_player_ids`, `invalid_external_user_ids`, `invalid_aliases`, ...) when
                // the notification WAS created but some recipients were skipped.
                if (!$result->getId()) {
                    echo 'Notification was not sent: ', print_r($result->getErrors(), true), PHP_EOL;
                } elseif ($result->getErrors()) {
                    echo 'Notification created: ', $result->getId(), ' (partial failures: ', print_r($result->getErrors(), true), ')', PHP_EOL;
                } else {
                    echo 'Notification created: ', $result->getId(), PHP_EOL;
                }
            } catch (\onesignal\client\ApiException $e) {
                echo 'Exception when calling DefaultApi->createNotification: ', $e->getMessage(), PHP_EOL;
                echo 'Status Code: ', $e->getCode(), PHP_EOL;
                echo 'Response Body: ', $e->getResponseBody(), PHP_EOL;
            } catch (\Exception $e) {
                echo 'Exception when calling DefaultApi->createNotification: ', $e->getMessage(), PHP_EOL;
            }
        - lang: go
          label: Go SDK
          source: |-
            package main

            import (
                "context"
                "fmt"
                "os"

                "github.com/google/uuid"
                "github.com/OneSignal/onesignal-go-api/v5"
            )

            func main() {
                configuration := onesignal.NewConfiguration()
                apiClient := onesignal.NewAPIClient(configuration)

                restAuth := context.WithValue(context.Background(), onesignal.RestApiKey, "YOUR_REST_API_KEY")

                notification := onesignal.NewNotification("YOUR_APP_ID")
                notification.SetEmailSubject("Welcome to OneSignal")
                notification.SetEmailBody("<h1>Hello!</h1><p>Thanks for signing up.</p>")
                notification.SetIncludeAliases(map[string][]string{"external_id": {"YOUR_USER_EXTERNAL_ID"}})
                notification.SetTargetChannel("email")
                // Idempotency key: a client-generated UUID that lets you safely retry on network failure.
                // If two requests arrive with the same key inside the 30-day window, only the first is
                // sent and the second returns the original response. The `github.com/google/uuid` module
                // is not a declared dep of this SDK; run `go get github.com/google/uuid` (or `go mod tidy`
                // after importing it) before building. DO NOT reuse keys across logically distinct sends.
                notification.SetIdempotencyKey(uuid.NewString())

                resp, r, err := apiClient.DefaultApi.CreateNotification(restAuth).Notification(*notification).Execute()
                if err != nil {
                    fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.CreateNotification``: %v\n", err)
                    fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
                    if apiErr, ok := err.(*onesignal.GenericOpenAPIError); ok {
                        fmt.Fprintf(os.Stderr, "Response Body: %s\n", apiErr.Body())
                    }
                    return
                }
                // `resp.GetId()` discriminates the two HTTP 200 shapes. An empty string means no
                // notification was created (e.g. all targets were unreachable / not subscribed).
                // `resp.GetErrors()` is `interface{}` because the field is polymorphic: a `[]string` in
                // the no-subscribers case, or a map keyed by recipient-identifier type
                // (`invalid_player_ids`, `invalid_external_user_ids`, `invalid_aliases`, ...) when
                // the notification WAS created but some recipients were skipped.
                if resp.GetId() == "" {
                    fmt.Fprintf(os.Stderr, "Notification was not sent: %v\n", resp.GetErrors())
                } else if errors := resp.GetErrors(); errors != nil {
                    fmt.Fprintf(os.Stdout, "Notification created: %s (partial failures: %v)\n", resp.GetId(), errors)
                } else {
                    fmt.Fprintf(os.Stdout, "Notification created: %s\n", resp.GetId())
                }
            }
        - lang: ruby
          label: Ruby SDK
          source: >-
            require 'onesignal'

            # setup authorization

            OneSignal.configure do |config|
              # Configure Bearer authorization: rest_api_key
              config.rest_api_key = 'YOUR_REST_API_KEY'

            end


            api_instance = OneSignal::DefaultApi.new

            require 'securerandom'


            notification = OneSignal::Notification.new

            notification.app_id = 'YOUR_APP_ID'

            notification.email_subject = 'Welcome to OneSignal'

            notification.email_body = '<h1>Hello!</h1><p>Thanks for signing
            up.</p>'

            notification.include_aliases = { 'external_id' =>
            ['YOUR_USER_EXTERNAL_ID'] }

            notification.target_channel = 'email'

            # Idempotency key: a client-generated UUID that lets you safely
            retry on network failure.

            # If two requests arrive with the same key inside the 30-day window,
            only the first is sent

            # and the second returns the original response. Use
            SecureRandom.uuid — DO NOT reuse keys

            # across logically distinct sends.

            notification.idempotency_key = SecureRandom.uuid


            begin
              # Create notification
              result = api_instance.create_notification(notification)
              # `result.id` discriminates the two HTTP 200 shapes. An empty string means no
              # notification was created (e.g. all targets were unreachable / not subscribed).
              # `result.errors` is polymorphic: an `Array<String>` in the no-subscribers case, or
              # a Hash keyed by recipient-identifier type (`invalid_player_ids`,
              # `invalid_external_user_ids`, `invalid_aliases`, ...) when the notification WAS
              # created but some recipients were skipped.
              if result.id.to_s.empty?
                puts "Notification was not sent: #{result.errors}"
              elsif result.errors
                puts "Notification created: #{result.id} (partial failures: #{result.errors})"
              else
                puts "Notification created: #{result.id}"
              end
            rescue OneSignal::ApiError => e
              puts "Error when calling DefaultApi->create_notification: #{e}"
              puts "Status Code: #{e.code}"
              # `e.error_messages` flattens any error-envelope shape to an Array<String>;
              # the raw body remains on `e.response_body`.
              puts "Error Messages: #{e.error_messages}"
              puts "Response Body: #{e.response_body}"
            end
        - lang: java
          label: Java SDK
          source: |-
            // Import classes:
            import java.util.Arrays;
            import java.util.HashMap;
            import java.util.List;
            import java.util.Map;
            import java.util.UUID;

            import com.onesignal.client.ApiClient;
            import com.onesignal.client.ApiException;
            import com.onesignal.client.Configuration;
            import com.onesignal.client.auth.*;
            import com.onesignal.client.model.*;
            import com.onesignal.client.api.DefaultApi;

            public class Example {
              public static void main(String[] args) {
                ApiClient defaultClient = Configuration.getDefaultApiClient();
                defaultClient.setBasePath("https://api.onesignal.com");

                HttpBearerAuth rest_api_key = (HttpBearerAuth) defaultClient.getAuthentication("rest_api_key");
                rest_api_key.setBearerToken("YOUR_REST_API_KEY");

                DefaultApi apiInstance = new DefaultApi(defaultClient);
                Notification notification = new Notification();
                notification.setAppId("YOUR_APP_ID");
                notification.setEmailSubject("Welcome to OneSignal");
                notification.setEmailBody("<h1>Hello!</h1><p>Thanks for signing up.</p>");
                Map<String, List<String>> aliases = new HashMap<>();
                aliases.put("external_id", Arrays.asList("YOUR_USER_EXTERNAL_ID"));
                notification.setIncludeAliases(aliases);
                notification.setTargetChannel(Notification.TargetChannelEnum.EMAIL);
                // Idempotency key: a client-generated UUID that lets you safely retry on network failure.
                // If two requests arrive with the same key inside the 30-day window, only the first is
                // sent and the second returns the original response. Use UUID.randomUUID() — DO NOT
                // reuse keys across logically distinct sends.
                notification.setIdempotencyKey(UUID.randomUUID().toString());

                try {
                  CreateNotificationSuccessResponse result = apiInstance.createNotification(notification);
                  // `result.getId()` discriminates the two HTTP 200 shapes. An empty string means no
                  // notification was created (e.g. all targets were unreachable / not subscribed).
                  // `result.getErrors()` is polymorphic (declared as `Object`): a `List<String>` in the
                  // no-subscribers case, or a Map keyed by recipient-identifier type
                  // (`invalid_player_ids`, `invalid_external_user_ids`, `invalid_aliases`, ...) when
                  // the notification WAS created but some recipients were skipped.
                  if (result.getId() == null || result.getId().isEmpty()) {
                    System.out.println("Notification was not sent: " + result.getErrors());
                  } else if (result.getErrors() != null) {
                    System.out.println("Notification created: " + result.getId() + " (partial failures: " + result.getErrors() + ")");
                  } else {
                    System.out.println("Notification created: " + result.getId());
                  }
                } catch (ApiException e) {
                  System.err.println("Exception when calling DefaultApi#createNotification");
                  System.err.println("Status code: " + e.getCode());
                  System.err.println("Reason: " + e.getResponseBody());
                  System.err.println("Response headers: " + e.getResponseHeaders());
                  e.printStackTrace();
                }
              }
            }
        - lang: csharp
          label: C# SDK
          source: |-
            using System;
            using System.Collections.Generic;
            using System.Diagnostics;
            using OneSignalApi.Api;
            using OneSignalApi.Client;
            using OneSignalApi.Model;

            namespace Example
            {
                public class CreateNotificationExample
                {
                    public static void Main()
                    {
                        Configuration config = new Configuration();
                        config.BasePath = "https://api.onesignal.com";
                        config.AccessToken = "YOUR_REST_API_KEY";

                        var apiInstance = new DefaultApi(config);

                        var notification = new Notification
                        {
                            AppId = "YOUR_APP_ID",
                            EmailSubject = "Welcome to OneSignal",
                            EmailBody = "<h1>Hello!</h1><p>Thanks for signing up.</p>",
                            IncludeAliases = new Dictionary<string, List<string>>
                            {
                                { "external_id", new List<string> { "YOUR_USER_EXTERNAL_ID" } }
                            },
                            TargetChannel = Notification.TargetChannelEnum.Email,
                            // Idempotency key: a client-generated UUID that lets you safely retry on
                            // network failure. If two requests arrive with the same key inside the
                            // 30-day window, only the first is sent and the second returns the original
                            // response. Use Guid.NewGuid() — DO NOT reuse keys across logically distinct
                            // sends.
                            IdempotencyKey = Guid.NewGuid().ToString()
                        };

                        try
                        {
                            CreateNotificationSuccessResponse result = apiInstance.CreateNotification(notification);
                            // `result.Id` discriminates the two HTTP 200 shapes. An empty string means
                            // no notification was created (e.g. all targets were unreachable / not
                            // subscribed). `result.Errors` is polymorphic: a `List<string>` in the
                            // no-subscribers case, or an object keyed by recipient-identifier type
                            // (`invalid_player_ids`, `invalid_external_user_ids`, `invalid_aliases`, ...)
                            // when the notification WAS created but some recipients were skipped.
                            if (string.IsNullOrEmpty(result.Id))
                            {
                                Debug.WriteLine("Notification was not sent: " + result.Errors);
                            }
                            else if (result.Errors != null)
                            {
                                Debug.WriteLine("Notification created: " + result.Id + " (partial failures: " + result.Errors + ")");
                            }
                            else
                            {
                                Debug.WriteLine("Notification created: " + result.Id);
                            }
                        }
                        catch (ApiException e)
                        {
                            Debug.Print("Exception when calling DefaultApi.CreateNotification: " + e.Message);
                            Debug.Print("Status Code: " + e.ErrorCode);
                            Debug.Print("Response Body: " + e.ErrorContent);
                            Debug.Print(e.StackTrace);
                        }
                    }
                }
            }
        - lang: rust
          label: Rust SDK
          source: |-
            use onesignal_rust_api::apis::configuration::Configuration;
            use onesignal_rust_api::apis::default_api;
            use onesignal_rust_api::models::notification::TargetChannelType;
            use onesignal_rust_api::models::Notification;
            use uuid::Uuid;

            #[tokio::main]
            async fn main() {
                let mut configuration = Configuration::new();
                configuration.rest_api_key_token = Some("YOUR_REST_API_KEY".to_string());

                let mut notification = Notification::new("YOUR_APP_ID".to_string());
                notification.email_subject = Some("Welcome to OneSignal".to_string());
                notification.email_body = Some("<h1>Hello!</h1><p>Thanks for signing up.</p>".to_string());
                let mut aliases = std::collections::HashMap::new();
                aliases.insert(
                    "external_id".to_string(),
                    vec!["YOUR_USER_EXTERNAL_ID".to_string()],
                );
                notification.include_aliases = Some(aliases);
                notification.target_channel = Some(TargetChannelType::Email);
                // Idempotency key: a client-generated UUID that lets you safely retry on network failure.
                // If two requests arrive with the same key inside the 30-day window, only the first is
                // sent and the second returns the original response. The `uuid` crate must be declared
                // in your own Cargo.toml (Cargo doesn't expose transitive crates by name to downstream
                // code) — add `uuid = { version = "1", features = ["v4"] }` to your `[dependencies]`.
                // DO NOT reuse keys across logically distinct sends.
                notification.idempotency_key = Some(Uuid::new_v4().to_string());

                match default_api::create_notification(&configuration, notification).await {
                    Ok(resp) => {
                        // `resp.id` discriminates the two HTTP 200 shapes. An empty string or `None`
                        // means no notification was created (e.g. all targets were unreachable / not
                        // subscribed). `resp.errors` is polymorphic (typed as `Option<serde_json::Value>`):
                        // a `Vec<String>` in the no-subscribers case, or an object keyed by
                        // recipient-identifier type (`invalid_player_ids`, `invalid_external_user_ids`,
                        // `invalid_aliases`, ...) when the notification WAS created but some recipients
                        // were skipped.
                        match resp.id.as_deref() {
                            Some("") | None => eprintln!("Notification was not sent: {:?}", resp.errors),
                            Some(id) if resp.errors.is_some() => {
                                println!("Notification created: {} (partial failures: {:?})", id, resp.errors)
                            }
                            Some(id) => println!("Notification created: {}", id),
                        }
                    }
                    Err(onesignal_rust_api::apis::Error::ResponseError(content)) => {
                        eprintln!("create_notification failed: HTTP {}", content.status);
                        eprintln!("Response Body: {}", content.content);
                    }
                    Err(e) => eprintln!("create_notification failed: {:?}", e),
                }
            }
components:
  schemas:
    BasicErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            type: string
          description: One or more human-readable error messages.
        success:
          type: boolean
          description: >-
            Present (and `false`) on some endpoints (notifications, templates,
            segments). Not emitted by every endpoint.
        reference:
          type: array
          items:
            type: string
          description: >-
            Documentation URL fragments related to the error. Only emitted by
            the API-key auth error helpers.

````