> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heydollr.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Realtime Status

> Subscribe to live payment updates with Dollr realtime keys instead of polling.

**Realtime keys** are short-lived tokens for subscribing to live payment events on a checkout session. Dollr uses **Supabase Realtime** under the hood.

<Note>
  **API Reference:** [Collection realtime key](/api-reference/realtime-keys/get-collection-realtime-key)
</Note>

<Info>
  The Dollr Open API does **not** expose inbound HTTP webhooks. For backend fulfillment, see [Payment status patterns](/guides/payment-status-patterns).
</Info>

## When to use

| Approach                            | Best for                                              |
| ----------------------------------- | ----------------------------------------------------- |
| **Polling**                         | Simple backends; few concurrent payments              |
| **Realtime keys**                   | Live checkout UI while customer approves MoMo or card |
| **Hosted checkout + source status** | Success page verification                             |

## Prerequisites

| Credential          | Source                                                                       |
| ------------------- | ---------------------------------------------------------------------------- |
| Dollr Bearer token  | [Authentication](/authentication)                                            |
| `SUPABASE_URL`      | [Environments](/reference/environments) — merchant portal Developer settings |
| `SUPABASE_ANON_KEY` | Same section                                                                 |

## Step 1 — Obtain a collection realtime key

```http theme={null}
POST /v1/realtime-keys/collection
```

| Field          | Type        | Required | Description                                           |
| -------------- | ----------- | -------- | ----------------------------------------------------- |
| `session_id`   | **integer** | Yes      | Checkout session ID from `POST /v1/sessions/checkout` |
| `source_type`  | string      | Yes      | `INVOICE` or `ORDER`                                  |
| `reference_id` | string      | Yes      | Your UUID v4 (same as execution idempotency key)      |

```bash theme={null}
curl -X POST "https://api.heydollr.app/v1/realtime-keys/collection" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": 55,
    "source_type": "INVOICE",
    "reference_id": "550e8400-e29b-41d4-a716-446655440000"
  }'
```

**Response:**

| Field          | Description                                |
| -------------- | ------------------------------------------ |
| `access_token` | Short-lived JWT for Supabase Realtime auth |
| `expires_in`   | Token lifetime in **seconds**              |

<Warning>
  `session_id` is an **integer** here. Execution endpoints expect `session_id` as a **string** — see [API conventions](/api-conventions#resource-id-types).
</Warning>

## Step 2 — Connect with Supabase Realtime

```javascript theme={null}
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_ANON_KEY,
  {
    auth: { autoRefreshToken: false, persistSession: false },
    accessToken: async () => realtimeKey.access_token,
  }
);
supabase.realtime.setAuth(realtimeKey.access_token);

const channel = supabase.channel(
  `payment-intent:${sessionId}:${referenceId}`
);

channel
  .on(
    "postgres_changes",
    {
      event: "*",
      schema: "public",
      table: "checkout_payment_intent_public_status",
      filter: `reference_id=eq.${referenceId}`,
    },
    (payload) => {
      const row = payload.new;
      console.log("Status update:", row);
      // Update your UI — then verify via GET /v1/status/collection/{reference_id}
    }
  )
  .subscribe((status) => {
    if (status === "SUBSCRIBED") console.log("Watching payment");
    if (status === "CHANNEL_ERROR") fallbackToPolling();
  });
```

### Channel naming

```
payment-intent:{session_id}:{reference_id}
```

### Table

`checkout_payment_intent_public_status` — filtered by `reference_id`.

## Step 3 — Fallback to polling

If realtime disconnects or times out:

```http theme={null}
GET /v1/status/collection/{reference_id}
```

Always persist `reference_id` before execute. Use realtime for **UX**; use status API for **fulfillment decisions**.

## Timeout guidance

Subscribe for up to **30 seconds** after execute, then fall back to polling. MoMo payments may take several minutes in `PROCESSING`.

## Related

* [Payment status patterns](/guides/payment-status-patterns)
* [Realtime Keys API](/api/realtime-keys)
* [Environments](/reference/environments)
* [Sessions & executions](/concepts/sessions-and-executions)
