# Registering for Notifications on iOS

> \[!CAUTION]
>
> Twilio deprecated Notify in October 2022 and no longer supports it. Learn more about [transitioning off Notify](https://support.twilio.com/hc/en-us/articles/11746930233115-Transitioning-off-Notify).
>
> If you're starting a new project, use [Programmable Messaging](/docs/messaging) for SMS notifications. For push notifications, integrate directly with platform-specific services such as APNs for iOS or FCM for Android. If you've already built on Notify, visit the [transition guide](https://support.twilio.com/hc/en-us/articles/11746930233115-Transitioning-off-Notify) to learn about your options.

Ready to send your first notification? Of course, you're not! That's why you're
here. But don't worry, we'll get you registered so you can start sending
notifications faster than a collision-free hash table lookup (OK, maybe
not that fast).

A Notifications application involves two components:

* A client (iOS) app that registers for and receives notifications
* A server app that creates bindings and sends notifications

The aim of this guide is to show you how these two components work together
when you register for notifications. Let's get to it!

## Table of Contents

* [Client: Registering a Device with APNS](#client-registering-a-device-with-apns)
* [Client + Server: Creating a Binding](#client--server-creating-a-binding)

## Client: Registering a Device with APNS

Before working with Twilio Notifications, we'll need to register our device
with APNS. This registration will happen every app launch, and in our
**AppDelegate** and we can specify the type of notification (sound, alert,
or badge) that we'd like to accept. On the first launch, iOS will prompt
us to enable push notifications with a popup alert.

Register a Device

```objective-c
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Override point for customization after application launch.
  if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings
                                                       settingsForTypes:(UIUserNotificationTypeSound | 
                                                         UIUserNotificationTypeAlert | 
                                                         UIUserNotificationTypeBadge)
                                                             categories:nil]];
        
    [UIApplication sharedApplication] registerForRemoteNotifications];
  } else {
    [[UIApplication sharedApplication] registerForRemoteNotifications];
  }
  return YES;
}
```

```swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  // Override point for customization after application launch.
  let settings = UIUserNotificationSettings(forTypes: .Alert, categories: nil)
  UIApplication.sharedApplication().registerUserNotificationSettings(settings)
  UIApplication.sharedApplication().registerForRemoteNotifications()
  return true
}
```

Once we've enabled notifications, iOS will send an asynchronous response to the
app via the **didRegisterForRemoteNotifications** function. Make sure you've
properly configured your [iOS](/docs/notify/configure-ios-push-notifications) app for notifications or else the registration won't work.

## Client + Server: Creating a Binding

### Client

Once we've received a successful registration response from the **didRegisterForRemote
NotificationsWithDeviceToken** method, it's time to create a
[Binding](/docs/notify/api/binding-resource).
A "Binding" represents a unique device that can receive a notification.
It associates a unique device token (provided by iOS) with an
identity and an optional set of tags that you define for your
application. When you want to send a notification, Twilio will send your
notification only to Bindings that match the parameters you specify
(more on that later).

> \[!WARNING]
>
> In iOS 13, the format of the string returned when you call the `description` method on an `NSData` object has changed from previous iOS versions. This means that code that parses the device token string from a call like `[deviceToken description]` or similar, where `deviceToken` is an `NSData` object, will break in iOS 13.
>
> The preferred way of creating a string of hex characters from bytes would be to iterate through each of the bytes and create a new string using a format string. There is an example in the Objective-C snippet for Creating a Binding.

The client app should send a request to the server
containing the device token and any additional information the server might
need to create the binding (typically Identity and BindingType). We'll use the NSURLSession networking API that is part of the iOS standard library to make the request. You could also use another library, such as [AFNetworking](https://github.com/AFNetworking/AFNetworking) or [Alamofire](https://github.com/Alamofire/Alamofire).

The last step on the client side is storing the Endpoint identifier generated by Twilio and included in the response. Storing the Endpoint and reusing it in subsequent requests will allow us to avoid creating duplicated Bindings when the device token changes. Here we use the KeychainAccess helper class from our [quickstart app](/docs/notify/quickstart/ios) but you can use your own way of accessing the keychain.

Create a Binding (Client-side)

```objective-c
- (NSString*) createDeviceTokenString:(NSData*) deviceToken {
    const unsigned char *tokenChars = deviceToken.bytes;
    
    NSMutableString *tokenString = [NSMutableString string];
    for (int i=0; i < deviceToken.length; i++) {
        NSString *hex = [NSString stringWithFormat:@"%02x", tokenChars[i]];
        [tokenString appendString:hex];
    }
    return tokenString;
}

-(void) registerDevice:(NSData *) deviceToken identity:(NSString *) identity {
  // Create a POST request to the /register endpoint with device variables to register for Twilio Notifications
    
  NSString *deviceTokenString = [self createDeviceTokenString:deviceToken];


  NSURLSession *session = [NSURLSession sharedSession];

  NSURL *url = [NSURL URLWithString:serverURL];
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
  request.HTTPMethod = @"POST";

  [request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
  [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

  NSDictionary *params = @{@"identity": identity,
                        @"BindingType": @"apn",
                            @"Address": deviceTokenString};

  NSError* err=nil
  NSString *endpoint = [KeychainAccess readEndpoint:identity error:err];
  if (err == nil){
    [params setObject:endpoint forKey:@"endpoint"];
  }

  NSError *error;
  NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
  request.HTTPBody = jsonData;

  NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Response: %@", responseString);

    if (error == nil) {
      NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
      NSLog(@"JSON: %@", response);

      [KeychainAccess saveEndpoint:identity endpoint:response["endpoint"]]

    } else {
      NSLog(@"Error: %@", error);
    }
  }];
  [task resume];
}
```

```swift
func registerDevice(identity: String, deviceToken: String) {

    // Create a POST request to the /register endpoint with device variables to register for Twilio Notifications
    let session = NSURLSession.sharedSession()

    let url = NSURL(string: serverURL)
    let request = NSMutableURLRequest(URL: url!, cachePolicy: .UseProtocolCachePolicy, timeoutInterval: 30.0)
    request.HTTPMethod = "POST"

    request.addValue("application/json", forHTTPHeaderField: "Accept")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")

    let params = ["identity": identity,
                  "BindingType" : "apn",
                  "Address" : deviceToken]

    //Check if we have an Endpoint identifier already for this app
    if let endpoint = try? KeychainAccess.readEndpoint(identity: identity){
        params["endpoint"] = endpoint
    } else {
      print("Error retrieving endpoint from keychain: \(error)")
    }


    let jsonData = try! NSJSONSerialization.dataWithJSONObject(params, options: [])
    request.HTTPBody = jsonData

    let task = session.dataTaskWithRequest(request) { (responseData:NSData?, response:NSURLResponse?, error:NSError?) in
      if let responseData = responseData {
        let responseString = NSString(data: responseData, encoding: NSUTF8StringEncoding)
        print("Response Body: \(responseString)")
        do {
          let responseObject = try NSJSONSerialization.JSONObjectWithData(responseData, options: [])
          print("JSON: \(responseObject)")
          if let responseDictionary = responseObject as? [String: Any] {
            try KeychainAccess.saveEndpoint(identity: identity, endpoint: responseDictionary["endpoint"] as! String)
          }
        } catch let error {
          print("Error: \(error)")
        }
      }
    }
    task.resume()
  }
```

### Server

In our server app, we'll receive the `POST` request. It'll contain the following
four parameters.

| name        | description                                                                                                                                                                                                                                                                       |
| :---------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Identity    | The Identity to which this Binding belongs. Identity is defined by your application and can have multiple endpoints.                                                                                                                                                              |
| BindingType | The type of the Binding determining the transport technology to use. We will use `apn` here.                                                                                                                                                                                      |
| Address     | The device token obtained from iOS.                                                                                                                                                                                                                                               |
| Endpoint    | The identifier of the device to which this registration belongs. This is generated the first time you create a Binding. Then you need to store it in the keychain and provide it in your subsequent registrations to avoid duplicating Bindings even if the device token changes. |

> \[!WARNING]
>
> Notify uses **Identity** as a unique identifier of a user. You should not use directly identifying information (aka personally identifiable information or PII) like a **person's name, home address, email or phone number, etc., as Identity** because the systems that will process this attribute assume it is not directly identifying information.

We'll use **index.js** in our server app and these four parameters to send
an API call to Twilio, using the next generation [Twilio Node SDK](https://github.com/twilio/twilio-node). This will
help us create a new Binding. We implement this logic in the /register
endpoint, but this is not required. You can come up with your own API,
and perhaps integrate it into a login or a session initialization flow.

Create a Binding (Server-side)

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function createBinding() {
  const binding = await client.notify.v1
    .services("ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .bindings.create({
      address: "apn_device_token",
      bindingType: "apn",
      endpoint: "endpoint_id",
      identity: "00000001",
      tag: ["preferred device"],
    });

  console.log(binding.sid);
}

createBinding();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

binding = client.notify.v1.services(
    "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
).bindings.create(
    endpoint="endpoint_id",
    tag=["preferred device"],
    identity="00000001",
    binding_type="apn",
    address="apn_device_token",
)

print(binding.sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Notify.V1.Service;
using System.Threading.Tasks;
using System.Collections.Generic;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var binding = await BindingResource.CreateAsync(
            endpoint: "endpoint_id",
            tag: new List<string> { "preferred device" },
            identity: "00000001",
            bindingType: BindingResource.BindingTypeEnum.Apn,
            address: "apn_device_token",
            pathServiceSid: "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

        Console.WriteLine(binding.Sid);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import java.util.Arrays;
import com.twilio.Twilio;
import com.twilio.rest.notify.v1.service.Binding;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Binding binding =
            Binding
                .creator("ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "00000001", Binding.BindingType.APN, "apn_device_token")
                .setEndpoint("endpoint_id")
                .setTag(Arrays.asList("preferred device"))
                .create();

        System.out.println(binding.getSid());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	notify "github.com/twilio/twilio-go/rest/notify/v1"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &notify.CreateBindingParams{}
	params.SetEndpoint("endpoint_id")
	params.SetTag([]string{
		"preferred device",
	})
	params.SetIdentity("00000001")
	params.SetBindingType("apn")
	params.SetAddress("apn_device_token")

	resp, err := client.NotifyV1.CreateBinding("ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.Sid != nil {
			fmt.Println(*resp.Sid)
		} else {
			fmt.Println(resp.Sid)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$binding = $twilio->notify->v1
    ->services("ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    ->bindings->create(
        "00000001", // Identity
        "apn", // BindingType
        "apn_device_token", // Address
        [
            "endpoint" => "endpoint_id",
            "tag" => ["preferred device"],
        ]
    );

print $binding->sid;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

binding = @client
          .notify
          .v1
          .services('ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
          .bindings
          .create(
            endpoint: 'endpoint_id',
            tag: [
              'preferred device'
            ],
            identity: '00000001',
            binding_type: 'apn',
            address: 'apn_device_token'
          )

puts binding.sid
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:notify:v1:services:bindings:create \
   --service-sid ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
   --endpoint endpoint_id \
   --tag "preferred device" \
   --identity 00000001 \
   --binding-type apn \
   --address apn_device_token
```

```bash
curl -X POST "https://notify.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Bindings" \
--data-urlencode "Endpoint=endpoint_id" \
--data-urlencode "Tag=preferred device" \
--data-urlencode "Identity=00000001" \
--data-urlencode "BindingType=apn" \
--data-urlencode "Address=apn_device_token" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "address": "apn_device_token",
  "binding_type": "apn",
  "credential_sid": null,
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z",
  "endpoint": "endpoint_id",
  "identity": "00000001",
  "notification_protocol_version": "3",
  "service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "sid": "BSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "tags": [
    "26607274"
  ],
  "links": {
    "user": "https://notify.twilio.com/v1/Services/ISaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Users/24987039"
  },
  "url": "https://notify.twilio.com/v1/Services/ISaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Bindings/BSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

Now that we've registered the client app with APNS and created a
Binding, it's time to send some notifications! Check out our [Sending Notifications](/docs/notify/send-notifications) guide for more information.

[Next: Sending Notifications »](/docs/notify/send-notifications)
