Publisher API Introduction

Latest API Version: 1.0.15

Pre-requisites

Before you can send pushes through Boxcar Push API to reach your devices, you need to obtain from Boxcar Push Console the following information:

  • HOST: This is the server to use to send HTTPS API calls.
  • PUBLISH_KEY and PUBLISH_SECRET: This is needed to either sign API calls or to use basic HTTP authentication to verify the application publishers rights. Note: The publisher need to be allowed to use basic authentication over HTTPS as an alternative method to URL signature over HTTPS, to be allowed to call URL without implementing signature algorithm.

Goal of this document

This documents presents the basic set of feature to allow to integrate with back-end most common needs.

It is not a reference document presenting all the features of the API but should get you up and running quickly on using Boxcar Push API.

General API requirements

Data are send using JSON format.

It means the “Content-Type” must be “application/json”.

CURL URL example:

curl -X POST -u "<publish_key>:<publish_secret>" \
     -H "Content-Type: application/json" \
     --data '<JSON formatted payload>' \
     https://HOST/api/push/ 

The above example uses Basic Authentication. For description of the authentication methods supported, refer to the “URL Signature” section on this document.

Publisher methods

Sending push notifications ― POST /api/push

Notifications are send by sending a POST HTTP requests on /api/push on the proper HOST.

Here is a basic push notification example to send data to all subscribers in the ‘football’ channel:

curl -X POST -u "PuGjDgxlYfpAxOIkn:ewPljwerrjx" \
     -H "Content-Type: application/json" \
     --data @push.json \
     https://HOST/api/push/ 

And here is the associated payload in the push.json file:

1
2
3
4
5
6
7
8
{
 "aps":{
     "badge":"auto",
     "alert":"Beckham in first training session with Paris-St-Germain",
     "sound":"sport.caf"},
 "tags":{"or":["football"]},
 "id":"WEAXPVRK"
}

Sending an HTTP request with a JSON formatted payload is all is needed to get started sending pushes from a publisher.

After successfully accepting the request, the server will return a 201 (Created) response. The body of the response is a simple json document that contains the ID of the created push:

1
{"ok":"141"}

As per HTTP specs, the full url of the created push is also returned in the “Location” header.

Here are some of the first level keys you can use in your JSON data. Except aps (Apple Push Service), which hold the basic content to support push, all others values are optional. It means you can start simple and build more and more complex behavior.

aps (iOS and Android, with some reserves)

This is the standard Apple Push Notification content. It is a mandatory object, that need to contain at least one of its optional subkeys, among badge, alert, sound.

In its most basic form, this is a JSON object itself containing three optional keys:

  • badge (optional, iOS only, ignored on Android): Its value can be either an integer, but the most common practice on Boxcar Push Service is to use “auto” to let Boxcar platform handle automatically the counter. The platform will automatically reset that badge when the user open the target application. If omitted, the badge on the application will stay unchanged.

  • alert (optional, iOS and Android): This is the text of the message that will be send as content for notification alert message (popup and notification center). If omitted, no popup nor alert text will be displayed. The alert content can be defined also as a localized message, with a key and arguments:
    • loc-key a string representing the internationalized string to be loaded on the device, depending on the runtime locale.
    • loc-args a list of strings arguments that will be merged with the localized string, in case it needs to be parametrized with fixed values.
  • sound (optional, iOS and Android, with some restrictions): This is the sound file to play on the device when the notification is received. If omitted, no sound will be played. To play the default sound, you can simply use the value “default” or any non existing shorter name to save space.

  • category (optional): This corresponds to the “category” field on APNS notifications. It is used to add notification actions, allowing the user to interact with the received notification. If omitted, no category will be included.

  • mutable-content (optional): This corresponds to the “mutable-content” field on APNS notifications. It is used to let know the application that some post-processing would be needed when the push is received. Can be used in conjunction with the @img custom field to let the iOS SDK download an image for the push presentation. If omitted, no mutable-content will be included.

