API Endpoints
Complete reference for the Spray and Play REST API. All endpoints, request formats, and response examples.
API Endpoints
> Complete reference for the Spray and Play REST API. All endpoints return JSON responses
> with consistent success/error formats and include rate limit headers.
Base URL
https://app.playtrenches.xyz/apiFor local development:
http://localhost:3000/api---
User Endpoints
Get User Profile
GET /api/userReturns information about the authenticated user.
Auth: Session cookie required
Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"handle": "@sprayer_username",
"email": "user@example.com",
"wallet": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletEvm": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletSol": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"balance": 1000.50,
"beliefScore": 45,
"boostPoints": 250,
"referralCode": "ABC123",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-02-16T10:30:00Z"
}
}TypeScript Example:
interface User {
id: string;
handle: string;
email: string;
wallet: string;
walletEvm: string;
walletSol: string;
balance: number;
beliefScore: number;
boostPoints: number;
referralCode: string;
createdAt: string;
updatedAt: string;
}
const getUser = async (): Promise<User> => {
const response = await fetch('/api/user', {
credentials: 'include'
});
if (!response.ok) {
throw new Error('Failed to fetch user');
}
const { data } = await response.json();
return data;
};---
Update User Profile
POST /api/userUpdate wallet addresses and profile information.
Auth: Session cookie required
Request Body:
{
"wallet": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletEvm": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletSol": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
}Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"wallet": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletEvm": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"walletSol": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"updatedAt": "2026-02-16T10:35:00Z"
}
}---
Get Payout Preference
GET /api/user/payout-preferenceReturns the user's current payout preference (balance credit vs wallet payout).
Auth: Session cookie required
Response:
{
"payoutToBalance": false
}---
Update Payout Preference
POST /api/user/payout-preferenceToggle whether rewards are credited to balance or sent to withdrawal wallet.
Auth: Session cookie required
Security: CSRF token required
Request Body:
{
"payoutToBalance": true
}Response:
{
"success": true,
"payoutToBalance": true
}Behavior:
true→ Rewards added to platform balance (for re-spraying)false→ Rewards sent to withdrawal wallet (default)
---
Get User Positions
GET /api/user/positionsReturns user's active positions across all trenches.
Auth: Session cookie required
Response:
{
"success": true,
"data": [
{
"id": "pos_123",
"trenchId": "cuid_rapid_001",
"trenchName": "Rapid Fire",
"trenchLevel": "RAPID",
"status": "ACTIVE",
"entryAmount": 1000.00,
"expectedPayout": 2500.00,
"expectedPayoutAt": "2026-03-03T00:00:00Z",
"autoBoostEnabled": false,
"createdAt": "2026-02-01T00:00:00Z",
"tokens": [
{ "symbol": "BLT", "amount": 333.33, "usdValue": 333.33 },
{ "symbol": "SPRAY", "amount": 333.33, "usdValue": 333.33 },
{ "symbol": "PLAY", "amount": 333.34, "usdValue": 333.34 }
]
}
]
}---
Get User Stats
GET /api/user/statsReturns user statistics and historical performance.
Auth: Session cookie required
Response:
{
"success": true,
"data": {
"totalSprayed": 15000.00,
"totalEarned": 2250.00,
"avgApy": 42.5,
"totalPositions": 12,
"activePositions": 3,
"tasksCompleted": 45,
"raidsParticipated": 23,
"referrals": 8,
"referralEarnings": 120.00
}
}---
Trench Endpoints
List All Trenches
GET /api/trenches/v2Returns all 3 perpetual trenches with full details.
Auth: None (public endpoint)
Rate Limit: 100 req/min
Response:
{
"success": true,
"data": {
"trenches": [
{
"level": "RAPID",
"name": "Rapid Fire",
"description": "24h cycle, high frequency",
"totalReserveUsd": 1500000,
"insuranceBuffer": 150000,
"minThreshold": 300000,
"status": "ACTIVE",
"canSpray": true,
"riskLevel": "low",
"riskIndicators": ["🟢"],
"featuredProjects": [
{ "id": "proj_1", "name": "Token A", "apy": 45.2 }
],
"participantCount": 1250,
"totalSprayed": 5000000,
"avgApy": 45.5,
"duration": "24h",
"entryRange": "$5 - $1,000",
"themeColor": "#10b981"
},
{
"level": "MID",
"name": "Mid Strike",
"description": "7-day lock for balanced returns",
"totalReserveUsd": 2500000,
"insuranceBuffer": 250000,
"minThreshold": 500000,
"status": "ACTIVE",
"canSpray": true,
"riskLevel": "medium",
"riskIndicators": ["🟡"],
"featuredProjects": [
{ "id": "proj_2", "name": "Token B", "apy": 65.8 }
],
"participantCount": 890,
"totalSprayed": 8000000,
"avgApy": 62.3,
"duration": "7d",
"entryRange": "$100 - $10,000",
"themeColor": "#f59e0b"
},
{
"level": "DEEP",
"name": "Deep Vault",
"description": "30-day lock for maximum yield",
"totalReserveUsd": 4000000,
"insuranceBuffer": 400000,
"minThreshold": 800000,
"status": "ACTIVE",
"canSpray": true,
"riskLevel": "high",
"riskIndicators": ["🟠"],
"featuredProjects": [
{ "id": "proj_3", "name": "Token C", "apy": 95.5 }
],
"participantCount": 450,
"totalSprayed": 12000000,
"avgApy": 88.7,
"duration": "30d",
"entryRange": "$1,000 - $100,000",
"themeColor": "#ef4444"
}
],
"platformStats": {
"totalReserveUsd": 8000000,
"totalSprayers": 3200,
"featuredProjectCount": 15,
"avgPlatformApy": 58.2
}
}
}TypeScript Example:
interface Trench {
level: 'RAPID' | 'MID' | 'DEEP';
name: string;
description: string;
totalReserveUsd: number;
insuranceBuffer: number;
status: 'ACTIVE' | 'PAUSED' | 'EMERGENCY';
canSpray: boolean;
riskLevel: string;
avgApy: number;
duration: string;
entryRange: string;
themeColor: string;
}
const getTrenches = async (): Promise<Trench[]> => {
const response = await fetch('/api/trenches/v2');
const { data } = await response.json();
return data.trenches;
};---
Get Trench Details
GET /api/trenches/:idReturns detailed information for a specific trench.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Trench UUID |
---
Get Trench Queue
GET /api/trenches/:id/queueReturns trench queue position data and waiting list information.
---
Spray Endpoints
Create Spray
POST /api/spray/v2Creates a new spray position with 0.5% fee and proportional allocation.
Auth: Session cookie required
Rate Limit: 10 req/min
Request Body:
{
"trenchId": "cuid_rapid_001",
"amount": 1000
}Preview Mode:
{
"trenchId": "cuid_rapid_001",
"amount": 1000,
"action": "preview"
}Response:
{
"success": true,
"data": {
"sprayId": "spray_abc123",
"amount": 1000,
"fee": 5,
"effectiveAmount": 995,
"allocation": [
{ "tokenSymbol": "BLT", "amount": 331.67, "usdValue": 331.67 },
{ "tokenSymbol": "SPRAY", "amount": 331.67, "usdValue": 331.67 },
{ "tokenSymbol": "PLAY", "amount": 331.66, "usdValue": 331.66 }
],
"expectedPayout": 1194,
"payoutDate": "2026-02-17T22:00:00Z",
"insuranceApplied": false,
"trench": {
"level": "RAPID",
"duration": "24h"
}
}
}TypeScript Example:
interface SprayRequest {
trenchId: string;
amount: number;
action?: 'preview' | 'execute';
}
interface SprayResponse {
sprayId: string;
amount: number;
fee: number;
effectiveAmount: number;
allocation: Array<{
tokenSymbol: string;
amount: number;
usdValue: number;
}>;
expectedPayout: number;
payoutDate: string;
}
const createSpray = async (
trenchId: string,
amount: number,
preview: boolean = false
): Promise<SprayResponse> => {
const response = await fetch('/api/spray/v2', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
trenchId,
amount,
action: preview ? 'preview' : 'execute'
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const { data } = await response.json();
return data;
};
// Preview before spraying
const preview = await createSpray('trench_123', 1000, true);
console.log(`Fee: $${preview.fee}, Expected payout: $${preview.expectedPayout}`);
// Execute spray
const spray = await createSpray('trench_123', 1000);
console.log(`Spray created: ${spray.sprayId}`);Error Codes:
| Code | Status | Description |
|---|---|---|
TRENCH_INACTIVE | 400 | Trench is paused or in emergency mode |
MIN_AMOUNT_NOT_MET | 400 | Below minimum spray amount ($50) |
MAX_AMOUNT_EXCEEDED | 400 | Above maximum spray amount for trench |
INSUFFICIENT_BALANCE | 400 | User balance too low |
RATE_LIMITED | 429 | Too many spray requests |
---
Task Endpoints
List Available Tasks
GET /api/tasksReturns available tasks that users can complete for boost points.
Auth: Session cookie required
Rate Limit: 30 req/min
Response:
{
"success": true,
"data": [
{
"id": "task_1",
"title": "Follow on Twitter",
"description": "Follow @playtrenches on Twitter",
"reward": 50,
"taskType": "ONE_TIME",
"category": "SOCIAL",
"link": "https://x.com/spraytrenches",
"order": 1,
"isActive": true,
"maxCompletions": 1,
"currentCompletions": 0
},
{
"id": "task_2",
"title": "Join Discord",
"description": "Join our Discord community",
"reward": 75,
"taskType": "ONE_TIME",
"category": "COMMUNITY",
"link": "https://discord.gg/MQeZDKZWC9",
"order": 2,
"isActive": true
}
]
}---
Complete Task
POST /api/tasks/v2/:id/completeSubmit task completion with proof.
Auth: Session cookie required
Rate Limit: Tier-based with velocity check
Request Body:
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"proofUrl": "https://twitter.com/user/status/123456789"
}Response Headers:
| Header | Description |
|---|---|
X-AntiGaming-RiskScore | 0-100 risk score |
X-AntiGaming-Flags | FLAGGED_FOR_REVIEW if suspicious |
---
Raid Endpoints
List Active Raids
GET /api/raid-centerReturns active raids that users can participate in.
Auth: Session cookie required
Rate Limit: 10 req/min per IP
Response:
{
"success": true,
"data": [
{
"id": "raid_1",
"projectId": "proj_123",
"projectName": "Token Launch",
"actionType": "LIKE",
"platform": "TWITTER",
"reward": 100,
"maxParticipants": 500,
"currentParticipants": 234,
"deadline": "2026-02-17T00:00:00Z",
"status": "ACTIVE"
}
]
}---
Execute Raid
POST /api/raid-centerExecute a raid action.
Auth: Session cookie required
Rate Limit: Tier-based with velocity check
Request Body:
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"raidCenterId": "raid_1",
"actionType": "LIKE",
"proofUrl": "https://twitter.com/user/status/123456789"
}---
Waiting List Endpoints
Join Waiting List
POST /api/waiting-listJoin a project waiting list.
Auth: Session cookie required
Rate Limit: 1 req/min per user
Request Body:
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"waitingListId": "wl_abc123"
}---
Jump Queue Position
POST /api/waiting-list/jumpJump queue position using completed tasks.
Auth: Session cookie required
Rate Limit: 1 req/min per user
Request Body:
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"waitingListId": "wl_abc123",
"taskId": "task_1"
}---
Secure Spot
POST /api/waiting-list/secureSecure a spot with deposit verification.
Auth: Session cookie required
Rate Limit: 1 req/min per user
Security: On-chain verification required
Request Body:
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"waitingListId": "wl_abc123",
"txHash": "5VERq8X7KYP6HQ...",
"expectedAmount": 10
}---
Project Onboarding
Submit Application
POST /api/projects/applySelf-service project onboarding.
Rate Limit: 1 req/min (IP-based)
Request Body:
{
"name": "My Token Project",
"tokenSymbol": "MTP",
"chainId": 1,
"contractAddress": "0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E",
"promisedApy": 45.5,
"initialReserve": 5000,
"contactEmail": "admin@project.com",
"website": "https://myproject.com",
"description": "A revolutionary DeFi protocol"
}---
Get Onboarding Config
GET /api/projects/applyReturns supported chains, min/max reserves, and constraints.
Response:
{
"success": true,
"data": {
"supportedChains": [
{ "id": 1, "name": "Ethereum", "currency": "ETH" },
{ "id": 56, "name": "BSC", "currency": "BNB" },
{ "id": 137, "name": "Polygon", "currency": "MATIC" },
{ "id": 8453, "name": "Base", "currency": "ETH" }
],
"minReserve": 5000,
"maxReserve": 1000000,
"minApy": 10,
"maxApy": 200
}
}---
System Endpoints
Health Check
GET /api/healthSystem health check. No authentication required.
Response:
{
"overall": "healthy",
"timestamp": "2026-02-16T15:30:00Z",
"uptime": 302400,
"version": "abc1234",
"environment": "production",
"checks": {
"database": {
"status": "connected",
"latency": 15
},
"redis": {
"status": "connected",
"latency": 45
},
"rpc": {
"status": "healthy",
"chains": ["ethereum", "solana", "base"]
}
}
}---
Get Metrics
GET /api/metricsPerformance metrics (requires API key).
Headers: Authorization: Bearer API_KEY
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
window | number | 5 | Time window in minutes |
raw | boolean | false | Include raw data |
limit | number | 100 | Limit for raw data |
Response:
{
"success": true,
"data": {
"requests": {
"total": 15420,
"successful": 15280,
"failed": 140,
"avgLatency": 45
},
"errors": {
"rateLimited": 89,
"unauthorized": 32,
"serverError": 19
}
}
}---
Real-Time Updates (SSE)
Server-Sent Events
GET /api/sse?userId=USER_IDReal-time updates stream for live data.
Auth: Session cookie recommended
Event Types:
| Type | Description | Payload |
|---|---|---|
PRICE_UPDATE | Token price updates | { token, price, change24h } |
TRENCH_UPDATE | Trench status changes | { trenchId, status, stats } |
PAYOUT_COMPLETED | Payout notifications | { positionId, amount, txHash } |
POSITION_UPDATE | Position changes | { positionId, status, value } |
JavaScript Example:
const connectToSSE = (userId: string) => {
const eventSource = new EventSource(`/api/sse?userId=${userId}`);
eventSource.addEventListener('PRICE_UPDATE', (event) => {
const data = JSON.parse(event.data);
updatePriceDisplay(data);
});
eventSource.addEventListener('PAYOUT_COMPLETED', (event) => {
const data = JSON.parse(event.data);
showNotification(`Payout received: $${data.amount}`);
});
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
// Reconnect after delay
setTimeout(() => connectToSSE(userId), 5000);
};
return () => eventSource.close();
};---
Error Codes Reference
HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 409 | Conflict (duplicate) |
| 429 | Rate Limited |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
Application Error Codes
| Code | Description |
|---|---|
TRENCH_INACTIVE | Trench is paused or emergency mode |
MIN_AMOUNT_NOT_MET | Below minimum spray amount |
MAX_AMOUNT_EXCEEDED | Above maximum spray amount |
INSUFFICIENT_BALANCE | User balance too low |
RATE_LIMITED | Too many requests |
INVALID_PROOF | Task proof validation failed |
ALREADY_COMPLETED | Task already completed |
WAITING_LIST_FULL | No spots available |
DEPOSIT_NOT_FOUND | Transaction not found on-chain |
REORG_DETECTED | Blockchain reorg detected |
INVALID_SIGNATURE | Webhook signature invalid |
SESSION_EXPIRED | User session has expired |
---
Rate Limits Summary
Public API
| Endpoint | Limit |
|---|---|
/api/trenches/* | 100 req/min |
/api/spray/* | 10 req/min |
/api/user/* | 60 req/min |
/api/waiting-list | 1 req/min |
/api/waiting-list/jump | 1 req/min |
/api/waiting-list/secure | 1 req/min |
/api/tasks/* | 30 req/min |
/api/raid-center | 10 req/min (GET), Tier-based (POST) |
/api/deposits/* | 20 req/min |
---
> 📢 Important Note
>
> All payouts are now fully automated. Legacy manual
> claiming endpoints have been removed. Users receive payouts directly to their registered wallets.