# Point-in-time lookups (as_of)

URL: https://igregulator.io/docs/point-in-time/
Markdown: https://igregulator.io/docs/point-in-time.md

> Reconstruct a gambling licence's status on a past date with as_of — strictly within iGregulator's observation window, with corrections and gaps made explicit.

iGregulator keeps the **transition history** of every licence, so you can ask
"what was this operator's status on date X" — the question a compliance
review asks constantly ("was this merchant licensed at the time of the
transaction three months ago?") and the one no incumbent can answer, because
none keeps the history.

Pass `?as_of=` to `/v1/check`, `/v1/licenses/{id}`, or `/v1/operators/{slug}`.

## The one rule that matters

**`as_of` answers only within our observation window. We never extrapolate a
status before `tracking_since` — the moment we first recorded the licence.**

Our history begins when our scraper first saw a record (`change_type:
"created"`). We do not know what was true before that, so we never guess.
Asking about a date before `tracking_since` returns `knowledge:
"before_tracking"` with a **null** status — not a fabricated "active". A tool
that invented pre-observation history would force you to assert a historical
fact the data never witnessed; that is worse than not having the feature.

> **iGregulator answers "as of date X" only within its observation window —
> it tells you when it started watching, and never invents a status it didn't
> observe.**

## The states of knowledge

| `knowledge` | When | `status_as_of` |
| --- | --- | --- |
| `observed` | The date is within our window (≥ `tracking_since`). | The real status then. |
| `corrected` | The event in effect on that date is one we later **withdrew**. | `null`. We report neither the withdrawn status nor the one before it — neither is something we observed for that date. `correction` says what was withdrawn, when, and why. |
| `before_tracking` | The date predates when we started watching. | `null` — unknowable, **not** a guess. `tracking_since` tells you the lower bound. |
| `no_such_license` | We have no history for this licence at all. | `null`. |
| `no_license_resolved` | (`/v1/check` only) A fuzzy match with no specific licence to time-travel. | `null`. |

The `as_of` object also returns `established_by` — the exact history
transition in effect on your date (`changed_at`, `new_status`, `change_type`,
`source_url`) — so you can see *when* that status was last confirmed relative
to your query.

## Date semantics

`as_of` takes exactly two forms:

- **A date, `YYYY-MM-DD`** — interpreted as **end of that day, UTC** (status at
  close of day). Today's date (in UTC) answers as of the moment of the request:
  the rest of the day hasn't happened yet, so "now" is the latest we can answer for.
- **A full ISO-8601 datetime** — date, time (seconds and fractions optional) and
  a UTC offset (`Z` or `±hh:mm`), honoured as given: `2026-03-01T12:00:00Z`,
  `2026-03-01T14:00+02:00`.

Anything else is a `400` (`code: invalid_query`, `details.field: "as_of"`), never a
guess at what you meant:

- another format — `01/03/2026`, `2026/03/01`, `2026-3-1`, `20260301`,
  `March 1 2026`;
- a datetime without an offset — `2026-03-01T12:00:00` is a local time in a zone
  we can't know, and guessing UTC would answer for an instant you didn't ask about;
- a date or time that doesn't exist — `2026-02-30`, `2026-13-01`, `T25:00`;
- a date or instant **in the future** — we never answer about a date we haven't
  observed. It is never silently clamped to "now".

The same rules apply on `/v1/check`, `/v1/licenses/{id}` and `/v1/operators/{slug}`.

## Examples

`before_tracking` — asking before we started watching:

```json
// GET /v1/licenses/140a822c-…?as_of=2026-01-01
{
  "as_of": "2026-01-01T23:59:59.999Z",
  "knowledge": "before_tracking",
  "status_as_of": null,
  "established_by": null,
  "tracking_since": "2026-04-17T15:15:40.055Z"
}
```

`observed` — a date after a revocation transition:

```json
// GET /v1/licenses/140a822c-…?as_of=2026-05-20
{
  "as_of": "2026-05-20T23:59:59.999Z",
  "knowledge": "observed",
  "status_as_of": "revoked",
  "established_by": {
    "changed_at": "2026-05-13T01:00:05.215Z",
    "new_status": "revoked",
    "change_type": "status_change",
    "source_url": "https://www.gamblingcommission.gov.uk/downloads/business-licence-data.zip"
  },
  "tracking_since": "2026-04-17T15:15:40.055Z"
}
```

`corrected` — a date inside a period we got wrong and said so:

```json
// GET /v1/licenses/6e31e34b-…?as_of=2026-08-20
{
  "as_of": "2026-08-20T23:59:59.999Z",
  "knowledge": "corrected",
  "status_as_of": null,
  "established_by": null,
  "correction": {
    "changed_at": "2026-08-10T02:00:21.269Z",
    "withdrawn_status": "revoked",
    "corrected_at": "2026-09-17T17:20:11.123Z",
    "note": "Inferred from the licence disappearing from the register, not from a regulator publication. No regulator publication of a revocation was found."
  },
  "tracking_since": "2026-04-18T15:15:41.000Z"
}
```

History is never deleted here — a wrong event is marked and superseded — so the
record of what we *used to say* is still there, and `as_of` must not serve it back
as fact. `withdrawn_status` is that record; **it is not the status**. Until
2026-09-17 we reported licences that dropped off a register as `revoked`; those
events are withdrawn, and a date inside one of those windows answers `corrected`.
On 2026-10-01 two more sets were withdrawn the same way: 755 `→ revoked` events on
licences the regulator publishes as given up (711 UKGC licences the Commission
lists as `Surrendered`, 44 Curaçao licences "revoked at the request of the
operator"), and 148 Curaçao `active → pending` events written when we still read
"Assessment in progress" as pending (the CGA keeps such a licence in force). Dates
inside those windows answer `corrected` too. Treat it like `before_tracking`: we
cannot tell you the status on that date.

## Endpoint notes

- **`/v1/licenses/{id}?as_of=`** — cleanest: one licence, one `as_of` object.
- **`/v1/operators/{slug}?as_of=`** — resolved **per licence** (each licence
  in the array gets its own `as_of`); we don't collapse a multi-jurisdiction
  operator into a single status — you aggregate as your policy requires.
- **`/v1/check?domain=X&as_of=`** — the domain→licence attribution is
  **today's**: we answer for the licence the domain is on now, and only that
  licence's **status** is time-travelled. We keep no record of when a domain was
  linked to a licence, so if a site changed hands, the answer is about today's
  licensee's licence, not about whoever ran the site on your date. The response
  says this in three places:
  - `verdict` and `match` still describe **today**;
  - `verdict_detail` **leads with the answer for your date**, then says
    "Today: …";
  - the `as_of` object names the licence it answered for — `license_id`,
    `license_number`, `operator` — with `scope: "licence"` and a `link_note`.

```json
// GET /v1/check?domain=bet365.com&as_of=2026-03-01   (trimmed)
{
  "query": { "domain": "bet365.com" },
  "verdict": "licensed",
  "verdict_detail": "On 2026-03-01 we were not yet tracking Hillside (UK Gaming) ENC's UK Gambling Commission licence 055149-R-331499-004 (we first recorded it on 2026-04-17), so its status then is unknown. Today: bet365.com is listed, as of our read on 2026-09-30, on an active UK Gambling Commission licence held by Hillside (UK Gaming) ENC (licence 055149-R-331499-004); see jurisdictions[] for this domain's 2 other operator links.",
  "match": { "license_id": "ea65fd0a-7434-45db-9ac5-8ae5de967423", "status": "active", "...": "…" },
  "as_of": {
    "as_of": "2026-03-01T23:59:59.999Z",
    "scope": "licence",
    "license_id": "ea65fd0a-7434-45db-9ac5-8ae5de967423",
    "license_number": "055149-R-331499-004",
    "operator": "Hillside (UK Gaming) ENC",
    "knowledge": "before_tracking",
    "status_as_of": null,
    "established_by": null,
    "tracking_since": "2026-04-17T15:15:42.283Z",
    "link_note": "We do not record when this domain was linked to this licence; this is the licence's status on that date."
  }
}
```

A `before_tracking` or `corrected` answer is not "licensed then", whatever
`verdict` says about today. An `observed` answer says the status and the record it
rests on ("On 2026-05-20 … was revoked, per our record of 2026-05-13"). For a
licence-number query (`?license_number=…&as_of=`) there is no domain link to
qualify: `link_note` is `null`, and the answer is that licence's status on the
date. When no licence was resolved (`no_license_resolved`), `license_id`,
`license_number` and `operator` are `null`.
