Skip to content

Notifications API ​

RekberPay keeps an in-app notification for every escrow, payment and dispute event that concerns the user. These endpoints read that feed. Workspace notifications for enterprise members are separate; see Enterprise workspace.

Endpoints ​

MethodPathEndpointAuth
GET/v1/notificationsList notificationsKey or session
GET/v1/notifications/unread-countCount unread notificationsKey or session
GET/v1/notifications/streamStream the unread countKey or session
PATCH/v1/notifications/:id/readMark one as readKey or session
POST/v1/notifications/mark-all-readMark all as readKey or session
GET/v1/notifications/preferencesGet notification settingsKey or session
PUT/v1/notifications/preferencesSave notification settingsKey or session

List notifications ​

GET/v1/notifications

Newest first. body is HTML ready to display; metadata holds IDs such as escrow_id.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not needed. Reading has no side effects.

Query parameters ​

NameTypeRequiredDescription
unread_onlystringNotrue for unread only
pageintegerNoDefault 1
limitintegerNo1 to 50. Default 20

Example request ​

bash
curl "https://api.rekberpay.com/v1/notifications?limit=3" \
  -H "Authorization: Bearer $REKBERPAY_API_KEY"
js
const res = await fetch('https://api.rekberpay.com/v1/notifications?limit=3', {
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
    },
});
const data = await res.json();
python
import os

import requests

resp = requests.get(
    "https://api.rekberpay.com/v1/notifications?limit=3",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications?limit=3');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": [
        {
            "id": "ccccccc2-cccc-4ccc-8ccc-cccccccccccc",
            "user_id": "11111110-1111-4111-8111-111111111111",
            "type": "payment_success",
            "title": "Pembayaran Berhasil",
            "body": "<p style=\"margin: 0 0 16px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Aria [shortened]",
            "metadata": {
                "escrow_id": "55555551-5555-4555-8555-555555555555"
            },
            "is_read": false,
            "created_at": "2026-10-13T14:23:18.818Z",
            "total_count": "6"
        },
        {
            "id": "ddddddd2-dddd-4ddd-8ddd-dddddddddddd",
            "user_id": "11111110-1111-4111-8111-111111111111",
            "type": "escrow_joined",
            "title": "Pihak Lain Bergabung",
            "body": "<p style=\"margin: 0 0 16px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Aria [shortened]",
            "metadata": {
                "escrow_id": "55555551-5555-4555-8555-555555555555",
                "amount": 300000
            },
            "is_read": false,
            "created_at": "2026-10-13T14:23:18.802Z",
            "total_count": "6"
        },
        {
            "id": "eeeeeee2-eeee-4eee-8eee-eeeeeeeeeeee",
            "user_id": "11111110-1111-4111-8111-111111111111",
            "type": "escrow_completed_buyer",
            "title": "Transaksi Selesai",
            "body": "<p style=\"margin: 0 0 16px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Aria [shortened]",
            "metadata": {
                "escrow_id": "33333330-3333-4333-8333-333333333333",
                "amount": 250000
            },
            "is_read": false,
            "created_at": "2026-10-13T14:23:18.759Z",
            "total_count": "6"
        }
    ],
    "pagination": {
        "page": 1,
        "limit": 3,
        "total": 6,
        "total_pages": 2
    }
}

Lists are cut to the first 3 items and long text is shortened here.

Errors ​

StatusCodeCause
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Count unread notifications ​

GET/v1/notifications/unread-count

The number of unread notifications. count comes back as a string of digits, so convert it before comparing.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not needed. Reading has no side effects.

Example request ​

bash
curl https://api.rekberpay.com/v1/notifications/unread-count \
  -H "Authorization: Bearer $REKBERPAY_API_KEY"
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/unread-count', {
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
    },
});
const data = await res.json();
python
import os

import requests

resp = requests.get(
    "https://api.rekberpay.com/v1/notifications/unread-count",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/unread-count');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "count": "6"
    }
}

Errors ​

StatusCodeCause
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Stream the unread count ​

GET/v1/notifications/stream

A Server-Sent Events stream of the unread count, so a bell can update without polling. The response is text/event-stream, not JSON. Each message is one event: line and one data: line of JSON:

  • retry: 5000 first, the reconnect delay in milliseconds.
  • event: unread with {"count": n} right after it opens, then again whenever the count changes. Here count is a number.
  • : ping every 25 seconds. A comment line, which keeps proxies from closing a quiet stream.
  • event: evicted with {} when a newer stream of the same user took this one's place. Close the stream and fall back to polling Count unread notifications; do not reconnect.

The server ends every stream after 10 minutes. Reconnect after the retry delay, and you get a fresh count at once. Notifications created by background jobs (auto-release, auto-refund) may only show up at that next reconnect, so keep a slow poll as a backup.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie. A browser EventSource sends the cookie when it is created with { withCredentials: true }.
  • Rate limit: 30 connection attempts a minute per user. At most 5 open streams per user on each API server; opening another closes the oldest with event: evicted.
  • Idempotency: Not needed. Reading has no side effects.

Example request ​

bash
curl -N https://api.rekberpay.com/v1/notifications/stream \
  -H "Authorization: Bearer $REKBERPAY_API_KEY" \
  -H "Accept: text/event-stream"
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/stream', {
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
        Accept: 'text/event-stream',
    },
});
const decoder = new TextDecoder();
let buffer = '';
for await (const chunk of res.body) {
    buffer += decoder.decode(chunk, { stream: true });
    let end;
    while ((end = buffer.indexOf('\n\n')) !== -1) {
        const message = buffer.slice(0, end);
        buffer = buffer.slice(end + 2);
        const event = /^event: (.+)$/m.exec(message)?.[1];
        const data = /^data: (.+)$/m.exec(message)?.[1];
        if (event === 'unread') console.log('unread', JSON.parse(data).count);
    }
}
python
import json
import os