More complex values of the aps object are supported. The platform supports the variations in the payload, as described in Apple Push Notification Programming Guide. However, they should be used with care to support cross platform notifications.

Example:

1
2
3
4
5
6
{
 "aps":{
  "badge":"auto",
  "alert":"Beckham in first training session with Paris-St-Germain",
  "sound":"sport.caf"}
}

Example with a localized string:

1
2
3
4
5
6
7
8
9
{
 "aps":{
  "badge":"auto",
  "alert":{
   "loc-key": "NEW_MATCH_STARTED",
   "loc-args": ["A.C. Milan", "Lazio"]
  },
  "sound":"sport.caf"}
}

Example with mutable-content flag and some image URL to set on the push. iOS devices only support secured (HTTPS) links:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
 "aps":{
  "badge":"auto",
  "alert":{
   "loc-key": "NEW_MATCH_STARTED",
   "loc-args": ["A.C. Milan", "Lazio"]
  },
  "sound":"sport.caf",
  "mutable-content":1},
 "@img":"https://upload.wikimedia.org/wikipedia/commons/1/1d/Football_Pallo_valmiina-cropped.jpg"
}

This info is passed to third-party push service (reformatted for correct behaviour on each platform).

Device selection criteria

You have to use one and only one criterium among the following to describe to which devices set you wish your push notification to be send.

aliases (iOS and Android)

The aliases value is an array of string, defining the list of devices to send the notification to, identified by their assigned identifier. It is usually the numeric id of the user as known by the mobile device or the email address. This allows to send notification to individuals instead of device tokens. The various publishers can thus send notification with the identifier they use in their system and Boxcar Push Service is in charge of making the matching.

This info is not passed to third-party push service and is used by our push platform to select the list of devices to push to, but is not passed to devices.

tags (iOS and Android)

The tags value is an structure containing an array of strings defining the list of tagged devices that the notification need to be send to, and a boolean operator (‘and’ / ‘or’) that defines the criteria to match devices against those tags.

You can imagine tags as channels to which the devices subscribe to. The boolean operator is mandatory although it only makes relevance if the tag list contains two or more tags. When this operator is set to ‘or’, any device registered to at least one of the passed tags will be selected as a notification target. Usually this is the tag matching operator you would choose, however there are some special scenarios where you would want to ensure that only devices registered to all the specified tags (at the same time) are selected as a notification target.

The following example shows a tag filter where only users registered at ‘news’ and ‘music’ simultaneously should be notified:

1
2
3
4
5
6
7
{
 "aps":{
  "badge":"auto",
  "alert":"Motorheads Lemmy gets a life-size statue",
  "sound":"news.caf"},
 "tags":{"and":["news", "rock"]}
}
Constraints and implicit tag creation

When you send a publication to this API, there are two checks applied to the tag list before this alert is pushed to all specified targets.

  1. If the publisher sending the alert, as identified by his access and secret keys, was previously restricted to push on a given subset of the project tags (you can define such constraints from the Boxcar Push Console) the publish API will check that only tags from this subset were specified on the payload. Otherwise the publish call is rejected with an error result.
  2. If the alert specifies a list of tags where none of them exist on the project, the publish call is rejected with an error result.

You can however send a special boolean flag implicit_tag_creation set to true in your alert payload to indicate that you want to create any missing tag in your project that was specified in the list.

Example, lets assume a similar payload to the previous example, and that ‘hardrock’ tag doesn’t yet exist on the project. Setting implicit_tag_creation to true ensures this tag is created and the publish call is not rejected.

1
2
3
4
5
6
7
8
{
 "aps":{
  "badge":"auto",
  "alert":"Motorheads Lemmy gets a life-size statue",
  "sound":"news.caf"},
 "tags":{"or":["hardrock"]},
 "implicit_tag_creation":true
}

