Quick start
In Web Admin, create a third-party application for the target company. Copy its App ID and App Secret, and configure an optional Callback URL if final results are needed. Engine creates notification-center entries for eligible users in the bound company and attempts system Push only for eligible registered devices.
Endpoint and authentication
API environments:
- Test: https://aim-api-test.proton-system.com
- Production: https://aim-api.proton-system.com
Every server-to-server JSON request must include Authorization: Basic Base64(KEY:SECRET) using HTTP Basic Authentication, where KEY is the App ID and SECRET is the App Secret:
Endpoint: POST /openapi/v1/notifications.
curl --request POST 'https://<your-engine-host>/openapi/v1/notifications' \
--header 'Authorization: Basic <Base64(AppID:AppSecret)>' \
--header 'Content-Type: application/json' \
--data '{"requestId":"order-20260819-001","title":"Order completed","body":"Your order has been completed.","imageUrls":["https://cdn.example.com/order/001-1.webp","https://cdn.example.com/order/001-2.webp"]}'Request contract
The strict JSON body accepts the required requestId, title, and body fields plus optional imageUrls. Omitting imageUrls, or sending null or [], means there are no images. Otherwise send 1-9 URLs in display order. Each value is trimmed, must be unique, must be an absolute HTTPS URL without username or password, and may contain at most 2048 Unicode characters. If any URL is invalid, the whole request is rejected. Engine stores but never fetches, probes, proxies, or caches these URLs. The complete request body is limited to 256 KiB. Limits are 128 Unicode characters for requestId, 100 for title, and 1000 for body. Each App ID is limited to 10 requests per minute and 100 per hour.
Repeating the same requestId with the same title, body, and ordered imageUrls returns the original stored result. After processing, its status can therefore be SUCCESS, PARTIAL_SUCCESS, or FAILED instead of ACCEPTED. Reusing the requestId with different content or image order returns IDEMPOTENCY_CONFLICT.
Acceptance response
A valid request returns HTTP 202:
{
"requestId": "order-20260819-001",
"notificationId": "00000000-0000-0000-0000-000000000001",
"status": "ACCEPTED"
}ACCEPTED means Engine stored the request for dispatch. It does not prove that APNs/FCM or a device delivered the notification.
Callback results
If a Callback URL is configured, Engine sends one terminal result:
{
"requestId": "order-20260819-001",
"status": "PARTIAL_SUCCESS",
"recipientCount": 8,
"pushAcceptedCount": 1,
"pushFailedCount": 1
}recipientCount is the number of notification-center recipients. pushAcceptedCount and pushFailedCount are Push Outbox batch counts, not user counts, device counts, or proof of system-banner delivery.
Callback test
Each admin Callback test sends a distinct probe:
{
"requestId": "callback-test-<unique-id>",
"status": "SUCCESS",
"recipientCount": 1,
"pushAcceptedCount": 1,
"pushFailedCount": 0,
"test": true
}When test is true, validate the shape and return 2xx, but do not match the probe to a submitted notification request or update business delivery state. Its counts are fixed probe values, not real recipients or Push Outbox batches.
Terminal status is SUCCESS, PARTIAL_SUCCESS, or FAILED. Return any 2xx response to acknowledge it. Otherwise Engine retries after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, and 24 hours. Callbacks currently have no HMAC signature: require HTTPS, match the requestId of non-test results to your own request, restrict exposure where possible, and process callbacks idempotently.
Error reference
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Content type, JSON shape, size, or field validation failed. |
| 401 | INVALID_APP_CREDENTIALS | App ID or App Secret is invalid. |
| 403 | APPLICATION_INACTIVE | The application or bound company is inactive. |
| 409 | IDEMPOTENCY_CONFLICT | The requestId was reused with different content. |
| 429 | RATE_LIMITED | The per-application rate limit was exceeded. |
| 503 | NOTIFICATION_UNAVAILABLE | Notification processing is temporarily unavailable. |
Security and delivery scope
The mobile client accepts at most 5 MiB per image and gives the complete image download operation 10 seconds. It does not follow 3xx redirects, so every URL must return the image directly.
App ID and App Secret are server-to-server credentials. Never embed them in a browser, mobile app, public repository, URL, or client-side storage. Rotate the App Secret if it is exposed. Every eligible active user in the bound company receives a notification-center entry and is included in recipientCount. System Push is attempted only for devices with an active PushInstallation that permits the BUSINESS category, and still does not guarantee a system banner on every device. imageUrls are rendered only in notification detail; they are not included in Push or Callback payloads. The title and body must remain complete and understandable without the images. Image download or rendering failure does not change the accepted, Callback, or Push status. The mobile client downloads each image directly from the public CDN, so use no-auth URLs that need no cookies, keep them available for at least 90 days, and account for the CDN receiving the user's IP, request time, and User-Agent. Because URL content can change, use immutable object URLs when stable historical display matters.