import requests

with requests.get(
    "https://api.rekberpay.com/v1/notifications/stream",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
        "Accept": "text/event-stream",
    },
    stream=True,
    timeout=(10, 90),
) as resp:
    event = None
    for line in resp.iter_lines(decode_unicode=True):
        if line.startswith("event: "):
            event = line[len("event: "):]
        elif line.startswith("data: ") and event == "unread":
            print("unread", json.loads(line[len("data: "):])["count"])
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/stream');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
        'Accept: text/event-stream',
    ],
    CURLOPT_WRITEFUNCTION => function ($ch, $chunk) {
        foreach (explode("\n", $chunk) as $line) {
            if (str_starts_with($line, 'data: ')) {
                echo $line, PHP_EOL;
            }
        }
        return strlen($chunk);
    },
]);
curl_exec($ch);
curl_close($ch);

Example response ​

200 OK with Content-Type: text/event-stream; charset=utf-8. The stream as it arrives:

text
retry: 5000

event: unread
data: {"count":6}

: ping

event: unread
data: {"count":7}

Errors ​

Errors come back as JSON before the stream starts.

StatusCodeCause
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver 30 connection attempts a minute. Wait for Retry-After seconds
503STREAM_UNAVAILABLEThe server holds too many open streams. Poll the unread count and try again after Retry-After seconds

Mark one as read ​

PATCH/v1/notifications/:id/read
  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not supported. A retry runs the call again.

Path parameters ​

NameTypeDescription
idUUIDThe notification ID

Example request ​

bash
curl -X PATCH https://api.rekberpay.com/v1/notifications/ccccccc2-cccc-4ccc-8ccc-cccccccccccc/read \
  -H "Authorization: Bearer $REKBERPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/ccccccc2-cccc-4ccc-8ccc-cccccccccccc/read', {
    method: 'PATCH',
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
const data = await res.json();
python
import os

import requests

resp = requests.patch(
    "https://api.rekberpay.com/v1/notifications/ccccccc2-cccc-4ccc-8ccc-cccccccccccc/read",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    json={},
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/ccccccc2-cccc-4ccc-8ccc-cccccccccccc/read');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(new stdClass()),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "id": "ccccccc2-cccc-4ccc-8ccc-cccccccccccc",
        "is_read": true
    }
}

Errors ​

StatusCodeCause
404NOT_FOUNDNo notification with this ID for you
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Mark all as read ​

POST/v1/notifications/mark-all-read

marked is how many were unread before the call.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not supported. A retry runs the call again.

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/notifications/mark-all-read \
  -H "Authorization: Bearer $REKBERPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/mark-all-read', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
const data = await res.json();
python
import os

import requests

resp = requests.post(
    "https://api.rekberpay.com/v1/notifications/mark-all-read",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    json={},
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/mark-all-read');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(new stdClass()),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "marked": 5
    }
}

Errors ​

StatusCodeCause
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Get notification settings ​

GET/v1/notifications/preferences

Which kinds of notification the user wants. Every kind is on until it is switched off.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not needed. Reading has no side effects.

Example request ​

bash
curl https://api.rekberpay.com/v1/notifications/preferences \
  -H "Authorization: Bearer $REKBERPAY_API_KEY"
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/preferences', {
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
    },
});
const data = await res.json();
python
import os

import requests

resp = requests.get(
    "https://api.rekberpay.com/v1/notifications/preferences",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/preferences');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "escrow_status": true,
        "payment_received": true,
        "dispute_opened": true,
        "promo": true
    }
}

Errors ​

StatusCodeCause
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Save notification settings ​

PUT/v1/notifications/preferences

Replaces the settings. Send all four fields.

  • Auth: A personal API key (Authorization: Bearer <key>) or a session cookie with X-CSRF-Token on writes.
  • Rate limit: 300 requests a minute per user, shared by every route.
  • Idempotency: Not supported. A retry runs the call again.

Body (JSON) ​

NameTypeRequiredDescription
escrow_statusbooleanYesEscrow status changes
payment_receivedbooleanYesPayments
dispute_openedbooleanYesDisputes
promobooleanYesNews and offers

Example request ​

bash
curl -X PUT https://api.rekberpay.com/v1/notifications/preferences \
  -H "Authorization: Bearer $REKBERPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "escrow_status": true,
    "payment_received": true,
    "dispute_opened": true,
    "promo": false
  }'
js
const res = await fetch('https://api.rekberpay.com/v1/notifications/preferences', {
    method: 'PUT',
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_API_KEY}`,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        escrow_status: true,
        payment_received: true,
        dispute_opened: true,
        promo: false
    }),
});
const data = await res.json();
python
import os

import requests

resp = requests.put(
    "https://api.rekberpay.com/v1/notifications/preferences",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_API_KEY']}",
    },
    json={
        "escrow_status": True,
        "payment_received": True,
        "dispute_opened": True,
        "promo": False,
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/notifications/preferences');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'escrow_status' => true,
        'payment_received' => true,
        'dispute_opened' => true,
        'promo' => false,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "escrow_status": true,
        "payment_received": true,
        "dispute_opened": true,
        "promo": false
    }
}

Errors ​

StatusCodeCause
400INVALID_BODYA field is missing or not a boolean
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or API key, the session expired, or the key is wrong or revoked
401WORKSPACE_KEY_ONLYA workspace key (rpe_...) was sent. Those only work under /v1/enterprise
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
403ACCOUNT_INACTIVE, SUSPENDEDThe account is closed, being deleted or suspended
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Escrow, payment services and B2B deals for Indonesian businesses.