Unlocks

Spend one unlock to reveal a single censored record in full. Free tier only; the paid tiers have nothing to reveal.

POST /unlocks

Reveal one censored record

Send your key with this call.

Spend one unlock to reveal a single censored record in full. The grant is permanent: it survives the weekly unlock reset and applies to that record from any later query that reaches it, so a row revealed once stays revealed.

Two things that are easy to get wrong:

- charged: false means the record was already held. Holding it again costs nothing, so a double click or a retry after a dropped response is safe. - An unlock lifts value masking only. It does not open the ai_analysis or ai_chat file-browser tabs, which stay refused below the Premium file-browser entitlement because each is a paid language-model call with no censored form to serve.

Authentication is the same as on the other /api routes. The call writes a grant and reaches no upstream, so it is not metered as a search and carries only the global rate limiter.

What you send.

JSON body, required.

  • kind string required

    Which surface the record came from. The two surfaces address a record differently, so the kind is part of its identity rather than a hint.

    One of breach, device

  • record_id string required

    The record_id the row carried - a content digest for breach rows, the provider's stealerlog_id for device rows.

  • term string

    The query the reader was looking at when they spent the unit. Audit trail only; it is never read back into a gate, so it neither widens nor narrows the grant.

  • query_type string

    The search type behind that query. Audit trail only.

What comes back.

  • 200 The record is held. The balance rides along on every outcome, refusals included, so the control that was just pressed can redraw its remaining count without a second call.

    • success boolean required

    • data object

      • unlocks integer

        Unlocks spent in the current unlock period, counted after this call.

      • unlocks_limit integer

        Unlock allowance for the unlock period; 5 a week on the free tier.

      • kind string

        One of breach, device

      • record_id string

      • unlocked boolean

      • charged boolean

        Whether this call spent a unit. false means the record was already held, which costs nothing, so a double click or a retry after a dropped response is safe.

  • 400 The body would not parse, `kind` is neither `breach` nor `device`, or `record_id` is empty or longer than 128 characters.

    • success boolean required

    • error string required

    • code string

      Machine-readable error tag. Omitted whenever it is empty, which is most generic errors, so branch on status too.

      One of quota_exceeded, hourly_limit, file_access_limit, plan_upgrade_required, upgrade_required, feature_not_enabled, email_verification_required, monitor_limit, monitor_surface_not_allowed, monitor_first_seen_not_allowed, monitor_webhook_invalid, monitor_webhook_not_allowed, monitor_webhook_key_required

  • 401 The request carried no valid session or API key.

    The same shape as 400.

  • 403 The plan has no unlock mechanism at all. Every paid tier answers this way: paid rows are not censored, and Pro's masked device browser is the Premium upsell rather than something to spend units on. The code is the same `plan_upgrade_required` the device gates send.

    The same shape as 400.

  • 429 The unlock allowance is spent. It refills on its own weekly clock, reported as `unlocks_reset_at` by `GET /search/stats`, rather than with the search counters. Unlike the other quota refusals this one still carries `data`, with `unlocks` and `unlocks_limit`, so the caller can redraw the balance without a second request.

    • success boolean required

    • error string required

    • code string

      Machine-readable error tag. Omitted whenever it is empty, which is most generic errors, so branch on status too.

      One of quota_exceeded, hourly_limit, file_access_limit, plan_upgrade_required, upgrade_required, feature_not_enabled, email_verification_required, monitor_limit, monitor_surface_not_allowed, monitor_first_seen_not_allowed, monitor_webhook_invalid, monitor_webhook_not_allowed, monitor_webhook_key_required

    • data object

      • unlocks integer

      • unlocks_limit integer