تصدیق
انٹیگریشن کلیدوں (hlk_) کے ساتھ Bearer تصدیق: Apple ID سے سائن ان کرنے پر ایک ڈیفالٹ کلید بن جاتی ہے، اور آپ ہر سروس کے لیے محدود دائرہ کار والی کلیدیں شامل کر سکتے ہیں۔
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_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345Permissions
Each key has one permission level per resource. A higher level includes the lower ones.
| Resource | Levels | Access |
|---|---|---|
activities | none, read, update, manage | read: list and get activities. update: also update existing ones. manage: also create and delete them, and PATCH ?upsert=true. |
notifications | none, send, schedule | send: POST /notifications and reading answers. schedule: also the scheduled notifications endpoints. |
widgets | none, read, write | read: list and get widgets. write: also create, update and delete them (widgets API). |
emails | none, send | send: 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.
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:
- Open Settings → Manage Keys in the iOS app — the same screen revokes existing keys.
- Tap +.
- Set a name, choose what the key may do, and optionally limit it to slugs such as
grafana-*. - Copy the generated
hlk_key and store it securely -- it is shown only once.
یہ سیکشن ایک ایپ اپڈیٹ کی اُس خصوصیت کو بیان کرتا ہے جو App Store کے جائزے کے لیے زیرِ التوا ہے۔ اپڈیٹ لائیو ہوتے ہی یہ یہاں خودکار طور پر اَن لاک ہو جائے گی۔
The app sets a level for each resource, with presets such as Notifications only, and can limit a key to widget slugs and give it an expiry.


Tap a key to change its levels, slug limits or expiry later; each change saves right away. The default key's levels, slug limits and expiry stay fixed.
یہ سیکشن ایک ایپ اپڈیٹ کی اُس خصوصیت کو بیان کرتا ہے جو App Store کے جائزے کے لیے زیرِ التوا ہے۔ اپڈیٹ لائیو ہوتے ہی یہ یہاں خودکار طور پر اَن لاک ہو جائے گی۔
The default key is not listed in Manage Keys: it always has every resource at its highest level, and the only change it takes is a roll, from Roll Key under Settings → Integration Key.
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
/auth/meGet 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-*"]
}
}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
| Field | Type | Description |
|---|---|---|
id | string | User ID |
nickname | string | null | Display name |
activity_count | integer | Number of activities owned by the user |
subscribed | boolean | Whether the user has an active subscription |
quota_period_month | integer | YYYYMM bucket for the current monthly usage period (UTC) |
notifications_used / notifications_limit | integer | Notifications sent this period and your tier's cap. *_limit is omitted when uncapped. |
live_activity_updates_used / live_activity_updates_limit | integer | Live Activity updates this month and your tier's cap |
widget_updates_used / widget_updates_limit | integer | Widget updates this month and your tier's cap |
emails_used / emails_limit | integer | Emails sent this month and your tier's cap (free 50, paid 200) |
quota_resets_at | string | ISO 8601 instant the active counters reset |
integration_key | object | The key that made the request: id, name, is_default, permissions, and activity_slugs, widget_slugs and expires_at when set |
Access Control
| Access Level | Endpoints |
|---|---|
| No auth | GET /health |
Any hlk_ key | GET /auth/me |
activities: read | GET /activities, GET /activities/{slug} |
activities: update | Everything read allows, plus PATCH /activities/{slug} |
activities: manage | Everything update allows, plus POST /activities, DELETE /activities/{slug}, PATCH /activities/{slug}?upsert=true |
notifications: send | POST /notifications, GET /notifications/answers/{id} |
notifications: schedule | Everything send allows, plus POST /notifications/scheduled, GET /notifications/scheduled, GET /notifications/scheduled/{id}, DELETE /notifications/scheduled/{id} |
widgets: read | GET /widgets, GET /widgets/{slug} |
widgets: write | Everything read allows, plus POST /widgets, PATCH /widgets/{slug}, DELETE /widgets/{slug} |
emails: send | POST /emails |