Developers
Sign in

Developers · v1

H2H Notification API

Send notifications from your company's own systems straight to your employees in the Altum One mobile app.

Base URLhttps://api.altumone.id

Overview

The Host-to-Host (H2H) Notification API lets your company's own systems — for example an internal workspace app, a ticketing tool or an ERP — notify your employees in the Altum One mobile app. One request reaches each recipient as:

  • Bell entry

    A new item in the in-app notification bell — always written.

  • Banner or push

    A live banner at the top if the app is open, otherwise a push on the lock screen.

  • Optional link

    Tapping opens an https link, e.g. the page in your own system.

If the employee has the app open, the notification shows as a live banner at the top of the screen (tapping it opens the link); otherwise it arrives as a push notification. Either way, the bell entry is always written.

Delivery to the Altum One web apps is coming later; v1 delivers to the mobile app only.

Quick start

  1. In Admin Suite → Integrasi → API Token, create a token. It is shown once — copy it and store it as the environment variable ALTUM_API_TOKEN on your server.
  2. Send one request:
curl -X POST https://api.altumone.id/api/h2h/v1/notifications \
  -H "Authorization: Bearer $ALTUM_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "to": ["[email protected]"], "title": "Hello from our system" }'
  1. Done. The response is 202 Accepted and the employee sees the notification in the app right away.

Authentication

Every request carries your token as a Bearer token:

Header
Authorization: Bearer <token>
  • Tokens look like altum_ followed by 43 characters.
  • A token belongs to one company and can only notify that company's employees.
  • You can revoke a token in Admin Suite at any time. A revoked token gets 401 UNAUTHORIZED.
  • Allowed link domains (optional, per token): when set, link must be an https URL on one of those hosts (subdomains included); anything else is refused with 422 LINK_NOT_ALLOWED.

Keep the token server-side. Never put it in a browser, a mobile app or a public repository — anyone holding it can notify your whole company. Read it from an environment variable.

Endpoints

All endpoints live under https://api.altumone.id/api/h2h/v1, take and return JSON, and need the Authorization header.

Check a token

GET/api/h2h/v1/ping

Confirms the token works and shows which company and token it belongs to.

curl https://api.altumone.id/api/h2h/v1/ping \
  -H "Authorization: Bearer $ALTUM_API_TOKEN"
Response · 200 OK
{
  "company": { "name": "PT Permata Indo Sejahtera", "slug": "permata" },
  "token": { "name": "MWS", "prefix": "altum_Ab12Cd" }
}

Send a notification

POST/api/h2h/v1/notifications

Headers

AuthorizationstringRequired
Bearer token.
Content-TypestringRequired
application/json
Idempotency-Keystring, ≤ 100 charsOptional
Recommended. Makes retries safe — see Idempotency.

Body

A JSON object with the fields below. Unknown fields are not allowed — a body with any other field, or one that isn't valid JSON, gets 400 VALIDATION_ERROR.

tostring[] | "all"Required
Work emails of the recipients (1–1000, case-insensitive; duplicates are ignored), matched to active employees of the token's company. Or the string "all" for every active employee.
titlestring, 1–120 charsRequired
Notification title.
bodystring, ≤ 500 charsOptional
Notification text.
linkhttps URL, ≤ 500 charsOptional
Opened when the employee taps the notification.
pushTitle, pushBodystring, ≤ 120 / ≤ 500 charsOptional
What the lock-screen push shows instead of title/body. Use them to keep sensitive details out of the push — the full text stays inside the app.
enobjectOptional
English version — { "title", "body", "pushTitle", "pushBody" } — shown to employees whose app is set to English.
referencestring, ≤ 100 charsOptional
Your own id for this notification; echoed back in responses.
Request body
{
  "to": ["[email protected]", "[email protected]"],
  "title": "Tugas baru: Audit stok Q4",
  "body": "Anda ditugaskan oleh Rina. Tenggat 12 November.",
  "link": "https://mws.permata.co.id/tasks/123",
  "pushTitle": "Tugas baru di MWS",
  "pushBody": "Buka Altum One untuk melihat detailnya.",
  "en": {
    "title": "New task: Q4 stock audit",
    "body": "Assigned to you by Rina. Due 12 November.",
    "pushTitle": "New task in MWS",
    "pushBody": "Open Altum One to see the details."
  },
  "reference": "MWS-123"
}
Response · 202 Accepted
{
  "id": "cm3k9x2q10001abcd",
  "status": "accepted",
  "recipients": 2,
  "notFound": ["[email protected]"],
  "reference": "MWS-123",
  "createdAt": "2026-11-05T09:00:00.000Z"
}

