List jobs
GET /api/businesses/{slug}/jobsReturns the business’s published jobs, newest first, one page at a time.
curl "https://app.simplifylocal.app/api/businesses/{slug}/jobs?limit=20" \ -H "Authorization: Bearer sl_live_…"Query parameters
Section titled “Query parameters”All optional.
| Parameter | Type | Default | Notes |
|---|---|---|---|
limit |
integer | 100 |
Page size, 1–100. Out of range → 400 invalid_limit. |
cursor |
string | — | The pagination.next_cursor from the previous page. Omit on the first request. Malformed → 400 invalid_cursor. |
updated_since |
timestamp | — | Only jobs whose updated_at is later than this value. ISO 8601 (2026-10-01T00:00:00Z). Not parseable → 400 invalid_updated_since. Combines with cursor. |
indexable |
true |
— | Only jobs with noindex: false, the ones that belong in a sitemap. Any other value is ignored. |
reviews |
true |
— | Embed each job’s matched reviews[]. Without it, list rows return reviews: []. Any other value is ignored. |
aggregates |
false |
— | Skip the aggregates block and return aggregates: null. Use it on every page after the first: aggregates cover the whole business and are identical on every page. Any other value is ignored. |
Ordering
Section titled “Ordering”Jobs are ordered by completed_at descending, then id descending. Jobs without a completed_at come last. The order is stable across pages: a job published while you paginate does not shift the rows you have already seen.
Response
Section titled “Response”200 OK
{ "business": { "slug": "…", "name": "…", "canonical_domain": "https://…", "jobs_base_path": "/work", "…": "…" }, "jobs": [ { "slug": "house-washing-marietta", "headline": "…", "meta_description": "…", "service_type": "house-washing", "service_city": "marietta", "completed_at": "2026-04-12T14:30:00Z", "published_at": "2026-04-13T09:02:11Z", "updated_at": "2026-04-13T09:02:11Z", "noindex": false, "media": [ { "url": "https://…", "width": 1600, "height": 1200, "alt": "…", "kind": "hero", "…": "…" } ], "related_jobs": [], "reviews": [], "…": "…" } ], "pagination": { "next_cursor": "eyJj…", "has_more": true }, "aggregates": { "total_jobs": 42, "most_recent_completed_at": "2026-04-12T14:30:00Z", "services": [ "…" ], "cities": [ "…" ] }}| Field | Type | Notes |
|---|---|---|
business |
Business |
The business and its path configuration, on every response. |
jobs |
Job[] |
This page of jobs, as summaries (see below). |
pagination.next_cursor |
string or null |
Pass as cursor to fetch the next page. null on the last page. |
pagination.has_more |
boolean | true when another page exists. has_more: true always comes with a non-null next_cursor. |
aggregates |
JobsAggregates or null |
Counts across all published jobs, not just this page. null when you sent aggregates=false or when the counts could not be computed; the job list is still served. |
List rows are summaries
Section titled “List rows are summaries”Each row has the same shape as a full Job, but the fields that only make sense on a page of their own are blank on the list. Fetch Get a job for the full record.
| Field | On a list row |
|---|---|
body_markdown |
"" |
body_html |
null |
schema_org |
null |
related_jobs, source_line_items |
[] |
what_we_found, what_we_did, judgment_calls, what_we_recommend |
null |
money_page_service_url, money_page_area_url, canonical_slug |
null |
reviews |
[] unless you sent reviews=true |
Everything else (headline, meta_description, classification, timestamps, media, og_image_url, noindex, project_facts, work_duration_minutes) is populated.
Headers
Section titled “Headers”| Header | Notes |
|---|---|
ETag |
A weak validator over the response body. Send it back as If-None-Match to get 304 Not Modified with an empty body when nothing changed. See Caching. |
Cache-Control |
Not sent on a normal response. Cache by ETag revalidation only. |
Errors
Section titled “Errors”| Status | error |
|---|---|
400 |
invalid_cursor, invalid_limit, invalid_updated_since |
401 / 403 / 404 / 410 |
See Authentication. |
500 |
lookup_failed — temporary; retry. |
Fetching everything
Section titled “Fetching everything”# First pagecurl "https://app.simplifylocal.app/api/businesses/{slug}/jobs?limit=100" \ -H "Authorization: Bearer sl_live_…"
# Every later page: pass the cursor, skip the aggregatescurl "https://app.simplifylocal.app/api/businesses/{slug}/jobs?limit=100&aggregates=false&cursor=eyJj…" \ -H "Authorization: Bearer sl_live_…"Loop until has_more is false. For an incremental sync, store the newest updated_at you have seen and pass it as updated_since next time.