Skip to main content

Overview

POST /v1/streams/bulk returns confirmed streams using the same Stream objects as Get Streams. This is a public endpoint. No API key is required. It uses POST only so that multi-valued filters can be sent in the request body. Despite the verb, it is a read-only query: nothing is created or modified, and the result set is not scoped to any API key’s organization. This endpoint is the bulk counterpart of Get Streams. Reach for it when Get Streams is too limited, specifically when you need to:
  1. Filter by multiple values at once: several stream IDs, several organizations, one or more target-token chains, or a set of (chainId, address) target tokens, instead of the single-value query params accepted by Get Streams.
  2. Paginate the result set with the optional page and limit query params.
Filters of different kinds are combined with AND; multiple values within a single filter are combined with OR. As with Get Streams, only confirmed streams are ever returned.
targetChainIds and targetTokens filter on each stream’s target token (the token tracked via customArgs.targetTokenId), not its reward token. Use the decimal EVM chain IDs listed in Get Tokens.

Endpoint

Filter by multiple stream IDs

curl -X POST "https://earn.turtle.xyz/v1/streams/bulk" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "6f0f2a1c-1c2d-4f3e-9a8b-7c6d5e4f3a2b"
    ]
  }'

Filter by organizations and target tokens

curl -X POST "https://earn.turtle.xyz/v1/streams/bulk" \
  -H "Content-Type: application/json" \
  -d '{
    "organizationIds": ["9f51b66a-d13a-4b55-8515-ae6e4ef7cf25"],
    "targetChainIds": [1, 8453],
    "targetTokens": [
      { "chainId": 1, "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }
    ],
    "withSnapshots": false,
    "usersCount": true
  }'

Paginate the result set

Pagination is opt-in. Send page and/or limit as query parameters to receive one page plus a pagination object in the response.
curl -X POST "https://earn.turtle.xyz/v1/streams/bulk?page=1&limit=50" \
  -H "Content-Type: application/json" \
  -d '{ "organizationIds": ["9f51b66a-d13a-4b55-8515-ae6e4ef7cf25"] }'

Parameters

Request Body

All body fields are optional. Sending an empty body is allowed, but only together with a bounded limit query parameter (see Response Semantics).
ids
uuid[]
Filter by stream IDs. Returns streams whose id is in this list.
organizationIds
uuid[]
Filter by owning organization IDs. Returns streams belonging to any of these organizations.
targetChainIds
integer[]
Filter by streams whose target token is on any of these chains. Values are decimal EVM chain IDs. See Get Tokens for the supported list.
targetTokens
EvmToken[]
Filter by streams whose target token matches any of these EVM (chainId, address) tokens.
withSnapshots
boolean
default:"false"
Include the full historical snapshots array for each returned stream. Behaves exactly as on Get Streams.
usersCount
boolean
default:"false"
Add userCount and activeUserCount to each included snapshot object. Behaves exactly as on Get Streams.

EvmToken

chainId
integer
required
Decimal EVM chain ID of the target token.
address
string
required
Target token contract address on that chain. Matching is case-insensitive.

Query Parameters

Pagination is optional. Omit both parameters to return all matching streams in a single response, without a pagination object.
page
integer
Page number for the paginated result set. Providing page or limit switches the endpoint into paginated mode. Values lower than 1 are normalized by the backend to 1.
limit
integer
Number of streams to return per page. Providing page or limit switches the endpoint into paginated mode. Values lower than 1 are normalized to 20. Values above 500 are rejected with 400 Invalid Argument.

Response Example

When pagination is requested, the response includes a pagination object. The streams array holds the same Stream objects documented in Get Streams.
{
  "streams": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "chainId": 1,
      "contractAddress": "0x4C6F5a1aA2B9985d4A8b9189C2118E7f55E2f701",
      "orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
      "type": 2,
      "strategy": "Fixed APR",
      "startTimestamp": "2026-03-11T00:00:00Z",
      "endTimestamp": "2026-04-11T00:00:00Z",
      "lastSnapshot": { "...": "see Get Streams for the full Stream object" },
      "snapshots": [],
      "rewardToken": { "...": "see Get Streams" }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 128,
    "totalPages": 3,
    "hasNext": true,
    "hasPrevious": false
  }
}
The Stream object is identical to the one returned by Get Streams. See that page for the complete field-by-field schema, including customArgs, adapters, point, lastSnapshot, committedSnapshot, snapshots, and rewardToken.

Response Semantics

Sending organizationIds and targetChainIds together returns streams that belong to one of the organizations and whose target token is on one of the chains. Within a single filter, multiple values are matched with OR (an IN lookup).
If you omit both page and limit, the endpoint returns every matching stream and no pagination object. As soon as either query parameter is present, the response is paginated and includes a pagination object.
To avoid loading the entire stream table, an empty body (no ids, organizationIds, targetChainIds, or targetTokens) must be paired with a bounded limit query parameter. Without a filter and without a limit, the request is rejected with 400 Invalid Argument.
Like Get Streams, this endpoint only returns streams whose creation has been confirmed. Pending streams are never included.
If no stream matches the provided filters, the endpoint returns streams: [] (together with a pagination object when pagination was requested) rather than failing.

Response Fields

streams: Stream[]
pagination?: PaginationResponse
streams
Stream[]
required
List of confirmed streams matching the provided filters. Each item is a Stream object. See Get Streams for the full schema.
pagination
PaginationResponse
Pagination metadata describing the current page and the total size of the result set. Present only when page or limit was supplied; omitted otherwise.

PaginationResponse

page
integer
Current page returned by the backend after normalization.
limit
integer
Number of items returned per page after normalization or capping.
total
integer
Total number of streams matching the filters across all pages.
totalPages
integer
Total number of available pages for the current limit.
hasNext
boolean
Whether a page after the current one exists.
hasPrevious
boolean
Whether a page before the current one exists.

Error Handling

Status Code: 400 Bad Request
{
  "error": {
    "status": "INVALID_ARGUMENT",
    "error": "a bounded limit (max 500) is required when no filter is provided"
  }
}
Solution: Provide at least one filter (ids, organizationIds, targetChainIds, or targetTokens), or supply a bounded limit query parameter.
Status Code: 400 Bad RequestEach filter has an upper bound: 100 ids, 20 organizationIds, 5 targetChainIds, and 100 targetTokens. Exceeding any of these returns INVALID_ARGUMENT with a message such as too many stream ids (max 100).Solution: Split large requests into multiple calls that stay within the per-filter limits.
Status Code: 400 Bad Request
{
  "error": {
    "status": "INVALID_ARGUMENT",
    "error": "limit too high (max 500)"
  }
}
Solution: Request a limit of 500 or fewer and page through the result set.
Status Code: 500 Internal Server ErrorSolution: Retry the request and contact Turtle if the issue persists.