# API Overview

# API Overview

Tok provides a REST API for accessing bank account data and initiating payments across Balkan markets.

---

## API Style

| Aspect | Detail |
|--------|--------|
| Style | REST |
| Specification | OpenAPI 3.1 |
| Base URL | `https://api.tokapi.io/v1` |
| Response format | JSON |
| Auth | API keys (server-to-server) + OAuth2 (PSD2 consent flows) |

---

## Authentication

### API Key Authentication (Server-to-Server)

All requests require an API key in the `Authorization` header:

```http
Authorization: ApiKey tok_live_xxxxxxxxxxxxxxxxxxxx
```

API keys are organisation-scoped. Each Tok client organisation has its own key pair (live + sandbox).

### OAuth2 (PSD2 Consent Flows)

When a user connects a bank account, Tok initiates a PSD2 OAuth2 flow:

```
1. POST /v1/consents  →  returns redirect URL to bank's SCA portal
2. User authenticates at bank (SCA: password + SMS/app)
3. Bank redirects to: https://api.tokapi.io/v1/callback?code=XXX&state=YYY
4. Tok exchanges code for access + refresh tokens (stored encrypted)
5. Bank connection active — transactions sync automatically
```

Tokens are stored AES-256-GCM encrypted with GCP Cloud KMS. They are never exposed via API.

---

## Core Endpoints

### Accounts

```http
GET /v1/accounts
```
Returns all bank accounts connected to the organisation.

```http
GET /v1/accounts/{accountId}
```
Returns details for a specific account (balance, IBAN, currency, bank name).

---

### Transactions

```http
GET /v1/accounts/{accountId}/transactions
  ?dateFrom=2026-01-01
  &dateTo=2026-03-01
  &limit=100
  &cursor=...
```
Returns paginated transactions for a bank account. Supports cursor-based pagination.

**Transaction object:**
```json
{
  "id": "txn_01HXYZ...",
  "externalId": "BANK-TXN-123456",
  "bookingDate": "2026-02-25",
  "valueDate": "2026-02-25",
  "amount": "5000.0000",
  "currency": "RSD",
  "direction": "inbound",
  "creditorIban": "RS35105008123123123173",
  "debtorIban": "RS35105008000000019174",
  "remittanceInfo": "Invoice INV-2026-001",
  "source": "open_banking"
}
```

---

### Consents

```http
POST /v1/consents
```
Initiate a PSD2 consent flow for a bank. Returns a redirect URL.

```json
{
  "bankId": "erste-hr",
  "callbackUrl": "https://app.bilko.io/banking/callback"
}
```

```http
GET /v1/consents/{consentId}
```
Returns consent status: `active`, `expired`, `revoked`, or `error`.

```http
DELETE /v1/consents/{consentId}
```
Revoke a consent (user disconnects bank).

---

### Payments (PISP — Phase 2, Q3 2026)

```http
POST /v1/payments
```
Initiate a payment via bank's payment initiation API (PISP scope).

```json
{
  "creditorIban": "RS35105008123123123173",
  "amount": "1500.00",
  "currency": "RSD",
  "remittanceInfo": "Invoice INV-2026-042"
}
```

---

## Multi-Tenancy

Every API call is scoped to an **organisation**. The organisation is determined by the API key.

- No cross-organisation data access is possible
- Bank connections, consents, and transactions are all organisation-scoped
- Each organisation can have multiple users with different roles

---

## Rate Limiting

Rate limits are per-organisation, per-tier.

| Tier | Requests / minute | Burst |
|------|------------------|-------|
| Free | 60 | 10 |
| Pro | 300 | 50 |
| Enterprise | 1,000 | 200 |

Rate limit headers on every response:
```http
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1741100460
```

When rate limited, the API returns `429 Too Many Requests` with a `Retry-After` header.

---

## SDKs

Official SDKs handle authentication, retries, and response parsing.

| SDK | Language | Package | Install |
|-----|----------|---------|---------|
| Node.js SDK | TypeScript | `@tokapi/sdk` | `npm install @tokapi/sdk` |
| Python SDK | Python 3.10+ | `tokapi-sdk` | `pip install tokapi-sdk` |
| Kotlin SDK | Kotlin | `io.tokapi:sdk-kotlin` | Gradle: `implementation("io.tokapi:sdk-kotlin:1.0.0")` |

**Node.js quickstart:**
```typescript
import { TokClient } from '@tokapi/sdk';

const tok = new TokClient({ apiKey: 'tok_live_xxxx' });

const accounts = await tok.accounts.list();
const transactions = await tok.transactions.list(accounts[0].id, {
  dateFrom: '2026-01-01',
  dateTo: '2026-03-01',
});
```

**Python quickstart:**
```python
from tokapi import TokClient

tok = TokClient(api_key="tok_live_xxxx")
accounts = tok.accounts.list()
transactions = tok.transactions.list(accounts[0].id, date_from="2026-01-01")
```

---

## Error Format

All errors follow a consistent structure:

```json
{
  "error": {
    "code": "CONSENT_EXPIRED",
    "message": "The bank consent has expired. Please reconnect the bank account.",
    "requestId": "req_01HXYZ..."
  }
}
```

Common error codes:

| Code | HTTP | Meaning |
|------|------|---------|
| `INVALID_API_KEY` | 401 | API key missing or invalid |
| `CONSENT_EXPIRED` | 403 | 90-day PSD2 consent expired |
| `CONSENT_REVOKED` | 403 | User revoked consent at bank |
| `BANK_API_ERROR` | 502 | Bank API unavailable |
| `RATE_LIMITED` | 429 | Organisation rate limit exceeded |
| `NOT_FOUND` | 404 | Resource not found |

---

## OpenAPI Spec

The full machine-readable OpenAPI 3.1 specification is at:
- File: `docs/api/openapi.yaml` in the Tok repository
- Developer portal: [developer.tokapi.io](https://developer.tokapi.io)

---

## Sandbox

All API keys come in pairs: `tok_live_*` and `tok_sandbox_*`. Use sandbox keys for development — sandbox data is not real bank data and does not trigger real bank connections.

Sandbox base URL: `https://sandbox.api.tokapi.io/v1`