Skip to main content
Schedule recurring exports of cell scores from Locus and have them emailed to you on a weekly or monthly cadence. Each delivery runs the saved filter against the latest cell_scores and attaches the result as a CSV or JSON file. For one-off downloads, use the on-demand exports endpoint described in ML exports.

When to use it

Use scheduled exports when you want a hands-off feed of Locus scores for a specific market, score band, or analyst inbox — for example:
  • A weekly CSV of all cells in a metro for territory planning.
  • A monthly JSON snapshot of high-composite cells (e.g. composite ≥ 70) for portfolio review.
  • Recurring deliveries to a shared analyst alias so the same dataset lands in the same place every week.
Each schedule is owned by the user that creates it and can only be read, updated, or deleted by that user.

Endpoints

All endpoints require an authenticated session. Schedules are scoped to the calling user.

GET /api/scheduled-exports

List scheduled exports owned by the current user. Response
{
  "schedules": [
    {
      "id": "8c1f9f0a-3a9b-4c7e-9f4d-2b8c4d3e1a90",
      "name": "Weekly SF scores",
      "filters": { "metro": "sf", "compositeMin": 70 },
      "format": "csv",
      "frequency": "weekly",
      "target_email": "analyst@yourcompany.com",
      "last_sent_at": "2026-04-22T08:00:12Z",
      "last_error": null,
      "created_at": "2026-04-15T14:22:01Z"
    }
  ]
}
FieldTypeDescription
idstring (UUID)Schedule identifier. Pass to DELETE to remove.
namestringHuman-readable label, used in the email subject and attachment filename.
filtersobjectFilter blob applied to cell_scores on each run. See Filters.
formatstringcsv or json.
frequencystringweekly or monthly.
target_emailstringAddress that receives each delivery.
last_sent_atstring | nullTimestamp of the last successful run. null if it has never run.
last_errorstring | nullError message from the most recent failed run, or null if the last run succeeded.
created_atstringWhen the schedule was created.

POST /api/scheduled-exports

Create a new scheduled export. Body parameters
NameTypeRequiredDescription
namestringSchedule name (≤120 characters).
target_emailstringAddress to deliver the export to. Must contain @.
formatstringcsv (default) or json.
frequencystringweekly (default) or monthly.
filtersobjectFilter blob applied to cell_scores. Defaults to {} (all cells). Maximum 8 KB of JSON.
Filters The filter blob is stored as JSON and re-evaluated on every run, so updates to cell_scores show up automatically. The cron worker currently honors:
KeyTypeDescription
metrostringMetro slug (e.g. sf, nyc).
compositeMinnumberLower bound on the composite score (inclusive).
compositeMaxnumberUpper bound on the composite score (inclusive).
Each delivery is capped at 5,000 rows, ordered by descending composite. If the filter matches no rows, the run is recorded as successful and no email is sent. Example — create a weekly schedule
curl -X POST https://axiomlocus.io/api/scheduled-exports \
  -H "Content-Type: application/json" \
  --cookie "sb-access-token=..." \
  -d '{
    "name": "Weekly SF scores",
    "target_email": "analyst@yourcompany.com",
    "format": "csv",
    "frequency": "weekly",
    "filters": { "metro": "sf", "compositeMin": 70 }
  }'
Response
{
  "schedule": {
    "id": "8c1f9f0a-3a9b-4c7e-9f4d-2b8c4d3e1a90",
    "name": "Weekly SF scores",
    "filters": { "metro": "sf", "compositeMin": 70 },
    "format": "csv",
    "frequency": "weekly",
    "target_email": "analyst@yourcompany.com",
    "created_at": "2026-04-29T19:00:00Z"
  }
}

DELETE /api/scheduled-exports?id=<uuid>

Delete a scheduled export. The id must be a UUID owned by the current user.
curl -X DELETE \
  "https://axiomlocus.io/api/scheduled-exports?id=8c1f9f0a-3a9b-4c7e-9f4d-2b8c4d3e1a90" \
  --cookie "sb-access-token=..."
Response
{ "success": true }

Delivery cadence

A cron worker evaluates schedules every Monday at 08:00 UTC and runs any schedule whose last_sent_at is older than its cadence (or has never run):
  • weekly — runs once last_sent_at is at least 7 days old.
  • monthly — runs once last_sent_at is at least 30 days old.
Because the worker fires weekly, weekly is the floor cadence — monthly schedules will fire on the first Monday after their 30-day window elapses.

Email format

Each successful run sends an email from Axiom Locus <reports@axiomlocus.io> with:
  • Subject: Your scheduled Axiom Locus export: <name> (<row_count> rows)
  • Attachment: <slugified-name>-<YYYY-MM-DD>.<csv|json>
CSV attachments include a header row and the columns h3_index, metro_slug, neighborhood, lat, lng, composite, confidence, the eight signal-group scores (business_vitality, population_momentum, demographics, economic_strength, development_pipeline, accessibility, safety_environment, amenity_demand), and computed_at. JSON attachments contain an array of objects with the same keys.

Failure handling

If a run fails (for example, an upstream Resend outage), the error message is written to last_error on the schedule and the schedule remains due — the worker will retry on the next cron tick. A successful run clears last_error and bumps last_sent_at. List the schedule with GET to see whether the last run succeeded.

Limits

LimitValue
Filter blob size8 KB of JSON
Schedule name length120 characters
Rows per delivery5,000
Cron cadenceMondays at 08:00 UTC
S3 delivery is not yet supported — schedules deliver to email only.