API and data model
Every staking endpoint with its method, path and permission key, the six database tables and their columns, and the enums the whole product turns on.
Everything on this page is generated from the shipped route handlers and models. Permission keys are enforced server-side; a frontend screen that hides a button is convenience, the key on the endpoint is the control.
User endpoints
All under /api/staking. Authenticated unless marked public.
/api/staking/stats counts ACTIVE and PENDING_WITHDRAWAL principal only. A
position that has asked to leave but not yet settled is still locked capital;
one that has completed or been cancelled has already been paid back. Every
staking surface uses this definition, so the landing page, the user dashboard
and the admin console agree.
Admin endpoints
All under /api/admin/staking.
Dashboard and reporting
Pools
Positions
Earnings and performance
/earning/distribute (singular) pays an explicit amount as a BONUS.
/earnings/distribute (plural) runs the APR accrual engine and writes REGULAR
rows. They are deliberately separate namespaces so they can never double-pay a
period. Calling the wrong one is the most likely way to overpay a pool.
Tables
All six use UUID primary keys, timestamps and soft deletes.
staking_pools
| Column | Type | Notes |
|---|---|---|
name |
string(191) | 2–100 characters |
token · symbol |
string(50) · string(10) | Symbol drives all wallet routing |
icon · description |
string(191) · text | |
walletType |
enum | FIAT · SPOT · ECO |
walletChain |
string(191) | Required for ECO |
apr |
decimal(10,8) | ≥ 0 |
lockPeriod |
integer | ≥ 1 day |
minStake · maxStake |
decimal(36,18) | Max is nullable and must exceed min |
availableToStake |
decimal(36,18) | Live capacity |
earlyWithdrawalFee · adminFeePercentage |
decimal(10,8) | 0–100 |
status |
enum | ACTIVE · INACTIVE · COMING_SOON |
isPromoted · order |
boolean · integer | Presentation |
earningFrequency |
enum | DAILY · WEEKLY · MONTHLY · END_OF_TERM |
autoCompound |
boolean | |
externalPoolUrl · profitSource · fundAllocation · risks · rewards |
url · text x4 | Disclosure copy, never read by logic |
Positions are RESTRICT on delete; admin earnings and performance records
cascade.
staking_positions
| Column | Type | Notes |
|---|---|---|
userId · poolId |
uuid | |
amount |
decimal(36,18) | Must be > 0 |
startDate · endDate |
datetime | Start must precede end |
status |
enum | ACTIVE · COMPLETED · CANCELLED · PENDING_WITHDRAWAL |
withdrawalRequested · withdrawalRequestDate |
boolean · datetime | The date prices an early exit |
adminNotes · completedAt |
text · datetime | completedAt only valid on COMPLETED |
apr · adminFeePercentage · earlyWithdrawalFee |
decimal(16,8), nullable | Terms snapshotted at stake time. Null on legacy rows falls back to the live pool. |
lastDistributionDate |
datetime, nullable | The accrual watermark. Null is treated as startDate. |
staking_earning_records
| Column | Type | Notes |
|---|---|---|
positionId |
uuid | |
amount |
double | ≥ 0 |
type |
enum | REGULAR · BONUS · REFERRAL |
description |
string(191) | Truncated by writers to fit |
isClaimed · claimedAt |
boolean · datetime | |
periodBucket |
string(100), nullable | Distribution-cycle key |
Unique on (positionId, type, periodBucket). NULL buckets on legacy rows never
collide because MySQL treats NULLs as distinct. REGULAR rows written by the
accrual engine carry accrual_YYYY-MM-DD; bonus distributions carry
poolId:frequency:LABEL:cycle. Nothing currently writes REFERRAL.
staking_admin_earnings
| Column | Type | Notes |
|---|---|---|
poolId |
uuid | |
amount · currency |
double · string(10) | Currency mirrors the pool symbol |
isClaimed |
boolean | Bookkeeping acknowledgement only |
type |
enum | PLATFORM_FEE · EARLY_WITHDRAWAL_FEE · PERFORMANCE_FEE · OTHER |
periodBucket |
string(100), nullable | Unique with (poolId, type) |
staking_external_pool_performances
poolId, date (not in the future), apr, totalStaked, profit, notes.
Reference data — no engine reads it.
staking_admin_activities
userId (null for cron-driven actions), action
(create · update · delete · approve · reject · distribute), type
(pool · position · earnings · settings · withdrawal) and relatedId.
Wallet and transaction types
| Type | Written when |
|---|---|
STAKING |
Principal debited at stake time, and principal returned at settlement |
STAKING_REWARD |
A user claims earnings |
Idempotency keys used by the money paths: staking_create_<positionId> for the
stake debit, staking_principal_return_<positionId> for the principal return
(shared across every transition), and a hash of the claimed row IDs for a claim.
Permission keys
| Key | Guards |
|---|---|
access.staking |
Admin overview, dashboard and analytics endpoints |
access.staking.pool · view.staking.pool |
Pool screens and reads |
create.staking.pool · edit.staking.pool · delete.staking.pool |
Pool writes |
access.staking.position · view.staking.position |
Position screens and reads |
create.staking.position · edit.staking.position · delete.staking.position |
Position writes, including withdrawal approval |
access.staking.earning · view.staking.earning |
Earnings screen and reads |
create.staking.earning · edit.staking.earning |
Both distribute endpoints, manual earnings, claiming |
view.staking.performance · create.staking.performance |
External performance records |
view.staking.activity |
Activity log |
access.staking.settings |
Staking settings screen |
Key derivation and the places a key must exist are covered in Permissions.