OracleDesk is an AI-powered prediction market backend built with:
- Node.js
- Express.js
- TypeScript
- Prisma ORM
- PostgreSQL
- Circle Wallets API
- Arc Testnet
- Redis
- JWT Authentication
- IPFS (Pinata)
- Gemini AI
The backend powers:
- AI-generated prediction markets
- Reasoning traces
- Copy trading
- Portfolio analytics
- Oracle market resolution
- Subscription/paywall system
- USDC micropayments
- Circle wallet integration
https://oracledesk-backend.onrender.com/api/v1Local:
http://localhost:8000/api/v1All API responses follow the same structure.
{
"ok": true,
"data": {},
"error": null,
"meta": {}
}{
"ok": false,
"data": null,
"error": {
"code": "ERROR_CODE",
"message": "Human readable message",
"details": {}
}
}OracleDesk uses JWT Bearer authentication.
Authorization: Bearer <JWT_TOKEN>POST /auth/connectAuthenticates a wallet and returns a JWT token.
Content-Type: application/json{
"walletAddress": "0x123..."
}{
"ok": true,
"data": {
"token": "jwt_token",
"user": {
"id": "uuid",
"walletAddress": "0x123..."
}
},
"error": null
}{
"ok": false,
"data": null,
"error": {
"code": "INVALID_WALLET",
"message": "Wallet address is required"
}
}Base Route:
/api/v1/marketsGET /marketsReturns paginated prediction markets.
| Param | Type | Required | Description |
|---|---|---|---|
| page | number | No | Default: 1 |
| limit | number | No | Default: 20 |
| status | string | No | Market status |
| category | string | No | Market category |
| currency | string | No | USDC or EURC |
PENDING
ACTIVE
RESOLVING
RESOLVED
CANCELLEDFED
ECB
ELECTION
GEOPOLITICAL
CRYPTO
MACRO
SPORTS
ENTERTAINMENT
POLITICSUSDC
EURC{
"ok": true,
"data": [
{
"id": "uuid",
"question": "Will BTC hit $150k before Dec 2026?",
"category": "CRYPTO",
"status": "ACTIVE",
"settlementCurrency": "USDC",
"yesPrice": 0.67,
"noPrice": 0.33,
"expiryTimestamp": "2026-12-01T00:00:00.000Z"
}
],
"error": null,
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}GET /markets/:id{
"ok": true,
"data": {
"id": "uuid",
"question": "Will BTC hit $150k before Dec 2026?",
"category": "CRYPTO",
"status": "ACTIVE",
"description": "AI generated market...",
"expiryTimestamp": "2026-12-01T00:00:00.000Z"
},
"error": null
}POST /markets/generateRequired
Authorization: Bearer <token>
Content-Type: application/jsonTriggers AI market generation job.
{
"ok": true,
"data": {
"jobId": "uuid",
"status": "RUNNING"
},
"error": null
}GET /markets/generation-status/:jobIdRequired
{
"ok": true,
"data": {
"status": "COMPLETED",
"marketId": "uuid",
"question": "Will ETH ETF be approved?",
"category": "CRYPTO"
},
"error": null
}Base Route:
/api/v1/portfolioGET /portfolioReturns overall AI trading portfolio statistics.
{
"ok": true,
"data": {
"totalUsdc": 10000,
"deployedCapital": 2300,
"availableCapital": 7700,
"openPositions": 7,
"totalPnl": 320,
"dailyPnl": 22,
"builderFeesEarned": 14,
"correlationRisk": {
"hasCorrelatedPositions": false,
"correlatedPairs": []
}
},
"error": null
}GET /portfolio/positions| Param | Type | Description |
|---|---|---|
| page | number | Pagination |
| limit | number | Pagination |
| status | string | OPEN, CLOSED, STOP_LOSS, HEDGED |
{
"ok": true,
"data": [
{
"id": "uuid",
"status": "OPEN",
"size": 100,
"pnl": 12,
"market": {
"question": "Will Fed cut rates?",
"category": "FED"
},
"trade": {
"direction": "YES",
"amount": 100,
"edgeDetected": 0.12
}
}
],
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}Base Route:
/api/v1/tracesGET /traces| Param | Type |
|---|---|
| page | number |
| limit | number |
| agentType | string |
{
"ok": true,
"data": [
{
"id": "uuid",
"agentType": "TRADER",
"decisionType": "BUY_YES",
"edge": 0.12,
"probabilityEstimate": 0.74,
"marketProbability": 0.61,
"confidenceInterval": {
"lower": 0.69,
"upper": 0.79
},
"previewSources": [],
"verified": true,
"ipfsCid": "Qm..."
}
]
}GET /traces/:id| Access | Description |
|---|---|
| FREE_PREVIEW | Only preview sources |
| PER_TRACE | Full access |
| DAILY_PASS | Full access |
{
"ok": true,
"data": {
"id": "uuid",
"sourcesUsed": [],
"accessLevel": "FREE_PREVIEW",
"lockedFields": [
"fullSources",
"hedgeConditions",
"betFraction"
],
"unlockPrice": 0.005,
"dailyPassPrice": 0.5
}
}{
"ok": true,
"data": {
"id": "uuid",
"sourcesUsed": [],
"hedgeConditions": [],
"betFraction": 0.04,
"accessLevel": "PER_TRACE"
}
}POST /traces/verifyRequired
{
"traceId": "uuid"
}{
"ok": true,
"data": {
"traceId": "uuid",
"ipfsCid": "Qm...",
"storedHash": "abc",
"computedHash": "abc",
"verified": true,
"verifiedAt": "2026-05-20T12:00:00.000Z"
}
}POST /traces/:id/unlockRequired
{
"txHash": "0xabc...",
"amount": 0.005,
"type": "PER_TRACE"
}PER_TRACE
DAILY_PASS{
"ok": true,
"data": {
"subscription": {},
"trace": {}
}
}GET /traces/access/allowanceRequired
{
"ok": true,
"data": {
"dailyLimit": 10,
"perTraceLimit": 1,
"currency": "USDC",
"spentToday": 0,
"isActive": true
}
}If user has never configured spending allowance:
{
"ok": true,
"data": null,
"error": null
}PUT /traces/access/allowanceRequired
{
"dailyLimit": 10,
"perTraceLimit": 1,
"currency": "USDC"
}GET /traces/paymentsRequired
{
"ok": true,
"data": [
{
"txHash": "0xabc...",
"type": "PER_TRACE",
"amount": 0.005,
"currency": "USDC",
"status": "CONFIRMED"
}
]
}Base Route:
/api/v1/tradePOST /trade/copyRequired
{
"traceId": "uuid",
"marketId": "uuid",
"amount": 100,
"userWallet": "0x..."
}{
"ok": true,
"data": {
"tradeId": "uuid",
"status": "PENDING"
}
}PATCH /trade/copy/:id/confirmRequired
{
"ok": true,
"data": {
"id": "uuid",
"status": "EXECUTED",
"txHash": "0xabc..."
}
}Base Route:
/api/v1/oracleGET /oracle/markets/:marketId/resolution{
"ok": true,
"data": {
"id": "uuid",
"status": "RESOLVING",
"resolvedOutcome": true,
"resolvedAt": null,
"agentLogs": []
}
}POST /oracle/resolveRequired
{
"marketId": "uuid",
"yesWon": true,
"rationale": "Official Fed announcement"
}{
"ok": true,
"data": {
"market": {},
"txHash": "0xabc..."
}
}POST /webhooks/circlex-circle-signature
x-circle-key-idHandles Circle transaction confirmations and payment reconciliation.
| Code | Description |
|---|---|
| UNAUTHORIZED | Missing auth |
| INVALID_TOKEN | Invalid JWT |
| TOKEN_EXPIRED | JWT expired |
| Code | Description |
|---|---|
| MARKET_NOT_FOUND | Market missing |
| MARKET_NOT_DEPLOYED | No chain address |
| MARKET_NOT_RESOLVABLE | Invalid state |
| Code | Description |
|---|---|
| TRACE_NOT_FOUND | Missing trace |
| MISSING_TRACE_ID | traceId required |
| PAYMENT_UNVERIFIED | Circle tx invalid |
| Code | Description |
|---|---|
| ALLOWANCE_DAILY_LIMIT | Daily limit exceeded |
| ALLOWANCE_PER_TRACE_LIMIT | Per trace limit exceeded |
| INVALID_ALLOWANCE | Invalid limits |
All paginated endpoints return:
{
"meta": {
"page": 1,
"limit": 20,
"total": 120,
"totalPages": 6
}
}Private key of the autonomous OracleDesk AI trading wallet.
Used for:
- automated trades
- market making
- resolution execution
- treasury operations
Example:
AGENT_PRIVATE_KEY=0xabc123...Generate from:
- MetaMask
- Rabby
- Foundry wallet
- Hardhat wallet
Public wallet address derived from AGENT_PRIVATE_KEY.
Example:
AGENT_WALLET_ADDRESS=0x742d35Cc6634C0532925a3b844Bc454e4438f44eThe Circle-controlled wallet used for:
- contract execution
- USDC payments
- treasury transfers
Example:
CIRCLE_WALLET_ADDRESS=0xabc123...You get this from:
- Circle Developer Console
- Create Wallet
- Copy wallet address
ok === falsedata === null- pagination meta
- expired JWTs
- subscription states
- React
- Next.js
- React Query / TanStack Query
- Axios
- Zustand
- Wagmi
- RainbowKit
- Viem
src/
├── api/
│ ├── auth.ts
│ ├── markets.ts
│ ├── traces.ts
│ ├── portfolio.ts
│ ├── oracle.ts
│ └── trade.ts- User opens trace preview
- Frontend shows locked fields
- User pays USDC
- Frontend gets txHash
- Call unlock endpoint
- Backend verifies payment
- Backend returns full trace
- Call
/markets/generate - Receive
jobId - Poll
/markets/generation-status/:jobId - Stop polling when:
- COMPLETED
- FAILED
Frontend should NEVER expose:
- Circle API keys
- JWT secret
- Agent private key
- Pinata secret
- Database URL
Before production deployment:
- enable strict Circle verification
- rotate JWT secret
- enable HTTPS
- add rate limiting
- add Redis queue workers
- add websocket streaming
- enable monitoring/logging