Account resources. The profile on an account, its products, subscription, and scan history are in Members.
| Resource | Path | Purpose |
|---|---|---|
| Accounts (collection) | /api/v1/accounts/ |
GET paginated accounts; count is all accounts (ACTIVE, INVITED, and TERMINATED); POST create account with its member (Create account) |
| Account | /api/v1/accounts/{account_id}/ |
Retrieve or delete one account (delete cascades to the member) |
| Account onboarding invite | /api/v1/accounts/{account_id}/send_onboarding_invite/ |
POST send onboarding invite email |
| Members | /api/v1/members/ |
Profiles, products, subscriptions, credits, and scan history (Members) |
primary_subscription_product_id is a shortcut to that member’s subscription product_id. It is null when the member has no subscription.
On-demand products keep credits assigned from the org pool (Scan credits, Credit pool).
POST /api/v1/accounts/
Creates an account with one member and the products in product_ids. Profile field shapes are in Profile fields. An on-demand id draws one credit from the org pool and leaves primary_subscription_product_id null unless a subscription id is included. A subscription id consumes one seat and sets primary_subscription_product_id to that product_id. This happens at create time for both ACTIVE and INVITED accounts. Sending an onboarding invite does not add a product.
Products are listed in Product API. For a subscription, pick a product_id with available > 0 on GET /api/v1/seats/. When available is 0, buy more with POST /api/v1/seats/. For an on-demand product, pick a product_id with available > 0 on GET /api/v1/credits/. When that available is 0, buy more with POST /api/v1/credits/.
| Field | Required | Description |
|---|---|---|
email |
Yes | Login email for the new account |
product_ids |
Yes | One or more ids from GET /api/v1/products/. At most one subscription. Each on-demand id draws one credit from the org pool. Each subscription id needs an available seat |
status |
No | "ACTIVE" (default) or "INVITED". ACTIVE provisions a ready-to-use account with no onboarding email. INVITED creates the account without email; call POST .../send_onboarding_invite/ to send it |
birth_year |
No | Available. Current year − 150 … current year |
birth_month, birth_day |
No | Available. 1–12 / 1–31 |
names |
No | Available. Same shape as Profile fields |
addresses |
No | Available. Same shape as Profile fields |
emails |
No | Available. Same shape as Profile fields |
phone_numbers |
No | Available. Same shape as Profile fields |
usernames, employers |
No | Available. Same shapes as Profile fields |
Profile fields other than email are optional. Without a name, city, state, or birth year, scan and removal on the account are severely limited.
product_ids 101 is Core. That consumes one seat and sets primary_subscription_product_id to 101.
POST /api/v1/accounts/
{
"email": "newuser@example.com",
"product_ids": [101],
"status": "INVITED",
"birth_year": 1990,
"names": [{ "first_name": "Jane", "last_name": "Smith", "no_middle_name": true }],
"addresses": [{ "city": "New York", "state": "NY", "country": "US" }]
}
product_ids 201 is an on-demand product. The member is assigned one credit from the org pool. primary_subscription_product_id is null. No scan runs until POST /api/v1/scan/.
POST /api/v1/accounts/
{
"email": "scanonly@example.com",
"product_ids": [201],
"status": "ACTIVE",
"birth_year": 1990,
"names": [{ "first_name": "Jane", "last_name": "Smith", "no_middle_name": true }],
"addresses": [{ "city": "New York", "state": "NY", "country": "US" }]
}
201 Created)Returns the account object (same shape as list/retrieve), including account_id and members.
| Event | Effect |
|---|---|
POST /api/v1/accounts/ succeeds |
One product on the account per product_ids entry. Subscription: one seat, and primary_subscription_product_id is set. On-demand: one credit drawn from the org pool, and primary_subscription_product_id stays null unless a subscription id was included |
| Account deleted with unspent on-demand credits | Those credits return to the org pool available (Credit pool). Spent credits stay spent |
Credit consumed by POST /scan/ |
credits_remaining on that product goes down by one. The spend is listed on that product’s credits |
| Account deleted while it holds a subscription product | The seat returns to available |
POST .../send_onboarding_invite/ |
No credit and no seat change |
| Status | Condition |
|---|---|
400 |
Validation error, duplicate email, empty product_ids, unknown id (error: product_not_configured), or more than one subscription in product_ids (error: use_subscription_update) |
401 |
Missing or invalid API key |
402 |
No available seat (error: insufficient_seats; includes product_id and available). Buy with POST /api/v1/seats/ and retry. Or the org credit pool available is 0 for an on-demand id (error: insufficient_credits; includes product_id and available). Buy with POST /api/v1/credits/ and retry |
403 |
Partner inactive |
GET /api/v1/accounts/
Returns a paginated page of accounts for the authenticated partner. count includes all accounts: ACTIVE, INVITED, and TERMINATED. Load partner metadata from GET /api/v1/ separately. See Pagination.
| Param | Default | Max | Description |
|---|---|---|---|
limit |
100 |
250 |
Accounts per page (Pagination) |
offset |
0 |
— | Starting index into the account list |
GET /api/v1/accounts/?limit=50&offset=50
| Top-level key | Description |
|---|---|
count |
All accounts: ACTIVE, INVITED, and TERMINATED |
next |
URL for the next page, or null |
previous |
URL for the previous page, or null |
results |
Current page of accounts, including terminated rows |
Each page includes non-terminated accounts first (ACTIVE, then INVITED), then terminated accounts newest first. Non-terminated rows include a members array (active profiles only) and products, the active products on that account. Terminated rows are redacted (PII removed on termination). Follow next until it is null to enumerate the full directory. Every product on the member, including terminated rows and on-demand products with credits_remaining 0, is on GET /api/v1/members/{member_id}/products/. Credit balances are on GET /api/v1/members/{member_id}/credits/.
Each entry in results uses this shape (terminated rows redact PII as noted).
| Field | Type | Description |
|---|---|---|
account_id |
integer | Account primary key |
status |
string | "ACTIVE", "INVITED", or "TERMINATED" |
primary_email |
string | Login or contact email; "redacted" when terminated |
primary_subscription_product_id |
integer | null | Shortcut to the primary member’s subscription product_id. Set when that member’s is_primary is true. null when the member has no subscription |
products |
array | Active products on the account’s member. Same object as Product API. Inactive rows are on GET /api/v1/members/{member_id}/products/ |
created_at |
string | When the account was created (UTC, ISO 8601; see Partner timestamps) |
terminated_at |
string | null | When the account was terminated; null unless status is "TERMINATED" |
members |
array | Active members. See Member summary. [] when terminated |
removed |
integer | null | Account removal total using the dashboard’s counting rules; 0 when none qualify, null when terminated |
removed counts results currently marked removed across all members of the
account, including terminated members. It has no date filter. Listing pages,
linked aggregator results (such as a Google copy of a source result), and results
still exposed on Google are excluded. The active-only members array is not the
scope of this count; use the same account and member scope when comparing it with
the dashboard.
A page that disappears without a submitted removal request can count. This is a count of recorded removal status, not proof that Kanary caused the removal. It is not a cumulative count of removal events: a result that becomes active again no longer counts. Date-filtered dashboard totals can differ from this account total.
An account with no active subscription and no credits stays "ACTIVE" and has no actions available. Scan and removal calls return 402 (error: no_actions) until credits or a subscription are added.
{
"results": [
{
"account_id": 12345,
"status": "ACTIVE",
"primary_email": "enduser@company.com",
"primary_subscription_product_id": 101,
"products": [
{
"product_id": 101,
"product_name": "Core",
"description": "Scan and removal subscription on the Core catalog.",
"charge_type": "subscription",
"billing_frequency": "monthly",
"price_per_seat": 999,
"credits_remaining": null
}
],
"created_at": "2026-01-15T10:00:00.456789+00:00",
"terminated_at": null,
"removed": 12,
"members": [
{
"member_id": 67890,
"primary_name": "Bob Example",
"primary_email": "bob@example.com",
"is_primary": true,
"profile_threat_score": 6.2
}
]
},
{
"account_id": 12000,
"status": "ACTIVE",
"primary_email": "scan@company.com",
"primary_subscription_product_id": null,
"products": [
{
"product_id": 201,
"product_name": "Core Scan",
"description": "On-demand scan of the Core catalog.",
"charge_type": "on_demand",
"billing_frequency": "one_time",
"price_per_seat": 299,
"credits_remaining": 1
}
],
"created_at": "2026-09-01T09:00:00.000000+00:00",
"terminated_at": null,
"members": [
{
"member_id": 70001,
"primary_name": "Scan User",
"primary_email": "scan@company.com",
"is_primary": true,
"profile_threat_score": null
}
]
},
{
"account_id": 12001,
"status": "ACTIVE",
"primary_email": "nocredits@company.com",
"primary_subscription_product_id": null,
"products": [],
"created_at": "2026-09-10T09:00:00.000000+00:00",
"terminated_at": null,
"members": [
{
"member_id": 70002,
"primary_name": "No Credits",
"primary_email": "nocredits@company.com",
"is_primary": true,
"profile_threat_score": 4.1
}
]
},
{
"account_id": 11000,
"status": "TERMINATED",
"primary_email": "redacted",
"primary_subscription_product_id": null,
"products": [],
"created_at": "2025-11-01T09:00:00.000000+00:00",
"terminated_at": "2026-04-10T16:30:00.000000+00:00",
"removed": null,
"members": []
}
],
"count": 4,
"next": null,
"previous": null
}
| Status | Condition |
|---|---|
400 |
Invalid limit or offset |
401 |
Missing or invalid API key |
403 |
Partner inactive |
GET /api/v1/accounts/{account_id}/
POST /api/v1/accounts/{account_id}/send_onboarding_invite/
Sends the partner onboarding invite email to the account’s login address (primary_email). The partner admin linked to the API key is CC’d. Safe to call again to resend.
Account must have status "INVITED". Create invited accounts with POST /api/v1/accounts/ and "status": "INVITED" (no email is sent on create).
No request body.
POST /api/v1/accounts/12345/send_onboarding_invite/
200 OK){
"sent": true
}
| Status | Condition |
|---|---|
400 |
Account is not INVITED, is terminated, email send failed, or authenticated user has no linked account |
401 |
Missing or invalid API key |
403 |
Partner inactive |
404 |
Account not found |
DELETE /api/v1/accounts/{account_id}/
Permanently terminates the account and every member on it. All PII on the account and across all profiles is cleared. Deleted PII cannot be recovered.
DELETE /api/v1/accounts/12345/?confirm=true
Omit confirm or any value other than true returns 400 Bad Request with a message explaining that deletion is irreversible and requires confirmation.
GET /api/v1/accounts/ as a redacted terminated row.| Scope | Preserved metadata |
|---|---|
| Account | created_at, terminated_at, primary_subscription_product_id, and the products that were on the account (product_id, credits_remaining) |
| Members | Per-member created_at, terminated_at (one entry per deleted profile) |
| Exposures | Count of exposures found, aggregated across all members on the account |
| Sites | Domains / sites where information was found (no PII content) |
| Attributes | Count of profile attributes that were on the account (totals across members), not the attribute values |
200 OK){
"message": "Account deleted. All personally identifiable information for this account and every profile on it has been permanently cleared and cannot be recovered.",
"account_id": 12345,
"terminated_at": "2026-05-19T14:30:00Z",
"members_deleted_count": 1,
"metadata": {
"account": {
"created_at": "2026-01-15T10:00:00Z",
"terminated_at": "2026-05-19T14:30:00Z"
},
"members": [
{
"member_id": 67890,
"created_at": "2026-01-20T09:00:00Z",
"terminated_at": "2026-05-19T14:30:00Z"
}
],
"results_found_count": 120,
"profile_attributes_count": 12
}
}
Display message to the end user as the final confirmation after delete completes.
| Status | Condition |
|---|---|
400 |
confirm query parameter missing or not true |
404 |
Account not found |
With no active subscription and no credits, a further POST /api/v1/scan/ returns 402:
{
"error": "no_actions",
"message": "This account has no actions available.",
"account_id": 12000
}
{
"account_id": 12000,
"status": "ACTIVE",
"primary_subscription_product_id": null,
"products": [
{
"product_id": 201,
"product_name": "Core Scan",
"description": "On-demand scan of the Core catalog.",
"charge_type": "on_demand",
"billing_frequency": "one_time",
"price_per_seat": 299,
"credits_remaining": 1
}
]
}
The example above is the active products array on the account: Core Scan still has a credit. Every product on the member, including a spent on-demand row with credits_remaining 0, is on GET /api/v1/members/{member_id}/products/. With no active subscription and no credits left on any product, the account has no actions available.