Skip to content
ContentRemovalDeskDocumentation

Get started

Make your first request

Connect a verified agency, link a creator, and follow a real scan from request to findings.

REST API · JSONv0.2.0 · Live CRD integration
On this page

1. Verify your agency and create a key

Create a CRD agency account at /create-agency and complete onboarding and the existing agency KYC process. After approval, the owner can open /agency/api to provision the agency’s API account automatically. There is no separate API approval or manual enablement step.

Sign in as the agency owner and open /agency/api. Create a key with the permissions your integration needs. Save the complete crd_live_ secret in your server’s secret store when it is shown; it cannot be displayed again.

Use the secret, not the record ID

A key_… value identifies a credential in the dashboard. It cannot authenticate requests. Use the complete one-time secret; create a replacement if it was lost.

2. Confirm your connection

Set CRD_API_KEY in your backend environment. The examples call https://api.crd.systems; to try them against a copy running on your own computer, set CRD_BASE_URL. Call GET /v1/me to check the credential, environment, assigned workspace, and engine configuration.

Use a key with workspaces:read and save the assigned workspace ID. If configuration is unavailable, have CRD restore it before creating resources. A test secret cannot authenticate to the live service.

Choose the enrollment path that matches the creator

Optional aliases and supported profile_urls may be supplied on either enrollment path. A 201 response means the API enrollment was created, not that protection is active. email_sent: true means the email provider accepted the invitation message; it does not prove inbox delivery or acceptance. Invitations expire after seven days. An identical enrollment retry does not resend email; use the existing agency invitation controls for a resend. There is no public API resend endpoint.

Creator situationWhat your backend sendsWhat happens next
Already returned by the agency rosterReuse its returned crt_… ID; use PATCH for identity edits.Read eligibility and explicitly activate if needed. No invitation is required.
Existing CRD creator in this agency; assign your external IDPOST with workspace_id, external_id, display_name, and crd_user_id.Links the existing profile; the current mandate and entitlement remain authoritative.
New creator being invitedPOST with workspace_id, external_id, display_name, email, first_name, last_name, and optional locale.CRD sends the existing invitation email. The creator accepts and completes the required portal steps before eligibility.

4. Read eligibility, then explicitly activate

Read GET /v1/creators/{id} after enrollment. The creator needs an approved, signed, unexpired authorization and an active entitlement. The response reports authorization, entitlement, eligible, and protection_status. A newly created enrollment response is not proof that these checks passed.

When eligible is true, send a separate PUT /v1/creators/{id}/protection with {"status":"active"}. This is required even if the creator was already authorized. Accepting an invitation or approving a mandate does not automatically make that PUT request.

Activation enables the API scan schedule and starts its usage interval. It does not buy, cancel, or replace the native CRD subscription. A Read only key cannot activate; use Read and write.

Enrollment, eligibility, and activation are different

A creator can be linked and eligible while protection_status is still not_activated. Your integration decides when to send the activation request after receiving or reading eligible: true.

Copyable enrollment and activation sequence

This Node.js example uses a Read and write key and the API origin supplied for your account. Replace every fictional identity before sending a live request. For an existing agency creator, use its crd_user_id instead of the email/name invitation fields, or reuse the ID returned by the roster.

The agency’s decision to enable protection belongs in your application. This example represents that saved choice with CRD_PROTECTION_REQUESTED. A successful invitation does not activate protection: the code makes a fresh eligibility read and sends the separate active PUT only when both the saved choice and current eligibility allow it.

After the initial enrollment, store its API creator ID. On creator.updated, refresh that ID and repeat only the eligibility/activation decision. This logic runs in your integration; CRD does not automatically activate a creator merely because its authorization was approved.

Node.js · enroll, inspect, and explicitly activatejavascript
const baseUrl = process.env.CRD_BASE_URL;
const key = process.env.CRD_API_KEY;
if (!baseUrl || !key) throw new Error('Set CRD_BASE_URL and CRD_API_KEY');

async function crd(path, method = 'GET', body) {
  const response = await fetch(`${baseUrl}${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${key}`,
      ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
    },
    ...(body === undefined ? {} : { body: JSON.stringify(body) }),
  });
  const result = await response.json();
  if (!response.ok) throw new Error(`${response.status}: ${result.error?.code}`);
  return result;
}

const connection = await crd('/v1/me');
const enrollment = await crd('/v1/creators', 'POST', {
  workspace_id: connection.workspaces[0].id,
  external_id: 'your-stable-creator-001',
  display_name: 'Example Creator',
  email: '[email protected]',
  first_name: 'Example',
  last_name: 'Creator',
  locale: 'en',
  aliases: ['example_creator'],
  profile_urls: ['https://onlyfans.com/example_creator'],
});
// Save enrollment.id and this original payload in your application.
// 201 creates enrollment; a matching repeat may return 200.
// The invitation email comes from enrollment, not activation.

const current = await crd(`/v1/creators/${enrollment.id}`);
// In production, read the agency's saved choice from YOUR application.
// This environment flag is only a runnable example of that saved intent.
const protectionRequested = process.env.CRD_PROTECTION_REQUESTED === 'true';
if (protectionRequested && current.eligible) {
  const protection = await crd(`/v1/creators/${current.id}/protection`,
    'PUT', { status: 'active' });
  console.log({ creatorId: current.id, protection: protection.protection_status });
} else {
  console.log({ creatorId: current.id, eligible: current.eligible,
    action: protectionRequested ? 'await_creator_requirements' : 'await_agency_choice' });
}
// After creator.updated, run a fresh GET and the decision above again.
// Do not repeat enrollment just to check eligibility or resend an email.

5. Request and follow a scan

Send POST /v1/creators/{id}/scans with an empty JSON body and an Idempotency-Key unique to this logical scan. Save the returned scan ID. A 202 response means queued; poll GET /v1/scans/{id} or receive a signed webhook.

After completion, read GET /v1/creators/{id}/cases. Results use that creator’s native CRD leak records, including existing and scheduled-scan findings. Native findings can have scan_id: null; API scan provenance is preserved when available. Register your HTTPS receiver in /agency/api before requesting the scan if you want its events delivered.

6. Track a deindex request

For an eligible case with verified API-scan provenance, POST /v1/cases/{id}/deindex-requests with provider: google and a stable Idempotency-Key. Store its ID and follow GET /v1/deindex-requests/{id}.

The API queues a real record for CRD processing. Native findings without verified API-scan provenance continue through the existing admin workflow; the API deindex route does not accept them. Acceptance does not mean Google received the request or removed a result. Display submitted_to_provider and removal_verified independently from the request status.

Request & response example

GET/v1/me
curl --request GET 'https://api.crd.systems/v1/me' \
  --header "Authorization: Bearer $CRD_API_KEY"
Use your secret key in the environment variable.
Example response · 200
{
  "partner": {
    "id": "ptn_example",
    "name": "Example Agency",
    "kind": "agency"
  },
  "workspace_id": "wsp_example",
  "key_id": "key_example",
  "scopes": [
    "workspaces:read",
    "creators:read",
    "creators:write"
  ],
  "expires_at": null,
  "environment": "live",
  "workspaces": [
    {
      "id": "wsp_example",
      "name": "Example Agency",
      "external_id": "agency_001"
    }
  ],
  "engine_configured": true
}

Illustrative response. Replace example resource IDs with the IDs returned by your API requests. View endpoint details.