
EVE FINANCE
Eve Broker API Reference
Complete developer documentation for the Eve Broker API
The Eve Broker API lets you build a complete trading platform for end users in the capacity of a broker-dealer.
| Capability | You | Eve |
|---|---|---|
| 🎨 Frontend Experience | UI / UX / App / Web | — |
| 📝 Customer Onboarding | Collect & submit KYC | Review |
| 💰 Fund Custody | — | SIPC protection ($500K) |
| 📈 Order Routing | — | Multi-venue routing |
| 📜 Regulatory Compliance | — | FINRA member |
| 🧾 Clearing & Settlement | — | Apex Clearing |
| 📊 Reporting | — | Auto statements / confirms |
Three Partnership Models
| Model | Account Structure | Use Case |
|---|---|---|
| Fully-Disclosed | Individual account per customer | Standard broker app |
| Omnibus | One master account, you keep internal books | High-frequency / institutional |
| RIA | Registered Investment Advisor | Advisory services |
Endpoint Matrix
| Environment | Broker API | Market Data | Auth |
|---|---|---|---|
| Live | broker-api.eve.markets | data.eve.markets | authx.eve.markets |
| Sandbox | broker-api.sandbox.eve.markets | data.sandbox.eve.markets | authx.sandbox.eve.markets |
Client Credentials (Recommended)
Step 1: Obtain an access token (valid for 15 minutes)
Bash
curl -X POST "https://authx.sandbox.eve.markets/v1/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"Response
{"access_token": "eyJ...", "expires_in": 899, "token_type": "Bearer"}Step 2: Include the token in all requests
curl -H "Authorization: Bearer eyJ..." \
"https://broker-api.sandbox.eve.markets/v1/accounts"Reuse tokens: Do not re-request within 15 minutes. Supports both client_secret_post and private_key_jwt (RFC 7523).
Legacy Authentication
curl -H "APCA-API-KEY-ID: xxx" \
-H "APCA-API-SECRET-KEY: xxx" \
"https://api.eve.markets/v2/account"Idempotency
Creation requests support the Idempotency-Key header:
- Same key + same body → returns existing result (no duplication)
- Same key + different body → 422 error
- Recommended format: UUID
Complete Flow
↓
Onfido identity verification → Upload result → CIP submission
↓
NEW → SUBMITTED → PENDING → APPROVED → ACTIVE
Core API Endpoints
| Operation | Endpoint | Description |
|---|---|---|
| Create account | POST /v1/accounts | Submit contact + identity + disclosures |
| List accounts | GET /v1/accounts | Max 1000, paginate by created_after/before |
| Get account | GET /v1/accounts/{id} | Includes documents attribute |
| Update account | PATCH /v1/accounts/{id} | Modify information |
| Close account | POST /v1/accounts/{id}/actions/close | Must liquidate & withdraw first |
| Upload document | POST /v1/accounts/{id}/documents/upload | PDF/JPG/PNG |
| Get CIP | GET /v1/accounts/{id}/cip | Customer Identification Program |
| Submit CIP | POST /v1/accounts/{id}/cip | Submit KYC verification result |
| Onfido token | GET /v1/accounts/{id}/onfido-sdk-tokens | Get SDK token |
| Onfido result | PATCH /v1/accounts/{id}/onfido-sdk | Upload SDK verification result |
Account Creation Request Body (Fully-Disclosed)
JSON
{
"contact": {
"email_address": "john@example.com",
"phone_number": "7065912538",
"street_address": ["20 S Craig Ave"],
"city": "San Mateo",
"state": "CA",
"postal_code": "33345"
},
"identity": {
"given_name": "John",
"family_name": "Doe",
"date_of_birth": "1990-01-01",
"tax_id_type": "USA_SSN",
"tax_id": "661010666",
"country_of_citizenship": "USA",
"country_of_birth": "USA",
"country_of_tax_residence": "USA",
"funding_source": ["employment_income"],
"annual_income_min": "50000",
"annual_income_max": "100000",
"total_net_worth_min": "100000",
"total_net_worth_max": "500000",
"liquid_net_worth_min": "50000",
"liquid_net_worth_max": "250000",
"liquidity_needs": "does_not_apply",
"investment_experience": "limited",
"risk_tolerance": "moderate",
"investment_objective": "growth",
"employment_status": "employed",
"employer_name": "Acme Corp",
"visa_type": "not_applicable"
},
"disclosures": {
"is_control_person": false,
"is_affiliated_exchange_or_finra": false,
"is_politically_exposed": false,
"is_immediate_family_exposed": false,
"employment_status": "employed"
},
"agreements": [
{
"agreement": "customer_agreement",
"signed_at": "2024-01-01T00:00:00Z",
"ip_address": "127.0.0.1"
},
{
"agreement": "options_agreement",
"signed_at": "2024-01-01T00:00:00Z",
"ip_address": "127.0.0.1"
}
],
"trusted_contact": {
"given_name": "Jane",
"family_name": "Doe",
"email_address": "jane@example.com"
}
}Multi-Account (MLA)
Existing users can open sub-accounts by passing primary_account_holder_id:
JSON
{
"primary_account_holder_id": "existing-account-uuid",
"account_type": "ira",
"minor_type": "traditional_ira"
}Onfido Identity Verification
- Get SDK Token:
GET /v1/accounts/{id}/onfido-sdk-tokens→{"sdk_token": "..."} - Frontend uses token to launch Onfido SDK (user selfie + ID scan)
- After verification, upload result:
PATCH /v1/accounts/{id}/onfido-sdk(Onfido callback auto-notifies Eve)
CIP Minimum Required Fields
POST /v1/accounts/{'{id}'}/cip
{
"tax_id_type": "USA_SSN",
"tax_id": "661010666",
"date_of_birth": "1990-01-01"
}File Upload
Supports PDF, JPG, PNG:
curl -X POST "https://broker-api.sandbox.eve.markets/v1/accounts/{id}/documents/upload" \
-H "Authorization: Bearer ..." \
-F "file=@driver_license.jpg" \
-F "document_type=id_card" \
-F "document_sub_type=drivers_license"Who is Responsible for KYC?
KYC responsibility differs based on your partnership model:
| Model | KYC Owner | Post-Onboarding Status |
|---|---|---|
| Trading App / RIA | Eve | SUBMITTED → Eve auto-review |
| Fully-Disclosed Broker | You | APPROVED (directly after your review) |
| Omnibus | No individual onboarding | — |
Model 1: Trading App / RIA — Eve Reviews
You collect info → Eve reviews → You wait for results
├─ contact (contact info)
├─ identity (identity + financial info)
├─ disclosures (compliance declarations)
└─ agreements (signed agreements)
② Account → SUBMITTED → Eve auto KYC
├─ Blacklist screening
├─ SSN verification
├─ Address verification
└─ OFAC / sanctions list check
③ Result (SSE push):
├─ APPROVED → ACTIVE ✅
├─ APPROVAL_PENDING → Eve manual review ⏳
├─ ACTION_REQUIRED → supplementary docs 📎
└─ REJECTED ❌
Upload Supplementary Documents
curl -X POST "https://broker-api.sandbox.eve.markets/v1/accounts/{id}/documents/upload" \
-H "Authorization: Bearer ***" \
-F "file=@utility_bill.pdf" \
-F "document_type=proof_of_address" \
-F "document_sub_type=utility_bill"Common ACTION_REQUIRED reasons:
- Address unverified → Upload utility bill / bank statement
- Identity unconfirmed → Upload driver's license / passport
- SSN mismatch → Upload SSN card
Model 2: Fully-Disclosed Broker — You Review
You complete KYC yourself → Tell Eve the result → Immediate account opening
- You perform your own KYC (using your vendor: Jumio / Plaid IDV / LexisNexis etc.)
POST /v1/accounts→ status directlyAPPROVED(since you already verified)- Eve only runs blacklist screening (match → REJECTED / APPROVAL_PENDING)
POST /v1/accounts/{id}/cip← Submit your KYC result
CIP Minimum Required Fields (FINRA)
| Field | Description |
|---|---|
| Name | Full name |
| Date of Birth | Date of birth |
| Address | Residential address |
| Tax ID (SSN/TIN) | Taxpayer identification number |
Onfido Identity Verification Flow (Recommended for Trading App)
① User fills form
② POST /v1/accounts
③ GET /v1/accounts/{id}/onfido-sdk-tokens → returns sdk_token
④ Return sdk_token to frontend
⑤ Launch Onfido SDK — user photo + selfie, Onfido auto-verifies
⑥ Verification complete (callback)
⑦ PATCH /v1/accounts/{id}/onfido-sdk
⑧ Eve receives result, continues KYC review
Key Implementation Points
1. Get SDK Token:
GET /v1/accounts/{account_id}/onfido-sdk-tokens
→ {"sdk_token": "eyJ..."}2. Frontend Integration (onfido-sdk-ui npm package):
JavaScript
import { Onfido } from 'onfido-sdk-ui';
Onfido.init({
token: sdkToken,
containerId: 'onfido-mount',
onComplete: (data) => {
fetch('/api/onfido-result', {
method: 'PATCH',
body: JSON.stringify({ account_id, result: data })
});
}
});3. Upload Onfido Result:
PATCH /v1/accounts/{account_id}/onfido-sdk
# Body can be empty (Onfido auto-notifies Eve)International Clients — W-8BEN
Non-US tax residents (W-9 not applicable) must submit W-8BEN:
POST /v1/accounts/{id}/documents/upload \
-F "file=@w8ben.pdf" \
-F "document_type=w8ben"W-8BEN must be renewed every 3 years (signing year + 3 years).
KYC Status Enumeration
| Status | Meaning | Your Action |
|---|---|---|
| ONBOARDING | Just created, KYC not started | Wait or trigger Onfido |
| SUBMITTED | Submitted for review | Wait for Eve |
| APPROVAL_PENDING | KYC not auto-passed, manual review | Wait |
| ACTION_REQUIRED | Supplementary materials needed | Upload documents |
| APPROVED | Approved | Can deposit & trade |
| ACTIVE | Activated | All features available |
| REJECTED | Rejected | Contact user / Eve |
| SUBMISSION_FAILED | System failure | Eve auto-handles |
Practical Minimal KYC Pipeline
Python (pseudocode)
class EveKYC:
def onboard(self, user_data):
# 1. Create account
account = self.api.post('/v1/accounts', {
'contact': user_data.contact,
'identity': {
'given_name': user_data.first_name,
'family_name': user_data.last_name,
'date_of_birth': user_data.dob, # "1990-01-01"
'tax_id_type': 'USA_SSN',
'tax_id': user_data.ssn, # "661010666"
'funding_source': ['employment_income'],
'annual_income_min': user_data.income_range,
},
'disclosures': {},
'agreements': [
{'agreement': 'customer_agreement', 'signed_at': now, 'ip_address': user_ip}
]
})
account_id = account['id']
# 2. Trigger Onfido
sdk_token = self.api.get(f'/v1/accounts/{account_id}/onfido-sdk-tokens')
return account_id, sdk_token['sdk_token']
def on_onfido_complete(self, account_id):
# 3. Notify Eve after Onfido completes
self.api.patch(f'/v1/accounts/{account_id}/onfido-sdk')
# 4. If Fully-Disclosed, submit CIP
self.api.post(f'/v1/accounts/{account_id}/cip', {
'tax_id_type': 'USA_SSN',
'tax_id': ssn,
'date_of_birth': dob
})
def check_status(self, account_id):
# 5. Poll or listen via SSE for status changes
acct = self.api.get(f'/v1/accounts/{account_id}')
return acct['status'] # SUBMITTED / ACTION_REQUIRED / APPROVED / ACTIVEKey Pitfalls
Strict SSN format validation — do not submit numbers like 123456789 that look like test data.
approved_level and margin_multiplier — cannot be set at onboarding; only via PATCH after account is ACTIVATED.
W-8BEN date format — the form uses MM-DD-YYYY, but API submission must use YYYY-MM-DD.
Onfido token in memory only — do not persist; discard after use.
SSE events may duplicate — deduplicate using the at field.
Production rate limits — do not send concurrent onboarding request bursts.
| Status | Meaning | Actions Available |
|---|---|---|
| NEW | Just submitted | Edit, upload documents |
| SUBMITTED | Submitted for review | Wait |
| PENDING | Under review | — |
| ACTION_REQUIRED | Supplementary materials needed | Upload docs / Onfido |
| APPROVED | Approved | Deposit, trade |
| ACTIVE | Activated | All |
| DISABLED | Disabled | Contact Eve |
| CLOSED | Closed | Irreversible |
| REJECTED | Rejected | Contact Eve |
| SUSPENDED | Suspended | Contact Eve |
Status Flow
↓ ↓ ↓ ↓
REJECTED ACTION_ CLOSED DISABLED / SUSPENDED
REQUIRED
↓
APPROVED
Account Attributes
| Attribute | Description |
|---|---|
| account_type | trading / ira |
| minor_type | traditional_ira / roth_ira / sep_ira |
| margin | Margin account enabled |
| options_approved_level | 0 - 4 |
| crypto_status | Crypto trading enabled |
| currency | USD / multi-currency (LCT) |
| system_day_trades_left | Remaining day trades |
All data must pass FINRA CAIS validation, otherwise a 422 is returned.
Name / Address Romanization
given_name, family_name, street_address, city, state etc. must be in ASCII range 32-126. To preserve the original script, use local_* fields (e.g. local_given_name).
SSN Validation Rules
661010666(9 digits)000123456(Area Number cannot be 000)666123456(Area Number cannot be 666)123004567(Group Number cannot be 00)1234560000(Serial Number cannot be 0000)111111111(cannot be all same digits)123456789(cannot be sequential ascending)987654321(cannot be sequential descending)Funding Source Verification
JSON
"funding_source": ["employment_income"] // at least one required
"annual_income_min": "50000_99999" // annual income rangeAge Restriction
Must be ≥ 18 years old.
funding_source Options
Financial Range Enumerations
| Range | Enum Value |
|---|---|
| < $10K | 0_9999 |
| $10K - $25K | 10000_24999 |
| $25K - $50K | 25000_49999 |
| $50K - $100K | 50000_99999 |
| $100K - $250K | 100000_249999 |
| $250K - $500K | 250000_499999 |
| > $500K | 500000_up |
Agreement Types
Fund Flow
Wire Transfer → ↑
Instant Funding → ↑
Journals → ↑
7.1 Sandbox Testing
In sandbox, all transfers are instant:
POST /v1/accounts/{'{id}'}/transfers
{
"transfer_type": "ach",
"relationship_id": "rel-uuid",
"direction": "INCOMING",
"amount": "5000.00"
}→ Account immediately available
7.2 ACH Deposits & Withdrawals
Step 1: Plaid Link — user authorizes in-app → obtain processor_token
Step 2: Create ACH Relationship
POST /v1/accounts/{'{id}'}/ach-relationships
{
"processor_token": "plaid-processor-token",
"account_owner_name": "John Doe"
}Status: PENDING → APPROVED
Step 3: Initiate Transfer
POST /v1/accounts/{'{id}'}/transfers
{
"transfer_type": "ach",
"relationship_id": "rel-uuid",
"direction": "INCOMING",
"amount": "1000.00"
}Status: QUEUED → APPROVED → PROCESSING → COMPLETE
7.3 Wire Transfers
First create a bank object:
POST /v1/accounts/{'{id}'}/recipient-banks
{
"name": "Chase",
"bank_code_type": "ABA",
"bank_code": "021000021",
"account_number": "123456789"
}Then transfer:
POST /v1/accounts/{'{id}'}/transfers
{
"transfer_type": "wire",
"bank_id": "bank-uuid",
"direction": "OUTGOING",
"amount": "5000.00",
"fee_payment_method": "user"
}Incoming wires require FFC instructions: FFC: {correspondent_name} {account_number}
7.4 International Wire (SWIFT)
POST /v1/accounts/{'{id}'}/recipient-banks
{
"name": "HSBC Hong Kong",
"bank_code_type": "SWIFT",
"bank_code": "HSBCHKHH",
"account_number": "000123456",
"bank_country_code": "HKG",
"bank_city": "Hong Kong",
"international_bank_name": "HSBC"
}7.5 Journals
Internal transfers between accounts:
POST /v1/journals
{
"from_account": "account-id-A",
"to_account": "account-id-B",
"entry_type": "JNLC",
"amount": "1000.00"
}entry_type: JNLC (cash) or JNLS (security)
Order Submission
POST /v2/orders
{
"symbol": "AAPL",
"qty": 1,
"side": "buy",
"type": "market",
"time_in_force": "day",
"client_order_id": "my-order-001"
}Order Types
| Type | Description |
|---|---|
| market | Execute at best available price |
| limit | Execute at specified price or better |
| stop | Stop order (triggers market order) |
| stop_limit | Stop-limit order |
| trailing_stop | Trailing stop order |
Time in Force (TIF)
Order Lifecycle
↓ ↓
rejected canceled
↓
expired
Position Management
GET /v2/positions # List all positions
GET /v2/positions/{symbol} # Get specific position
DELETE /v2/positions/{symbol} # Close positionMarket Data
GET /v2/stocks/{symbol}/quotes/latest # Latest quote
GET /v2/stocks/{symbol}/bars # Historical bars
GET /v2/stocks/{symbol}/trades/latest # Latest tradesServer-Sent Events stream real-time updates for account status changes, trade executions, and transfers.
JavaScript
const eventSource = new EventSource(
'https://broker-api.sandbox.eve.markets/v1/events?token=YOUR_TOKEN'
);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Event:', data);
// Deduplicate using data.at field
};Event Types
| Event | Description |
|---|---|
| accounts.updated | Account status changed |
| trades.executed | Order filled |
| transfers.completed | Transfer completed |
| journals.processed | Journal processed |
| non_trading_day | Market holiday notification |
SSE events may duplicate — always deduplicate using the at timestamp field.
Automated portfolio rebalancing lets you define target allocations and execute trades to maintain them.
POST /v1/rebalancing/runs
{
"account_id": "account-uuid",
"portfolio_type": "predefined",
"portfolio_name": "Tech Focus",
"allocation": {
"AAPL": 0.40,
"MSFT": 0.30,
"GOOGL": 0.30
}
}The API calculates required trades and executes them automatically.
Participate in Initial Public Offerings for eligible accounts.
POST /v1/ipo/subscriptions
{
"account_id": "account-uuid",
"ipo_id": "ipo-uuid",
"shares": 100,
"price_limit": "50.00"
}Status flow: PENDING → ALLOCATED → CONFIRMED
Trade Treasury bonds, corporate bonds, and other fixed-income securities.
GET /v1/treasuries # List available treasuries
POST /v1/orders # Submit bond order with CUSIPDaily reconciliation processes run at market close to ensure consistency between Eve and Apex Clearing.
- Position reconciliation
- Cash balance reconciliation
- Trade settlement confirmation
- Corporate action processing
- Monthly statements auto-generated
GET /v1/account/portfolio/{account_id} # End-of-day snapshot
GET /v1/statements # List statementsEve supports extended-hours trading for 5 days a week, enabling pre-market and after-hours order execution.
Pre-Market
4:00 - 9:30 AM ET
Regular Hours
9:30 AM - 4:00 PM ET
After Hours
4:00 - 8:00 PM ET
Managed (custody) accounts allow advisors to trade on behalf of clients.
POST /v1/accounts
{
"account_type": "trading",
"managed": true,
"manager_id": "advisor-uuid"
}Automated Customer Account Transfer (ACAT) for moving assets between brokerages.
POST /v1/acat/transfers
{
"account_id": "account-uuid",
"transfer_type": "FULL",
"contra_broker": "DTC#",
"contra_account_number": "12345678"
}Status: PENDING → IN_PROGRESS → COMPLETED
Step-by-Step Integration
- Register — Contact Eve to obtain
client_idandclient_secret - Sandbox testing — Use sandbox environment for all development
- Implement OAuth2 — Client Credentials flow, cache tokens for 15 min
- Build onboarding flow — Account creation + KYC + Onfido
- Integrate Plaid — Bank linking for ACH transfers
- Implement SSE listener — Real-time event handling
- Go live — Switch endpoints to production, test with small amounts
Recommended Tech Stack
Backend
Node.js / Python / Go
Frontend
React / Vue / Angular
KYC Vendor
Onfido / Jumio / Plaid IDV
Bank Linking
Plaid
Q: How long do access tokens last?
A: 15 minutes. Cache and reuse until expiry.
Q: What is the difference between the three partnership models?
A: Fully-Disclosed = individual accounts per customer; Omnibus = one master account with your internal books; RIA = for registered investment advisors.
Q: Who handles KYC?
A: In Trading App / RIA mode, Eve handles KYC. In Fully-Disclosed mode, you handle KYC and submit results via CIP endpoint.
Q: How do I handle ACTION_REQUIRED status?
A: Upload the requested supplementary documents (utility bill, ID, SSN card) via the document upload endpoint.
Q: Are transfers instant in production?
A: No — only in sandbox. In production, ACH transfers take 1-3 business days; wires are typically same-day.
Q: How often must W-8BEN be renewed?
A: Every 3 years (signing year + 3 years).
© 2004 EVE FINANCE. All rights reserved. Eve Broker API Documentation.