# YEMScan API Developer Guide

## Table of Contents

1. [Introduction](#introduction)
2. [Getting Started](#getting-started)
3. [Authentication](#authentication)
4. [Configuration](#configuration)
5. [Base URL](#base-url)
6. [API Endpoints](#api-endpoints)
7. [Value Format (YEM)](#value-format-yem)
8. [Request & Response Format](#request--response-format)
9. [Error Handling](#error-handling)
10. [Transaction Status Values](#transaction-status-values)
11. [Code Examples](#code-examples)
12. [Rate Limits](#rate-limits)
13. [References](#references)

---

## Introduction

This API is a **simplified wrapper** for the [YEMChain blockchain API](https://yemscan.com/api/) (YEMScan). It lets you create YEM transactions, check balances, and query blockchain data through a single REST API. Authentication to the upstream YEMScan service is handled server-side; you do not send API keys in your requests.

### What You Can Do

- **Create transactions** – Send YEM between UIDs (batch up to 100 per request)
- **Get balances** – Query balances for up to 100 UIDs
- **Globals** – Total accounts and transactions on the chain
- **Transaction volume** – 1-day and 7-day volume for an asset
- **Transaction statuses** – Check if transaction hashes are confirmed, failed, or not found
- **Asset stats** – Price and wallet count for an asset (e.g. YEM)
- **Public key** – Get Ethereum public key for a UID
- **Transaction details** – Get full transaction by hash
- **Validate third-party access** – Check if a UID is allowed to access the platform (e.g. FinFlo)

### Key Features

- Simplified REST endpoints (no YEMScan headers required from clients)
- Server-side authentication via environment variables
- Decimal amount support for `value` (e.g. `12.34` YEM); converted to API integer format internally
- Consistent response shape: `success`, `message`, and endpoint-specific data
- Human-readable transaction statuses: `not_found`, `failed`, `confirmed`

---

## Getting Started

### Prerequisites

- HTTP client (e.g. cURL, fetch, axios)
- JSON for request/response
- Base URL of the deployed app (e.g. `https://your-domain.com/public`)

### Quick Start

1. **Base URL**: Use `{your-app-base-url}/api/yemscan` (e.g. `https://debit.gmpayapp.site/public/api/yemscan`).
2. **Health check**: Verify the API and YEMScan connectivity:

```bash
curl -X GET "https://your-domain.com/public/api/yemscan/health"
```

---

## Authentication

**No client authentication.** All calls to this API are unauthenticated from the client’s perspective. The server uses configured YEMScan credentials (API key, custom domain, UID) to talk to [yemscan.com](https://yemscan.com/api/). You only need to know the correct base URL of the app.

### Required: uid and access granted

All YEMScan operations (except **validate-access**, **health**, and **getUid**) require the **user's UID** and that the user has **granted access** to the platform (e.g. FinFlo). For each request:

1. Send the **`uid`** query parameter (the logged-in user's UID, e.g. `1296648`).
2. The server calls YEM Foundation to ensure `access_granted` is true for that UID and platform.
3. If access is not granted, the API returns **403** with `access_granted: false`.
4. If access is granted, the server calls YEMScan using that user's Pernum so the request is allowed.

Example: `GET /transaction?hash=0x...&uid=1296648`. Without `uid` you get 400; with `uid` but no access you get 403.

---

## Configuration

The API uses the following environment variables (configured on the server, not sent by clients):

| Variable | Required | Description |
|----------|----------|-------------|
| `yemscan.api_key` | Yes | YEMScan API key (request from YEM Foundation) |
| `yemscan.custom_domain` | Yes | Your registered domain (e.g. `yourdomain.com`) |
| `yemscan.uid` | Yes | Your UID (Pernum = UID + 1000000000 is sent in headers) |
| `yemscan.api_base_url` | No | Default: `https://yemscan.com/api` |
| `yemscan.foundation_api_url` | No | Default: `https://yem.foundation/api` (for validate-access) |
| `yemscan.platform_name` | No | Default: `FinFlo` (platform name for third-party access validation) |
| `yemscan.verify_ssl` | No | `true` or `false`; default `true` |

If any required variable is missing, `/health` returns `503` with a message that YEMScan is not configured.

---

## Base URL

All endpoints are relative to:

```
{your-app-base-url}/api/yemscan
```

Example:

```
https://debit.gmpayapp.site/public/api/yemscan
```

---

## API Endpoints

### Health Check

Verify configuration and connectivity to YEMScan.

**Endpoint**: `GET /health`

**Success (200)**:
```json
{
  "success": true,
  "message": "YEMScan API OK",
  "configured": true
}
```

**Not configured (503)**:
```json
{
  "success": false,
  "message": "YEMScan not configured (check yemscan.api_key, yemscan.custom_domain, yemscan.uid)",
  "configured": false
}
```

**Upstream unreachable (503)**:
```json
{
  "success": false,
  "message": "YEMScan API unreachable",
  "configured": true
}
```

---

### Create Transactions

Create one or more YEM transactions (max 100 per request). You can send a **single transaction object** or a **batch** in a `transactions` array.

**Endpoint**: `POST /transactions`

**Request body – single transaction**:
```json
{
  "from_uid": 123,
  "to_uid": 456,
  "value": 12.34,
  "reason": "Payment for order #12345",
  "asset": "YEM",
  "from_curr": "EUR",
  "to_curr": "USD"
}
```

**Request body – batch**:
```json
{
  "transactions": [
    {
      "from_uid": 123,
      "to_uid": 456,
      "value": 12.34,
      "reason": "Payment for order #12345",
      "asset": "YEM",
      "from_curr": "EUR",
      "to_curr": "USD"
    },
    {
      "from_uid": 789,
      "to_uid": 101,
      "value": 5.67,
      "reason": "Refund",
      "asset": "YEM",
      "from_curr": "USD",
      "to_curr": "GBP"
    }
  ]
}
```

**Fields**:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `from_uid` | integer | Yes | Sender UID |
| `to_uid` | integer | Yes | Recipient UID |
| `value` | number | Yes | Amount (decimal or integer; e.g. 12.34 = 12.34 YEM) |
| `reason` | string | Yes | Reason/memo |
| `asset` | string | Yes | Asset symbol (e.g. `YEM`) |
| `from_curr` | string | Yes | Sender currency code |
| `to_curr` | string | Yes | Recipient currency code |

**Success (200)**:
```json
{
  "success": true,
  "message": "1 transactions inserted successfully.",
  "inserted_count": 1,
  "transaction_hashes": [
    "0xa1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef12345678"
  ]
}
```

---

### Get Balances

Retrieve balances for up to 100 UIDs.

**Endpoint**: `GET /balances`

**Query parameters**:

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `uids` | Yes | — | Comma-separated UIDs (e.g. `123,456,789`) |
| `tokenSymbol` | No | `YEM` | Asset symbol |

**Example**: `GET /balances?uids=123,456&tokenSymbol=YEM`

**Success (200)**:
```json
{
  "success": true,
  "message": "Balances retrieved",
  "balances": {
    "123": "1000.00",
    "456": "2000.00"
  }
}
```

---

### Get Globals

Global blockchain statistics.

**Endpoint**: `GET /globals`

**Success (200)**:
```json
{
  "success": true,
  "message": "Global stats retrieved successfully in 5ms",
  "total_accs": 15000,
  "total_txns": 50000
}
```

---

### Get Transaction Volume

Transaction volume for an asset (1d and 7d).

**Endpoint**: `GET /volume`

**Query parameters**:

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `tokenSymbol` | No | `YEM` | Asset symbol |

**Example**: `GET /volume?tokenSymbol=YEM`

**Success (200)**:
```json
{
  "success": true,
  "message": "Transaction volume retrieved successfully in 2ms",
  "volume_1d": 15000.25,
  "volume_7d": 105000.75
}
```

---

### Get Transaction Statuses

Check status of up to 100 transaction hashes (e.g. after creating transactions).

**Endpoint**: `GET /transaction-statuses`

**Query parameters**:

| Parameter | Required | Description |
|-----------|----------|-------------|
| `hashes` | Yes | Comma-separated transaction hashes (max 100) |

**Example**: `GET /transaction-statuses?hashes=0xabc...,0xdef...`

**Success (200)**:
```json
{
  "success": true,
  "message": "Statuses retrieved",
  "statuses": {
    "0xa1b2c3d4...": "confirmed",
    "0xb2c3d4e5...": "failed",
    "0xc3d4e5f6...": "not_found"
  }
}
```

Possible status values: `not_found`, `failed`, `confirmed`.

---

### Get Asset Stats

Price and number of wallets holding an asset.

**Endpoint**: `GET /asset-stats`

**Query parameters**:

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `tokenSymbol` | No | `YEM` | Asset symbol |

**Example**: `GET /asset-stats?tokenSymbol=YEM`

**Success (200)**:
```json
{
  "success": true,
  "message": "Asset stats retrieved",
  "price": "1.00",
  "wallets": 1257632
}
```

---

### Get Public Key

Ethereum public key for a UID.

**Endpoint**: `GET /public-key/{uid}` or `GET /public-key?uid={uid}`

**Example**: `GET /public-key/12345` or `GET /public-key?uid=12345`

**Success (200)**:
```json
{
  "success": true,
  "message": "Public key retrieved",
  "public_key": "0x742d35cc6634c0532925a3b844b91678f8c8f3a0"
}
```

**Not found (404)**:
```json
{
  "success": false,
  "message": "Public key not found for uid: 12345"
}
```

---

### Get Transaction

Full transaction details by hash.

**Endpoint**: `GET /transaction/{hash}` or `GET /transaction?hash={hash}`

**Example**: `GET /transaction/0x278d9e20...` or `GET /transaction?hash=0x278d9e20...`

**Success (200)**:
```json
{
  "success": true,
  "message": "Transaction retrieved",
  "transaction": {
    "hash": "0x278d9e202a17d833f05f744758c5eb423411529e90cc0e5f04aa6825c30aab6e",
    "blockNumber": 476232,
    "from_uid": 999999,
    "to_uid": 789,
    "value": 73,
    "asset": "YEM",
    "timestamp": 1765650241,
    "status": true,
    "onchaindata": "|0.73|CHF|0.91|USD"
  }
}
```

Note: `value` in the transaction object is in integer form (2 decimals); e.g. `73` = 0.73 YEM.

**Not found (404)**:
```json
{
  "success": false,
  "message": "Transaction not found"
}
```

---

### Validate third-party access

Check whether a UID is authorized to access the platform (e.g. FinFlo). Call when the user opens the app with a stored Pernum/UID or when they add their Pernum.

**Endpoint**: `GET /validate-access` or `GET /third-party-access` (alias)

**Query parameters**:

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `uid` | Yes | — | User ID to validate |
| `platform_name` | No | From server (`yemscan.platform_name`) or `FinFlo` | Platform name sent to YEM Foundation |

**Example**: `GET /validate-access?uid=789` or `GET /validate-access?uid=789&platform_name=FinFlo`

**Success (200, access granted)**:
```json
{
  "success": true,
  "access_granted": true,
  "uid": 789,
  "platform_name": "FinFlo",
  "message": "Access granted"
}
```

**Success (200, access not granted or error from YEM Foundation)**:
```json
{
  "success": false,
  "access_granted": false,
  "uid": 789,
  "platform_name": "FinFlo",
  "message": "Access not granted"
}
```

**Missing uid (400)**:
```json
{
  "success": false,
  "access_granted": false,
  "message": "uid required (query parameter)"
}
```

---

## Value Format (YEM)

- **When creating transactions**: Send `value` as a decimal (e.g. `12.34` for 12.34 YEM). The API converts it to the upstream integer format (e.g. 1234) automatically.
- **When reading transaction details**: The upstream API returns `value` as an integer with 2 decimal places (e.g. `73` = 0.73 YEM). Our response passes this through in the `transaction` object.

---

## Request & Response Format

- **Content-Type**: Use `Content-Type: application/json` for POST bodies.
- **Responses**: JSON. Every response includes:
  - `success` (boolean)
  - `message` (string)
  - Additional fields depending on the endpoint (e.g. `balances`, `transaction_hashes`, `statuses`).

---

## Error Handling

**Validation errors (400)** – Missing or invalid parameters:

```json
{
  "success": false,
  "message": "uids required (comma-separated)"
}
```

**Not found (404)** – e.g. transaction hash or public key not found:

```json
{
  "success": false,
  "message": "Transaction not found"
}
```

**Upstream/API errors (400/503)** – May include:

```json
{
  "success": false,
  "message": "Create transactions failed",
  "error_code": 400,
  "raw_response": { ... }
}
```

Use `message` for user-facing text; `raw_response` (when present) for debugging.

---

## Transaction Status Values

After calling **Get Transaction Statuses**, each hash maps to one of:

| Value | Meaning |
|-------|--------|
| `not_found` | Hash not yet seen or invalid |
| `failed` | Transaction failed on chain |
| `confirmed` | Transaction confirmed on chain |

---

## Code Examples

### cURL

**Health check**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/health"
```

**Create a single transaction**
```bash
curl -X POST "https://your-domain.com/public/api/yemscan/transactions" \
  -H "Content-Type: application/json" \
  -d '{
    "from_uid": 123,
    "to_uid": 456,
    "value": 12.34,
    "reason": "Payment for order #12345",
    "asset": "YEM",
    "from_curr": "EUR",
    "to_curr": "USD"
  }'
```

**Get balances**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/balances?uids=123,456&tokenSymbol=YEM"
```

**Get globals**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/globals"
```

**Get transaction statuses**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/transaction-statuses?hashes=0xabc,0xdef"
```

**Get transaction by hash**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/transaction/0x278d9e202a17d833f05f744758c5eb423411529e90cc0e5f04aa6825c30aab6e"
```

**Validate third-party access**
```bash
curl -X GET "https://your-domain.com/public/api/yemscan/validate-access?uid=789"
# or with platform name:
curl -X GET "https://your-domain.com/public/api/yemscan/validate-access?uid=789&platform_name=FinFlo"
```

### JavaScript (fetch)

**Create transaction**
```javascript
const response = await fetch('https://your-domain.com/public/api/yemscan/transactions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    from_uid: 123,
    to_uid: 456,
    value: 12.34,
    reason: 'Payment for order #12345',
    asset: 'YEM',
    from_curr: 'EUR',
    to_curr: 'USD'
  })
});
const data = await response.json();
console.log(data.transaction_hashes);
```

**Get balances**
```javascript
const uids = [123, 456].join(',');
const res = await fetch(`https://your-domain.com/public/api/yemscan/balances?uids=${uids}&tokenSymbol=YEM`);
const data = await res.json();
console.log(data.balances);
```

**Poll transaction status**
```javascript
const hashes = ['0xabc...', '0xdef...'].join(',');
const res = await fetch(`https://your-domain.com/public/api/yemscan/transaction-statuses?hashes=${encodeURIComponent(hashes)}`);
const data = await res.json();
// data.statuses: { "0xabc...": "confirmed", "0xdef...": "not_found" }
```

**Validate third-party access (e.g. on app open or when adding Pernum)**
```javascript
const uid = 789;
const res = await fetch(`https://your-domain.com/public/api/yemscan/validate-access?uid=${uid}`);
const data = await res.json();
if (data.access_granted) {
  // User has authorized their Pernum for this platform
} else {
  // Show message: data.message
}
```

---

## Rate Limits

The **upstream YEMScan API** enforces **10 requests per minute per API key**. This wrapper does not add its own rate limiting; if you exceed the upstream limit, you will get errors from YEMScan. For higher limits, contact the [YEM Foundation](https://yemscan.com/api/) and specify YEMChain V2.0.

---

## References

- [YEMScan API (official)](https://yemscan.com/api/) – Upstream API documentation and required headers
- In-app API docs – Visit `{your-app-base-url}/api/docs` for the web view that includes the YEMScan section
