© blackforestbytes made by Mike Schwörer
API Documentation Send

Simple Cloud Notifier

Introduction

With this API you can send push notifications to your phone.

To receive them you will need to install the SimpleCloudNotifier app from the play store. When you open the app you can click on the account tab to see you unique user_id and key. These two values are used to identify and authenticate your device so that send messages can be routed to your phone.

You can at any time generate new keys in the app with different permissions.

There is also a web interface for this API to manually send notifications to your phone or to test your setup.

Quota

By default you can send up to 50 messages per day per device. If you need more you can upgrade your account in the app to get 1000 messages per day, this has the additional benefit of removing ads and supporting the development of the app (and making sure I can pay the server costs).

API Requests

To send a new notification you send a POST request to the URL https://simplecloudnotifier.de/. All Parameters can either directly be submitted as URL parameters or they can be put into the POST body (either multipart/form-data or JSON).

You need to supply a valid [user_id, key] pair and a title for your message, all other parameter are optional.

API Response

If the operation was successful the API will respond with an HTTP statuscode 200 and an JSON payload indicating the send message and your remaining quota

{
    "success":true,
    "message":"Message sent",
    "messagecount": 634,
    "quota":17,
    "quota_max":100,
    "scn_msg_id":"..."
}

If the operation is not successful the API will respond with a 4xx or 500 HTTP statuscode.

Statuscode Explanation
200 (OK) Message sent
400 (Bad Request) The request is invalid (missing parameters or wrong values)
401 (Unauthorized) The user_id was not found, the key is wrong or the [user_id, key] combination does not have the SEND permissions on the specified channel
403 (Forbidden) The user has exceeded its daily quota - wait 24 hours or upgrade your account
500 (Internal Server Error) There was an internal error while sending your data - try again later

There is also always a JSON payload with additional information. The success field is always there and in the error case you can read the message field to get a more information about the problem.

{
    "success": false,
    "error": 2101,
    "errhighlight": -1,
    "message": "Daily quota reached (100)"
}

Message Content

Every message must have a title set. But you also (optionally) add more content, while the title has a max length of 120 characters, the content can be up to 10.000 characters. You can see the whole message with title and content in the app or when clicking on the notification.

If needed the content can be supplied in the content parameter.

curl                                          \
    --data "user_id={userid}"                 \
    --data "key={key}"                        \
    --data "title={message_title}"            \
    --data "content={message_content}"        \
    https://simplecloudnotifier.de/

Message Priority

Currently you can send a message with three different priorities: 0 (low), 1 (normal) and 2 (high). In the app you can then configure a different behaviour for different priorities, e.g. only playing a sound if the notification is high priority.

Priorites are either 0, 1 or 2 and are supplied in the priority parameter. If no priority is supplied the message will get the default priority of 1.

curl                                          \
    --data "user_id={userid}"                 \
    --data "key={key}"                        \
    --data "title={message_title}"            \
    --data "priority={0|1|2}"                 \
    https://simplecloudnotifier.de/

Channel

By default all messages are sent to the user default channel (typically main) You can specify a different channel with the channel parameter, if the channel does not already exist it will be created. Channel names are case-insensitive and can only contain letters, numbers, underscores and minuses ( /[[:alnum:]\-_]+/ )

curl                                          \
    --data "user_id={userid}"                 \
    --data "key={key}"                        \
    --data "title={message_title}"            \
    --data "channel={my_channel}"             \
    https://simplecloudnotifier.de/

Permissions

A user account can have multiple keys with different permissions. A Key has one or more permissions assigned:

Permission Identifier Explanation
ADMIN A Allows modification of the current user, creating/editing keys, channels, subsriptions, etc. and includes all other permissions
CHANNEL READ CR Allows reading and listing messages
CHANNEL SEND CS Allows sending messages
USER READ UR Allows querying the current user

Keys can also be scoped to specific channels. A Key can either have access to all channels the user has access to, or only to a subset. The permitted channels can either be channels of the user or foreign channels with an active subscription.

A common use case is to create a key with only the CS (Channel Send) permission and only a single channel. This key can then be used to send messages without having full access to the account.

Message Uniqueness (Idempotency)

Sometimes your script can run in an environment with an unstable connection, and you want to implement an automatic re-try mechanism to send a message again if the last try failed due to bad connectivity.

To ensure that a message is only send once you can generate a unique id for your message (I would recommend a simple uuidgen or head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32). If you send a message with a UUID that was already used in the near past the API still returns OK, but no new message is sent.

The message_id is optional - but if you want to use it you need to supply it via the msg_id parameter.

curl                                          \
    --data "user_id={userid}"                 \
    --data "key={key}"                        \
    --data "title={message_title}"            \
    --data "msg_id={message_id}"              \
    https://simplecloudnotifier.de/

Be aware that the server only saves send messages for a short amount of time. Because of that you can only use this to prevent duplicates in a short time-frame, older messages with the same ID are probably already deleted and the message will be send again.

Custom Time

You can modify the displayed timestamp of a message by sending the timestamp parameter. The format must be a valid UNIX timestamp (elapsed seconds since 1970-01-01 GMT)

The custom timestamp must be within 48 hours of the current time. This parameter is only intended to supply a more precise value in case the message sending was delayed.

curl                                          \
    --data "user_id={userid}"                 \
    --data "key={key}"                        \
    --data "title={message_title}"            \
    --data "timestamp={unix_timestamp}"       \
    https://simplecloudnotifier.de/

Bash script example

