Back to home

TrueInterview API reference

Every TrueInterview question, company, article, interview report and plan that is on a public page is also reachable as JSON. The API is read-only, needs no API key, and is described by an OpenAPI document, so an agent can load it as a tool definition rather than being told about it in prose.

The spec

  • openapi.jsonThe OpenAPI 3.1 description of every operation below. Also served at /api/openapi.json.
  • API indexA JSON list of every operation, its URL and its summary.

The spec is the contract. Every operation in it carries a unique operationId, a description, typed parameters and a response schema, which is the shape an LLM function-calling converter needs — point your tooling at the URL above rather than hand-writing tool definitions from this page.

How to call it

Every operation is a GET under /api/v1, needs no authentication, and answers with the same envelope: { "ok": true, "data": … } on success, and { "ok": false, "error": { "code", "message", "hint", "documentation" } } on failure, with an HTTP status that matches the code. There is no HTML error page anywhere on this API, including for a path that does not exist.

curl -s "https://trueinterview.io/api/v1/questions?company=Google&type=algorithm&limit=2"
{
  "ok": true,
  "data": {
    "questions": [
      {
        "slug": "two-sum",
        "number": 1,
        "title": "Two Sum",
        "type": "algorithm",
        "difficulty": "easy",
        "company": "Google",
        "companies": ["Google"],
        "url": "https://trueinterview.io/questions/two-sum"
      }
    ],
    "page": { "page": 1, "limit": 2, "total": 1, "hasMore": false }
  }
}

A parameter this API does not recognise is refused rather than ignored, because a filter that was silently dropped returns a full page of results that look like an answer:

{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "`difficulty` must be one of: easy, medium, hard.",
    "hint": "Received `trivial`.",
    "documentation": "https://trueinterview.io/developers/api#listQuestions"
  }
}

Rate limits, and what is not published

The quota is 240 requests per 60 seconds per client address, and every response says where you are in it. Read the headers rather than finding the limit by hitting it:

RateLimit-Policy: "public";q=240;w=60
RateLimit: "public";r=239;t=42
RateLimit-Limit: 240
RateLimit-Remaining: 239
RateLimit-Reset: 42
  • RateLimit-Policy and RateLimit follow the IETF RateLimit fields draft: q is the quota, w the window, r what you have left and t the seconds until it is restored.
  • The same three numbers repeat as RateLimit-Limit / -Remaining / -Reset and as X-RateLimit-*, for clients that read those instead. They are three spellings of one measurement, never three limits.
  • Past the quota you get HTTP 429, the RATE_LIMITED code and Retry-After in seconds. Wait that long, then retry.
  • RateLimit is absent when the request carried no address to count against. That is not a full quota, it is an unmeasured one — pace against RateLimit-Policy instead.
  • From a browser, the numbers are readable: every rate-limit header is named in Access-Control-Expose-Headers.
  • A volumetric limit at the network edge sits in front of all of this and is what stops a flood; the headers exist so a well-behaved client never meets it.
  • List operations return at most 50 rows per request. A larger limit is clamped, not refused.
  • Responses are cacheable for an hour at a shared cache, so repeating a call costs nothing.
  • Metadata only: question statements, solutions, test cases, article prose and interview write-ups are in no response. Follow the url field to the page, and cite the page.
  • Read-only: there is no write, checkout, or account operation, and no authenticated endpoint. The job-application agent is a signed-in product surface, not an API.
  • Mirroring the catalog through this API is not permitted — see the Terms of Service and /robots.txt.

Versioning and deprecation

The major version is in the path. Everything documented here is /api/v1, and this build publishes version 1.0.0 of it, which every response repeats in X-Api-Version. A change that would break a client written against this page gets a new major path instead of being applied to this one.

Inside a version, fields and operations may be added at any time. Parse leniently: ignore a field you do not recognise rather than failing on it, and do not assume the set of operations is closed.

An operation or a version that is going away is announced at least 180 days before it stops answering, and the announcement arrives in the responses themselves rather than only on this page:

  • Deprecation (RFC 9745) — a Structured Field Date naming the moment the operation became deprecated. It keeps answering normally.
  • Sunset (RFC 8594) — the date after which it stops answering, once that date is set.
  • Link with rel="deprecation" — the note explaining what replaces it.
Deprecation: @1688169599
Sunset: Sun, 30 Jun 2024 23:59:59 GMT
Link: <https://trueinterview.io/developers/api#versioning>; rel="deprecation"

Absence of those headers is the signal that an operation is current, which is the case for every operation on this page today. Nothing here has ever been deprecated. The same statement is machine-readable at /api, under versioning.

From a shell

Every operation is a plain GET, so curl and jq are a complete client. No key, no session, no preflight — the two lines below are the whole integration for most scripts.