Please notice this flag is ignored if the publisher is restricted to push over a subset of tags, as explained in point 1.

Special and custom tags

Tags cannot start with an at sign (@) as this is a reserved prefix for Boxcar system tags. We have list of predefined tags that can be used directly but the platform, for example:

  • @all: to send to all devices in the project (no matter which type / OS they are).
  • @anonymous: Send a notification to all devices that have no defined alias.
  • @registered: Send a notification to all devices that have a defined alias.

For these special tags the boolean operator is completely ignored.

For custom tags, expected naming is lower case string containing only alphanumeric chars, dash, dot and underscore). When languages are used, it is common to append it to tag. Example:

  • breaking-news_en
  • breaking-news_fr
  • sport
  • my-news-category-1
  • my-news.category-1

This info is not passed to third-party push service and is only used by our push platform to select the list of devices to push to. As such is not passed to devices.

Important note: When register a device with an incorrect tag, tags parameter is ignored a warning is returned, but device registration succeeds.

device_tokens (iOS and Android)

The device_tokens value is an array of device identifiers for iOS or Android (as string). It is very rare to use it directly outside of the development phase as it requires the sender to have access to that information. More commonly, the publishers prefers aliases of tags to address a set of devices managed by Boxcar Push Service.

For iOS, this is the device token. For Android, this is the device registration ID.

This info is not passed in the payload of the push to third-party push service. It is used to define the list of devices to send the notification to, but is not passed to devices.

Application filter criteria (experimental)

There is no limit on usage of application filter criteria. You can combine any or all of them with with any device filter criterium.

Note: this feature is experimental and may be not accurate on Android devices.

target_os (iOS and Android)

This is an array of string containing the list of platform to push to:

  • ios: Send a notification to all iOS devices.
  • android: Send a notification to all Android devices.
  • kindle: Send a notification to all Kindle Fire devices.

No value or an empty array means: “push to all available platforms”.

This info is not passed to third-party push service and is used by our push platform to select the list of devices to push to, but is not passed to devices.

client_ids (iOS and Android)

We have a parameter in the API that can limit to which clients in the project the notification will be limited to. The client_ids key contain a list of integer, which is the id of the client, as created in the push platform.

Example:

1
2
3
4
5
6
7
{
 "client_ids":[1,2],
 "aps":{"badge":"auto",
        "alert":"alert message",
        "sound":"default.caf"},
 "id":"JHQRKHEE"
}

This fields can be combined with tags filter.

Example combination of filters

Here is a more complex push payload mixing target\os and tags. Please, note that if a device appears more that once through the various parameters, the platform will take care of sending only one push notifications:

1
2
3
4
5
6
7
8
{
 "tags":{"or":["politics","sports"]},
 "target_os":"ios",
 "aps":{"badge":"auto",
        "alert":"alert message",
        "sound":"default.caf"},
 "id":"JHQRKHEE"
}

Notification scheduling

Boxcar Push API allows to create notifications that will be sent at a later time. This is done through the field scheduled_at, which expects a date string follwing ISO 8601 syntax.

Example:

1
2
3
4
5
6
7
8
{
 "tags":{"or":["politics","sports"]},
 "target_os":"ios",
 "aps":{"badge":"auto",
	"alert":"alert message",
	"sound":"default.caf"},
 "scheduled_at":"2016-07-28T16:45:00Z",
 "id":"JHQRKHEE"   }

The payload above describes a notification that should be delivered to the specified audience at 2016-07-28 16:45:00 UTC. It is important to always set this date using UTC timezone.

The time schedule should be set to a value 5 minutes or more ahead of current time, otherwise it will be rejected.

Other fields

id (iOS and Android)

The id value is a string. This is the id of the push in the publisher system. If no id is provided, Boxcar Push Service will generate one automatically.

This info is passed to third-party push service in the push payload.

rich_content (iOS and Android)

The rich_content value is extended HTML content to display on the device once the application is opened. This is the associated content to download to provide the real content matching the alert for the users.

