Batch Requests
How to compute positions across date ranges and mix endpoint types in a single API call.
Batch Requests
The batch endpoint lets you send up to 50 computation requests in a single HTTP call. This is ideal for computing positions across date ranges, comparing data at multiple moments, or combining different endpoint types.
Computing a Year of Daily Sun Positions
Instead of making 365 individual requests, send them all in one batch:
curl -X POST https://api.morphemeris.com/v1/batch \
-H "Authorization: Bearer morphemeris_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{ "endpoint": "/v1/positions", "params": { "datetime": "2024-01-01T00:00:00Z", "bodies": "sun" } },
{ "endpoint": "/v1/positions", "params": { "datetime": "2024-01-02T00:00:00Z", "bodies": "sun" } },
{ "endpoint": "/v1/positions", "params": { "datetime": "2024-01-03T00:00:00Z", "bodies": "sun" } }
]
}'Each result includes the full position data at the corresponding index:
{
"data": {
"results": [
{ "index": 0, "status": 200, "data": [{ "body": "sun", "longitude": 280.35, "..." }] },
{ "index": 1, "status": 200, "data": [{ "body": "sun", "longitude": 281.37, "..." }] },
{ "index": 2, "status": 200, "data": [{ "body": "sun", "longitude": 282.39, "..." }] }
],
"summary": { "total": 3, "succeeded": 3, "failed": 0 }
},
"meta": { "credits_used": 3, "..." }
}Since the maximum batch size is 50, a full year requires 8 batches of 50 requests each (365 / 50). This uses 365 credits total, the same as individual requests, but with 8 HTTP round-trips instead of 365.
Mixing Endpoint Types
A batch can combine different endpoints. For example, compute a full chart (positions + houses) at one moment and also get the Delta T and sidereal time:
curl -X POST https://api.morphemeris.com/v1/batch \
-H "Authorization: Bearer morphemeris_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"endpoint": "/v1/chart",
"params": {
"datetime": "1990-06-15T14:30:00Z",
"lat": 40.7128,
"lon": -74.006,
"bodies": "planets"
}
},
{ "endpoint": "/v1/delta-t", "params": { "datetime": "1990-06-15T14:30:00Z" } },
{ "endpoint": "/v1/sidereal-time", "params": { "datetime": "1990-06-15T14:30:00Z", "lon": -74.006 } }
]
}'This costs 3 credits (1 + 1 + 1) and returns chart data, Delta T, and sidereal time in a single response.
Handling Partial Failures
If one sub-request has an error (e.g., missing a required parameter), the other sub-requests still succeed:
{
"data": {
"results": [
{ "index": 0, "status": 200, "data": [{ "body": "sun", "..." }] },
{
"index": 1,
"status": 400,
"error": {
"code": "missing_parameter",
"message": "Exactly one of 'datetime' or 'jd' must be provided.",
"param": "datetime"
}
},
{ "index": 2, "status": 200, "data": { "delta_t_seconds": 56.17, "..." } }
],
"summary": { "total": 3, "succeeded": 2, "failed": 1 }
}
}Check the summary.failed count and inspect individual result status codes to handle errors programmatically.
Building Batch Requests Programmatically
In Python:
import requests
from datetime import datetime, timedelta
# Compute Sun/Moon positions for the first 50 days of 2024
base = datetime(2024, 1, 1)
sub_requests = [
{
"endpoint": "/v1/positions",
"params": {
"datetime": (base + timedelta(days=i)).strftime("%Y-%m-%dT00:00:00Z"),
"bodies": "sun,moon"
}
}
for i in range(50)
]
resp = requests.post(
"https://api.morphemeris.com/v1/batch",
headers={"Authorization": "Bearer morphemeris_live_YOUR_KEY"},
json={"requests": sub_requests}
)
data = resp.json()
for result in data["data"]["results"]:
if result["status"] == 200:
positions = result["data"]
# Process positions...In JavaScript:
const dates = Array.from({ length: 50 }, (_, i) => {
const d = new Date(2024, 0, 1 + i);
return d.toISOString();
});
const response = await fetch("https://api.morphemeris.com/v1/batch", {
method: "POST",
headers: {
Authorization: "Bearer morphemeris_live_YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
requests: dates.map((dt) => ({
endpoint: "/v1/positions",
params: { datetime: dt, bodies: "sun,moon" },
})),
}),
});
const { data } = await response.json();
const succeeded = data.results.filter((r) => r.status === 200);Tips
- Credit cost is the same whether you batch or send individual requests. Batching saves HTTP overhead, not credits.
- Rate limiting counts the batch as 1 request, so batching is more efficient than parallel individual requests.
- Each sub-request is independent. There is no way to share common parameters across sub-requests. Build shared params into each sub-request client-side.
- Maximum 50 sub-requests per batch. For larger workloads, split into multiple batch calls.