In Novu, we call the entities designed to receive notifications as Subscribers. Each subscriber is unique and identified by a unique subscriberId.

subscriberId is a unique identifier used by Novu to keep track of a specific subscriber. We recommend using the internal unique id your application uses for a specific user.

Each subscriber has the following data points:

  • User Data - Data stored in the subscriber object that you can easily access in your notification templates. This contains basic info such as first name, last name, avatar, locale, email, and phone. This data is fixed and structured.
  • Custom Data - Apart from the above fixed structured user data, any unstructured custom data such as user’s address, nationality, height, etc can also be stored in the data field using key-value pairs.
  • Channel Specific Credentials - deviceTokens required to send push notifications and webhookUrl for chat channel providers can also be stored.

Subscriber attributes

FieldTypeRequiredExample
subscriberIdstringtrueb0bea066-f5fe-11ed-b67e-0242ac120002
firstNamestringfalseJohn
lastNamestringfalseDoe
emailstringfalsejohn.doe@domain.org.
phonestringfalse+13603963366
localestringfalseen
avatarstringfalsehttps://example.com/images/avatar.jpg
dataobjectfalse{"key": "value"}

Subscriber response schema

Novu subscriber object

{
  "_id": "NOVU_GENERATED_SUBSCRIBER_ID",
  "_organizationId": "NOVU_GENERATED_ORG_ID",
  "_environmentId": "NOVU_GENERATED_ENV_ID",
  "firstName": "John",
  "lastName": "Doe",
  "subscriberId": "subscriberId",
  "email": "[john.doe@org.com](mailto:john.doe@org.com)",
  "phone": "+98712345670"
  "data": {
    "custome_key_1" : "custom_value_1",
    "custome_key_2" : "custom_value_2"
  }
  "channels": [
  {
    "credentials": {
      "deviceTokens": [
        "token1",
        "token2"
      ]
    },
    "_integrationId": "NOVU_GENERATED_INTEGRATION_ID",
    "providerId": "fcm"
  },
  {
    "credentials": {
      "webhookUrl": "URL"
    },
    "_integrationId": "NOVU_GENERATED_INTEGRATION_ID",
    "providerId": "discord"
  }
  ],
  "deleted": false,
  "createdAt": "2022-10-13T17:40:53.231Z",
  "updatedAt": "2022-10-13T17:41:53.238Z",
  "__v": 0,
  "isOnline": false,
  "lastOnlineAt": "2022-10-13T17:41:53.238Z",
  "avatar": "AVATAR_URL",
  "id": "NOVU_GENERATED_SUBSCRIBER_ID"
}

Create a subscriber

You can create a subscriber in Novu using the identify method provided in Novu’s SDK.

The identify method serves the purpose of handling existing “subscriberId” providers within the database. When a provider with the same subscriberId already exists, this method performs an update operation using the data present in the payload. In cases where there is no pre-existing entry, the method generates a new one, thus exhibiting an behavior.

It is possible for two subscribers to have the same email address in our system. This is because the subscriberId is the unique identifier that distinguishes one subscriber from another.

import { Novu } from "@novu/node";

// Insert your Novu API Key here
const novu = new Novu("<NOVU_API_KEY>");

// Create a subscriber on Novu
await novu.subscribers.identify("132", {
  email: "john.doe@domain.com",
  firstName: "John",
  lastName: "Doe",
  phone: "+13603963366",
});
The phone parameter must be parsed as a string.

You should now be able to see your new subscriber on the Novu dashboard.

You can also add additional fields such as phone, avatar, and data.

Remember, all user IDs added to Novu need to be unique.

If you face issues with the subscriber creation only taking the user ID and omitting other fields such as firstName, lastName, etc., you could consider updating the subscriber after creation.

Please also be aware that although it’s currently possible to create a subscriber with an empty subscriberId, this subscriber cannot be deleted later.

We support creating new subscriber using two ways, Ahead of Trigger means adding subscribers before triggering notification or Inline of Trigger means sending complete subscriber data in to field while triggering.

1. Ahead of Trigger

Create the subscriber and then trigger the notification to this subscriber. Here subscriberId is the required field and other fields are optional.

import { Novu } from '@novu/node';

const novu = new Novu('<NOVU_API_KEY>');

await novu.subscribers.identify('111', {
  email: 'john.doe@domain.com',
  firstName: 'John',
  lastName: 'Doe',
  phone: '+13603963366',
  avatar: 'https://example.com/images/avatar.jpg',
  locale: 'en-US',
  data: { customKey1: 'customVal1', customKey2: 'customVal2' },
});

Novu will create a subscriber if one does not exist and will update the existing subscriber based on the identify payload. You can call this function during registration or signup to make sure the subscriber data is up-to-date, if you wish to save additional attributes with a subscriber, you can pass additional custom data in the data field as key-value pairs.

2. Inline of Trigger

A non-existing subscriber can be added by sending subscriber data in to field of the trigger method. If any subscriber with provided subscriberId does not exists, a new subscriber will be created. In this case, subscriber will be created first and then the trigger will be executed synchronously.

import { Novu } from '@novu/node';

const novu = new Novu('<NOVU_API_KEY>');