This info is not passed in push payload to third-party push service but can be used by mobile devices to retrieve additionnal payload on our Push Service. This allows to bypass limitations of the third-party push services.

expires_after (iOS and Android)

Set the time to live, in seconds, time for this push. The push is droped if the device is not able to receive it the next T seconds after the push was sent. This could be because the device is out of reception, turned off, or some other circumstance that make GCM/APNS not delivering it immediately. Refer to the official GCM/APNS docs for specific conditions. Example, expire after 30 minutes:

1
2
3
4
5
6
7
8
9
{
 "tags":{"or":["politics","sports"]},
 "target_os":"ios",
 "aps":{"badge":"auto",
        "alert":"alert message",
        "sound":"default.caf"},
 "id":"JHQRKHEE",
 "expires_after": 1800
}
@title (Android only)

Set the text to be displayed as a notification title in Android devices.

Example:

1
2
3
4
5
6
7
8
9
{
 "tags":{"or":["sports", "tennis"]},
 "target_os":"android",
 "aps":{"badge":"auto",
        "alert":"Petkovic wins Tournament of Champions final",
        "sound":"default.caf"},
 "id":"JHQRKHEE",
 "@title":"Tennis - Tournament of Champions"
}
@img

Set the URL for an image to be displayed as a big background picture when the notification is expanded.

iOS

In order for this mechanism to work the “mutable-content” field must be present on the “aps” structure and set to 1. Only secured links (HTTPS) are supported by iOS.

Example:

1
2
3
4
5
6
7
8
9
{
 "tags":{"or":["sports", "tennis"]},
 "aps":{"badge":"auto",
        "alert":"Petkovic wins Tournament of Champions final",
        "sound":"default.caf",
        "mutable-content":1},
 "id":"JHQRKHEE",
 "@img":"https://mysite/news/res/petkovic.jpg"
}
Android

The image will be center-cropped. When the push arrives, the device establishes an HTTP connection, reads the image from the remote site and sets it as the background picture for the notification widget. Source picture should be ≤ 450 DP wide, ~2:1 aspect. Bitmaps outside these bounds will just be wasting RAM (and possibly exceeding Binder IPC limits). Even if the mutable-content is ignored for Android devices it is recommended to be set to be compatible with iOS devices.

As a reference, 450 DP is equivalent to the following amount of pixels, depending on the density type of the hardware:

  • LDPI devices: 337,5 pixels
  • MDPI devices: 450 pixels
  • HDPI devices: 675 pixels
  • XHDPI devices: 900 pixels
  • XXHDPI devices: 1350 pixels
  • XXXHDPI devices: 1800 pixels

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
 "tags":{"or":["sports", "tennis"]},
 "target_os":"android",
 "aps":{"badge":"auto",
        "alert":"Petkovic wins Tournament of Champions final",
        "sound":"default.caf",
        "mutable-content":1},
 "id":"JHQRKHEE",
 "@img":"https://mysite/news/res/petkovic.jpg"
}

This feature is available only on Android devices with API level >= 16.

Custom fields

Custom fields can be used. All value, not reversed by the platform is transparently passed in the push payload to the device. Example, to pass a custom object_id you can add a custom field “oid”:

1
2
3
4
5
6
7
8
{
 "tags":{"or":["@all"]},
 "aps":{"badge":"auto",
        "alert":"alert message",
        "sound":"default.caf"},
 "oid": 12,
 "id":"JHQRKHEE"
}

Other

Other values are available for specific needs, like selecting set of devices based on the event of some actions (created, registered, last seen, for example).

Tag management

There is a set of API functions to list, create, view, deprecate and remove project tags.

Create a new tag - POST /api/tag_manager

The following call creates a new tag based on the specified name (string).

HTTP Request

Action: POST /api/tag_manager

Headers: [{Content-Type, application/json}]

Payload (POST body):

1
{"name": TagName}

