> ## 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.

# Server SDK reference

> Install, configure, and use OneSignal server SDKs to send push notifications, emails, and SMS from your backend in Node.js, Python, Java, Go, PHP, Ruby, C#, and Rust.

All OneSignal server SDKs are generated from the same OpenAPI specification, so they share a consistent interface regardless of language. Each SDK wraps the [OneSignal REST API](/reference/create-message) and provides typed models for requests and responses.

Every SDK covers the same set of endpoints: Notifications, Users, Subscriptions, Segments, Templates, Live Activities, Custom Events, API Keys, and Apps.

## Available SDKs

| Language  | Package                                                                                            | Repository                                                  |
| --------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| Node.js   | [@onesignal/node-onesignal](https://www.npmjs.com/package/@onesignal/node-onesignal)               | [GitHub](https://github.com/OneSignal/onesignal-node-api)   |
| Python    | [onesignal-python-api](https://pypi.org/project/onesignal-python-api/)                             | [GitHub](https://github.com/OneSignal/onesignal-python-api) |
| Java      | [onesignal-java-client](https://central.sonatype.com/artifact/com.onesignal/onesignal-java-client) | [GitHub](https://github.com/OneSignal/onesignal-java-api)   |
| Go        | [onesignal-go-api](https://pkg.go.dev/github.com/OneSignal/onesignal-go-api)                       | [GitHub](https://github.com/OneSignal/onesignal-go-api)     |
| PHP       | [onesignal/onesignal-php-api](https://packagist.org/packages/onesignal/onesignal-php-api)          | [GitHub](https://github.com/OneSignal/onesignal-php-api)    |
| Ruby      | [onesignal](https://rubygems.org/gems/onesignal)                                                   | [GitHub](https://github.com/OneSignal/onesignal-ruby-api)   |
| C# (.NET) | [OneSignalApi](https://www.nuget.org/packages/OneSignalApi)                                        | [GitHub](https://github.com/OneSignal/onesignal-dotnet-api) |
| Rust      | [onesignal-rust-api](https://crates.io/crates/onesignal-rust-api)                                  | [GitHub](https://github.com/OneSignal/onesignal-rust-api)   |

***

## Before you begin

Gather these values from your OneSignal dashboard before installing an SDK. See [Keys & IDs](./keys-and-ids) for where to find each one.

1. **App ID** — the unique identifier for your OneSignal app.
2. **REST API Key** — required for most endpoints (sending notifications, managing users).
3. **Organization API Key** *(optional)* — only required for organization-level endpoints like creating or listing apps.

***

## Installation

<Note>
  Version numbers below are examples. Check the package registry for each SDK to install the latest version.
</Note>

<Tabs>
  <Tab title="Node.js">
    ```bash theme={null}
    npm install @onesignal/node-onesignal
    ```
  </Tab>

  <Tab title="Python">
    Requires Python 3.6+.

    ```bash theme={null}
    pip install onesignal-python-api
    ```
  </Tab>

  <Tab title="Java">
    Requires Java 1.8+ and Maven 3.8.3+ or Gradle 7.2+.

    **Maven**

    ```xml theme={null}
    <dependency>
      <groupId>com.onesignal</groupId>
      <artifactId>onesignal-java-client</artifactId>
      <version>5.8.1</version>
    </dependency>
    ```

    **Gradle**

    ```groovy theme={null}
    implementation "com.onesignal:onesignal-java-client:5.8.1"
    ```
  </Tab>

  <Tab title="Go">
    ```bash theme={null}
    go get github.com/OneSignal/onesignal-go-api/v5
    ```
  </Tab>

  <Tab title="PHP">
    Requires PHP 7.3+.

    Add to `composer.json`:

    ```json theme={null}
    {
      "require": {
        "onesignal/onesignal-php-api": "^5.3"
      }
    }
    ```

    Then run `composer update`.
  </Tab>

  <Tab title="Ruby">
    Add to your `Gemfile`:

    ```ruby theme={null}
    gem 'onesignal', '~> 5.8.0'
    ```

    Then run `bundle install`.
  </Tab>

  <Tab title="C# (.NET)">
    ```bash theme={null}
    dotnet add package OneSignalApi
    ```
  </Tab>

  <Tab title="Rust">
    Add to `Cargo.toml` under `[dependencies]`:

    ```toml theme={null}
    onesignal-rust-api = "5.8.0"
    ```
  </Tab>
</Tabs>

***

## Configuration

Every SDK requires authentication via API keys. Two key types are available:

* **REST API Key** — required for most endpoints (sending notifications, managing users, etc.). Found in your app's **Settings > Keys & IDs**.
* **Organization API Key** — only required for organization-level endpoints like creating or listing apps. Found in **Organization Settings**.

<Warning>
  Store your API keys in environment variables or a secrets manager. Never commit them to source control. The examples below read from `ONESIGNAL_REST_API_KEY` and `ONESIGNAL_ORGANIZATION_API_KEY`.
</Warning>

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    const OneSignal = require('@onesignal/node-onesignal');

    const configuration = OneSignal.createConfiguration({
      restApiKey: process.env.ONESIGNAL_REST_API_KEY,
      organizationApiKey: process.env.ONESIGNAL_ORGANIZATION_API_KEY,
    });

    const client = new OneSignal.DefaultApi(configuration);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    import onesignal
    from onesignal.api import default_api

    configuration = onesignal.Configuration(
        rest_api_key=os.environ['ONESIGNAL_REST_API_KEY'],
        organization_api_key=os.environ.get('ONESIGNAL_ORGANIZATION_API_KEY'),
    )

    with onesignal.ApiClient(configuration) as api_client:
        client = default_api.DefaultApi(api_client)
        # Call client.create_notification(...) and other methods here.
    ```

    <Note>
      Because `ApiClient` is a context manager, make your `client.create_notification(...)` calls inside the `with` block so the underlying HTTP session stays open.
    </Note>
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import com.onesignal.client.ApiClient;
    import com.onesignal.client.Configuration;
    import com.onesignal.client.auth.HttpBearerAuth;
    import com.onesignal.client.api.DefaultApi;

    ApiClient defaultClient = Configuration.getDefaultApiClient();

    HttpBearerAuth restApiAuth = (HttpBearerAuth) defaultClient
        .getAuthentication("rest_api_key");
    restApiAuth.setBearerToken(System.getenv("ONESIGNAL_REST_API_KEY"));

    HttpBearerAuth orgApiAuth = (HttpBearerAuth) defaultClient
        .getAuthentication("organization_api_key");
    orgApiAuth.setBearerToken(System.getenv("ONESIGNAL_ORGANIZATION_API_KEY"));

    DefaultApi client = new DefaultApi(defaultClient);
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    import (
        "context"
        "os"

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

    restAuth := context.WithValue(
        context.Background(),
        onesignal.RestApiKey,
        os.Getenv("ONESIGNAL_REST_API_KEY"),
    )

    orgAuth := context.WithValue(
        restAuth,
        onesignal.OrganizationApiKey,
        os.Getenv("ONESIGNAL_ORGANIZATION_API_KEY"),
    )

    apiClient := onesignal.NewAPIClient(onesignal.NewConfiguration())
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    use onesignal\client\api\DefaultApi;
    use onesignal\client\Configuration;
    use GuzzleHttp;

    $config = Configuration::getDefaultConfiguration()
        ->setRestApiKeyToken(getenv('ONESIGNAL_REST_API_KEY'))
        ->setOrganizationApiKeyToken(getenv('ONESIGNAL_ORGANIZATION_API_KEY'));

    $client = new DefaultApi(
        new GuzzleHttp\Client(),
        $config
    );
    ```
  </Tab>

  <Tab title="Ruby">
    ```ruby theme={null}
    require 'onesignal'

    OneSignal.configure do |config|
      config.rest_api_key = ENV['ONESIGNAL_REST_API_KEY']
      config.organization_api_key = ENV['ONESIGNAL_ORGANIZATION_API_KEY']
    end

    client = OneSignal::DefaultApi.new
    ```
  </Tab>

  <Tab title="C# (.NET)">
    ```csharp theme={null}
    using OneSignalApi.Api;
    using OneSignalApi.Client;

    var config = new Configuration();
    config.BasePath = "https://api.onesignal.com";
    config.AccessToken = Environment.GetEnvironmentVariable("ONESIGNAL_REST_API_KEY");

    var client = new DefaultApi(config);
    ```

    <Note>
      The .NET SDK's `Configuration.AccessToken` holds a single bearer token. To call organization-level endpoints, initialize a separate `Configuration` with your Organization API Key. See the [.NET DefaultApi docs](https://github.com/OneSignal/onesignal-dotnet-api/blob/main/docs/DefaultApi.md) for per-endpoint auth requirements.
    </Note>
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use onesignal_rust_api::apis::configuration::Configuration;
    use std::env;

    fn create_configuration() -> Configuration {
        let mut config = Configuration::new();
        config.rest_api_key_token = env::var("ONESIGNAL_REST_API_KEY").ok();
        config.organization_api_key_token = env::var("ONESIGNAL_ORGANIZATION_API_KEY").ok();
        config
    }
    ```
  </Tab>
</Tabs>

***

## Send a push notification

Send push notifications to web and mobile [Subscriptions](./subscriptions) by targeting a segment. Each example wraps the send call in try/catch (or the language equivalent) so failures surface instead of silently swallowing errors.

<CodeGroup>
  ```javascript Node.js theme={null}
  const notification = new OneSignal.Notification();
  notification.app_id = 'YOUR_APP_ID';
  notification.contents = { en: 'Hello from OneSignal!' };
  notification.headings = { en: 'Push Notification' };
  notification.included_segments = ['Subscribed Users'];

  try {
    const response = await client.createNotification(notification);
    console.log('Notification ID:', response.id);
  } catch (error) {
    console.error('Failed to create notification:', error);
  }
  ```

  ```python Python theme={null}
  notification = onesignal.Notification(
      app_id='YOUR_APP_ID',
      contents=onesignal.LanguageStringMap(en='Hello from OneSignal!'),
      headings=onesignal.LanguageStringMap(en='Push Notification'),
      included_segments=['Subscribed Users'],
  )

  try:
      response = client.create_notification(notification)
      print('Notification ID:', response.id)
  except Exception as e:
      print('Failed to create notification:', e)
  ```

  ```java Java theme={null}
  import com.onesignal.client.model.Notification;
  import com.onesignal.client.model.LanguageStringMap;

  Notification notification = new Notification();
  notification.setAppId("YOUR_APP_ID");

  LanguageStringMap contents = new LanguageStringMap();
  contents.setEn("Hello from OneSignal!");
  notification.setContents(contents);

  LanguageStringMap headings = new LanguageStringMap();
  headings.setEn("Push Notification");
  notification.setHeadings(headings);

  notification.setIncludedSegments(Arrays.asList("Subscribed Users"));

  try {
      var response = client.createNotification(notification);
      System.out.println("Notification ID: " + response.getId());
  } catch (Exception e) {
      System.err.println("Failed to create notification: " + e.getMessage());
  }
  ```

  ```go Go theme={null}
  notification := *onesignal.NewNotification("YOUR_APP_ID")
  notification.SetContents(onesignal.LanguageStringMap{En: onesignal.PtrString("Hello from OneSignal!")})
  notification.SetHeadings(onesignal.LanguageStringMap{En: onesignal.PtrString("Push Notification")})
  notification.SetIncludedSegments([]string{"Subscribed Users"})

  response, _, err := apiClient.DefaultApi.
      CreateNotification(orgAuth).
      Notification(notification).
      Execute()

  if err != nil {
      log.Fatal(err)
  }
  fmt.Println("Notification ID:", response.GetId())
  ```

  ```php PHP theme={null}
  use onesignal\client\model\Notification;
  use onesignal\client\model\LanguageStringMap;

  $content = new LanguageStringMap();
  $content->setEn('Hello from OneSignal!');

  $headings = new LanguageStringMap();
  $headings->setEn('Push Notification');

  $notification = new Notification();
  $notification->setAppId('YOUR_APP_ID');
  $notification->setContents($content);
  $notification->setHeadings($headings);
  $notification->setIncludedSegments(['Subscribed Users']);

  try {
      $response = $client->createNotification($notification);
      echo 'Notification ID: ' . $response->getId();
  } catch (\Exception $e) {
      error_log('Failed to create notification: ' . $e->getMessage());
  }
  ```

  ```ruby Ruby theme={null}
  notification = OneSignal::Notification.new({
    app_id: 'YOUR_APP_ID',
    contents: { en: 'Hello from OneSignal!' },
    headings: { en: 'Push Notification' },
    included_segments: ['Subscribed Users']
  })

  begin
    response = client.create_notification(notification)
    puts "Notification ID: #{response.id}"
  rescue => e
    puts "Failed to create notification: #{e.message}"
  end
  ```

  ```csharp C# theme={null}
  using OneSignalApi.Model;

  var notification = new Notification(appId: "YOUR_APP_ID")
  {
      Contents = new LanguageStringMap(en: "Hello from OneSignal!"),
      Headings = new LanguageStringMap(en: "Push Notification"),
      IncludedSegments = new List<string> { "Subscribed Users" }
  };

  try
  {
      var response = client.CreateNotification(notification);
      Console.WriteLine("Notification ID: " + response.Id);
  }
  catch (Exception e)
  {
      Console.Error.WriteLine("Failed to create notification: " + e.Message);
  }
  ```

  ```rust Rust theme={null}
  use onesignal_rust_api::apis::default_api;
  use onesignal_rust_api::models::{Notification, LanguageStringMap};

  let mut contents = LanguageStringMap::new();
  contents.en = Some("Hello from OneSignal!".to_string());

  let mut headings = LanguageStringMap::new();
  headings.en = Some("Push Notification".to_string());

  let mut notification = Notification::new("YOUR_APP_ID".to_string());
  notification.contents = Some(Box::new(contents));
  notification.headings = Some(Box::new(headings));
  notification.included_segments = Some(vec!["Subscribed Users".to_string()]);

  let config = create_configuration();
  match default_api::create_notification(&config, notification).await {
      Ok(response) => println!("Notification ID: {}", response.id.unwrap_or_default()),
      Err(e) => eprintln!("Failed to create notification: {:?}", e),
  }
  ```
</CodeGroup>

<Accordion title=".NET: Normalize newline characters manually">
  The .NET SDK does not normalize newline characters automatically. If your content contains `\r\n`, normalize it before passing to `Contents`:

  ```csharp theme={null}
  var normalizedContent = yourContent
      .Replace("\\r\\n", "\n")
      .Replace("\\n", "\n")
      .Replace("\r\n", "\n")
      .Replace("\r", "\n");
  ```
</Accordion>

***

## Send an email

Send emails to [Subscriptions](./subscriptions) with the `email` channel.

<CodeGroup>
  ```javascript Node.js theme={null}
  const notification = new OneSignal.Notification();
  notification.app_id = 'YOUR_APP_ID';
  notification.email_subject = 'Important Update';
  notification.email_body = '<h1>Hello!</h1><p>This is an HTML email.</p>';
  notification.included_segments = ['Subscribed Users'];
  notification.target_channel = 'email';

  try {
    const response = await client.createNotification(notification);
    console.log('Notification ID:', response.id);
  } catch (error) {
    console.error('Failed to create notification:', error);
  }
  ```

  ```python Python theme={null}
  notification = onesignal.Notification(
      app_id='YOUR_APP_ID',
      email_subject='Important Update',
      email_body='<h1>Hello!</h1><p>This is an HTML email.</p>',
      included_segments=['Subscribed Users'],
      target_channel='email',
  )

  try:
      response = client.create_notification(notification)
      print('Notification ID:', response.id)
  except Exception as e:
      print('Failed to create notification:', e)
  ```

  ```java Java theme={null}
  Notification notification = new Notification();
  notification.setAppId("YOUR_APP_ID");
  notification.setEmailSubject("Important Update");
  notification.setEmailBody("<h1>Hello!</h1><p>This is an HTML email.</p>");
  notification.setIncludedSegments(Arrays.asList("Subscribed Users"));
  notification.setTargetChannel(Notification.TargetChannelEnum.EMAIL);

  try {
      var response = client.createNotification(notification);
      System.out.println("Notification ID: " + response.getId());
  } catch (Exception e) {
      System.err.println("Failed to create notification: " + e.getMessage());
  }
  ```

  ```go Go theme={null}
  notification := *onesignal.NewNotification("YOUR_APP_ID")
  notification.SetEmailSubject("Important Update")
  notification.SetEmailBody("<h1>Hello!</h1><p>This is an HTML email.</p>")
  notification.SetIncludedSegments([]string{"Subscribed Users"})
  notification.SetTargetChannel("email")

  response, _, err := apiClient.DefaultApi.
      CreateNotification(orgAuth).
      Notification(notification).
      Execute()

  if err != nil {
      log.Fatal(err)
  }
  fmt.Println("Notification ID:", response.GetId())
  ```

  ```php PHP theme={null}
  $notification = new Notification();
  $notification->setAppId('YOUR_APP_ID');
  $notification->setEmailSubject('Important Update');
  $notification->setEmailBody('<h1>Hello!</h1><p>This is an HTML email.</p>');
  $notification->setIncludedSegments(['Subscribed Users']);
  $notification->setTargetChannel('email');

  try {
      $response = $client->createNotification($notification);
      echo 'Notification ID: ' . $response->getId();
  } catch (\Exception $e) {
      error_log('Failed to create notification: ' . $e->getMessage());
  }
  ```

  ```ruby Ruby theme={null}
  notification = OneSignal::Notification.new({
    app_id: 'YOUR_APP_ID',
    email_subject: 'Important Update',
    email_body: '<h1>Hello!</h1><p>This is an HTML email.</p>',
    included_segments: ['Subscribed Users'],
    target_channel: 'email'
  })

  begin
    response = client.create_notification(notification)
    puts "Notification ID: #{response.id}"
  rescue => e
    puts "Failed to create notification: #{e.message}"
  end
  ```

  ```csharp C# theme={null}
  var notification = new Notification(appId: "YOUR_APP_ID")
  {
      EmailSubject = "Important Update",
      EmailBody = "<h1>Hello!</h1><p>This is an HTML email.</p>",
      IncludedSegments = new List<string> { "Subscribed Users" },
      TargetChannel = Notification.TargetChannelEnum.Email
  };

  try
  {
      var response = client.CreateNotification(notification);
      Console.WriteLine("Notification ID: " + response.Id);
  }
  catch (Exception e)
  {
      Console.Error.WriteLine("Failed to create notification: " + e.Message);
  }
  ```

  ```rust Rust theme={null}
  use onesignal_rust_api::models::notification::TargetChannelType;

  let mut notification = Notification::new("YOUR_APP_ID".to_string());
  notification.email_subject = Some("Important Update".to_string());
  notification.email_body = Some("<h1>Hello!</h1><p>This is an HTML email.</p>".to_string());
  notification.included_segments = Some(vec!["Subscribed Users".to_string()]);
  notification.target_channel = Some(TargetChannelType::Email);

  let config = create_configuration();
  match default_api::create_notification(&config, notification).await {
      Ok(response) => println!("Notification ID: {}", response.id.unwrap_or_default()),
      Err(e) => eprintln!("Failed to create notification: {:?}", e),
  }
  ```
</CodeGroup>

***

## Send an SMS

Send SMS text messages to [Subscriptions](./subscriptions) with the `sms` channel.

<CodeGroup>
  ```javascript Node.js theme={null}
  const notification = new OneSignal.Notification();
  notification.app_id = 'YOUR_APP_ID';
  notification.contents = { en: 'Your SMS message content here' };
  notification.included_segments = ['Subscribed Users'];
  notification.target_channel = 'sms';
  notification.sms_from = '+15551234567';

  try {
    const response = await client.createNotification(notification);
    console.log('Notification ID:', response.id);
  } catch (error) {
    console.error('Failed to create notification:', error);
  }
  ```

  ```python Python theme={null}
  notification = onesignal.Notification(
      app_id='YOUR_APP_ID',
      contents=onesignal.LanguageStringMap(en='Your SMS message content here'),
      included_segments=['Subscribed Users'],
      target_channel='sms',
      sms_from='+15551234567',
  )

  try:
      response = client.create_notification(notification)
      print('Notification ID:', response.id)
  except Exception as e:
      print('Failed to create notification:', e)
  ```

  ```java Java theme={null}
  LanguageStringMap contents = new LanguageStringMap();
  contents.setEn("Your SMS message content here");

  Notification notification = new Notification();
  notification.setAppId("YOUR_APP_ID");
  notification.setContents(contents);
  notification.setIncludedSegments(Arrays.asList("Subscribed Users"));
  notification.setTargetChannel(Notification.TargetChannelEnum.SMS);
  notification.setSmsFrom("+15551234567");

  try {
      var response = client.createNotification(notification);
      System.out.println("Notification ID: " + response.getId());
  } catch (Exception e) {
      System.err.println("Failed to create notification: " + e.getMessage());
  }
  ```

  ```go Go theme={null}
  notification := *onesignal.NewNotification("YOUR_APP_ID")
  notification.SetContents(onesignal.LanguageStringMap{En: onesignal.PtrString("Your SMS message content here")})
  notification.SetIncludedSegments([]string{"Subscribed Users"})
  notification.SetTargetChannel("sms")
  notification.SetSmsFrom("+15551234567")

  response, _, err := apiClient.DefaultApi.
      CreateNotification(orgAuth).
      Notification(notification).
      Execute()

  if err != nil {
      log.Fatal(err)
  }
  fmt.Println("Notification ID:", response.GetId())
  ```

  ```php PHP theme={null}
  $content = new LanguageStringMap();
  $content->setEn('Your SMS message content here');

  $notification = new Notification();
  $notification->setAppId('YOUR_APP_ID');
  $notification->setContents($content);
  $notification->setIncludedSegments(['Subscribed Users']);
  $notification->setTargetChannel('sms');
  $notification->setSmsFrom('+15551234567');

  try {
      $response = $client->createNotification($notification);
      echo 'Notification ID: ' . $response->getId();
  } catch (\Exception $e) {
      error_log('Failed to create notification: ' . $e->getMessage());
  }
  ```

  ```ruby Ruby theme={null}
  notification = OneSignal::Notification.new({
    app_id: 'YOUR_APP_ID',
    contents: { en: 'Your SMS message content here' },
    included_segments: ['Subscribed Users'],
    target_channel: 'sms',
    sms_from: '+15551234567'
  })

  begin
    response = client.create_notification(notification)
    puts "Notification ID: #{response.id}"
  rescue => e
    puts "Failed to create notification: #{e.message}"
  end
  ```

  ```csharp C# theme={null}
  var notification = new Notification(appId: "YOUR_APP_ID")
  {
      Contents = new LanguageStringMap(en: "Your SMS message content here"),
      IncludedSegments = new List<string> { "Subscribed Users" },
      TargetChannel = Notification.TargetChannelEnum.Sms,
      SmsFrom = "+15551234567"
  };

  try
  {
      var response = client.CreateNotification(notification);
      Console.WriteLine("Notification ID: " + response.Id);
  }
  catch (Exception e)
  {
      Console.Error.WriteLine("Failed to create notification: " + e.Message);
  }
  ```

  ```rust Rust theme={null}
  use onesignal_rust_api::models::notification::TargetChannelType;

  let mut contents = LanguageStringMap::new();
  contents.en = Some("Your SMS message content here".to_string());

  let mut notification = Notification::new("YOUR_APP_ID".to_string());
  notification.contents = Some(Box::new(contents));
  notification.included_segments = Some(vec!["Subscribed Users".to_string()]);
  notification.target_channel = Some(TargetChannelType::Sms);
  notification.sms_from = Some("+15551234567".to_string());

  let config = create_configuration();
  match default_api::create_notification(&config, notification).await {
      Ok(response) => println!("Notification ID: {}", response.id.unwrap_or_default()),
      Err(e) => eprintln!("Failed to create notification: {:?}", e),
  }
  ```
</CodeGroup>

***

## Common send patterns

Target specific users, target specific devices, or schedule delivery. The JSON field names shown below map identically across every SDK — call the equivalent setter on your `Notification` object (`setIncludeAliases` / `include_aliases`, `setSendAfter` / `send_after`, etc.).

<AccordionGroup>
  <Accordion title="Send by external ID">
    Send to specific users by their `external_id` alias. You must set `target_channel` when using aliases so OneSignal knows which channel to route the message on.

    <Note>
      Keys under `include_aliases` must match API alias labels exactly (for example, `external_id`, not `externalId`).
    </Note>

    <CodeGroup>
      ```javascript Node.js theme={null}
      const notification = new OneSignal.Notification();
      notification.app_id = 'YOUR_APP_ID';
      notification.contents = { en: 'Hello from OneSignal!' };
      notification.include_aliases = { external_id: ['YOUR_USER_EXTERNAL_ID'] };
      notification.target_channel = 'push';

      const response = await client.createNotification(notification);
      ```

      ```bash cURL theme={null}
      curl -X POST 'https://api.onesignal.com/notifications' \
        -H 'Authorization: key YOUR_REST_API_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "app_id": "YOUR_APP_ID",
          "contents": { "en": "Hello from OneSignal!" },
          "include_aliases": { "external_id": ["YOUR_USER_EXTERNAL_ID"] },
          "target_channel": "push"
        }'
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Send by subscription ID">
    Send to specific subscriptions by their OneSignal-generated subscription ID. Use this when you already know the exact devices or channels you want to reach.

    <CodeGroup>
      ```javascript Node.js theme={null}
      const notification = new OneSignal.Notification();
      notification.app_id = 'YOUR_APP_ID';
      notification.contents = { en: 'Hello from OneSignal!' };
      notification.include_subscription_ids = ['SUBSCRIPTION_ID_1', 'SUBSCRIPTION_ID_2'];

      const response = await client.createNotification(notification);
      ```

      ```bash cURL theme={null}
      curl -X POST 'https://api.onesignal.com/notifications' \
        -H 'Authorization: key YOUR_REST_API_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "app_id": "YOUR_APP_ID",
          "contents": { "en": "Hello from OneSignal!" },
          "include_subscription_ids": ["SUBSCRIPTION_ID_1", "SUBSCRIPTION_ID_2"]
        }'
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Schedule a send">
    Set `send_after` to a future timestamp to schedule delivery. Optionally set `delayed_option` to `timezone` or `last-active` to deliver per-subscription at a local time.

    <CodeGroup>
      ```javascript Node.js theme={null}
      const notification = new OneSignal.Notification();
      notification.app_id = 'YOUR_APP_ID';
      notification.contents = { en: 'Reminder: your event starts soon.' };
      notification.included_segments = ['Subscribed Users'];
      notification.send_after = 'Thu Sep 24 2026 14:00:00 GMT-0700';

      const response = await client.createNotification(notification);
      ```

      ```bash cURL theme={null}
      curl -X POST 'https://api.onesignal.com/notifications' \
        -H 'Authorization: key YOUR_REST_API_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "app_id": "YOUR_APP_ID",
          "contents": { "en": "Reminder: your event starts soon." },
          "included_segments": ["Subscribed Users"],
          "send_after": "Thu Sep 24 2026 14:00:00 GMT-0700"
        }'
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

***

## Verify your setup

After calling `createNotification`, check the response for a non-empty `id` to confirm the notification was accepted:

```json Successful response theme={null}
{
  "id": "b6b326a8-40aa-4204-b430-73cbc0f5d5b6",
  "recipients": 42,
  "external_id": null
}
```

<Warning>
  The API may return HTTP 200 with an empty `id` when no matching subscribed recipients are found. Always check `response.id` before assuming the send succeeded, and inspect `response.errors` for details.
</Warning>

```json Response with no matching recipients theme={null}
{
  "id": "",
  "recipients": 0,
  "errors": ["All included players are not subscribed"]
}
```

If you see an empty `id`, common causes are:

* Segment name is misspelled or has the wrong case (segment names are case-sensitive).
* The `external_id` or subscription ID does not exist in your app.
* All targeted subscriptions are unsubscribed.

***

## Common errors

| Status | Meaning                                                 | Action                                                                                           |
| ------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| 400    | Malformed request or invalid field                      | Check field names and payload shape against the [REST API reference](/reference/create-message). |
| 401    | Missing or invalid API key                              | Verify the key value and that it matches the app you're targeting.                               |
| 403    | Wrong key scope (e.g. app REST key for an org endpoint) | Use the Organization API Key for org-level endpoints.                                            |
| 404    | App, notification, user, or subscription not found      | Verify the ID or alias in the dashboard.                                                         |
| 409    | Conflict — duplicate resource                           | For idempotent sends, this typically means the `idempotency_key` was replayed.                   |
| 429    | Rate limit exceeded                                     | Wait for the `Retry-After` header before retrying; use exponential backoff.                      |
| 5xx    | Server error                                            | Retry with exponential backoff.                                                                  |

***

## Full API reference

Each server SDK supports the same set of endpoints — Notifications, Users, Subscriptions, Segments, Templates, Live Activities, Custom Events, API Keys, and Apps. The `DefaultApi` docs list every method; the models docs describe request and response shapes. Each SDK also ships an `AGENTS.md` with an integration guide tailored to LLM-assisted coding.

| SDK       | API methods                                                                                       | Models                                                                             | LLM/agent guide                                                                    |
| --------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Node.js   | [DefaultApi.md](https://github.com/OneSignal/onesignal-node-api/blob/main/DefaultApi.md)          | [models/](https://github.com/OneSignal/onesignal-node-api/tree/main/models)        | [AGENTS.md](https://github.com/OneSignal/onesignal-node-api/blob/main/AGENTS.md)   |
| Python    | [DefaultApi.md](https://github.com/OneSignal/onesignal-python-api/blob/main/docs/DefaultApi.md)   | [docs/](https://github.com/OneSignal/onesignal-python-api/tree/main/docs)          | [AGENTS.md](https://github.com/OneSignal/onesignal-python-api/blob/main/AGENTS.md) |
| Java      | [DefaultApi.md](https://github.com/OneSignal/onesignal-java-api/blob/main/docs/DefaultApi.md)     | [docs/](https://github.com/OneSignal/onesignal-java-api/tree/main/docs)            | [AGENTS.md](https://github.com/OneSignal/onesignal-java-api/blob/main/AGENTS.md)   |
| Go        | [DefaultApi.md](https://github.com/OneSignal/onesignal-go-api/blob/main/docs/DefaultApi.md)       | [docs/](https://github.com/OneSignal/onesignal-go-api/tree/main/docs)              | [AGENTS.md](https://github.com/OneSignal/onesignal-go-api/blob/main/AGENTS.md)     |
| PHP       | [DefaultApi.md](https://github.com/OneSignal/onesignal-php-api/blob/main/docs/Api/DefaultApi.md)  | [docs/Model/](https://github.com/OneSignal/onesignal-php-api/tree/main/docs/Model) | [AGENTS.md](https://github.com/OneSignal/onesignal-php-api/blob/main/AGENTS.md)    |
| Ruby      | [DefaultApi.md](https://github.com/OneSignal/onesignal-ruby-api/blob/main/docs/DefaultApi.md)     | [docs/](https://github.com/OneSignal/onesignal-ruby-api/tree/main/docs)            | [AGENTS.md](https://github.com/OneSignal/onesignal-ruby-api/blob/main/AGENTS.md)   |
| C# (.NET) | [DefaultApi.md](https://github.com/OneSignal/onesignal-dotnet-api/blob/main/docs/DefaultApi.md)   | [docs/](https://github.com/OneSignal/onesignal-dotnet-api/tree/main/docs)          | [AGENTS.md](https://github.com/OneSignal/onesignal-dotnet-api/blob/main/AGENTS.md) |
| Rust      | [default\_api docs](https://github.com/OneSignal/onesignal-rust-api/blob/main/docs/DefaultApi.md) | [docs/](https://github.com/OneSignal/onesignal-rust-api/tree/main/docs)            | [AGENTS.md](https://github.com/OneSignal/onesignal-rust-api/blob/main/AGENTS.md)   |

For the underlying REST API, see the [complete API reference](/reference/create-message).

***

## FAQ

### Which server SDK should I choose?

Use the SDK that matches your backend language. All server SDKs are generated from the same OpenAPI specification and support the same endpoints, so functionality is identical across languages.

### What is the difference between the REST API Key and Organization API Key?

The **REST API Key** is scoped to a single app and is required for most operations like sending notifications and managing users. The **Organization API Key** is scoped to your organization and is only needed for creating or listing apps. Most integrations only need the REST API Key.

### Can I use the REST API directly instead of an SDK?

Yes. The server SDKs are convenience wrappers around the [OneSignal REST API](/reference/create-message). You can call the API directly using any HTTP client with the `key` authentication scheme (`Authorization: key YOUR_REST_API_KEY`).

### Are these SDKs auto-generated?

Yes. All server SDKs are generated from the OneSignal OpenAPI specification using [OpenAPI Generator](https://openapi-generator.tech). This ensures consistent API coverage across all languages.

***

## Related pages

<Columns cols={2}>
  <Card title="REST API overview" icon="code" href="/reference/rest-api-overview">
    Endpoints, authentication, rate limits, and request/response formats.
  </Card>

  <Card title="Keys & IDs" icon="key" href="./keys-and-ids">
    Find your App ID, REST API key, and Organization API key.
  </Card>

  <Card title="Transactional messages" icon="paper-plane" href="./transactional-messages">
    Send OTPs, receipts, and time-sensitive alerts via API with personalized data.
  </Card>

  <Card title="Identity verification" icon="shield-halved" href="./identity-verification">
    Secure your integration with server-generated JWTs to prevent User impersonation.
  </Card>
</Columns>
