Bulk Timelines

Run the Timelines query over many locations and deliver the result as a file to your own bucket, once or on a schedule.

Bulk Timelines runs the Timelines query for many locations at once. The result is delivered as one file to your own bucket. You can run an order once (on demand) or on a cron schedule.

📘

Orders and runs

An order is the stored configuration: the locations, fields, time window, format, destination and an optional schedule. Its ID is orderId. You can pause, resume or rename an order.

A run is one execution of an order. Its ID is runId. A run cannot be changed. An on-demand order starts its run immediately. A scheduled order starts a run at each tick of its schedule.

🚧

Before you start

  • Your account must have the data-export entitlement.
  • An active destination credential must be registered for your account and destination bucket. If there is none, the request returns 422 missing_credential.

Create an order

curl -X POST "https://api.tomorrow.io/v4/data/orders/timelines?apikey=$TOMORROW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept-Encoding: deflate, gzip, br" \
  -d '{
    "name": "warehouses-next-5-days",
    "locations": [
      [32.0853, 34.7818],
      "40.7128, -74.0060",
      { "type": "Polygon", "coordinates": [[[-0.2,51.4],[0.1,51.4],[0.1,51.6],[-0.2,51.6],[-0.2,51.4]]] }
    ],
    "fields": ["temperature", "windSpeed", "precipitationIntensity"],
    "timesteps": ["1h"],
    "start": "now",
    "end": "nowPlus5d",
    "units": "metric",
    "timezone": "UTC",
    "format": "csv",
    "destination": { "type": "gcs", "bucket": "my-weather-exports", "prefix": "tomorrow" }
  }'

Response 201 Created for an on-demand order:

{
  "orderId": "ord_8c1f2a",
  "name": "warehouses-next-5-days",
  "runId": "3f1c2b9e-7a4d-4e8b-9c21-5d6e7f8a9b0c",
  "dataset": "timelines",
  "size": null
}

Body parameters

ParameterTypeRequiredDescription
locationsarrayOne of locations or feedIdThe locations. Each item is a [lat, lon] pair, a "lat, lon" string, a GeoJSON geometry (Point, Polygon, MultiPolygon and other types), or the ID of a saved location. Refer to formats.
feedIdstringOne of locations or feedIdThe ID of a stored assets feed. The feed is resolved when the run starts.
fieldsarray of stringsYesThe fields to export. Use the same names as in the Timelines API. The maximum is 100 fields.
formatstringYesThe format of the delivered file: csv, json (one array of location objects) or jsonl (one location object per line).
destinationobjectYesThe bucket that receives the file. Refer to Destination.
timestepsarray of stringsNoFor example ["1h"] or ["1d"]. Refer to Timestep Availability.
startstringNoThe start of the time window: an ISO 8601 time, now, nowPlusXm/h/d or nowMinusXm/h/d.
endstringNoThe end of the time window. It accepts the same formats as start.
timezonestringNoAn IANA timezone name, for example America/New_York.
dailyStartHourintegerNo0–23. The hour at which a daily timestep starts.
unitsstringNometric or imperial.
namestringNoA label for the order, with a maximum of 128 characters. It must be unique in your account. If not, the request returns 409 name_conflict.
activebooleanNoThe default is true. If false, the order is stored but does not run until you activate it. Refer to Pause, resume or rename an order.
triggerobjectNoOmit it for an on-demand order (one time request). For a scheduled order, refer to Scheduled orders.

Destination

{ "type": "gcs", "bucket": "my-bucket", "prefix": "optional/prefix" }
ParameterDescription
typegcs, s3 or azure.
bucketThe bucket name only. Do not include gs:// or a path.
prefixOptional. It is added to the start of each object key.

Scheduled orders

To make a recurring export, add a trigger with a 5-field cron expression. The request does not start a run. The response has nextRunTime and no runId.

Request for example:

{
  "feedId": "my-sites-feed",
  "fields": ["temperature", "humidity"],
  "timesteps": ["1h"],
  "start": "now",
  "end": "nowPlus2d",
  "format": "jsonl",
  "destination": { "type": "s3", "bucket": "my-weather-exports" },
  "trigger": { "type": "schedule", "schedule": "0 */6 * * *" }
}

Response:

{
  "orderId": "ord_9d2e3b",
  "dataset": "timelines",
  "nextRunTime": "2026-10-12T18:00:00Z",
  "size": null
}
📘

Relative time windows

On a scheduled order, relative values such as now and nowPlus2d are resolved at each run. In the example above, each run exports a new 2-day forecast.

Delivered files

Each run writes its files to a folder for that run. A new run never overwrites the files of an earlier run.

<bucket>/<prefix>/<accountId>/<orderId>/<runId>/timelines.<csv|json|jsonl>
<bucket>/<prefix>/<accountId>/<orderId>/<runId>/failures.json
<bucket>/<prefix>/<accountId>/<orderId>/<runId>/credits.json
<bucket>/<prefix>/<accountId>/<orderId>/<runId>/error.json
FileWhen it is writtenContents
timelines.<format>When the run delivers dataOne row for each location, timestep and interval. Point locations have lat and lon columns. Other geometries have a location column. Locations from a feed use the feed asset's key as id.
failures.jsonOnly when some locations failedThe locations that are not in the file, and the reason for each.
credits.jsonBest effort. A missing file does not mean that the delivery failed.credits_used, billed_calls, complete, balance_remaining, locations_total, locations_ok, locations_failed.
error.jsonOnly when the whole run was refusedorder_id, run_id, code, message, time.