where:

name: is a string representing the new tag e.g. {“name”:”science”}

HTTP Response

Code: 201

Payload:

1
{"ok": Id}

where:

id: is an integer representing the id of the new tag

List all existing tags

The following call retrieves all registered tags with associated information.

HTTP Request

Action: GET /api/tag_manager

Headers: [{Content-Type, application/json}]

HTTP Response

Code: 200

Payload:

1
2
3
4
5
6
[{"id" : Id,
  "name" : Name,
  "devices" : DeviceCount,
  "deprecated" : Deprecated,
  "created_at" : CreatedAt
}]

where:

id: is an integer representing the id of the tag identifier

name: is the string representing the tag name

devices: is an integer representing the amount of tag subscribers

deprecated: boolean flag signaling if the tag was deprecated

created_at: date of creation. String with the format YYYY-MM-DD’T’HH:mm:SS’Z’ e.g. ‘2015-01-04T20:54:12Z’

Get tag information

The following call retrieves information associated with a given tag identifier

HTTP Request

Action: GET /api/tag_manager/$TAG_ID

Headers: [{Content-Type, application/json}]

HTTP Response

Code: 200

Payload:

1
2
3
4
5
6
{"id" : Id,
  "name" : Name,
  "devices" : DeviceCount,
  "deprecated" : Deprecated,
  "created_at" : CreatedAt
}

where:

id: is an integer representing the id of the tag identifier

name: is the string representing the tag name

devices: is an integer representing the amount of tag subscribers

deprecated: boolean flag signaling if the tag was deprecated

created_at: date of creation. String with the format YYYY-MM-DD’T’HH:mm:SS’Z’ e.g. ‘2015-01-04T20:54:12Z’

Deprecate a tag

This API call deprecates a given tag specified by its identifier.

HTTP Request

Action: POST /api/tag_manager/$TAG_ID/deprecate

Headers: [{Content-Type, application/json}]

Payload (POST body): none

HTTP Response

Code: 204

Delete a tag

This API call removes a given tag specified by its identifier.

HTTP Request

Action: DELETE /api/tag_manager/$TAG_ID

Headers: [{Content-Type, application/json}]

HTTP Response

Code: 204

Cancelling a push notifications being sent ― DELETE /api/push/$PUSH_ID

A notification being sent can be cancelled.

Note: the push must exist. If the push has already finished, this call has no effect.

Return code is 202 “Accepted”. The actual cancellation is performed asynchronously, depending on your subscription plan delivery speed, it migh take a few seconds to completely stop.

Removing a scheduled push notification ― DELETE /api/push/$PUSH_ID

Similar to the previous action, if the push referenced in the resource part is programmed to be sent later, this API function will remove it.

Return code is 204 if success.

Updating a scheduled push notification ― PUT /api/push/$PUSH_ID

A notification that was scheduled to be sent later can be modified. A JSON payload is expected, with the same syntax required by the publish API call. In other words, this API function doesn’t handle incremental changes (deltas): the full push must be described with each call.

Return code is 204 if the push was modified successfully. An error is returned if the send_later_at field is not set at least 5 minutes later from now.

Getting info about an existing push - GET /api/push/$PUSH_ID

Returns a json struct with information about the given push. Current returned fields are:

1
2
3
4
5
6
7
8
9
{
	"state":"delivered",
	"created_at":"2014-08-11T17:33:08Z",
	"last_delivered_at":"2014-08-11T17:35:36Z",
	"send_later_at":"-",
	"sent":3507600,
	"errors":0,
	"opened":401462
}

state can be one of:

  • “queued”
  • “delivering”
  • “delivered”
  • “cancelled”
  • “scheduled”

Warning: don’t rely too much on the structure of this response. Fields other than “state” are susceptible to changes in future versions.

Listing all pushes in scheduled state - GET /api/push?type=scheduled&offset=$N

