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

# Transaction history

> Reading back what a terminal has taken — paging, filtering, and end-of-day reconciliation.

```http theme={null}
GET /v1/transactions
```

```bash theme={null}
curl -u 'term_a7f3k9d2:vpt_…' \
  'https://api.vibepay.mn/v1/transactions?from=2026-08-18T00:00:00Z&limit=100'
```

```json 200 OK theme={null}
{
  "transactions": [
    {
      "id": "tx_01k2y7v9j0e8ra7cx3mbq4d5nf",
      "amountMNT": 12500,
      "status": "COMPLETED",
      "type": "CHARGE",
      "vatReceiptID": "112219652816001097170000010053729",
      "vatStatus": "issued",
      "terminalID": "ter_01k2y7v8t5f3s9wq1mzd7b6cxa",
      "createdAt": "2026-08-18T09:14:22.481739Z"
    }
  ],
  "nextCursor": ""
}
```

Newest first, always scoped to **the terminal whose credentials you used**. There is no merchant
or terminal parameter, so one till can never read another's takings.

## Parameters

| Parameter | Type     | Default     | Notes                                 |
| --------- | -------- | ----------- | ------------------------------------- |
| `from`    | RFC 3339 | 30 days ago | Start of the window                   |
| `to`      | RFC 3339 | now         | Must not precede `from`               |
| `cursor`  | string   | —           | From the previous page's `nextCursor` |
| `limit`   | integer  | 100         | Clamped to 1000                       |

<Note>
  Only charges appear here. Employer top-ups and other wallet movements are not a terminal's
  business and are excluded.
</Note>

## Paging

Keep passing `nextCursor` until it comes back empty.

```python theme={null}
def all_transactions(frm, to):
    cursor = ""
    while True:
        params = {"from": frm, "to": to, "limit": 500}
        if cursor:
            params["cursor"] = cursor
        page = requests.get(f"{BASE}/v1/transactions", params=params,
                            auth=AUTH, timeout=30).json()
        yield from page["transactions"]
        cursor = page["nextCursor"]
        if not cursor:
            return
```

<Warning>
  The cursor is opaque. Do not decode it, store it long-term, or build one yourself — its format
  is not part of this contract and will change.
</Warning>

## What this endpoint is good for

<CardGroup cols={2}>
  <Card title="Checking credentials" icon="key">
    `?limit=1` returning `200` is the only way to prove a username and password pair is live.
  </Card>

  <Card title="Finding VAT receipt numbers" icon="receipt">
    The charge response cannot carry one. This is where `vatReceiptID` shows up.
  </Card>

  <Card title="Resolving an unknown outcome" icon="question">
    After a timeout or a `5xx`, look here before recharging.
  </Card>

  <Card title="End-of-day reconciliation" icon="calculator">
    One terminal per till makes the day's total a single query.
  </Card>
</CardGroup>

### Reconciling a timeout

The safest use of this endpoint. After a request whose outcome you never learned:

```python theme={null}
# Did that charge actually land? Look at the last minute of this terminal's history.
window_start = (datetime.now(timezone.utc) - timedelta(minutes=2)).isoformat()
recent = requests.get(f"{BASE}/v1/transactions",
                      params={"from": window_start, "limit": 20},
                      auth=AUTH, timeout=30).json()["transactions"]

landed = next((t for t in recent
               if t["amountMNT"] == amount and t["status"] == "COMPLETED"), None)
```

Sending the original `Idempotency-Key` again is simpler and more precise — a matched replay
returns the original transaction directly. Use this lookup when you no longer have the key.

### End of day

```bash theme={null}
curl -u 'term_…:vpt_…' \
  'https://api.vibepay.mn/v1/transactions?from=2026-08-18T00:00:00Z&to=2026-08-19T00:00:00Z&limit=1000' \
  | jq '[.transactions[] | select(.status == "COMPLETED") | .amountMNT] | add'
```

<Info>
  Timestamps are UTC. Mongolia is UTC+8, so a Mongolian business day beginning at 00:00 in
  Ulaanbaatar starts at `16:00:00Z` the previous day. Build your day boundaries from
  Asia/Ulaanbaatar and convert, or your first and last hours will land in the wrong day.
</Info>

Note that this is your **gross takings**, not your payout. Payouts settle weekly and are shown in
the [merchant dashboard](https://merchant.vibepay.mn).

## Errors

| Status | Body                                  | Meaning                   |
| ------ | ------------------------------------- | ------------------------- |
| `400`  | ``invalid `from` (expected RFC3339)`` | Bad timestamp format      |
| `400`  | ``invalid `to` (expected RFC3339)``   | Bad timestamp format      |
| `400`  | `` `from` must be before `to` ``      | The window runs backwards |
| `400`  | \`\`invalid \`limit\`\`\`             | Not a positive integer    |
| `401`  | `unauthorized`                        | Credentials dead          |
