Aller au contenu

Authentification

Authentification Bearer avec des clés d'intégration (hlk_) : la connexion avec votre identifiant Apple crée une clé par défaut, et vous pouvez ajouter des clés à portée limitée par service.

Token Format

A key is hlk_ followed by 32 base62 characters (~36 characters total). Only the SHA-256 hash is stored server-side, so a lost key cannot be recovered.

Authorization: Bearer hlk_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345

Permissions

Each key has one permission level per resource. A higher level includes the lower ones.

ResourceLevelsAccess
activitiesnone, read, update, manageread: list and get activities. update: also update existing ones. manage: also create and delete them, and PATCH ?upsert=true.
notificationsnone, send, schedulesend: POST /notifications and reading answers. schedule: also the scheduled notifications endpoints.
widgetsnone, read, writeread: list and get widgets. write: also create, update and delete them (widgets API).
emailsnone, sendsend: send email (POST /emails) to verified recipients.

A key can also be limited to specific activity slugs (activity_slugs) and widget slugs (widget_slugs), exact or as a prefix with a trailing *, and can have an expiry (expires_at). An expired key gets 401 with code integration_key.expired; a request above the key's levels gets 403 with code integration_key.permission_denied and a detail naming the level it needs, such as requires widgets:write. GET /auth/me works with every key and reports the calling key's permissions under integration_key.

ℹ Info

Keys created before permission levels existed keep exactly the access they had. The older fields are still returned and accepted. In responses, scope is activity:<level>, and notifications is true at send or above, widgets at write and emails at send. In a create or update, true means the resource's highest level and false means none; send either those fields or permissions, not both.

Keys of an organization are made in its console and can also be limited to some groups and device tags: they then send only inside them and see only the activities sent inside them (details).

Creating scoped keys

The default key has every resource at its highest level, which is all most integrations need. To limit a service to what it uses, create a dedicated key:

  1. Open Settings → Manage Keys in the iOS app — the same screen revokes existing keys.
  2. Tap +.
  3. Set a name, choose what the key may do, and optionally limit it to slugs such as grafana-*.
  4. Copy the generated hlk_ key and store it securely -- it is shown only once.
Bientôt dans la version 1.16.0 de l'app

Cette section décrit une fonctionnalité d'une mise à jour de l'app en attente de validation par l'App Store. Elle se déverrouille ici automatiquement dès que la mise à jour est disponible.

Bientôt dans la version 1.17.0 de l'app

Cette section décrit une fonctionnalité d'une mise à jour de l'app en attente de validation par l'App Store. Elle se déverrouille ici automatiquement dès que la mise à jour est disponible.

The default key can also create keys over the API (POST /integrations/keys, pushward key create), for example a notifications-only key for an alerting bridge:

curl -X POST https://api.pushward.app/integrations/keys \
  -H "Authorization: Bearer $PUSHWARD_DEFAULT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "alerts", "permissions": {"notifications": "send"}, "expires_at": "2027-01-01T00:00:00Z"}'

A resource left out of permissions gets none. A key created this way can never have a level above the default key's own.

Endpoints

GET /auth/me

Get the current user's profile, activity count, and current quota usage.

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "nickname": "Alice",
  "activity_count": 3,
  "subscribed": false,
  "quota_period_month": 202606,
  "notifications_used": 128,
  "notifications_limit": 500,
  "live_activity_updates_used": 86,
  "live_activity_updates_limit": 250,
  "widget_updates_used": 12,
  "widget_updates_limit": 50,
  "emails_used": 3,
  "emails_limit": 50,
  "quota_resets_at": "2026-07-01T00:00:00Z",
  "integration_key": {
    "id": "0b6f0c1e-5a3d-4c1f-9d0a-6f2e8b7c4a11",
    "name": "Grafana",
    "is_default": false,
    "permissions": {"activities": "none", "notifications": "send", "widgets": "write", "emails": "none"},
    "widget_slugs": ["grafana-*"]
  }
}
ℹ Info

Integration keys read their own live usage here — the iOS app polls /auth/me for its Usage screen and integrations (e.g. Home Assistant) surface the same counters. A *_limit field is omitted when that resource is uncapped on your tier. (Detailed subscription fields are only returned to the app's own session, not to integration keys.)

Response Fields

FieldTypeDescription
idstringUser ID
nicknamestring | nullDisplay name
activity_countintegerNumber of activities owned by the user
subscribedbooleanWhether the user has an active subscription
quota_period_monthintegerYYYYMM bucket for the current monthly usage period (UTC)
notifications_used / notifications_limitintegerNotifications sent this period and your tier's cap. *_limit is omitted when uncapped.
live_activity_updates_used / live_activity_updates_limitintegerLive Activity updates this month and your tier's cap
widget_updates_used / widget_updates_limitintegerWidget updates this month and your tier's cap
emails_used / emails_limitintegerEmails sent this month and your tier's cap (free 50, paid 200)
quota_resets_atstringISO 8601 instant the active counters reset
integration_keyobjectThe key that made the request: id, name, is_default, permissions, and activity_slugs, widget_slugs and expires_at when set

Access Control

Access LevelEndpoints
No authGET /health
Any hlk_ keyGET /auth/me
activities: readGET /activities, GET /activities/{slug}
activities: updateEverything read allows, plus PATCH /activities/{slug}
activities: manageEverything update allows, plus POST /activities, DELETE /activities/{slug}, PATCH /activities/{slug}?upsert=true
notifications: sendPOST /notifications, GET /notifications/answers/{id}
notifications: scheduleEverything send allows, plus POST /notifications/scheduled, GET /notifications/scheduled, GET /notifications/scheduled/{id}, DELETE /notifications/scheduled/{id}
widgets: readGET /widgets, GET /widgets/{slug}
widgets: writeEverything read allows, plus POST /widgets, PATCH /widgets/{slug}, DELETE /widgets/{slug}
emails: sendPOST /emails