Example timelines.csv:

id,lat,lon,timestep,startTime,temperature,windSpeed
tel-aviv,32.0853,34.7818,1h,2026-01-01T00:00:00Z,23.21,6.74
tel-aviv,32.0853,34.7818,1h,2026-01-01T01:00:00Z,23.46,7.07

Example failures.json:

{
  "order_id": "ord_8c1f2a",
  "run_id": "3f1c2b9e-7a4d-4e8b-9c21-5d6e7f8a9b0c",
  "locations_total": 1000,
  "locations_failed": 1,
  "failures": [
    { "location_id": "site-17", "reason": "location_not_found", "status": 400, "message": "..." }
  ]
}

The values of reason in failures.json are location_not_found, invalid_request, not_entitled, rate_limited, upstream_unavailable and unknown.

The values of code in error.json are permission_denied, feed_not_found, too_many_locations, invalid_order and invalid_query. invalid_query means that every location failed with the same query error, for example an unknown field or an incorrect timezone.

Track a run

GET https://api.tomorrow.io/v4/data/orders/timelines/{orderId}/runs/{runId}?apikey=<YOUR_API_KEY>

Poll this endpoint until the status is completed, failed, cancelled or skipped.

{
  "runId": "3f1c2b9e-7a4d-4e8b-9c21-5d6e7f8a9b0c",
  "status": "completed",
  "fileCount": 1,
  "filesDelivered": 1
}
StatusMeaning
queuedThe run was accepted but has not started.
runningThe run is in progress.
completedThe file was delivered. If outcome is partial, some locations are not in the file. failures.json lists them.
failedThe run did not deliver what was ordered.
cancellingA cancel request was accepted and is in progress.
cancelledYou cancelled the run.

Manage orders and runs

All paths start with https://api.tomorrow.io/v4 and need the apikey query parameter.

RequestDescription
GET /data/orders?dataset=timelinesLists your bulk timelines orders. Use limit and offset to get more pages.
GET /data/orders/timelines/{orderId}Gets an order, its schedule and its most recent run.
PATCH /data/orders/timelines/{orderId}Pauses, resumes or renames an order. Refer to Pause, resume or rename an order.
DELETE /data/orders/timelines/{orderId}Deletes the order and its schedule. Runs that are in progress are not cancelled. Cancel them first.
GET /data/orders/timelines/{orderId}/runsLists the runs of an order, newest first. You can filter with status, and you can repeat this parameter.
POST /data/orders/timelines/{orderId}/runsStarts a new run now. The request has no body. Relative start and end values are resolved when the run starts. Returns 202 with the new runId.
DELETE /data/orders/timelines/{orderId}/runsCancels all runs of the order that are not finished. The order continues to run on its schedule. To stop it, pause the order.
DELETE /data/orders/timelines/{orderId}/runs/{runId}Cancels one run. Cancellation is asynchronous: the status changes to cancelling first. Data that is already in delivery can still arrive.
🚧

Cancel runs before you delete an order

Deleting an order does not cancel its runs. After an order is deleted, you can cancel a run only with DELETE /data/orders/timelines/{orderId}/runs/{runId}.

Pause, resume or rename an order

curl -X PATCH "https://api.tomorrow.io/v4/data/orders/timelines/{orderId}?apikey=$TOMORROW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "active": false }'
  • {"active": false} pauses the order. Future runs do not start. A run that is in progress continues.
  • {"active": true} resumes the order. If the order was created with "active": false, this starts it for the first time.
  • {"name": "new-name"} renames the order.

Limits

LimitError
The maximum number of locations in one order. The maximum is given in the limit field of the error. An order with more locations is refused, not shortened.422 too_many_locations
A maximum of 100 fields in one order.422 too_many_fields
A maximum of 10 active orders in one account. This includes active scheduled orders and on-demand orders whose run is not finished.422 order_limit_exceeded

Errors

All error responses have the same structure:

{
  "code": "too_many_locations",
  "field": "locations",
  "limit": 50000,
  "message": "..."
}

Use code in your logic, because its values do not change. field is the request field that caused the error. limit is the limit that was exceeded, or the list of valid values.

StatusMeaning
400The request is not valid. Possible causes: an unknown or missing field, both locations and feedId, an incorrect cron expression, or an unsupported destination type.
401The API key is missing or not valid.
403The account does not have the export entitlement.
404The order or run does not exist, or another account owns it.
409name_conflict (the name is already used), run_pending (the order was created inactive and is not activated) or order_expired.
422The request is valid but cannot be done. Codes: missing_credential, location_not_found, feed_not_found, too_many_locations, too_many_fields, order_limit_exceeded.
502 / 503A temporary error in a dependency. Send the request again.