# Manatal Jobs API

> Query jobs from Manatal boards through one API with ?source=manatal — plus how Manatal's paginated API really behaves.

Source: https://hyperjobs.io/ats/manatal

Manatal is AI-assisted recruitment software sold to agencies and small businesses,
with a customer base that leans APAC and EU. Every board is backed by one public,
unauthenticated Django REST Framework API that serves postings with their
descriptions already inline. There are 48,926 Manatal postings in this dataset —
a number that moves hourly, so read it from [`/v1/meta`](/docs/api-reference/meta)
rather than trusting this sentence.

## Try it

```bash
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "source=manatal" \
  --data-urlencode "time_frame=7d" \
  --data-urlencode "limit=2"
```

```json title="Illustrative — the shape, not a live response"
{
  "data": [
    {
      "id": "manatal:northwind_48213",
      "title": "Recruitment Consultant",
      "company": {
        "slug": "northwind",
        "name": "Northwind",
        "domain": "northwind.io",
        "website": "https://northwind.io",
        "logo": "https://media.licdn.com/dms/image/…",
        "industry": "Staffing and Recruiting",
        "employee_count": 44
      },
      "location": {
        "remote": false,
        "countries": ["Singapore"],
        "cities": ["Singapore"],
        "regions": null,
        "raw": ["Singapore, Singapore"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": null,
      "seniority": null,
      "salary": null,
      "skills": ["sourcing", "client management"],
      "taxonomies": ["Human Resources"],
      "apply_url": "https://www.careers-page.com/northwind/job/L9V8R7Q6",
      "url": "https://www.careers-page.com/northwind/job/L9V8R7Q6",
      "source": "manatal",
      "posted_at": "2026-07-11T04:02:19.000Z",
      "expires_at": null,
      "updated_at": "2026-07-14T08:31:07.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}
```

## How Manatal boards actually work

One API backs every board, and it needs no auth:

```bash
curl "https://www.careers-page.com/api/v1.0/c/<slug>/jobs/?page=1"
```

It's plain Django REST Framework, so the envelope is the one you'd guess:
`{ count, next, previous, results[] }`. Descriptions arrive inline on the list
rows, which puts Manatal ahead of most of this pool — there is no detail fetch
and no HTML to parse.

`<slug>` is the tenant. Manatal renders boards two ways, `<slug>.careers-page.com`
and `careers-page.com/<slug>`, and the two are **mutually exclusive per tenant**:
`top-careers.careers-page.com` 404s while `careers-page.com/top-careers` returns
200. That looks like it matters and it doesn't. The API answers for every slug
either way, so you can ignore the board themes entirely and use the slug.

### `page_size` is ignored, and that is the whole problem

<Warning title="The server caps the page at 20 no matter what you ask for">
  Request `page_size=50` and you get 20. No error, no warning, no hint in the
  envelope that your parameter went in the bin — just a valid 200 with 20 rows on
  it.

  The failure this creates is silent and total. An adapter that trusts its own
  `page_size`, sees a full-looking page and stops has kept **20 of 221 jobs** on
  the board we measured. That's 9% of the board, delivered as a clean success with
  no error anywhere to alert you.

  The `count` field tells you the truth, and `next` is the only reliable way to
  reach the tail. Follow the server's cursor; never assume a page size you chose.
</Warning>

```bash
# Wrong: looks fine, keeps 9% of the board
curl "…/api/v1.0/c/<slug>/jobs/?page_size=50"   # → 20 rows

# Right: follow `next` until it's null
curl "…/api/v1.0/c/<slug>/jobs/?page=1"         # → { count: 221, next: "…page=2" }
```

### What a posting row carries

`position_name` is the title. `description` is inline HTML and is the reason this
platform is worth having. Location arrives both pre-formatted as
`location_display` and split into `city`, `state`, `country`, `address` and
`zipcode`, so you can take the board's own string or rebuild it from the parts.
`hash` is what builds the public URL at `careers-page.com/<slug>/job/<hash>`.

## What bites you

**There is no date. Anywhere in the API.** Not on the row, not in the envelope.
Manatal's API rows carry no created, posted or updated timestamp at all. The
subdomain theme's JSON-LD has one, but that's an N+1 per job for a single field,
which is a poor trade on a board this cheap to fetch. So `posted_at` on a Manatal
row is **our first-seen stamp, not the employer's publish date** — we'd rather
tell you that than let you build a freshness window on a date the source never
gave us.

**Job ids are tenant-local, not global.** Two Manatal boards will both happily
hand you a job `1`. The id has to be scoped by tenant before it can be a dedup
key, and if it isn't, boards silently overwrite each other.

**A `count` of 221 does not mean one request of 221.** It means twelve requests of
20. On a platform where the fetch looks like a one-liner, the pagination is the
entire job.

## Or use ours

The fetch is genuinely easy here. The scale isn't: Manatal has no public index of
its customers, so the tracked board list is assembled rather than fetched, and our
queue currently holds 1,080 Manatal boards. That list is the part that took the
time.

You get every board followed to its real tail rather than truncated at 20,
descriptions carried through, ids scoped per tenant so boards don't collide,
locations normalised out of the parts, Manatal rows deduplicated against the same
job on [LinkedIn](/ats/linkedin) or wherever else it's cross-posted, and expiry by
board diffing so a pulled role disappears.

The [company join](/docs/objects/company) is the honest gap on this platform: a
Manatal board tells you a slug, and the API publishes no employer domain, so the
identity has to be resolved rather than read. That resolution is work we do and
don't always win.

Query it with `?source=manatal`.
[Quickstart](/docs/quickstart), then [pricing](/pricing).
