# Simple Web Request

## Generic Web Request

### API Token

To obtain your API token, please provide us with your push certificate. You can either create a new push certificate for us or use your existing one.

### Endpoint to send messages

`POST https://push.contextsdk.com/v1/campaigns/schedule_message_for_user`

This endpoint is used to schedule a push notification message for a specific user on the ContextSDK platform. You need to send one web request per message you want to send.

#### Headers

| Header        | Description                                                                                                       | Example Value                |
| ------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| Authorization | The token used to authorize the request. Replace with a valid authentication token. Reach out to us to get access | `Token CTX-1234567890abcdef` |

#### Request Body

| Parameter              | Type                | Description                                                                                                                                                                                                                                                                  | Example Value                                        |
| ---------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| bundle\_id             | String              | The unique identifier of the application bundle                                                                                                                                                                                                                              | `com.contextsdk.demo`                                |
| platform               | String              | The platform on which the user will receive the message                                                                                                                                                                                                                      | `ios`                                                |
| user\_id               | String              | The unique identifier of the user                                                                                                                                                                                                                                            | `user@contextsdk.com`                                |
| deliver\_within\_hours | Int                 | The time frame, in hours, within which the message should be delivered                                                                                                                                                                                                       | `6`                                                  |
| campaign\_id           | String              | The same type of message should always have the same `campaign_id`. This is used for performance insights, and to train custom models for each `campaign_id`.                                                                                                                | `daily-reminder`                                     |
| idempotency\_key       | String *(optional)* | A unique identifier for the push notification message. If the same `idempotency_key` is used in multiple requests, only the last request will be processed.                                                                                                                  | `1234567890abcdef`                                   |
| delivery\_method       | String *(optional)* | The delivery method for the message. Possible values are `context_aware` and `traditional`. If no value is specified, we will automatically do an AB test on your behalf. If you already have the AB test cohort for the user, you can specify the corresponding value here. | `context_aware`                                      |
| **content**            | Object              | Details of the message to be delivered. See subfields below.                                                                                                                                                                                                                 |                                                      |
| title                  | String              | The title of the push notification message.                                                                                                                                                                                                                                  | `James, It's time to learn English`                  |
| subtitle               | String *(optional)* | The subtitle of the push notification message                                                                                                                                                                                                                                | `Start your English course now!`                     |
| body                   | String              | The body content of the push notification message                                                                                                                                                                                                                            | `It's time to learn English. Start your course now!` |
| sound                  | String *(optional)* | The full name of the audio file in the root of the main app bundle                                                                                                                                                                                                           | `sosumi.caf`                                         |
| badge                  | Int *(optional)*    | The number to display as the badge of the app icon, 0 resets the badge                                                                                                                                                                                                       | `1`                                                  |
| userInfo               | Object *(optional)* | Custom data to be sent with the push notification message                                                                                                                                                                                                                    | `{ "key": "value" }`                                 |
| thread-id              | String *(optional)* | An app-specific identifier for grouping related notifications. This value corresponds to the `threadIdentifier` property in the `UNNotificationContent` object.                                                                                                              |                                                      |
| imageUrl               | String *(optional)* | A URL pointing to a image file hosted publicly on the internet. Requires setting up a notification service extension to fetch the image, see section below                                                                                                                   |                                                      |

#### Example Request

```
POST /v1/campaigns/schedule_message_for_user HTTP/1.1
Host: push.contextsdk.com
Authorization: Token CTX-123456789ABCD
Content-Type: application/json

{
    "bundle_id": "com.contextsdk.demo",
    "platform": "ios",
    "user_id": "user@contextsdk.com",
    "content": {
        "title": "James, it's time for your english course!",
        "body": "Start your english course now!"
    },
    "deliver_within_hours": 3,
    "campaign_id": "daily-reminder",
    "delivery_method": "context_aware"
}
```

**Alternative delivery window specification**

The above `deliver_within_hours` parameter specifies the time frame within which the message should be delivered from the current time onwards. If you want to specify a specific time frame within which the message should be delivered, you can use the `target_delivery_time` parameter instead. That parameter should be a string in the format ISO 8601, e.g. `2025-01-25T18:32:00Z`.

**Localization**

ContextPush has native support to localize messages for your users. The `content.title`, `content.body`, and `content.subtitle` fields support supplying a dictionary of translations instead of just a single string. ContextPush will then use the localization matching the locale the receiving user has set on their phone. A `content.default_locale` needs to be specified to determine which translation to use if none matches the users locale.

All translated fields need to specify all locales, meaning it's not supported to translate `title` and `body` in two different sets of languages.

**Example Request**