Returns a JSON structure containing the next 10 scheduled pushes starting from the specified offset. Offset $N is a positive integer starting from 0. As an example, assuming there are 11 scheduled pushes and a list call is issued starting from offset 10 (/api/push?type=scheduled&offset=10), current returned fields are:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
	"items":[
  		{
  		"state":"delivered",
  		"created_at":"2014-08-11T17:33:08Z",
  		"last_delivered_at":"2014-08-11T17:35:36Z",
  		"send_later_at":"-",
  		"sent":3507600,
  		"errors":0,
  		"opened":401462
  		}
	],
	"offset":10,
	"page_size":10
}

URL Signature

If “Basic Authentication” is allowed for the publisher, implementation of the signature algorithm is optional. Basic authentication can thus be used. While being a bit less secure, it will simplify development and deployment in some complex environment.

Clients can never bypass URL signature, but the algorithm is always implemented in the provided libraries.

So, if you want to add an extra security layer to your publisher code or want to reimplement the client algorithm yourself, you can implement the signature algorithm.

The signature algorithm is already implemented in the provided bx_signature.rb script. You can use it as an example for implemented the optional signature algorithm in another programming language. The value of the signature is the result of HMAC SHA1 operation with PUBLISH_SECRET of the URL path and payload concatenated as:

method\nhost\nabsolute_path\nbody
  • method is the HTTP method (uppercase), usually “POST”
  • host is the hostname (lowercase). Does not include port.
  • absolute_path is the full query path without parameters
  • body is the content of the POST.

If you need to use URL signature, you will add two extra parameters in your HTTP query:

  • publish_key=<publish_key>
  • signature=<generated_signature>

and it adds a validity duration in JSON payload:

  • an “expires” key is added to JSON. This is the timestamp (epoch date) of the query. It defines at which time the query will expire and be rejected. This is define for security reason to avoid replay of the same signed identical query at a later time.

For example:

POST /api/push?publishkey=PuGjDgxlYfpAxOIkn!hCaX5jo&signature=1ea79daec692258278c2d3d5e88ae5f5a906c7f5 HTTP/1.1
Content-Type: application/json
Accept: */*
User-Agent: Ruby
Host: localhost:8001
Content-Length: 217

{"expires":1360790596,
"device_tokens":["67944d0694d688a67a7dd4d0e7cbc961eb5d5c7f3b7de761406ad3778101506e"],
"aliases":["my_username"],
"aps":{"badge":1,"alert":"alert message","sound":"default.caf"},
"id":"WEAXPVRK"}

Working examples

You can find a publish tool implementation written in Java and ready for use at our GitHub repository:

https://github.com/boxcar/boxcar-developer-push-examples/tree/master/java-publisher-client

A short python example, using signature authentication, is show below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/python

from hashlib import sha1
from urlparse import urlparse
from urllib import urlencode
from time import time
import hmac
import urllib2
import json

ACCESS_KEY = "$YOUR_ACCESS_KEY"
SECRET_KEY =  "$YOUR_SECRET"
ENDPOINT =  "https://boxcar-api.io/"

# Push to send.  See documentation for full list of options
push = {
        "id" : "111",
        "aps" : {
            "alert" : "Hello World!"
            },
        "expires" : str(int(time() + 30)),
        "tags" : {"or":["@all"]}
        }
payload = json.dumps(push)

# Calculate signature.
str_to_sign = "%s\n%s\n%s\n%s" % ("POST", urlparse(ENDPOINT).hostname, "/api/push", payload)
h = hmac.new(SECRET_KEY, str_to_sign, sha1)
signature = h.hexdigest()

# Perform request
params = urlencode({"publishkey": ACCESS_KEY , "signature" : signature})
req = urllib2.Request("%s/api/push?%s" % (ENDPOINT.rstrip("/"), params))
req.add_header("Content-Type", "application/json")
response = urllib2.urlopen(req, payload)
print "Got: \n %s" % response.read()