Unlock

Unlock entities (unified)

Unified unlock endpoint for districts, schools, and contacts. Routes through the unlock orchestrator, which decides between three paths: - **Fast path** (`outcome: "unlocked"`, HTTP 200): the entity already has extracted intelligence on file. Credits are deducted immediately and the intelligence is revealed for this org. - **Slow path** (`outcome: "unlock_pending"`, HTTP 202): the entity has no extracted intelligence yet. Credits are held against your balance, the extraction pipeline is triggered (~3-5 minutes), and the hold is committed to a real deduction on success or refunded on failure. Poll `GET /unlock-status/{entityType}/{entityId}` until the pipeline completes. - **Idempotent** (`outcome: "idempotent"`, HTTP 200): the org has already unlocked this entity. Returns immediately with 0 credits charged. **Contact unlocks require the parent district or school to be unlocked first.** If the parent is locked, the response is 403 PARENT_ENTITY_LOCKED. Optional `re_extract: true` (districts/schools only) re-triggers extraction on an already-unlocked entity. Charges credits again. Not valid for contacts. **Credit costs:** District (6School (6), Contact (2).

POST
/unlock

Unified unlock endpoint for districts, schools, and contacts. Routes through the unlock orchestrator, which decides between three paths:

  • Fast path (outcome: "unlocked", HTTP 200): the entity already has extracted intelligence on file. Credits are deducted immediately and the intelligence is revealed for this org.
  • Slow path (outcome: "unlock_pending", HTTP 202): the entity has no extracted intelligence yet. Credits are held against your balance, the extraction pipeline is triggered (~3-5 minutes), and the hold is committed to a real deduction on success or refunded on failure. Poll GET /unlock-status/{entityType}/{entityId} until the pipeline completes.
  • Idempotent (outcome: "idempotent", HTTP 200): the org has already unlocked this entity. Returns immediately with 0 credits charged.

Contact unlocks require the parent district or school to be unlocked first. If the parent is locked, the response is 403 PARENT_ENTITY_LOCKED.

Optional re_extract: true (districts/schools only) re-triggers extraction on an already-unlocked entity. Charges credits again. Not valid for contacts.

Credit costs: District (6School (6), Contact (2).

AuthorizationBearer <token>

API key (sk_live_... prefix). Generate keys in the UI under Settings > API Keys, then send it as Authorization: Bearer sk_live_...

In: header

Request Body

application/json

entity_type?string

Type of entity to unlock (required for single unlock)

Value in"district" | "school" | "contact"
entity_id?string

Single entity UUID (required for single unlock)

entities?array<>

Array of entities (for batch unlock)

channel?string
Value in"dashboard" | "mcp" | "api"
re_extract?boolean

Re-trigger extraction on an already-unlocked district/school.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://loading/api/v1/unlock" \  -H "Content-Type: application/json" \  -d '{}'
{
  "outcome": "idempotent",
  "unlocked": true,
  "already_unlocked": true,
  "credits_charged": 0,
  "credits_held": 0,
  "credits_remaining": 0,
  "hold_id": "string",
  "operation_key": "string",
  "job_id": "string",
  "message": "string"
}
{
  "outcome": "unlock_pending",
  "unlocked": false,
  "already_unlocked": true,
  "credits_charged": 0,
  "credits_held": 0,
  "credits_remaining": 0,
  "hold_id": "string",
  "operation_key": "string",
  "job_id": "string",
  "message": "string"
}
{
  "error": "string",
  "message": "string",
  "statusCode": -9007199254740991
}
{
  "error": "string",
  "message": "string",
  "balance": 0,
  "required": 0
}
{
  "error": "PARENT_ENTITY_LOCKED",
  "message": "string",
  "parent_entity_type": "district",
  "parent_entity_id": "550e8400-e29b-41d4-a716-446655440000",
  "unlock_cost": 0
}