# Sample data

> Where can I download illustrative sample records without signing up?

Source: https://docs.betterjobs.cc/data/samples/

Download real-shaped records before you write any code. No key, no signup. Every sample record validates against its schema in the OpenAPI spec.

> Illustrative data
>
> Sample records are made up. Companies are fictional and use `.example` domains such as `acme-robotics.example` and `northwind.example`. Use the files to build and test parsers, not to measure coverage.

## Files

| File                                        | Format           | Contents                                              | Schema                                                           |
| ------------------------------------------- | ---------------- | ----------------------------------------------------- | ---------------------------------------------------------------- |
| [`jobs.json`](/samples/jobs.json)           | JSON array       | 10 canonical jobs                                     | [`Job`](https://docs.betterjobs.cc/data/jobs.md)                 |
| [`jobs.csv`](/samples/jobs.csv)             | CSV, header row  | The same 10 jobs, flattened                           | [`Job`](https://docs.betterjobs.cc/data/jobs.md), flattened      |
| [`companies.json`](/samples/companies.json) | JSON array       | 3 company hiring profiles                             | [`CompanyProfile`](https://docs.betterjobs.cc/data/companies.md) |
| [`openapi.yaml`](/openapi.yaml)             | OpenAPI 3.1 YAML | The full API spec: every endpoint, schema and example | —                                                                |

[jobs.json](/samples/jobs.json) [jobs.csv](/samples/jobs.csv) [companies.json](/samples/companies.json) [openapi.yaml](/openapi.yaml)

## What the samples cover

The records are chosen to exercise the cases your code must handle, not just the happy path.

**`jobs.json`**

- Open and closed jobs. Closed jobs carry `closed_reason` (`filled`, `expired`); open jobs have `closed_reason: null`.
- Jobs with `salary: null` (no source reported pay) next to jobs with `salary.origin` `declared` and `inferred`.
- `location.remote` as `true`, `false` and `null` (unknown).
- `posted_at: null` and `last_verified_at: null` on some jobs.
- Re-listed jobs with `repost_count` above 0.
- Several values of `seniority`, `employment_type` and `job_family`. See [Taxonomies](https://docs.betterjobs.cc/data/taxonomies.md).
- `sources[]` with one to three providers per job, each listing the `fields` it contributed.

**`companies.json`** has one profile per state of `is_hiring.value`: `true` (Acme Robotics), `false` (Globex Analytics) and `null` (Northwind Traders, no careers page or ATS found). See [Companies](https://docs.betterjobs.cc/data/companies.md#record-sample).

## CSV layout

`jobs.csv` holds one row per canonical job. Nested objects are flattened into columns:

| Column                                                                          | From                                                                                   |
| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `company_id`, `company_name`, `company_domain`                                  | `company.*`                                                                            |
| `city`, `region`, `country_code`, `remote`                                      | `location.*`                                                                           |
| `salary_min`, `salary_max`, `salary_currency`, `salary_period`, `salary_origin` | `salary.*`                                                                             |
| `source_providers`                                                              | `sources[].provider`, joined with `\|` (for example `betterjobs\|theirstack\|techmap`) |
| `license_display`, `license_resale`                                             | `license.*`                                                                            |

All other columns keep their JSON names. An empty cell means `null`.

> CSV loses detail
>
> CSV keeps only the provider slugs from `sources[]`. Each source’s `provider_job_id`, `url`, timestamps and `fields` are only in JSON. It also cannot tell `null` from an empty string. Use JSON when provenance matters.

## Load a sample

**curl**

```bash
curl -sO https://docs.betterjobs.cc/samples/jobs.json
curl -sO https://docs.betterjobs.cc/samples/jobs.csv
curl -sO https://docs.betterjobs.cc/samples/companies.json
curl -sO https://docs.betterjobs.cc/openapi.yaml
```

**Python**

```python
import requests


jobs = requests.get("https://docs.betterjobs.cc/samples/jobs.json", timeout=30).json()


for job in jobs:
    remote = job["location"]["remote"]  # True, False or None (unknown)
    pay = job["salary"]  # None = no source reported pay
    print(job["id"], job["status"], remote, pay and pay["min"])
```

**TypeScript**

```ts
const jobs: any[] = await (await fetch("https://docs.betterjobs.cc/samples/jobs.json")).json();


for (const job of jobs) {
  const remote = job.location.remote; // true, false or null (unknown)
  const pay = job.salary; // null = no source reported pay
  console.log(job.id, job.status, remote, pay?.min ?? null);
}
```

To generate types instead of using `any`, point an OpenAPI generator at [`/openapi.yaml`](/openapi.yaml). See [OpenAPI and SDKs](https://docs.betterjobs.cc/platform/openapi-and-sdks.md).

## Live samples

The keyless sandbox, `POST /v1/sandbox/jobs/search`, returns fixed illustrative data in the exact `SearchResponse` shape, including `metadata`. It charges nothing and calls no provider. Start at the [Quickstart](https://docs.betterjobs.cc/getting-started/quickstart.md) or the [sandbox reference](/api/operations/sandboxsearchjobs/).

Every example in the [API reference](/api/) also validates against its schema, so you can use them as test fixtures.
