Prospex docs

Conventions and errors

What every Prospex surface shares: dates, ids and versions, pagination, parameters, headers, idempotency and the refusal vocabulary.

These rules hold on every surface. Each surface's own page covers only what differs.

Dates, ids and versions

  • Every timestamp is ISO 8601 in UTC, and every date is YYYY-MM-DD.
  • Ids come in two flavours. A Prospex company id is an integer and stable forever. Outreach ids are opaque strings such as prospect_4812, and the API takes them exactly as it gave them.
  • The API is versioned in its path, at /api/v1/outreach/. Feeds carry a version or schema_version in the body instead, bumped when a field changes meaning or leaves.
  • A new field does not bump a version. Unknown response fields should be ignored.

Pagination

Each paginated feed hands you a next_url that is absolute and carries every parameter you sent. Following it until it comes back empty is the whole of pagination. Cursors are opaque.

A built list is a ranking, and its order changes only when a build refreshes it. Its cursor carries the build it was issued under. A cursor from an older build answers 400 invalid_parameter and asks you to start again.

A list's signals are ordered by detection time. Its keyset cursor keeps page turns stable when newer signals arrive during a pull.

A project grows continuously, so its feed uses a keyset in one of two modes. Without updated_since it walks primary keys, which never move, so a page turn cannot skip a row that changed underneath you. With updated_since it walks oldest change first, and a row updated mid-walk is served again. Re-reading a row costs you a comparison. Skipping one costs you a company.

Page sizes: up to 500 rows on a list page, up to 200 on a project page.

Parameters

The list signal feed, the project feed and the API refuse a parameter they do not know, with a 400 that names it and lists what would have worked.

The list feed reads three parameters — tab, limit and cursor — and ignores anything else.

Headers

HeaderWhereWhy
Retry-After On a 429 Seconds until the limit resets: midnight for a daily limit, midnight on the 1st for monthly_row_limit. Sleep on this rather than on a guess.
X-Request-Id Every API response Also in the body as request_id, and recorded in the project's audit history. Quote it when something looks wrong.
X-RateLimit-* Every API response Limit, Remaining and Reset for the day's request allowance.
Idempotency-Key Sent by you, on every API mutation Required.

Idempotency

Every mutation carries an idempotency key you choose.

  • The same key with the same request returns the original response byte for byte, with Idempotency-Replayed: true, and spends nothing a second time.
  • The same key with a different request answers 422 idempotency_conflict.
  • Keys are scoped to the credential that used them, so two services in one account can both send nightly-2026-08-21 without colliding.