curl --request POST \
--url 'https://api.onesignal.com/notifications?c=email' \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"app_id": "YOUR_APP_ID",
"email_subject": "This is your email subject.",
"email_body": "<string>",
"include_aliases": {
"external_id": [
"<string>"
]
},
"target_channel": "email",
"include_subscription_ids": [
"<string>"
],
"email_to": [
"<string>"
],
"included_segments": [
"<string>"
],
"excluded_segments": [
"<string>"
],
"filters": [
{
"key": "<string>",
"value": "<string>"
}
],
"email_preheader": "<string>",
"name": "<string>",
"template_id": "<string>",
"custom_data": {},
"email_from_name": "Your Company",
"email_from_address": "<string>",
"email_sender_domain": "<string>",
"email_reply_to_address": "<string>",
"email_bcc": [
"<string>"
],
"include_unsubscribed": true,
"disable_email_click_tracking": true,
"send_after": "<string>",
"delayed_option": "<string>",
"delivery_time_of_day": "<string>",
"idempotency_key": "<string>"
}
'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;
}
}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)<?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;
}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())
}
}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// 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();
}
}
}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);
}
}
}
}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),
}
}{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"external_id": "<string>",
"errors": {
"invalid_email_tokens": [
"<string>"
],
"invalid_aliases": {
"external_id": [
"[\"user_id_1\", \"user_id_1\", \"user_id_2\"]"
],
"onesignal_id": [
"[\"1589641e-bed1-4325-bce4-d2234e578884\", \"1589641e-bed1-4325-bce4-d2234e578884\", \"1589641e-bed1-4325-bce4-d2234e578884\"]"
]
},
"invalid_player_ids": [
"<string>"
]
},
"warnings": {
"invalid_external_user_ids": "<string>"
}
}{
"errors": [
{
"Message Notifications must have English language content": "<string>",
"Incorrect subscription_id format in include_subscription_ids (not a valid UUID):": "<string>",
"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.": "<string>"
}
]
}{
"errors": [
"This API is not available for applications on your plan."
]
}{
"errors": [
"API rate limit exceeded"
]
}{
"errors": [
"Service temporarily unavailable"
]
}Send a message using the email channel.
curl --request POST \
--url 'https://api.onesignal.com/notifications?c=email' \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"app_id": "YOUR_APP_ID",
"email_subject": "This is your email subject.",
"email_body": "<string>",
"include_aliases": {
"external_id": [
"<string>"
]
},
"target_channel": "email",
"include_subscription_ids": [
"<string>"
],
"email_to": [
"<string>"
],
"included_segments": [
"<string>"
],
"excluded_segments": [
"<string>"
],
"filters": [
{
"key": "<string>",
"value": "<string>"
}
],
"email_preheader": "<string>",
"name": "<string>",
"template_id": "<string>",
"custom_data": {},
"email_from_name": "Your Company",
"email_from_address": "<string>",
"email_sender_domain": "<string>",
"email_reply_to_address": "<string>",
"email_bcc": [
"<string>"
],
"include_unsubscribed": true,
"disable_email_click_tracking": true,
"send_after": "<string>",
"delayed_option": "<string>",
"delivery_time_of_day": "<string>",
"idempotency_key": "<string>"
}
'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;
}
}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)<?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;
}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())
}
}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// 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();
}
}
}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);
}
}
}
}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),
}
}{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"external_id": "<string>",
"errors": {
"invalid_email_tokens": [
"<string>"
],
"invalid_aliases": {
"external_id": [
"[\"user_id_1\", \"user_id_1\", \"user_id_2\"]"
],
"onesignal_id": [
"[\"1589641e-bed1-4325-bce4-d2234e578884\", \"1589641e-bed1-4325-bce4-d2234e578884\", \"1589641e-bed1-4325-bce4-d2234e578884\"]"
]
},
"invalid_player_ids": [
"<string>"
]
},
"warnings": {
"invalid_external_user_ids": "<string>"
}
}{
"errors": [
{
"Message Notifications must have English language content": "<string>",
"Incorrect subscription_id format in include_subscription_ids (not a valid UUID):": "<string>",
"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.": "<string>"
}
]
}{
"errors": [
"This API is not available for applications on your plan."
]
}{
"errors": [
"API rate limit exceeded"
]
}{
"errors": [
"Service temporarily unavailable"
]
}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 or SMS to send to those channels. Ensure your Email setup is complete.Headers
Your App API key with prefix Key. See Keys & IDs.
Body
Your OneSignal App ID in UUID v4 format. See Keys & IDs.
The subject of the email. Supports Message Personalization.
The body of the email in HTML format. Required if template_id is not set. Supports Message Personalization.
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.
Show child attributes
Show child attributes
The targeted delivery channel. Required when using include_aliases. Accepts push, email, or sms.
push, email, sms Target users' specific 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.
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. Not compatible with any other targeting parameters like filters, include_aliases, included_segments, or excluded_segments. See Sending messages with the OneSignal API.
Target predefined Segments. 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.
Exclude users in predefined Segments. 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.
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.
1 - 200 elementsRequired. The fitler object.
- Filter
- Operator
Show child attributes
Show child attributes
Preview text displayed after the email subject.
An internal name you set to help organize and track messages. Not shown to recipients. Maximum 128 characters.
Include user or context-specific data (e.g., cart items, OTPs, links) in a message. Use with template_id. See Message Personalization. Max size: 2KB (Push/SMS), 10KB (Email).
The name the email is sent from. Defaults to the 'Sender Name' in the Email Settings of your OneSignal Dashboard. See Email setup and Senders.
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 and Senders.
The email address users reply to. Defaults to the 'Reply-To' address in the Email Settings of your OneSignal Dashboard. See Email setup.
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.
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.
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. Defaults to false.
Schedule delivery for a future date/time (in UTC). The format must be valid per the ISO 8601 standard and compatible with JavaScript’s Date() parser. Example: 2025-09-24T14:00:00-07:00
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. If enabled, set throttle_rate_per_minute to 0.
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).
A unique identifier used to prevent duplicate messages from repeat API calls. See Idempotent notification requests. Any RFC 9562 UUID supported. Valid for 30 days. Previously called external_id.
Response
200
- Message Sent
- Message Not Sent
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.
Notification ID in UUID v4 format. If id is an empty string, then the message was not sent.
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.
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.
Show child attributes
Show child attributes
Non-fatal warnings emitted alongside a successful send.
Show child attributes
Show child attributes
Was this page helpful?