Partner API Overview

Authentication, rate limits, response formats, and error handling.

Authentication

All write endpoints and position queries require an API key in the x-api-key header:

curl https://api.lavarage.xyz/api/v1/positions \
  -H "x-api-key: lava_live_abc123..."

To get an API key, email [email protected] or generate one via the Partners API:

curl -X POST https://api.lavarage.xyz/api/v1/partners/keys \
  -H "Authorization: Bearer ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"label": "my-integration"}'

Public endpoints (offers, tokens, health) do not require authentication.

Rate Limits

Endpoint GroupLimit
Transaction endpoints (open, close, split, merge)600 requests / 60s
Read endpoints (positions, offers, tokens)1800 requests / 60s
Public endpoints (no auth)30 requests / 60s per IP

Exceeding the limit returns HTTP 429 with code RATE_LIMIT_EXCEEDED. Implement exponential backoff starting at 1s.

Response Format

Transaction-building endpoints return a transaction field (base58-encoded unsigned VersionedTransaction) plus endpoint-specific fields:

EndpointResponse shape
POST /positions/open{ transaction, positionAddress, lastValidBlockHeight, quote }
POST /positions/open-by-token{ transaction, positionAddress, lastValidBlockHeight, quote }
POST /positions/close{ transaction, lastValidBlockHeight, quote }
POST /positions/split{ transaction, lastValidBlockHeight, newPositionAddresses }
POST /positions/partial-sell{ splitTransaction, closeTransaction, newPositionAddresses, swapQuote }
POST /positions/repay{ transaction, lastValidBlockHeight }
POST /positions/partial-repay{ transaction, lastValidBlockHeight }
const { transaction, lastValidBlockHeight } = await res.json()
const tx = VersionedTransaction.deserialize(bs58.decode(transaction))
const signed = await wallet.signTransaction(tx)
const sig = await connection.sendRawTransaction(signed.serialize())
// Use lastValidBlockHeight to detect expiry — see Transaction Confirmation guide

The transaction is unsigned — you are responsible for having the user sign it and submitting it to the Solana network. Lavarage never holds private keys for your users.

Error Format

All errors use a consistent structure:

{
  "statusCode": 400,
  "code": "POSITION_INSUFFICIENT_BALANCE",
  "message": "Insufficient balance — you need enough collateral token + protocol fee (~1%), AND ~0.01 SOL for transaction fees and account rent.",
  "detail": null,
  "path": "/api/v1/positions/open-by-token",
  "timestamp": "2026-03-15T12:00:00.000Z"
}

The code field is a stable string — safe to match programmatically. The message is human-readable and may change between versions. Always match on code, not message.

See the Error Reference for the full list of error codes.

Versioning

The current API version is v1. All endpoints are prefixed with /api/v1/. Breaking changes will be released under a new version prefix (/api/v2/) with a deprecation period.