curl -s "https://trueinterview.io/api/v1/companies" | jq -r '.data.companies[].slug'
curl -s "https://trueinterview.io/api/v1/questions?company=Google&limit=5" | jq '.data.questions[] | {slug, title, url}'

listQuestions — List practice questions

Returns a page of interview questions from the public catalog, newest bank number first, filtered by any combination of company, format, difficulty and a title search. Metadata only: follow url for the question page itself. Study articles are not included here — they are served by listArticles — but no-code practice questions (behavioural, knowledge) are, with type blog.

GET /api/v1/questions
  • company (query, string) — Only questions reported at this company, matched case-insensitively on the company name (for example Google).
  • type (query, algorithm | sql | system-design | object-oriented-programming | ai-coding) — Only questions of this format.
  • difficulty (query, easy | medium | hard) — Only questions of this difficulty.
  • q (query, string) — Case-insensitive substring match on the question title. A bare number matches the question number.
  • page (query, integer) — Which page of results to return, counting from 1.
  • limit (query, integer) — How many rows to return, at most 50. A larger value is clamped rather than refused.

getQuestion — Get one question by slug

Returns the metadata of a single question. The slug is the last segment of its page URL (/questions/<slug>). Answers 404 with the NOT_FOUND error code when the catalog holds no such question.

GET /api/v1/questions/{slug}
  • slug (path, string, required) — The question's URL slug, for example two-sum.

listCompanies — List companies with reported questions

Returns every company the question bank carries reported questions for, busiest first, with the count and the company landing page URL. Use it to resolve a company name to the slug the other operations and pages use.

GET /api/v1/companies
  • limit (query, integer) — How many rows to return, at most 50. A larger value is clamped rather than refused.

listArticles — List published articles

Returns a page of the written preparation guides published in the Study section, with the URL of each article. The prose itself is on the page, not in this response. Paged like listQuestions: the Study section holds more guides than one page can carry, so read page.hasMore rather than assuming one request is the whole set.

GET /api/v1/articles
  • page (query, integer) — Which page of results to return, counting from 1.
  • limit (query, integer) — How many rows to return, at most 50. A larger value is clamped rather than refused.

listJobs — List live job postings

Returns a page of the live postings on the public job board, newest first, narrowed by employment type, seniority rung, field and location. Metadata only: the posting text is on the employer's page at applyUrl, and url is the posting's own public page on this site — one role, no account needed. Answers the same rows the board itself serves — it is the board's own query path, not a second index. Postings come and go: a role that closes stops being returned, so a mirror of this list is only as current as its last refresh.

GET /api/v1/jobs
  • kind (query, newgrad | intern) — Which board to read. intern is internships; newgrad is everything that is NOT an internship, at every level — narrow with seniority for how senior the role is.
  • seniority (query, intern | new-grad | junior | senior | staff-plus | manager) — Only roles at this rung of the seniority ladder. Derived from the title where the pipeline has not classified one, so a rung filter reaches the whole catalog rather than the classified part of it.
  • family (query, tech | Software | Data & AI | Hardware & Engineering | Product & Design | Quantitative Finance | IT & Support | Science & Research | Healthcare | Skilled Trades & Operations | Finance & Accounting | Sales & Marketing | Business & Operations | People & Legal | Education | Other) — Only roles in this field. tech is the union of the six technical fields — the axis that excludes the non-technical postings the catalog also carries.
  • location (query, string) — Only roles in this country or region, by canonical name (United States, Europe). remote selects remote roles instead, wherever they are. An unrecognised value is refused rather than ignored.
  • postedWithinDays (query, 7 | 14 | 30 | 60 | 0) — Only roles posted or re-posted inside this many days. 0 is any age. A posting with no publication date falls outside every window.
  • page (query, integer) — Which page of results to return, counting from 1.
  • limit (query, integer) — How many rows to return, at most 50. A larger value is clamped rather than refused.

listInterviewExperiences — List recent interview experiences

Returns the newest candidate-written interview reports on the board — the company, the role, the headline and the permalink — plus how many the board holds in total. The write-up itself is on the linked page.

GET /api/v1/interview-experiences
  • limit (query, integer) — How many rows to return, at most 50. A larger value is clamped rather than refused.

listPlans — List subscription plans and prices

Returns every subscription plan with what it charges, how long the charge covers, and the per-month equivalent. Rendered from the same plan registry as the pricing page, so the number here is the number a customer is charged. Read-only: checkout happens on the site.

GET /api/v1/plans

Takes no parameters.

getSiteProfile — Describe this site

Returns what this site is, the jobs it is the right source for, what it is explicitly not for, its machine-readable files and its whole public site map — the JSON equivalent of /llms.txt. Start here when deciding whether to use this API at all.

GET /api/v1/site

Takes no parameters.