Calenzy API
APIs/For apps

Alerts API

Rules on a currency pair that notify a phone when the rate crosses a level.

/v1/alertsNot counted in your quota4 endpoints
Delivery is limited to the mobile apps we publish. A rule that fires is sent as a push notification through our Firebase project, so the receiving app has to be one of ours. Webhook and email delivery are planned. If you want alerts delivered to your own system, talk to us before you build: rules store and evaluate correctly, but nothing would reach you.

A rule says: tell me when EUR/USD rises above 1.1000. We check every rule against the rates of the Currencies API every 20 minutes, so a notification can arrive about 22 minutes after the crossing. Alerts are made for moves over a day, not for trading by the minute.

Rules belong to a device, an identifier you choose. Everything is scoped to your API key: two keys can use the same device identifier and never see each other's rules. Times are UTC, ISO 8601 with a Z.

How a rule fires

  • A rule fires when the rate crosses the target, then goes quiet.
  • It is ready to fire again once the rate moves back past the target plus a 0.15% buffer, so a rate resting on the level cannot flap.
  • isEnabled is yours and we never change it. A rule that fired stays enabled and fires again on the next real crossing.
  • At least 6 hours separate two notifications for the same rule.
  • A rule whose condition is already true when you create it waits for a real crossing rather than notifying at once.
  • Changing a rule's pair, direction or target starts it over. Switching isEnabled off and on does not.
Never end an Alerts path with a slash. The redirect would turn a PUT into a GET and drop the body.
PUT/v1/alerts/devices/{deviceId}

Register a device

Register a device, or refresh its push token and details.

Path
deviceIdRequiredstringYour own identifier: up to 255 letters, digits, ., _, : or -. Make it unguessable, such as a UUID: it is the only key to the device's rules
Body
fcmTokenstring or nullPush token. null clears it
platformstringios, android, web or server
localestringDevice language, up to 10 characters, such as en or zh-Hans
appVersionstringYour app version, up to 20 characters

Every field is optional, and only what you send changes. It is safe to retry and to call on every launch. A fresh token clears earlier delivery failures.

Request
PUTapi.calenzy.app/v1/alerts/devices/9C2B7C9E-1F41-4A57-B21D-1B8A2C0F4711
{
  "fcmToken": "YOUR_DEVICE_PUSH_TOKEN",
  "platform": "ios",
  "locale": "en",
  "appVersion": "1.4.0"
}
Response · 200 OK
{
  "status": "success"
}
PUT/v1/alerts/devices/{deviceId}/rules

Replace rules

Send the device's complete list of rules, up to 20.

This replaces the whole list: a rule you leave out is deleted. Always send every rule, never just the change.
Path
deviceIdRequiredstringAs registered
Body: a list of rules
idRequiredstringAn uppercase UUID you create. It names the rule and comes back in the notification
baseCurrencyRequiredstringThree letter code from List currencies
targetCurrencyRequiredstringThree letter code, different from baseCurrency
directionRequiredstringabove or below
targetRateRequirednumberThe level to watch, a positive decimal: the same value as Rate for one pair
isEnabledbooleantrue by default. A disabled rule is stored but never checked
createdAtstringISO 8601 date, used to order the list
Response

The stored list, as Read rules returns it, so you need no second call.

Request
PUTapi.calenzy.app/v1/alerts/devices/9C2B7C9E-1F41-4A57-B21D-1B8A2C0F4711/rules
[
  {
    "id": "A1B2C3D4-0000-4000-8000-000000000001",
    "baseCurrency": "EUR",
    "targetCurrency": "USD",
    "direction": "above",
    "targetRate": 1.2000,
    "isEnabled": true,
    "createdAt": "2026-08-25T09:12:33Z"
  }
]
Response · 200 OK
[
  {
    "id": "A1B2C3D4-0000-4000-8000-000000000001",
    "baseCurrency": "EUR",
    "targetCurrency": "USD",
    "direction": "above",
    "targetRate": 1.2,
    "isEnabled": true,
    "createdAt": "2026-08-25T09:12:33Z",
    "lastTriggeredAt": null,
    "lastTriggeredRate": null
  }
]
GET/v1/alerts/devices/{deviceId}/rules

Read rules

The device's rules, with when each one last fired.

Path
deviceIdRequiredstringAs registered
Response

Every field you sent, plus the only two we add:

lastTriggeredAtstring or nullWhen the rule last fired, UTC. null if it never has
lastTriggeredRatenumber or nullThe rate at that moment. null if it never fired
Request
GETapi.calenzy.app/v1/alerts/devices/9C2B7C9E-1F41-4A57-B21D-1B8A2C0F4711/rules
Response · 200 OK
[
  {
    "id": "A1B2C3D4-0000-4000-8000-000000000001",
    "baseCurrency": "EUR",
    "targetCurrency": "USD",
    "direction": "above",
    "targetRate": 1.2,
    "isEnabled": true,
    "createdAt": "2026-08-25T09:12:33Z",
    "lastTriggeredAt": null,
    "lastTriggeredRate": null
  },
  {
    "id": "A1B2C3D4-0000-4000-8000-000000000002",
    "baseCurrency": "EUR",
    "targetCurrency": "USD",
    "direction": "above",
    "targetRate": 1.1,
    "isEnabled": true,
    "createdAt": "2026-08-24T08:00:00Z",
    "lastTriggeredAt": "2026-08-25T07:30:20Z",
    "lastTriggeredRate": 1.16582624
  }
]
DEL/v1/alerts/devices/{deviceId}

Forget a device

Delete a device and every rule on it.

Use it when someone uninstalls the app or switches alerts off for good. It cannot be undone. To remove the rules and keep the device, send an empty list to Replace rules.

Path
deviceIdRequiredstringAs registered
Request
DELETEapi.calenzy.app/v1/alerts/devices/9C2B7C9E-1F41-4A57-B21D-1B8A2C0F4711
Response · 200 OK
{
  "status": "success"
}

Errors

We check everything before writing, so a refused PUT leaves the stored rules exactly as they were. Besides these, any call can answer one of the common errors.

CodeHTTPWhen
bad_request400A malformed body or device ID, a missing or invalid rule field, a repeated rule id, a target that is not a positive number, or more than 20 rules
invalid_currency400A currency code the Currencies API does not carry
same_currency400baseCurrency and targetCurrency are the same