Транзакции (Transaction Endpoints)¶
Аудитория: разработчики, frontend инженеры Последнее обновление: 2025-11-17 Краткое содержание: Полная документация Transaction endpoints — история транзакций пользователей, административное управление транзакциями, одобрение, подтверждение, генерация и выполнение переводов. Включает 12 реальных backend endpoints (2 user + 10 admin) с comprehensive примерами React интеграции.
Обзор endpoints¶
User Endpoints¶
| Метод | Endpoint | Описание | Требуется Auth |
|---|---|---|---|
| GET | /api/user/transactions |
История транзакций пользователя | ✅ Да |
| GET | /api/user/transactions/:id |
Детали конкретной транзакции | ✅ Да |
Admin Endpoints¶
| Метод | Endpoint | Описание | Требуется Auth |
|---|---|---|---|
| GET | /api/admin/transactions |
Список всех транзакций | ✅ Да (Admin) |
| POST | /api/admin/transactions |
Создать транзакцию | ✅ Да (Admin) |
| GET | /api/admin/transactions/:id |
Детали транзакции | ✅ Да (Admin) |
| POST | /api/admin/transactions/:id/approve |
Одобрить транзакцию | ✅ Да (Admin) |
| POST | /api/admin/transactions/:id/reject |
Отклонить транзакцию | ✅ Да (Admin) |
| POST | /api/admin/transactions/:id/confirm |
Подтвердить транзакцию | ✅ Да (Admin) |
| POST | /api/admin/transactions/generate |
Генерация transfer транзакций | ✅ Да (Admin) |
| POST | /api/admin/transactions/execute |
Выполнение investment transfers | ✅ Да (Admin) |
| GET | /api/admin/transaction-requests |
Список заявок на переводы | ✅ Да (Admin) |
| POST | /api/admin/transaction-requests/:id/complete |
Завершить заявку на перевод | ✅ Да (Admin) |
User Endpoints¶
GET /api/user/transactions¶
Получить историю транзакций пользователя с фильтрацией и пагинацией.
Запрос¶
GET /api/user/transactions?status=confirmed&type=deposit&page=1&limit=20
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Заголовки:
| Заголовок | Значение | Обязательно | Описание |
|---|---|---|---|
Authorization |
Bearer <token> |
✅ Да | User JWT токен |
Query параметры:
| Параметр | Тип | Обязательно | Описание | По умолчанию |
|---|---|---|---|---|
status |
string | ❌ Нет | Фильтр по статусу: pending, confirmed, failed, processing |
Все |
type |
string | ❌ Нет | Тип транзакции: deposit, withdrawal, transfer, investment, reversal |
Все |
page |
number | ❌ Нет | Номер страницы | 1 |
limit |
number | ❌ Нет | Количество записей на странице (max 100) | 100 |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"type": "deposit",
"amount": "1000.00",
"currency": "USDC",
"status": "confirmed",
"transactionHash": "0x1234567890abcdef...",
"blockNumber": 18234567,
"confirmations": 12,
"createdAt": "2025-10-01T10:30:00Z",
"confirmedAt": "2025-10-01T10:35:00Z"
},
{
"id": "660e9500-e29b-41d4-a716-446655440111",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"type": "withdrawal",
"amount": "250.00",
"currency": "USDC",
"status": "pending",
"transactionHash": null,
"blockNumber": null,
"confirmations": 0,
"createdAt": "2025-10-05T14:20:00Z",
"confirmedAt": null
}
],
"total": 42,
"page": 1,
"limit": 20,
"totalPages": 3
},
"timestamp": "2025-10-06T12:34:56Z"
}
Поля ответа:
| Поле | Тип | Описание |
|---|---|---|
data.transactions[] |
array | Массив транзакций пользователя |
data.transactions[].id |
string | UUID транзакции |
data.transactions[].type |
string | Тип транзакции |
data.transactions[].amount |
string | Сумма транзакции (SafeDecimal) |
data.transactions[].currency |
string | Валюта (USDC, ETH, USD) |
data.transactions[].status |
string | Статус транзакции |
data.transactions[].transactionHash |
string|null | Blockchain transaction hash (если есть) |
data.transactions[].blockNumber |
number|null | Номер блока в blockchain |
data.transactions[].confirmations |
number | Количество подтверждений блока |
data.transactions[].createdAt |
string | Дата создания (ISO 8601) |
data.transactions[].confirmedAt |
string|null | Дата подтверждения (ISO 8601) |
data.total |
number | Общее количество транзакций |
data.page |
number | Текущая страница |
data.limit |
number | Записей на странице |
data.totalPages |
number | Всего страниц |
Типы транзакций:
| Тип | Описание | Направление |
|---|---|---|
deposit |
Пополнение баланса | Incoming |
withdrawal |
Вывод средств | Outgoing |
transfer |
Внутренний перевод | Internal |
investment |
Инвестирование | Outgoing |
reversal |
Отмена/возврат транзакции | Incoming |
Статусы транзакций:
| Статус | Описание |
|---|---|
pending |
Транзакция создана, ожидает обработки |
processing |
Транзакция обрабатывается |
confirmed |
Транзакция подтверждена и завершена |
failed |
Транзакция не удалась |
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
| 401 | TOKEN_INVALID |
Неверная подпись JWT |
| 400 | INVALID_LIMIT |
Limit превышает максимум (100) |
| 400 | INVALID_PAGE |
Некорректное значение page |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
# Получить все транзакции
curl -X GET https://app.saga.surf/api/user/transactions \
-H "Authorization: Bearer $TOKEN"
# Фильтр по статусу
curl -X GET "https://app.saga.surf/api/user/transactions?status=confirmed" \
-H "Authorization: Bearer $TOKEN"
# Фильтр по типу и пагинация
curl -X GET "https://app.saga.surf/api/user/transactions?type=deposit&page=1&limit=10" \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
interface Transaction {
id: string;
userID: string;
type: 'deposit' | 'withdrawal' | 'transfer' | 'investment' | 'reversal';
amount: string;
currency: string;
status: 'pending' | 'processing' | 'confirmed' | 'failed';
transactionHash: string | null;
blockNumber: number | null;
confirmations: number;
createdAt: string;
confirmedAt: string | null;
}
interface TransactionsResponse {
transactions: Transaction[];
total: number;
page: number;
limit: number;
totalPages: number;
}
const fetchTransactions = async (
filters: {
status?: string;
type?: string;
page?: number;
limit?: number;
} = {}
): Promise<TransactionsResponse> => {
const token = localStorage.getItem('saga_access_token');
const params = new URLSearchParams();
if (filters.status) params.append('status', filters.status);
if (filters.type) params.append('type', filters.type);
if (filters.page) params.append('page', filters.page.toString());
if (filters.limit) params.append('limit', filters.limit.toString());
const response = await fetch(`/api/user/transactions?${params}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch transactions: ${response.statusText}`);
}
const { data } = await response.json();
return data;
};
// Использование
const transactions = await fetchTransactions({
status: 'confirmed',
page: 1,
limit: 20
});
console.log(`Найдено ${transactions.total} транзакций`);
transactions.transactions.forEach(tx => {
console.log(`${tx.type}: ${tx.amount} ${tx.currency} - ${tx.status}`);
});
GET /api/user/transactions/:id¶
Получить детальную информацию о конкретной транзакции.
Запрос¶
GET /api/user/transactions/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Path параметры:
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
id |
string | ✅ Да | UUID транзакции |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"type": "deposit",
"amount": "1000.00",
"currency": "USDC",
"status": "confirmed",
"transactionHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"blockNumber": 18234567,
"confirmations": 24,
"fromAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"toAddress": "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199",
"gasUsed": "21000",
"gasPrice": "50",
"createdAt": "2025-10-01T10:30:00Z",
"confirmedAt": "2025-10-01T10:35:00Z"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Поля ответа:
| Поле | Тип | Описание |
|---|---|---|
data.fromAddress |
string|null | Адрес отправителя |
data.toAddress |
string|null | Адрес получателя |
data.gasUsed |
string|null | Использованный gas (wei) |
data.gasPrice |
string|null | Цена gas (gwei) |
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 404 | TRANSACTION_NOT_FOUND |
Транзакция не найдена |
| 403 | FORBIDDEN |
Транзакция принадлежит другому пользователю |
| 401 | TOKEN_EXPIRED |
JWT токен истёк |
Пример cURL¶
TOKEN="eyJhbGciOiJIUzI1NiIs..."
TX_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X GET "https://app.saga.surf/api/user/transactions/${TX_ID}" \
-H "Authorization: Bearer $TOKEN"
Пример TypeScript¶
const getTransactionDetails = async (transactionId: string): Promise<Transaction> => {
const token = localStorage.getItem('saga_access_token');
const response = await fetch(`/api/user/transactions/${transactionId}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
if (response.status === 404) {
throw new Error('Transaction not found');
}
throw new Error(`Failed to fetch transaction: ${response.statusText}`);
}
const { data } = await response.json();
return data;
};
// Использование
const transaction = await getTransactionDetails('550e8400-e29b-41d4-a716-446655440000');
console.log(`Transaction ${transaction.id}: ${transaction.amount} ${transaction.currency}`);
if (transaction.transactionHash) {
console.log(`Blockchain TX: ${transaction.transactionHash}`);
console.log(`Confirmations: ${transaction.confirmations}`);
}
Admin Endpoints¶
GET /api/admin/transactions¶
Получить список всех транзакций в системе с фильтрацией.
Требуется роль: Admin
Запрос¶
GET /api/admin/transactions?status=pending&user_id=123e4567-e89b-12d3-a456-426614174000
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Query параметры:
| Параметр | Тип | Обязательно | Описание | По умолчанию |
|---|---|---|---|---|
status |
string | ❌ Нет | Фильтр по статусу | Все |
user_id |
string | ❌ Нет | Фильтр по пользователю (UUID) | Все |
type |
string | ❌ Нет | Фильтр по типу транзакции | Все |
page |
number | ❌ Нет | Номер страницы | 1 |
limit |
number | ❌ Нет | Записей на странице (max 100) | API default |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"userEmail": "user@example.com",
"type": "withdrawal",
"amount": "500.00",
"currency": "USDC",
"status": "pending",
"createdAt": "2025-10-06T10:00:00Z",
"processedAt": null
}
],
"total": 128,
"page": 1,
"limit": 20,
"totalPages": 7
},
"timestamp": "2025-10-06T12:34:56Z"
}
Дополнительные поля (vs user endpoint):
| Поле | Тип | Описание |
|---|---|---|
data.transactions[].userEmail |
string | Email пользователя |
data.transactions[].processedAt |
string|null | Время обработки администратором |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
# Все pending транзакции
curl -X GET "https://admin.saga.surf/api/admin/transactions?status=pending" \
-H "Authorization: Bearer $ADMIN_TOKEN"
# Транзакции конкретного пользователя
curl -X GET "https://admin.saga.surf/api/admin/transactions?user_id=123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer $ADMIN_TOKEN"
Пример TypeScript¶
const fetchAdminTransactions = async (filters: {
status?: string;
user_id?: string;
type?: string;
page?: number;
limit?: number;
} = {}): Promise<TransactionsResponse> => {
const adminToken = localStorage.getItem('admin_auth_token');
const params = new URLSearchParams();
Object.entries(filters).forEach(([key, value]) => {
if (value !== undefined) params.append(key, value.toString());
});
const response = await fetch(`/api/admin/transactions?${params}`, {
headers: {
'Authorization': `Bearer ${adminToken}`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch transactions: ${response.statusText}`);
}
const { data } = await response.json();
return data;
};
POST /api/admin/transactions¶
Создать новую транзакцию (для интеграционных тестов и admin операций).
Требуется роль: Admin
Запрос¶
POST /api/admin/transactions
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"userID": "123e4567-e89b-12d3-a456-426614174000",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"amount": "1000.00",
"currency": "USDC",
"txHash": "0x1234567890abcdef...",
"type": "deposit",
"status": "confirmed"
}
Тело запроса:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
userID |
string | ✅ Да | UUID пользователя |
walletAddress |
string | ❌ Нет | Ethereum адрес кошелька (42 символа) |
amount |
string | ✅ Да | Сумма транзакции (SafeDecimal string) |
currency |
string | ✅ Да | Валюта: USDC, ETH, USD |
txHash |
string | ❌ Нет | Blockchain transaction hash |
type |
string | ✅ Да | Тип: deposit, withdrawal, transfer, investment, reversal |
status |
string | ❌ Нет | Статус: pending, confirmed, failed, processing (default: failed для безопасности) |
Ответ¶
Успех (201 Created):
{
"success": true,
"data": {
"id": "770e9600-e29b-41d4-a716-446655440222",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"type": "deposit",
"amount": "1000.00",
"currency": "USDC",
"status": "confirmed",
"transactionHash": "0x1234567890abcdef...",
"createdAt": "2025-10-06T12:34:56Z"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 400 | USER_ID_REQUIRED |
UserID не предоставлен |
| 400 | AMOUNT_REQUIRED |
Amount не предоставлен |
| 400 | INVALID_AMOUNT_FORMAT |
Некорректный формат суммы |
| 400 | CURRENCY_REQUIRED |
Currency не предоставлена |
| 400 | INVALID_CURRENCY |
Неподдерживаемая валюта |
| 400 | TYPE_REQUIRED |
Тип транзакции не указан |
| 400 | INVALID_TRANSACTION_TYPE |
Неподдерживаемый тип |
| 400 | INVALID_WALLET_ADDRESS |
Некорректный формат адреса кошелька |
| 401 | UNAUTHORIZED |
Требуется Admin токен |
| 403 | FORBIDDEN |
Недостаточно прав |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X POST https://admin.saga.surf/api/admin/transactions \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userID": "123e4567-e89b-12d3-a456-426614174000",
"amount": "1000.00",
"currency": "USDC",
"type": "deposit",
"status": "confirmed"
}'
Пример TypeScript¶
interface CreateTransactionRequest {
userID: string;
walletAddress?: string;
amount: string;
currency: string;
txHash?: string;
type: 'deposit' | 'withdrawal' | 'transfer' | 'investment' | 'reversal';
status?: 'pending' | 'confirmed' | 'failed' | 'processing';
}
const createTransaction = async (
request: CreateTransactionRequest
): Promise<Transaction> => {
const adminToken = localStorage.getItem('admin_auth_token');
const response = await fetch('/api/admin/transactions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${adminToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to create transaction');
}
const { data } = await response.json();
return data;
};
// Использование
const transaction = await createTransaction({
userID: '123e4567-e89b-12d3-a456-426614174000',
amount: '1000.00',
currency: 'USDC',
type: 'deposit',
status: 'confirmed'
});
console.log(`Создана транзакция ${transaction.id}`);
GET /api/admin/transactions/:id¶
Получить детали конкретной транзакции (admin view с дополнительной информацией).
Требуется роль: Admin
Запрос¶
GET /api/admin/transactions/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Path параметры:
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
id |
string | ✅ Да | UUID транзакции |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"userEmail": "user@example.com",
"type": "withdrawal",
"amount": "500.00",
"currency": "USDC",
"status": "confirmed",
"transactionHash": "0x9876543210fedcba...",
"blockNumber": 18234890,
"confirmations": 15,
"fromAddress": "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199",
"toAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"createdAt": "2025-10-06T10:00:00Z",
"confirmedAt": "2025-10-06T10:05:00Z",
"processedBy": "admin-uuid-456",
"notes": "Одобрено после проверки"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Дополнительные admin поля:
| Поле | Тип | Описание |
|---|---|---|
data.userEmail |
string | Email пользователя |
data.processedBy |
string|null | UUID администратора |
data.notes |
string|null | Заметки администратора |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
TX_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X GET "https://admin.saga.surf/api/admin/transactions/${TX_ID}" \
-H "Authorization: Bearer $ADMIN_TOKEN"
POST /api/admin/transactions/:id/approve¶
Одобрить pending транзакцию.
Требуется роль: Admin
Запрос¶
POST /api/admin/transactions/550e8400-e29b-41d4-a716-446655440000/approve
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Path параметры:
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
id |
string | ✅ Да | UUID транзакции |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactionID": "550e8400-e29b-41d4-a716-446655440000",
"status": "approved",
"approvedBy": "admin-uuid-123",
"approvedAt": "2025-10-06T12:34:56Z",
"notes": "Одобрено администратором"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 400 | TRANSACTION_NOT_PENDING |
Транзакция не в статусе pending |
| 404 | TRANSACTION_NOT_FOUND |
Транзакция не найдена |
| 401 | UNAUTHORIZED |
Требуется Admin токен |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
TX_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X POST "https://admin.saga.surf/api/admin/transactions/${TX_ID}/approve" \
-H "Authorization: Bearer $ADMIN_TOKEN"
Пример TypeScript¶
const approveTransaction = async (transactionId: string): Promise<void> => {
const adminToken = localStorage.getItem('admin_auth_token');
const response = await fetch(`/api/admin/transactions/${transactionId}/approve`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${adminToken}`
}
});
if (!response.ok) {
throw new Error('Failed to approve transaction');
}
const { data } = await response.json();
console.log(`Транзакция ${data.transactionID} одобрена`);
};
POST /api/admin/transactions/:id/reject¶
Отклонить pending транзакцию.
Требуется роль: Admin
Запрос¶
POST /api/admin/transactions/550e8400-e29b-41d4-a716-446655440000/reject
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactionID": "550e8400-e29b-41d4-a716-446655440000",
"status": "rejected",
"rejectedBy": "admin-uuid-123",
"rejectedAt": "2025-10-06T12:34:56Z",
"reason": "Отклонено администратором"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
TX_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X POST "https://admin.saga.surf/api/admin/transactions/${TX_ID}/reject" \
-H "Authorization: Bearer $ADMIN_TOKEN"
POST /api/admin/transactions/:id/confirm¶
Подтвердить транзакцию с blockchain transaction hash.
Требуется роль: Admin
Запрос¶
POST /api/admin/transactions/550e8400-e29b-41d4-a716-446655440000/confirm
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
}
Тело запроса:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
txHash |
string | ✅ Да | Blockchain transaction hash для подтверждения |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactionID": "550e8400-e29b-41d4-a716-446655440000",
"txHash": "0x1234567890abcdef...",
"status": "confirmed",
"confirmedBy": "admin-uuid-123",
"confirmedAt": "2025-10-06T12:34:56Z",
"message": "Транзакция подтверждена и связанный withdrawal автоматически завершен"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 400 | TXHASH_REQUIRED |
TxHash не предоставлен |
| 404 | TRANSACTION_NOT_FOUND |
Транзакция не найдена |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
TX_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X POST "https://admin.saga.surf/api/admin/transactions/${TX_ID}/confirm" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
}'
POST /api/admin/transactions/generate¶
Генерировать transfer транзакции для pending операций.
Требуется роль: Admin
Запрос¶
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"generatedCount": 5,
"batchSize": 10,
"transactionIDs": [
"880e9700-e29b-41d4-a716-446655440333",
"990ea800-e29b-41d4-a716-446655440444"
]
},
"timestamp": "2025-10-06T12:34:56Z"
}
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X POST https://admin.saga.surf/api/admin/transactions/generate \
-H "Authorization: Bearer $ADMIN_TOKEN"
POST /api/admin/transactions/execute¶
Выполнить investment transfers для одобренных инвестиций.
Требуется роль: Admin
Запрос¶
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"executedCount": 3,
"maxBatchSize": 10,
"totalAmount": "15000.00",
"transactionIDs": [
"aa0eb900-e29b-41d4-a716-446655440555"
]
},
"timestamp": "2025-10-06T12:34:56Z"
}
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X POST https://admin.saga.surf/api/admin/transactions/execute \
-H "Authorization: Bearer $ADMIN_TOKEN"
GET /api/admin/transaction-requests¶
Получить список заявок на переводы (для funds-transfer UI).
Требуется роль: Admin
Запрос¶
GET /api/admin/transaction-requests?status=pending&page=1&limit=20
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Query параметры:
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
user_id |
string | ❌ Нет | Фильтр по пользователю |
type |
string | ❌ Нет | Тип заявки |
status |
string | ❌ Нет | Статус заявки |
currency |
string | ❌ Нет | Фильтр по валюте |
page |
number | ❌ Нет | Номер страницы |
limit |
number | ❌ Нет | Записей на странице |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"transactionRequests": [
{
"id": "bb0ec000-e29b-41d4-a716-446655440666",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"userEmail": "user@example.com",
"type": "withdrawal",
"fromAddress": "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199",
"toAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"amount": "500.00",
"currency": "USDC",
"status": "pending",
"createdAt": "2025-10-06T10:00:00Z"
}
],
"total": 12,
"page": 1,
"limit": 20,
"totalPages": 1
},
"timestamp": "2025-10-06T12:34:56Z"
}
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -X GET "https://admin.saga.surf/api/admin/transaction-requests?status=pending" \
-H "Authorization: Bearer $ADMIN_TOKEN"
POST /api/admin/transaction-requests/:id/complete¶
Завершить заявку на перевод с blockchain transaction hash.
Требуется роль: Admin
Запрос¶
POST /api/admin/transaction-requests/bb0ec000-e29b-41d4-a716-446655440666/complete
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"txHash": "0x1234567890abcdef...",
"notes": "Перевод выполнен успешно"
}
Тело запроса:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
txHash |
string | ✅ Да | Blockchain transaction hash |
notes |
string | ❌ Нет | Заметки администратора |
Ответ¶
Успех (200 OK):
{
"success": true,
"data": {
"requestID": "bb0ec000-e29b-41d4-a716-446655440666",
"txHash": "0x1234567890abcdef...",
"status": "completed",
"completedBy": "admin-uuid-123"
},
"timestamp": "2025-10-06T12:34:56Z"
}
Ошибки:
| Код статуса | Код ошибки | Описание |
|---|---|---|
| 400 | TXHASH_REQUIRED |
TxHash не предоставлен |
| 404 | REQUEST_NOT_FOUND |
Заявка не найдена |
Пример cURL¶
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."
REQUEST_ID="bb0ec000-e29b-41d4-a716-446655440666"
curl -X POST "https://admin.saga.surf/api/admin/transaction-requests/${REQUEST_ID}/complete" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"txHash": "0x1234567890abcdef...",
"notes": "Перевод выполнен успешно"
}'
Use Cases¶
Use Case 1: Transaction History Component¶
Сценарий: Пользователь просматривает свою историю транзакций с фильтрацией
React Component:
import React, { useEffect, useState } from 'react';
interface Transaction {
id: string;
type: string;
amount: string;
currency: string;
status: string;
transactionHash: string | null;
createdAt: string;
}
const TransactionHistory: React.FC = () => {
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState<string>('all');
useEffect(() => {
const fetchTransactions = async () => {
try {
const token = localStorage.getItem('saga_access_token');
const params = filter !== 'all' ? `?status=${filter}` : '';
const response = await fetch(`/api/user/transactions${params}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const { data } = await response.json();
setTransactions(data.transactions);
} catch (error) {
console.error('Failed to fetch transactions:', error);
} finally {
setLoading(false);
}
};
fetchTransactions();
}, [filter]);
if (loading) return <div>Загрузка...</div>;
const getStatusColor = (status: string) => {
switch (status) {
case 'confirmed': return 'text-green-600';
case 'pending': return 'text-yellow-600';
case 'failed': return 'text-red-600';
default: return 'text-gray-600';
}
};
const getTypeIcon = (type: string) => {
switch (type) {
case 'deposit': return '↓';
case 'withdrawal': return '↑';
case 'transfer': return '↔';
case 'investment': return '💰';
default: return '•';
}
};
return (
<div className="p-6">
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold">История транзакций</h2>
<select
value={filter}
onChange={(e) => setFilter(e.target.value)}
className="border rounded px-3 py-2"
>
<option value="all">Все</option>
<option value="confirmed">Подтверждённые</option>
<option value="pending">Ожидают</option>
<option value="failed">Неудачные</option>
</select>
</div>
<div className="space-y-3">
{transactions.map(tx => (
<div key={tx.id} className="border rounded-lg p-4 hover:shadow-md transition">
<div className="flex justify-between items-start">
<div className="flex items-start space-x-3">
<span className="text-2xl">{getTypeIcon(tx.type)}</span>
<div>
<h3 className="font-semibold capitalize">{tx.type}</h3>
<p className="text-sm text-gray-600">
{new Date(tx.createdAt).toLocaleDateString()}
</p>
{tx.transactionHash && (
<a
href={`https://etherscan.io/tx/${tx.transactionHash}`}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-blue-500 hover:underline"
>
View on Etherscan
</a>
)}
</div>
</div>
<div className="text-right">
<div className="text-xl font-bold">
{tx.type === 'withdrawal' || tx.type === 'investment' ? '-' : '+'}
{tx.amount} {tx.currency}
</div>
<span className={`text-sm font-medium ${getStatusColor(tx.status)}`}>
{tx.status}
</span>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default TransactionHistory;
Результат: Интерактивная история транзакций с фильтрацией, цветовым кодированием статусов и ссылками на blockchain explorer.
📋 Метаданные¶
Версия: 2.6.268
Обновлено: 2025-10-21
Статус: Published