Full cURL, Node.js and PHP versions are under Examples.

  • Delivery (bell entry + push) happens right after the reply.
  • Emails that don't match an active employee are listed (lower-cased) in notFound and skipped; the rest are still notified.
  • If none of the emails match, nothing is sent and the reply is 422 NO_RECIPIENTS.

Idempotency

Send an Idempotency-Key header to make retries safe. Use one key per event in your system (e.g. mws-task-123-assigned) — never a new random value per attempt.

  • Same token + same key within 24 hours → you get the original response again, with status 200 and the header Idempotency-Replayed: true. Nobody is notified twice.
  • Same key with a different body → 409 IDEMPOTENCY_CONFLICT.

Get a notification

GET/api/h2h/v1/notifications/:id

Returns a notification you sent, looked up by the notification id from the send response. It includes read: how many recipients have opened it in the app. Only notifications sent with a token of the same company are visible; anything else is 404 NOT_FOUND.

curl https://api.altumone.id/api/h2h/v1/notifications/cm3k9x2q10001abcd \
  -H "Authorization: Bearer $ALTUM_API_TOKEN"
Response · 200 OK
{
  "id": "cm3k9x2q10001abcd",
  "title": "Tugas baru: Audit stok Q4",
  "link": "https://mws.permata.co.id/tasks/123",
  "reference": "MWS-123",
  "recipients": 2,
  "notFound": ["[email protected]"],
  "read": 1,
  "createdAt": "2026-11-05T09:00:00.000Z"
}

Errors

Errors return a JSON body with a stable code (branch on this) and a human-readable message (for logs; may change).

Error body
{
  "error": {
    "code": "NO_RECIPIENTS",
    "message": "…"
  }
}
400VALIDATION_ERROR
The body isn't valid JSON, has unknown fields, or a field or header is invalid. Field errors come in details: [{ "field": "to.0", "message": "Invalid email" }].
400TOO_MANY_RECIPIENTS
More than 1000 emails in to.
401UNAUTHORIZED
Token missing, unknown or revoked.
404NOT_FOUND
No such notification for your company.
409IDEMPOTENCY_CONFLICT
The Idempotency-Key was already used with a different body.
422LINK_NOT_ALLOWED
link is not https on one of the token's allowed link domains.
422NO_RECIPIENTS
None of the emails match an active employee.
429RATE_LIMITED
Too many requests. Wait the number of seconds in the Retry-After header.
500INTERNAL
Something went wrong on our side. Retry with the same Idempotency-Key.

Limits

Requests
60 per minute, per token
Recipients
1000 emails per request
title
120 characters
body
500 characters
link
500 characters, https only
reference
100 characters
Idempotency-Key
100 characters, remembered 24 hours

A push needs the employee to have the Altum One app installed and notifications allowed. The bell entry is always written, so they see it next time they open the app.

Examples

Send a notification

A complete send with a link, a discreet push text and an English version. Every example reads the token from ALTUM_API_TOKEN.

curl -X POST https://api.altumone.id/api/h2h/v1/notifications \
  -H "Authorization: Bearer $ALTUM_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: mws-task-123-assigned" \
  -d '{
    "to": ["[email protected]", "[email protected]"],
    "title": "Tugas baru: Audit stok Q4",
    "body": "Anda ditugaskan oleh Rina. Tenggat 12 November.",
    "link": "https://mws.permata.co.id/tasks/123",
    "pushTitle": "Tugas baru di MWS",
    "pushBody": "Buka Altum One untuk melihat detailnya.",
    "en": {
      "title": "New task: Q4 stock audit",
      "body": "Assigned to you by Rina. Due 12 November.",
      "pushTitle": "New task in MWS",
      "pushBody": "Open Altum One to see the details."
    },
    "reference": "MWS-123"
  }'

Retry safely

Retry on network errors, timeouts, 429 and 5xx — with the same Idempotency-Key. If an earlier attempt actually got through, the retry gets the original reply (200) instead of notifying again. Don't retry other 4xx errors; fix the request.

# Re-running this exact command (same Idempotency-Key, same body) within
# 24 hours returns the original response with status 200 and
# "Idempotency-Replayed: true" — nobody is notified twice.
# -i prints the status line and headers so you can see that.
curl -i -X POST https://api.altumone.id/api/h2h/v1/notifications \
  -H "Authorization: Bearer $ALTUM_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: mws-task-123-assigned" \
  -d '{ "to": ["[email protected]"], "title": "Tugas baru: Audit stok Q4" }'

Changelog

  • 2026-11-05v1 — notifications.