Skip to main content

Batch Operations

Batch endpoints let you perform multiple operations in a single API call. Use these when you need to process a training week, onboard a team, or import historical activities.

Batch calculate

Calculate prescriptions for multiple scenarios at once. Ideal for building “training week” views or “what if” comparisons.
POST /v1/nutrition/calculate/batch
import requests

response = requests.post(
    "https://api.saturday.fit/v1/nutrition/calculate/batch",
    headers={"Authorization": "Bearer sk_test_abc123def456"},
    json={
        "athlete_id": "ath_abc123",
        "scenarios": [
            {
                "label": "Monday easy run",
                "activity_type": "run",
                "duration_min": 45,
                "intensity_level": 3,
            },
            {
                "label": "Wednesday intervals",
                "activity_type": "run",
                "duration_min": 60,
                "intensity_level": 7,
            },
            {
                "label": "Saturday long ride",
                "activity_type": "bike",
                "duration_min": 180,
                "intensity_level": 5,
                "thermal_stress_level": 7,
            },
        ],
    },
)

results = response.json()
for result in results["results"]:
    print(f"{result['label']}: {result['carb_g_per_hr']}g carbs/hr")

Response format

{
  "results": [
    {
      "index": 0,
      "label": "Monday easy run",
      "carb_g_per_hr": 30,
      "sodium_mg_per_hr": 300,
      "fluid_ml_per_hr": 400,
      "safety": { "confidence_score": 0.65, "warnings": [], "not_instructions": true }
    },
    {
      "index": 1,
      "label": "Wednesday intervals",
      "carb_g_per_hr": 55,
      "sodium_mg_per_hr": 400,
      "fluid_ml_per_hr": 500,
      "safety": { "confidence_score": 0.65, "warnings": [], "not_instructions": true }
    }
  ],
  "errors": [],
  "metadata": {
    "total_scenarios": 3,
    "successful": 3,
    "failed": 0,
    "request_id": "req_abc123def456"
  }
}
If individual scenarios fail, they appear in errors with the index and error detail. Successful scenarios are still returned — batch operations don’t fail atomically.

Limits

ConstraintValue
Max scenarios per batch50
Rate limitingCounts as 1 API call per scenario

Bulk athlete create

Onboard multiple athletes in one call. Useful for team imports or platform migrations.
POST /v1/athletes/batch
response = requests.post(
    "https://api.saturday.fit/v1/athletes/batch",
    headers={"Authorization": "Bearer sk_test_abc123def456"},
    json={
        "athletes": [
            {
                "external_id": "user-001",
                "name": "Alice Runner",
                "weight_kg": 58,
                "fitness_level": "advanced",
                "primary_sport": "run",
            },
            {
                "external_id": "user-002",
                "name": "Bob Cyclist",
                "weight_kg": 75,
                "fitness_level": "intermediate",
                "primary_sport": "bike",
            },
            {
                "external_id": "user-003",
                "name": "Carol Triathlete",
                "weight_kg": 65,
                "fitness_level": "elite",
                "primary_sport": "bike",
            },
        ],
    },
)

results = response.json()
for athlete in results["created"]:
    print(f"Created: {athlete['name']} -> {athlete['id']}")

Limits

ConstraintValue
Max athletes per batch100
Duplicate external_idError for that item, others continue

Activity import

Import multiple activities for an athlete at once. Useful for backfilling historical data from other platforms.
POST /v1/athletes/{athlete_id}/activities/import
response = requests.post(
    f"https://api.saturday.fit/v1/athletes/ath_abc123/activities/import",
    headers={"Authorization": "Bearer sk_test_abc123def456"},
    json={
        "activities": [
            {
                "type": "run",
                "name": "New Year's Day 10K",
                "duration_min": 48,
                "intensity_level": 7,
                "scheduled_at": "2025-01-01T09:00:00Z",
                "thermal_stress_level": 2,
            },
            {
                "type": "bike",
                "name": "Weekend group ride",
                "duration_min": 150,
                "intensity_level": 5,
                "scheduled_at": "2025-01-04T08:00:00Z",
            },
        ],
    },
)
Imported activities don’t automatically get prescriptions calculated — call the prescription endpoint for each activity that needs one, or let the athlete trigger calculations through your UI.

Error handling in batch operations

Batch operations use partial success semantics. If 3 out of 5 items succeed and 2 fail:
  • The 3 successful items are committed
  • The 2 failed items are returned in the errors array with index, error type, and message
  • The HTTP status is 200 (not 400) because some items succeeded
{
  "created": [
    { "index": 0, "id": "ath_abc123", "name": "Alice Runner" },
    { "index": 2, "id": "ath_def456", "name": "Carol Triathlete" }
  ],
  "errors": [
    {
      "index": 1,
      "error": {
        "type": "conflict",
        "code": "duplicate_external_id",
        "message": "An athlete with external_id 'user-002' already exists"
      }
    }
  ]
}
Check both created (or results) and errors arrays to handle the response correctly.