Depending on your use case it can be useful to create a bash script that handles things like resending messages if you have connection problems or waiting if there is no quota left.
Here is an example how such a scrippt could look like, you can put it into /usr/local/sbin and call it with scn_send "title" "content" (or with more parameters, see the script itself)

#!/usr/bin/env bash

#
# Wrapper around SCN ( https://simplecloudnotifier.de/ )
# ======================================================
#
# ./scn_send [@channel] title [content] [priority]
#
#
# Call with   scn_send              "${title}"
#        or   scn_send              "${title}" ${content}"
#        or   scn_send              "${title}" ${content}" "${priority:0|1|2}"
#        or   scn_send "@${channel} "${title}"
#        or   scn_send "@${channel} "${title}" ${content}"
#        or   scn_send "@${channel} "${title}" ${content}" "${priority:0|1|2}"
#
# content can be of format "--scnsend-read-body-from-file={path}" to read body from file
# (this circumvents max commandline length)
#

################################################################################

usage() {
    echo "Usage: "
    echo "  scn_send [@channel] title [content] [priority]"
    echo ""
}

function cfgcol { [ -t 1 ] && [ -n "$(tput colors)" ] && [ "$(tput colors)" -ge 8 ]; }

function rederr() { if cfgcol; then >&2 echo -e "\x1B[31m$1\x1B[0m"; else >&2 echo "$1"; fi; }
function green()  { if cfgcol; then     echo -e "\x1B[32m$1\x1B[0m"; else     echo "$1"; fi; }

################################################################################

#
# Get env 'SCN_UID' and 'SCN_KEY' from conf file
# 
# shellcheck source=/dev/null
. "/etc/scn.conf"
SCN_UID=${SCN_UID:-}
SCN_KEY=${SCN_KEY:-}

[ -z "${SCN_UID}" ] && { rederr "Missing config value 'SCN_UID' in /etc/scn.conf"; exit 1; }
[ -z "${SCN_KEY}" ] && { rederr "Missing config value 'SCN_KEY' in /etc/scn.conf"; exit 1; }

################################################################################

args=( "$@" )

title=""
content=""
channel=""
priority=""
usr_msg_id="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
sendtime="$(date +%s)"
sender="$(hostname)"

if command -v srvname &> /dev/null; then
  sender="$( srvname )"
fi

if [[ "${args[0]}" = "--" ]]; then
    # only positional args form here on (currently not handled)
    args=("${args[@]:1}")
fi

if [ ${#args[@]} -lt 1 ]; then
    rederr "[ERROR]: no title supplied via parameter"
    usage
    exit 1
fi

if [[ "${args[0]}" =~ ^@.* ]]; then
    channel="${args[0]}"
    args=("${args[@]:1}")
    channel="${channel:1}"
fi

if [ ${#args[@]} -lt 1 ]; then
    rederr "[ERROR]: no title supplied via parameter"
    usage
    exit 1
fi

title="${args[0]}"
args=("${args[@]:1}")

content=""

if [ ${#args[@]} -gt 0 ]; then
    content="${args[0]}"
    args=("${args[@]:1}")
fi

if [ ${#args[@]} -gt 0 ]; then
    priority="${args[0]}"
    args=("${args[@]:1}")
fi

if [ ${#args[@]} -gt 0 ]; then
    rederr "Too many arguments to scn_send"
    usage
    exit 1
fi

if [[ "$content" == --scnsend-read-body-from-file=* ]]; then
  path="$( awk '{ print substr($0, 31) }' <<< "$content" )"
  content="$( cat "$path" )"
fi

curlparams=()

curlparams+=( "--data-urlencode" "user_id=${SCN_UID}"  )
curlparams+=( "--data-urlencode" "key=${SCN_KEY}"      )
curlparams+=( "--data-urlencode" "title=$title"        )
curlparams+=( "--data-urlencode" "timestamp=$sendtime" )
curlparams+=( "--data-urlencode" "msg_id=$usr_msg_id"  )

if [[ -n "$content" ]]; then
    curlparams+=("--data-urlencode" "content=$content")
fi

if [[ -n "$priority" ]]; then
    curlparams+=("--data-urlencode" "priority=$priority")
fi

if [[ -n "$channel" ]]; then
    curlparams+=("--data-urlencode" "channel=$channel")
fi

if [[ -n "$sender" ]]; then
    curlparams+=("--data-urlencode" "sender_name=$sender")
fi

while true ; do

    outf="$(mktemp)"

    curlresp=$(curl --silent                             \
                    --output "${outf}"                   \
                    --write-out "%{http_code}"           \
                    "${curlparams[@]}"                   \
                    "https://simplecloudnotifier.de/"    )

    curlout="$(cat "$outf")"
    rm "$outf"

    if [ "$curlresp" == 200 ] ; then
        green "Successfully send"
        exit 0
    fi

    if [ "$curlresp" == 400 ] ; then
        rederr "Bad request - something went wrong"
        echo "$curlout"
        echo ""
        exit 1
    fi

    if [ "$curlresp" == 401 ] ; then
        rederr "Unauthorized - wrong userid/userkey"
        exit 1
    fi

    if [ "$curlresp" == 403 ] ; then
        rederr "Quota exceeded - wait 5 min before re-try"
        sleep 300
    fi

    if [ "$curlresp" == 412 ] ; then
        rederr "Precondition Failed - No device linked"
        exit 1
    fi

    if [ "$curlresp" == 500 ] ; then
        rederr "Internal server error - waiting for better times"
        sleep 60
    fi

    # if none of the above matched we probably have no network ...
    rederr "Send failed (response code $curlresp) ... try again in 5s"
    sleep 5
done