Endpoint

Sync jobs

Push every new JD from your ATS or careers page into Astris the moment it's published. One job at a time, or up to 100 in a batch.

Authentication

Requires the jobs scope. Key must be employer-scoped.

Endpoints

POST/api/v1/jobs/sync
POST/api/v1/jobs/bulk-sync
GET/api/v1/jobs

POST /api/v1/jobs/sync — request

Provide either text (Astris parses it) or parsed (you already have structured JD data).

textstring
The raw JD body. Astris parses it via the same pipeline used by the UI (Sonnet 4.6 + vision fallback for scanned PDFs).
parsedParsedJobDescription
Pre-parsed JD. Skips the parser entirely.
externalIdstring
Stable identifier from your system. When you re-POST with the same externalId, Astris updates the existing job (idempotent sync).
titlestring
Override the parsed title.
locationstring
Fallback "City, ST" if the parser didn't pick up location.

Response

{
  "jobId": "c4fcc511-612c-40d2-bfc5-4bbb79e04312",
  "slug": "apartment-maintenance-tech-c4fcc5",
  "action": "created",       // or "updated"
  "parsed": {
    "title": "Apartment Maintenance Tech",
    "requiredCertifications": ["EPA Section 608"],
    "hourlyMinUsd": 26,
    "hourlyMaxUsd": 32,
    "city": "Newark",
    "state": "NJ"
  }
}

Example — cron-driven nightly sync (Node.js)

import "dotenv/config";

const KEY = process.env.ASTRIS_API_KEY;

// Pull every active req from your ATS.
const reqs = await fetch("https://your-ats.example.com/api/requisitions?active=true")
  .then(r => r.json());

for (const r of reqs) {
  const res = await fetch("https://www.astrishr.com/api/v1/jobs/sync", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      externalId: r.id,            // your ATS's req id — used as upsert key
      title: r.title,
      location: r.location,
      text: r.fullDescription,
    }),
  });
  const data = await res.json();
  console.log(`${r.id} → ${data.action} (${data.jobId})`);
}

Run nightly via cron. The externalId upsert means re-runs are idempotent — closed reqs stay closed, edited reqs get updated.

POST /api/v1/jobs/bulk-sync

Same shape as /jobs/sync but accepts an array of up to 100 inputs. Processed sequentially to stay within Anthropic rate limits.

curl -X POST https://www.astrishr.com/api/v1/jobs/bulk-sync \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jobs": [
      { "externalId": "ATS-1", "text": "Maintenance Tech…" },
      { "externalId": "ATS-2", "text": "Leasing Consultant…" }
    ]
  }'
{
  "results": [
    { "jobId": "…", "slug": "…", "action": "created" },
    { "jobId": "…", "slug": "…", "action": "updated" }
  ],
  "summary": { "total": 2, "created": 1, "updated": 1, "failed": 0 }
}

GET /api/v1/jobs — list

List the most recent N jobs for the caller's employer. Use this to diff against your ATS state before deciding what to push.

curl https://www.astrishr.com/api/v1/jobs?limit=200 \
  -H "Authorization: Bearer $KEY"
{
  "jobs": [
    {
      "id": "…",
      "slug": "apartment-maintenance-tech-…",
      "title": "Apartment Maintenance Tech",
      "city": "Newark",
      "state": "NJ",
      "status": "open",
      "postedAt": "2026-06-08T17:30:00Z",
      "externalId": "ATS-12345"
    }
  ]
}