await novu.trigger('<WORKFLOW_TRIGGER_IDENTIFIER>', {
  to: {
    subscriberId: '111',
    email: 'john.doe@domain.com',
    firstName: 'John',
    lastName: 'Doe',
    phone: '+13603963366',
  },
  payload: {
    customVariable: 'variableValue',
    organization: {
      logo: 'https://organization.com/logo.png',
    },
  },
});

Bulk Subscriber Creation

You can create subscribers in bulk (up to 500 at once) via the SDKs or API.

The bulk subscriber creation feature is only available in v0.19.0 and above.
await novu.subscribers.bulkCreate([
  {
    subscriberId: 'test-subscriber-1',
    email: 'test-user@sd.com',
    firstName: 'subscriber-1',
    lastName: 'test-1',
  },
  {
    subscriberId: 'test-subscriber-2',
    email: 'test-user-2@sd.com',
    firstName: 'subscriber-2',
    lastName: 'test-2',
  },
  {
    subscriberId: 'test-subscriber-3',
  },
]);

Import subscribers

Here, mock_data.csv file is a CSV file having mock data. The below script will read this CSV file and create a new subscriber in Novu. Change example variables values like API_KEY value with your valid values. Download mock_data.csv file from here.

mock_data.csv file should be in the same directory of script

Steps:

  1. Export your user details in CSV format.
  2. Clean this exported CSV file. Keep only relevant fields.
  3. Move this CSV file to the script directory.
  4. Change the file name in the script with your file name.
  5. Run the script. (Make script.sh executable before using)
#!/bin/bash

# Change these variables with your own values
CSV_FILE="mock_data.csv"
API_ENDPOINT="https://api.novu.co/v1/subscribers"
API_KEY="ApiKey <API_KEY>"

OLDIFS=$IFS
IFS=','
[ ! -f $CSV_FILE ] && { echo "$CSV_FILE file not found"; exit 99; }

SECONDS=0

# Read the CSV file line by line
while read subscriberId firstName lastName email phone locale avatar
do
    # Check if subscriberId is empty or not present
    if [[ -z "$subscriberId" ]]; then
        echo "Skipping row with missing subscriberId"
        continue
    fi

    # Construct the JSON body for the POST request
    json_body="{\"subscriberId\": \"$subscriberId\""

    # Add optional fields to the JSON body if present
    if [[ -n "$firstName" ]]; then
        json_body="$json_body, \"firstName\": \"$firstName\""
    fi

    if [[ -n "$lastName" ]]; then
        json_body="$json_body, \"lastName\": \"$lastName\""
    fi

    if [[ -n "$email" ]]; then
        # Validate email using regex
        if [[ ! "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
            echo "Invalid email format for subscriberId: $subscriberId"
            continue
        fi
        json_body="$json_body, \"email\": \"$email\""
    fi

    if [[ -n "$phone" ]]; then
        json_body="$json_body, \"phone\": \"$phone\""
    fi

    if [[ -n "$locale" ]]; then
        # Validate locale using regex
        if [[ ! "$locale" =~ ^[a-zA-Z]{2}(-[a-zA-Z]{2})?$ ]]; then
            echo "Invalid locale format for subscriberId: $subscriberId"
            continue
        fi
        json_body="$json_body, \"locale\": \"$locale\""
    fi

    if [[ -n "$avatar" ]]; then
        json_body="$json_body, \"avatar\": \"$avatar\""
    fi

    if [[ -n "$address" || -n "$job" ]]; then
        json_body="$json_body, \"data\": {"

        if [[ -n "$address" ]]; then
            json_body="$json_body \"address\": \"$address\""
        else
            json_body="$json_body \"address\": \"\""
        fi

        if [[ -n "$job" ]]; then
            json_body="$json_body, \"job\": \"$job\""
        else
            json_body="$json_body, \"job\": \"\""
        fi

        json_body="$json_body }"
    fi

    json_body="$json_body}"

    echo $json_body

    #Send the cURL POST request with the JSON body and handle exceptions
    response=$(curl -s -X POST -H "Content-Type: application/json" -H "Authorization: $API_KEY" -d "$json_body" -w "%{http_code}" "$API_ENDPOINT")

    http_code=${response:${#response}-3}

    if [[ $http_code -eq 201 ]]; then
        echo "cURL request successful for subscriberId: $subscriberId - HTTP Status Code: $http_code"
    else
        echo "cURL request failed for subscriberId: $subscriberId - HTTP Status Code: $http_code - response : $response"
    fi

done < "$CSV_FILE"

ELAPSED="Time Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"

echo $ELAPSED

Delete a subscriber

To stop a subscriber from receiving notifications, you can delete the subscriber. This will hard delete the subscriber and means you will not be able to access this subscriber later. You will have to create this subscriber again.

import { Novu } from '@novu/node';

const novu = new Novu('<NOVU_API_KEY>');

await novu.subscribers.delete('111');

Update a subscriber

In some cases, you want to access a subscriber to update a specific user data field or custom data field. For example, when the users change their email address or personal details.

import { Novu } from '@novu/node';

const novu = new Novu('<NOVU_API_KEY>');

await novu.subscribers.update('111', {
  // new email
  email: 'john@domain.com',
  // new phone
  phone: '+19874567832',
});

Find a subscriber

Any subscriber can be retrieved using a unique subscriber identifier subscriberId. Check the returned subscriber schema here.

import { Novu } from '@novu/node';

const novu = new Novu('<NOVU_API_KEY>');

await novu.subscribers.get('111');