```
POST /v1/campaigns/schedule_message_for_user HTTP/1.1
Host: push.contextsdk.com
Authorization: Token CTX-123456789ABCD
Content-Type: application/json

{
    "bundle_id": "com.contextsdk.demo",
    "platform": "ios",
    "user_id": "user@contextsdk.com",
    "content": {
        "default_locale": "en",
        "title": {
          "en": "James, it's time for your english course!",
          "de": "James, es ist Zeit für deinen Englischkurs!"
        },
        "body": {
          "en": "Start your english course now!",
          "de": "Beginne jetzt mit deinem Englischkurs!"
        }
    },
    "deliver_within_hours": 3,
    "campaign_id": "daily-reminder",
    "delivery_method": "context_aware"
}
```

**Supporting images**

For context aware push notifications ContextSDK will handle fetching and setting the image on the notification before display. For notifications that are delivered traditionally (such as when explicitly using the traditional delivery mode, or in case there was no good moment during the delivery window) a `UNNotificationServiceExtension` needs to be used.

In your `UNNotificationServiceExtension` you can fetch the image and set it on the notification. Below is a full example for downloading and setting the image which can be integrated with your existing `UNNotificationServiceExtension`:

```
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {

        self.contentHandler = contentHandler
        guard let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
            contentHandler(request.content)
            return
        }
        self.bestAttemptContent = bestAttemptContent

        if let imageUrl = bestAttemptContent.userInfo["ctx_image_url"] as? String,
           let idempotencyKey = bestAttemptContent.userInfo["ctx_idempotency_key"] as? String,
            let fileUrl = URL(string: imageUrl) {
            let task = URLSession.shared.downloadTask(with: URLRequest(url: fileUrl)) { url, response, error in
                if let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) {
                    if let url = url,
                       let attachment = UNNotificationAttachment.saveImageToDisk(fileIdentifier: "\(idempotencyKey).jpg", sourcePath: url , options: nil) {
                        bestAttemptContent.attachments = [ attachment ]
                    }
                }
                contentHandler(bestAttemptContent)
            }
            task.resume()
        } else {
            contentHandler(request.content)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

@available(iOSApplicationExtension 10.0, *)
extension UNNotificationAttachment {

    static func saveImageToDisk(fileIdentifier: String, sourcePath: URL, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
        let fileManager = FileManager.default
        let folderName = ProcessInfo.processInfo.globallyUniqueString
        guard let folderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(folderName, isDirectory: true) else {
            return nil
        }

        do {
            try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
            let fileURL = folderURL.appendingPathComponent(fileIdentifier)
            try fileManager.moveItem(at: sourcePath, to: fileURL)
            let attachment = try UNNotificationAttachment(identifier: fileIdentifier, url: fileURL, options: options)
            return attachment
        } catch let error {
            print(error)
        }

        return nil
    }
}
```

**Note on traditional delivery**

When using the `traditional` delivery method, the notification will be sent to the user as soon as possible, usually with in at most 5 minutes. As such cancelling is only possible immediately after scheduling it.

### Endpoint to cancel delivery of a message

`POST https://push.contextsdk.com/v1/campaigns/cancel_message_for_user`

If a message is no longer applicable delivery can be cancelled if the message was not shown to the user yet. This requires you to set an idempotency key when scheduling the message. Cancelling a message is not possible if relying on the auto generated idempotency key.

#### Headers

| Header        | Description                                                                                                       | Example Value                |
| ------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| Authorization | The token used to authorize the request. Replace with a valid authentication token. Reach out to us to get access | `Token CTX-1234567890abcdef` |

#### Request Body

| Parameter        | Type   | Description                                                                                                                                                   | Example Value         |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| bundle\_id       | String | The unique identifier of the application bundle                                                                                                               | `com.contextsdk.demo` |
| platform         | String | The platform on which the user will receive the message                                                                                                       | `ios`                 |
| user\_id         | String | The unique identifier of the user                                                                                                                             | `user@contextsdk.com` |
| campaign\_id     | String | The same type of message should always have the same `campaign_id`. This is used for performance insights, and to train custom models for each `campaign_id`. | `daily-reminder`      |
| idempotency\_key | String | A unique identifier for the push notification message. If the same `idempotency_key` is used in multiple requests, only the last request will be processed.   | `1234567890abcdef`    |

#### Example Request

```
POST /v1/campaigns/cancel_message_for_user HTTP/1.1
Host: push.contextsdk.com
Authorization: Token CTX-123456789ABCD
Content-Type: application/json

{
    "bundle_id": "com.contextsdk.demo",
    "platform": "ios",
    "user_id": "user@contextsdk.com",
    "campaign_id": "daily-reminder",
    "idempotency_key": "427c60db-c3df-4098-a0f7-9b5d153438f4"
}
```
