Record API

Read the GhostPost.us record from inside your own product

GhostPost.us is an outside-in evidence and observation layer — read-only middleware between configured public job sources and downstream compliance, HR, and legal systems. It delivers the record; it does not execute remediation. Your product owns the interface, the workflow, and the decision. GhostPost.us supplies the dated, sourced record underneath it.

What GhostPost.us provides and the boundaries of the Record API

Coverage is limited to the sources configured and available for observation.

What the API provides

  • Observe the public sources it is configured and able to reach
  • Record what each of those sources displayed
  • Timestamp every observation
  • Preserve observation history
  • Show changes between successful observations
  • Surface requirement records with their sources, where available
  • Provide read-only access to the recorded observations

Where the boundary sits

The API returns observations. It carries no review status, no assignment, no resolution state, no severity, no score, and no verdict about an employer. Those are your product's to define — which is exactly why the record stays neutral enough for two systems that disagree to cite the same evidence.

Every endpoint is a read. Nothing in v1 writes, charges, or mutates the record.

Authentication

Server-to-server only. There is no browser API and no CORS surface — a key in client code is a key anyone can read.

Header

Authorization: Bearer gp_live_...

Keys are issued per workspace, from the Workspace tab, and scoped to that workspace's own record. GhostPost.us stores only a fingerprint, so a key is shown exactly once. A revoked key stops reading immediately; the record itself is untouched.

Test mode

Build the integration before your workspace holds a single observation.

A gp_test_ key calls the same endpoints and returns the same shape, backed by a fixed sample employer: greenhouse/sample-employer. The values never change between calls, so your integration tests stay stable.

The rule that matters

Test data is visually and programmatically distinguishable from live data: every sandbox payload carries mode: "test", sample: true, an X-GhostPost.us-Mode: test header, and an employer named "Sample Employer (GhostPost.us test data)".

No test response may be represented as a real GhostPost.us observation, a customer record, or a Field Test result. Test and sample records must never be mixed with live workspace observations — including in exports, histories, analytics, or anything your product displays downstream.

Sandbox call

curl -s https://ghostpost.us/api/public/v1/companies \
  -H "Authorization: Bearer gp_test_..."

Endpoints

Seven reads. That is the whole surface.

  • GET /api/public/v1

    Discovery — the contract and the endpoint index.

  • GET /api/public/v1/companies

    Every company this workspace holds a record for.

  • GET /api/public/v1/companies/{provider}/{account}

    One employer source: evidence plus source coverage.

  • GET /api/public/v1/companies/{provider}/{account}/observations

    Evidence — the observation history, timestamped and sourced.

  • GET /api/public/v1/companies/{provider}/{account}/coverage

    Monitor — each recorded read attempt and how it went.

  • GET /api/public/v1/companies/{provider}/{account}/changes?since=ISO8601

    Watch — what changed between observations.

  • GET /api/public/v1/requirements?jurisdiction=California

    Requirements — the records held for named jurisdictions.

The machine-readable contract is OpenAPI 3.1, served without a key at /api/public/v1/openapi.json. Generate a client from it.

Quickstart

Same read, three languages.

cURL

curl -s https://ghostpost.us/api/public/v1/companies \
  -H "Authorization: Bearer gp_live_..."

TypeScript

const res = await fetch(
  "https://ghostpost.us/api/public/v1/companies/greenhouse/sample-employer/changes?since=2026-07-01T00:00:00Z",
  { headers: { Authorization: `Bearer ${process.env.GHOSTPOST_API_KEY}` } },
);

if (res.status === 429) {
  // Operating limit. Retry-After is in seconds.
  const wait = Number(res.headers.get("retry-after") ?? 60);
}

const body = await res.json();
if (body.mode === "test") {
  // Sample data. Never store or display it as a real observation.
}

Python

import os, requests

r = requests.get(
    "https://ghostpost.us/api/public/v1/companies/greenhouse/sample-employer/observations",
    headers={"Authorization": f"Bearer {os.environ['GHOSTPOST_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
data = r.json()

assert data["mode"] == "live", "test payloads must never enter the live store"
for line in data["observations"]:
    print(line["observedAt"], line["kind"], line["summary"])

Evidence semantics your system must honor

These are the rules that make the record worth citing. A consuming product that breaks them turns evidence back into assumption.

Observed

Information GhostPost.us found and recorded in the public source at the time of observation.

Stated absent

The reviewed source explicitly indicates that the information is not provided.

Can't determine

The available public evidence does not allow GhostPost.us to determine the answer.

Source unavailable

GhostPost.us could not lawfully access or successfully read the source. This is not treated as an absence.

No requirement record identified

GhostPost.us does not currently have a sourced requirement record for this jurisdiction or topic in its regulatory dataset. This does not mean that no requirement exists, it does not mean the posting is compliant, and it does not mean there is no risk.

Unverified

The requirement or data point has not yet been sufficiently verified against the required source and should not be treated as established fact.
  • An unread source is unread. Never display it as “no postings”, “clean”, or “nothing found”.
  • Every line carries an observation time and the source it came from. Keep both when you store or display it.
  • GhostPost.us states what was observed. Do not present a GhostPost.us line as a determination, a violation, a score, or a risk rating.
  • Test and sample records must never be mixed with live workspace observations — not in exports, histories, analytics, or downstream displays.
  • Coverage is limited to the sources configured and available for observation.

Operating limits, request IDs, and errors

Rate limit

120 requests per minute per key to start. Over the limit returns 429 with a Retry-After header in seconds. Higher limits are a configuration change, not an integration change — ask if you need one.

Request IDs

Every response carries X-GhostPost.us-Request-Id and the same value in the body as requestId. Log it; quote it in a support thread and we can find the exact read.

Errors

401 missing or invalid key · 404 this workspace holds no record for that source · 429 over the operating limit. Every error body has error.code and error.message.

Versioning

The path is versioned (/v1) and every payload carries apiVersion. Fields are added, not removed or repurposed, within a version.

Get access

Workspace owners and admins issue live and test keys from the Workspace tab. For partner integrations, request access and tell us what you are building.