Skip to main content
The Time Machine API is experimental and can change before general availability.
Examples and coverage verified against the production API on 2026-10-26. Search and read the web as Keenable captured it at a past moment, given by query_time. Every result is a version of the page captured at or before query_time, so nothing published or edited later can appear. Use it to backtest agents and forecasts, to research what was known on a given date, or to build training datasets that can’t see the future.

Access

  • Send your API key in the X-API-Key header.
  • Time Machine must be turned on for your organization. If it isn’t, every call returns 403 with Feature not enabled. To turn it on, go to keenable.ai/time-machine or ask your Keenable contact.
  • Each search uses credits like a regular search, and each fetch like a regular fetch. If your organization has no credits left, calls return 402 with Insufficient credits.
  • Most responses carry an X-Request-Id header. Include its value when you report a problem.

Quick start

Set your API key in the environment, then run the examples below.
Search: what was known about the WeWork IPO on 1 September 2019, a month before it was withdrawn.
(The response contains 3 results; only 2 are shown here.) Search with filters, sent as a POST with a JSON body:
The response has the same shape as the GET search above. Fetch: one page as it was on 1 September 2019.
Other query_time values return other versions of the same URL:

query_time

Both endpoints require query_time. The response echoes it in UTC ISO 8601 form, for example 2019-09-01T00:00:00.000Z.
  • query_time must not be in the future, and now is not accepted. For current results, use the regular search API.
  • In a JSON body, query_time must be a string, so quote epochs: "1567296000".
  • In a GET query string, encode the + of a time zone offset as %2B. curl’s --data-urlencode does this for you.
GET or POST /v1/time_machine/search. GET takes the parameters in the query string. POST takes the same parameters as a JSON body.

Request

string
required
What to search for, in words. A URL is rejected; to read a URL, use fetch.
string
required
string
Only results from this domain, e.g. techcrunch.com. A leading www. is optional.
string
Only pages published after this date. Accepts a date, an ISO 8601 timestamp, a Unix epoch, or a relative offset counted back from query_time (7d means 7 days before query_time).
string
Only pages published before this date. Same formats as published_after.
integer
default:"10"
How many results to return, from 1 to 50.
integer
Maximum snippet length in characters, 180–10,000. Without it, snippets are typically 500–3,500 characters.
string
Your own ID for grouping related requests. You can send it as the X-Keenable-Session-Id header instead.
Any other parameter returns 400 with Unknown parameter(s) and the list of supported parameters. The site: operator inside query also works. The acquired_after: and acquired_before: operators are rejected. The published_after: and published_before: operators inside query take only absolute dates. A relative one, such as published_after:7d, is rejected, because there it would count back from now; use the published_after parameter, which counts back from query_time.

Response

string
Your query.
string
The query_time used, in UTC ISO 8601.
array
Results, most relevant first.
string
Present only when the API adjusted your query. For example, a query made only of site: operators is searched with the site’s name as the search term.
object
What this call was billed: sku (search.time_machine), amount (1), credits (credits charged) and paid (true when the credits came from your purchased balance, false when they came from your plan’s free credits).

Fetch

GET /v1/time_machine/fetch, GET only. Returns the latest version of the page that Keenable stored at or before query_time. It never fetches the live page. Keenable doesn’t have every older version of every page.

Request

string
required
The page’s URL. www. and non-www. forms return the same page, but http:// and https:// are different URLs.
string
required
integer
default:"50000"
Maximum content length, as a positive integer. Longer content is cut to max_chars characters, and a truncation note of about 70 characters is appended.
string
Your own ID for grouping related requests. You can send it as the X-Keenable-Session-Id header instead.

Response

string
The page’s URL, normalized.
string
The query_time used, in UTC ISO 8601.
string
When Keenable captured this version, in UTC ISO 8601.
string
The page’s publication date in this version, in UTC ISO 8601. Absent when unknown.
string
The page’s title in this version. Absent when unknown.
string
The page’s text in this version.
object
What this call was billed: sku (fetch.time_machine), amount (1), credits and paid, as in search.
If no version was captured at or before query_time, fetch returns 404 and the response suggests trying a later query_time.

Errors

Errors are JSON: {"error": "<title>", "message": "<details>"}. message is sometimes absent. A call that returns an error is not billed, and its response carries no usage.