LN Markets API
Documentation
Documentation
Overview
LN Markets offers a REST API to integrate with your program or trading bot. This API reference provides information on available endpoints and how to interact with it. For easier integration, we provide a ready-to-use TypeScript SDK and Python SDK.
Changelog
November 14, 2025
- Pagination Support: Introduced cursor-based pagination across all list endpoints for improved performance and reliability.
- Query Parameters: Added support for
from(start date),to(end date),limit(1-1000 items, default 1000), andcursor(pagination cursor) parameters - Response Format: All paginated endpoints now return a standardized response with
dataarray andnextCursorfield - Affected Endpoints:
GET /account/deposits/lightningGET /account/deposits/on-chainGET /account/deposits/internalGET /account/withdrawals/lightningGET /account/withdrawals/on-chainGET /account/withdrawals/internalGET /account/notificationsGET /futures/isolated/trades/closedGET /futures/isolated/trades/canceledGET /futures/isolated/funding-feesGET /futures/cross/orders/filledGET /futures/cross/funding-feesGET /futures/cross/transfersGET /futures/candlesGET /futures/funding-settlementsGET /synthetic-usd/swaps
- Query Parameters: Added support for
REST API
The API endpoint for mainnet is https://api.lnmarkets.com/v3/.
If you want to try our API with testnet bitcoin use https://api.testnet4.lnmarkets.com/v3.
GET requests
- Must not have a body
- Must not have header
Content-Type: application/json - Data is URL-encoded in the query string
- If there is a response body, it is always JSON
POST and PUT requests
- May have a body
- If there is a body, must have header
Content-Type: application/json - If there is a body, body must be valid JSON
- If there is a response body, it is always JSON
Authentication
Endpoints marked as Private require requests to be authenticated and signed. You can create and activate new API keys on your profile. As a best practice, your API keys should be assigned only permissions that are necessary for your application to function.
Headers
Authenticated requests must contain the following headers:
| Header | Description |
|---|---|
LNM-ACCESS-KEY | API Key |
LNM-ACCESS-PASSPHRASE | API Key passphrase |
LNM-ACCESS-SIGNATURE | Request signature |
LNM-ACCESS-TIMESTAMP | Request timestamp in milliseconds |
Signature
The LNM-ACCESS-SIGNATURE is generated by calculating an HMAC-SHA256 hash using the API secret key. The input to the hash is the string formed by concatenating timestamp, method, path, and data (in that order, without separators). The resulting hash is then encoded in Base64.
Having:
timestamp: same as theLNM-ACCESS-TIMESTAMPheader (request timestamp in milliseconds). It should be within 30 seconds of our server timemethod: request method in lowercase (e.g.get,post)path: request path of the URL, e.g.:/v3/accountdata: depending on the request method, either the request body as a JSON string (no space, no line return, should match Node'sJSON.stringifymethod) or the request query string (e.g.?key=value&key2=value2). If there is no data, it should be an empty string.
Example in TypeScript:
const url = new URL(request.url)
const data = request.body ? JSON.stringify(request.body) : url.search
const timestamp = Date.now()
const signature = createHmac('sha256', 'API_SECRET')
.update(`${timestamp}${request.method.toLowerCase()}${url.pathname}${data}`)
.digest('base64')
const headers = new Headers({
'LNM-ACCESS-KEY': 'API_KEY',
'LNM-ACCESS-PASSPHRASE': 'API_PASSPHRASE',
'LNM-ACCESS-TIMESTAMP': timestamp.toString(),
'LNM-ACCESS-SIGNATURE': signature,
})Have a look at our Typescript or Python SDK for more detailed examples.
Rate limit
The API uses a token bucket rate limiter with a refill rate of 20 tokens per second and a maximum capacity of 40 tokens.
Request costs:
- Authenticated requests: 1 token per request
- Unauthenticated requests: 5 tokens per request
This means authenticated users can make up to 20 requests per second with burst capacity to 40 and up to 300 requests per minute. While unauthenticated users are effectively limited to 4 request per second and 60 per minute.
The API follows the IETF HTTP API Rate Limit Headers specification (draft-10).
Rate Limit Headers
All responses include the following rate limit headers:
| Header | Description |
|---|---|
RateLimit-Policy | The static rate limit policy definition. Format: "default";q=<quota>;w=<window> |
RateLimit | The dynamic current rate limit state. Format: "default";r=<remaining> or "default";r=<remaining>;t=<reset> |
Retry-After | (429 responses only) The time in seconds to wait before making another request when rate limited. |
Example response headers:
RateLimit-Policy: "default";q=5;w=1
RateLimit: "default";r=3When rate limited (HTTP 429):
RateLimit-Policy: "default";q=5;w=1
RateLimit: "default";r=0;t=1
Retry-After: 1Pagination
Endpoints that return lists of data use cursor-based pagination for efficient navigation through large datasets. This approach is more reliable than offset-based pagination.
Query Parameters
Paginated endpoints accept the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
from | Date | Unix epoch 0 | Start date for filtering results |
to | Date | Current time | End date for filtering results |
limit | Number | 1000 | Maximum number of items to return (min: 1, max: 1000) |
cursor | Date | - | Cursor for fetching the next page (timestamp of last item) |
Response Format
Paginated responses return an object with two fields:
{
"data": [...], // Array of results
"nextCursor": null // Cursor for next page, or null if no more results
}data: Array containing the requested itemsnextCursor: ISO 8601 timestamp to use for fetching the next page. Whennull, there are no more results.
How It Works
- First Request: Call the endpoint without a
cursorparameter - Check Response: If
nextCursoris notnull, more results are available - Next Page: Make a new request with
cursorset to thenextCursorvalue from the previous response - Repeat: Continue until
nextCursorisnull
Results are ordered by creation date in descending order (newest first). The cursor represents the timestamp of the last item in the current page, and subsequent requests will return items created before that timestamp.
Best Practices
- Use appropriate
limitvalues to balance performance and number of requests (default 1000 is suitable for most use cases) - Store the
nextCursorvalue to resume pagination if needed - Use
fromandtoparameters to filter data by specific date ranges
Units
Unless stated otherwise:
- Bitcoin amounts are denominated in satoshis (1 bitcoin = 100,000,000 satoshis)
- Dates are returned as ISO 8601 date-time strings (e.g.
2025-09-01T15:04:21.129Z)
Errors
| Error Code | HTTP Status Code | Meaning |
|---|---|---|
| BAD_REQUEST | 400 | Bad Request |
| UNAUTHORIZED | 401 | Unauthorized - Failed authentication or you don’t have access to the requested resource |
| FORBIDDEN | 403 | Forbidden - Your API key may have the wrong scope |
| NOT_FOUND | 404 | Not Found |
| METHOD_NOT_SUPPORTED | 405 | Method Not Supported - You tried to access a resource with an invalid method |
| NOT_ACCEPTABLE | 406 | Not Acceptable |
| TIMEOUT | 408 | Request Timeout |
| CONFLICT | 409 | Conflict |
| PRECONDITION_FAILED | 412 | Precondition Failed |
| PAYLOAD_TOO_LARGE | 413 | Payload Too Large |
| UNSUPPORTED_MEDIA_TYPE | 415 | Unsupported Media Type |
| UNPROCESSABLE_CONTENT | 422 | Unprocessable Content |
| TOO_MANY_REQUESTS | 429 | Too Many Requests - Your connection is being rate limited |
| CLIENT_CLOSED_REQUEST | 499 | Client Closed Request |
| INTERNAL_SERVER_ERROR | 500 | Internal Server Error - Something went wrong, please try again or contact us |
| NOT_IMPLEMENTED | 501 | Not Implemented |
| BAD_GATEWAY | 502 | Bad Gateway |
| SERVICE_UNAVAILABLE | 503 | Service Unavailable - We're temporarily offline for maintenance, please try again later |
| GATEWAY_TIMEOUT | 504 | Gateway Timeout |