aria-partner-api

Exposure API

An exposure is a place Kanary found a profile’s PII.

Resource Path Purpose
Member exposures (collection) /api/v1/members/{member_id}/exposures/ GET paginated exposures for one profile; POST report a missed exposure
Exposure /api/v1/exposures/{exposure_id}/ GET detail
Status actions /api/v1/exposures/{exposure_id}/not_about_me/ /api/v1/exposures/{exposure_id}/not_a_risk/ POST mark as ignored

Pull exposures for a profile

GET /api/v1/members/{member_id}/exposures/

Returns a paginated page of exposures for the member in the path. The member must belong to an account under the authenticated partner. See Pagination.

Query parameters

Param Default Max Description
limit 100 250 Exposures per page (Pagination)
offset 0 — Starting index into the member’s exposure list

Example

GET /api/v1/members/67890/exposures/?limit=100&offset=0

Response

{
  "member_id": 67890,
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "exposure_id": 123456,
      "url": "https://example-broker.com/profile/12345",
      "scrape_task_id": 9001,
      "exposure_status": "ACTIVE",
      "site_id": 42,
      "site_domain": "example-broker.com",
      "site_threat_score": 7.5,
      "contents": "Bob Example\n123 Main St, NYC ...",
      "screenshot_url": "https://cdn.example.com/screenshots/abc.png?X-Amz-Signature=...",
      "last_submitted_at": null
    }
  ]
}

Poll by following next until it is null (see README — v1 limitations).

Response fields

Field Type Description
member_id integer Profile queried
count integer Total exposures for this member
next string | null URL for the next page, or null
previous string | null URL for the previous page, or null
results array Current page of exposures

Exposure object

Each item in results includes:

Field Type Description
exposure_id integer Primary key
url string | null Exposure URL; on some sites this may be a URL with an anchor fragment, or null when no direct URL exists
scrape_task_id integer | null Scan id that produced this exposure (null if none)
exposure_status string Enum string (see status values)
reason string | null Set when exposure_status is BLOCKED. null otherwise. See BLOCKED metadata
action_required string | null Set when exposure_status is BLOCKED. What the partner or user must do before Kanary can proceed. null otherwise
site_id integer | null Site id
site_domain string | null Site.domain for display; null when no site is linked
site_threat_score number Site-level privacy threat score (higher = higher risk). Not yet available — returns null until threat score data is wired
contents string | null Raw text scraped from the page
screenshot_url string | null Presigned URL from AWS when screenshots are enabled; null otherwise. Expires after a limited time—refetch the exposure for a fresh URL
last_submitted_at string (ISO 8601, UTC) | null When a mitigation, deletion, or escalation was last submitted

Status values

exposure_status values:

Value Definition
IGNORED User or partner marked not relevant / not a risk
ACTIVE Removal in progress
REMOVED Exposure removed
BLOCKED Kanary cannot proceed. reason and action_required are set. See BLOCKED metadata

BLOCKED metadata

When exposure_status is BLOCKED, the exposure includes reason and action_required. Both are null on every other status.

reason is one of:

action_required is one of:

{
  "exposure_id": 123456,
  "exposure_status": "BLOCKED",
  "reason": "user not on eligible subscription for Kanary to take action",
  "action_required": "upgrade"
}

Errors

Status Condition
400 Invalid limit or offset
401 Missing or invalid API key
403 Partner inactive
404 Member not found or terminated

Get a single exposure

GET /api/v1/exposures/{exposure_id}/

Returns detail for one exposure. If the id is invalid, the exposure belongs to a terminated member, or the exposure is not accessible to your partner, the API returns 404 Not Found (see Resource access).

Example

GET /api/v1/exposures/123456/

Response (200 OK)

{
  "exposure_id": 123456,
  "member_id": 67890,
  "url": "https://example-broker.com/profile/12345",
  "scrape_task_id": 9001,
  "exposure_status": "ACTIVE",
  "site_id": 42,
  "site_domain": "example-broker.com",
  "site_threat_score": 7.5,
  "contents": "Bob Example\n123 Main St, New York, New York ...",
  "screenshot_url": "https://cdn.example.com/screenshots/abc.png?X-Amz-Signature=...",
  "last_submitted_at": "2026-05-18T10:42:00Z"
}

Errors

Status Condition
401 Missing or invalid bearer token
403 Partner inactive
404 Exposure not found

Update exposure status

POST /api/v1/exposures/{exposure_id}/not_about_me
POST /api/v1/exposures/{exposure_id}/not_a_risk

Marks an exposure as ignored when it is not about the profile or not a risk. The status becomes IGNORED.

Matches made on phone or email alone can be about someone else who shares that contact data. Use not_about_me to record that the result is not about this user. This works on BLOCKED exposures as well.

Examples

POST /api/v1/exposures/123456/not_about_me
POST /api/v1/exposures/123456/not_a_risk

Success (200 OK)

{
  "exposure_id": 123456,
  "member_id": 67890,
  "exposure_status": "IGNORED",
  "status_update": "not_about_me"
}

Errors

Status Condition
401 Missing or invalid bearer token
403 Partner inactive
404 Exposure not found or member terminated

Report a missed exposure

POST /api/v1/members/{member_id}/exposures

Submits a URL Kanary did not find (manual exposure). Creates a new exposure for the profile.

Not available to trial members; returns 403 (error: trial_not_supported).

Request body

Field Required Description
url Yes Full exposure URL
name_id No Name attribute id on the profile that is exposed
address_id No Address attribute id on the profile that is exposed
email_id No Email attribute id on the profile that is exposed
phone_number_id No Phone attribute id on the profile that is exposed
username_id No Username attribute id on the profile that is exposed
exposed_on_google No Default false, true when the finding is a Google exposure
{
  "url": "https://example-broker.com/profile/12345",
  "name_id": 111,
  "exposed_on_google": false
}

Success (201 Created)

{
  "exposure_id": 123457,
  "member_id": 67890,
  "url": "https://example-broker.com/profile/12345",
  "exposure_status": "ACTIVE",
  "site_id": 99,
  "site_domain": "example-broker.com",
  "site_threat_score": 7.5,
  "scrape_task_id": null,
  "contents": null,
  "screenshot_url": null,
  "last_submitted_at": null
}

Errors

Status Condition
400 Missing url or invalid URL format
401 Missing or invalid bearer token
403 Partner inactive, or member is on a trial account (error: trial_not_supported)
404 Member not found or terminated
409 An exposure for this URL already exists for this member (ACTIVE, BLOCKED, or IGNORED). Use not_about_me / not_a_risk to update an existing exposure’s status instead of re-reporting.
422 URL domain is known but has no removal source configured

Scan-only exposures

A subscription change from Advanced to Core sets exposures to BLOCKED when they are no longer eligible for removal on Core. The count is exposures_blocked on the subscription’s changes.

Trial members cannot suggest exposures: POST .../exposures returns 403. Set a subscription to report missed results.