# RekberPay Public API

Read-only endpoints for the verified user directory and individual public profiles. No authentication required. CORS is open (`Access-Control-Allow-Origin: *`) on every endpoint in this document, so browsers, server-side scripts, and LLM agents can consume them directly.

**Base URL:** `https://rekberpay.com`

## Privacy

These endpoints **never** return personal contact information:

- No `email`, `phone`, `balance`, `kyc_documents`, or internal database identifiers
- Only ratings published in the public timeline count toward the public average
- Suspended accounts are excluded from every public response

## Caching

Responses include a `Cache-Control` header so browsers and CDNs can cache reasonably. Treat the data as eventually consistent — recent profile changes may take up to a few minutes to propagate.

## Rate limits

Public endpoints share a per-IP rate limit. Exceeding it returns `429` with `{ "error": { "code": "RATE_LIMITED" } }`. The reset interval is short (under a minute) — back off and retry.

---

## `GET /api/public/users`

Browse the public seller/buyer directory.

### Query parameters

| Name     | Type    | Default | Notes                                                                   |
| -------- | ------- | ------- | ----------------------------------------------------------------------- |
| `page`   | integer | `1`     | 1-indexed.                                                              |
| `limit`  | integer | `24`    | Range `1..50`.                                                          |
| `search` | string  | `""`    | Case-insensitive match on `username` or `full_name`. Trimmed, max 32.   |
| `sort`   | enum    | `top`   | `top` ranks by activity (verified, ratings, completed transactions). `new` orders newest first. |
| `verified` | enum  | `0`     | `1` or `true` returns verified users only and combines with either `sort`. `0` or `false` applies no filter. Any other value returns `400`. |

### Inclusion

A user appears in this listing only if they are an active member with verifiable activity (any escrow as buyer or seller, any received rating, or a verified account). Inactive or suspended accounts are excluded.

### Sample request

```bash
curl 'https://rekberpay.com/api/public/users?page=1&limit=10&sort=top&search=rizaldy'
```

### Sample response

```json
{
    "success": true,
    "data": {
        "users": [
            {
                "username": "rizaldyputra",
                "full_name": "Rizaldy Putra",
                "is_verified": true,
                "joined_at": "2026-02-14T03:21:08.000Z",
                "total_escrows_completed": 42,
                "average_rating": 4.92,
                "rating_count": 38
            }
        ],
        "page": 1,
        "limit": 10,
        "total": 1,
        "has_more": false
    }
}
```

### Errors

| Status | `error.code`     | Meaning                              |
| ------ | ---------------- | ------------------------------------ |
| 400    | `INVALID_QUERY`  | A query param failed validation.     |
| 429    | `RATE_LIMITED`   | Per-IP rate limit exceeded.          |

---

## `GET /api/public/users/:username`

Single public profile.

### Path parameters

| Name       | Type   | Notes                                                                |
| ---------- | ------ | -------------------------------------------------------------------- |
| `username` | string | Case-insensitive. Must match `^[a-z0-9_.]{1,32}$`.                   |

### Sample request

```bash
curl 'https://rekberpay.com/api/public/users/rizaldyputra'
```

### Sample response

```json
{
    "success": true,
    "data": {
        "username": "rizaldyputra",
        "full_name": "Rizaldy Putra",
        "is_verified": true,
        "joined_at": "2026-02-14T03:21:08.000Z",
        "total_escrows_completed": 42,
        "average_rating": 4.92,
        "rating_count": 38,
        "social_instagram": "rizaldyputra",
        "social_shopee": "https://shopee.co.id/rizaldyputra",
        "social_tiktokshop": null,
        "recent_ratings": [
            {
                "stars": 5,
                "review": "Pengiriman cepat, barang sesuai deskripsi.",
                "created_at": "2026-05-19T08:42:11.000Z",
                "rater_username": "dewi",
                "rater_is_verified": true,
                "ratee_role": "seller"
            }
        ]
    }
}
```

`recent_ratings` returns up to 20 most recent published ratings. For deeper paging, use `/api/public/users/:username/ratings`.

`ratee_role` indicates whether the profile owner was acting as `"buyer"` or `"seller"` in the transaction the rating refers to. May be `null` when the underlying transaction is no longer available.

### Errors

| Status | `error.code`      | Meaning                                                |
| ------ | ----------------- | ------------------------------------------------------ |
| 404    | `USER_NOT_FOUND`  | Username does not exist or fails the format check.     |
| 429    | `RATE_LIMITED`    | Per-IP rate limit exceeded.                            |

---

## `GET /api/public/users/:username/ratings`

Paginated published-ratings feed for a single user.

### Query parameters

| Name    | Type    | Default | Notes                  |
| ------- | ------- | ------- | ---------------------- |
| `page`  | integer | `1`     | 1-indexed.             |
| `limit` | integer | `20`    | Range `1..50`.         |

### Sample request

```bash
curl 'https://rekberpay.com/api/public/users/rizaldyputra/ratings?page=1&limit=20'
```

### Sample response

```json
{
    "success": true,
    "data": {
        "page": 1,
        "limit": 20,
        "total": 38,
        "items": [
            {
                "stars": 5,
                "review": "Pengiriman cepat.",
                "created_at": "2026-05-19T08:42:11.000Z",
                "rater_username": "dewi",
                "rater_is_verified": true,
                "ratee_role": "seller"
            }
        ]
    }
}
```

### Errors

| Status | `error.code`      | Meaning                                                |
| ------ | ----------------- | ------------------------------------------------------ |
| 400    | `INVALID_QUERY`   | `page` or `limit` failed validation.                   |
| 404    | `USER_NOT_FOUND`  | Username does not exist or fails the format check.     |
| 429    | `RATE_LIMITED`    | Per-IP rate limit exceeded.                            |

---

## Response envelope

Every endpoint returns a JSON object with a `success` boolean and either a `data` field or an `error` object:

```json
{ "success": true,  "data": ... }
{ "success": false, "error": { "code": "...", "message": "..." } }
```
