---
title: "Admin Client Detail"
method: GET
path: "/api/v1/admin/clients/{client_id}"
tags: ["admin"]
---

# Admin Client Detail

`GET /api/v1/admin/clients/{client_id}`

## Request

- Base URL: `https://api.nudgelink.co` (the document declares no server; this is the origin it was published from)
- URL: `https://api.nudgelink.co/api/v1/admin/clients/{client_id}`
- Auth: HTTP bearer

Everything an admin needs in one round-trip for the client-detail page.

Returns 404 if the client doesn't exist.

## Path parameters

- `client_id` string, uuid, required

## Response `200`

Successful Response

- AdminClientDetail
  - `id` string, uuid, required
  - `email` string, required
  - `company_name` string, required
  - `industry` string, required
  - `role` string, required
  - `subscription_plan` string, nullable, required
  - `plan_comped` boolean, required
  - `guarantee_status` string, required
  - `pilot_start_at` string, date-time, nullable, required
  - `pilot_expires_at` string, date-time, nullable, required
  - `created_at` string, date-time, required
  - `email_verified` boolean, required
  - `totp_enabled` boolean, required
  - `google_sub` string, nullable, required
  - `microsoft_sub` string, nullable, required
  - `disabled` boolean, required
  - `campaign_first_ux` boolean
  - `credits_balance` integer, required
  - `credits_included` integer, required
  - `credits_used_this_cycle` integer, required
  - `billing_cycle_start` string, date-time, nullable, required
  - `outreach_auto_send` boolean, required
  - `languages` string[], nullable, required
  - `calibration_anchors` object[], nullable
  - `icp_summary` string, nullable
  - `icp_criteria` string[]
  - `icp_keywords` string[]
  - `icp_industries` string[]
  - `icp_skills` string[]
  - `icp_locations` string[]
  - `extra_accounts_count` integer, required
  - `avg_deal_size_usd` number, nullable, required
  - `has_stripe_subscription` boolean, required
  - `total_paid_usd` number, required
  - `total_refunded_usd` number, required
  - `comped_credits_total` integer, required
  - `net_revenue_usd` number, required
  - `lead_count` integer, required
  - `sequence_counts` object, required
  - `account_count` integer, required
  - `accounts` AdminAccountMini[], required
    - `id` string, uuid, required
    - `label` string, required
    - `status` string, required
    - `warmup_week` integer, required
    - `ban_count` integer, required
    - `last_action_at` string, date-time, nullable, required
  - `recent_sequences` AdminSequenceMini[], required
    - `id` string, uuid, required
    - `lead_id` string, uuid, required
    - `lead_name` string, required
    - `status` string, required
    - `current_step` string, required
    - `next_action_at` string, date-time, nullable, required
    - `updated_at` string, date-time, required
  - `recent_billing` AdminBillingMini[], required
    - `id` string, uuid, required
    - `event_type` string, required
    - `amount` number, required
    - `reason` string, nullable, required
    - `created_at` string, date-time, required
  - `recent_audit` AdminAuditMini[], required
    - `id` string, uuid, required
    - `created_at` string, date-time, required
    - `actor_role` string, required
    - `action` string, required
    - `resource_type` string, nullable, required
    - `resource_id` string, uuid, nullable, required
  - `responded_leads` AdminRespondedLead[], required
    - `lead_id` string, uuid, required
    - `name` string, required
    - `company` string, required
    - `title` string, required
    - `status` string, required
    - `relevance_score` integer, nullable, required
    - `last_inbound_text` string, nullable, required
    - `last_inbound_classification` string, nullable, required
    - `last_inbound_at` string, date-time, nullable, required
  - `outreach_stats` AdminClientOutreachStats, required: Per-client outreach success funnel (board ask 2026-07-13: "% successful answers" on the client's admin page). Denominator is invites actually SENT — a connection request that left the building — not leads merely found, so the rate isn't diluted by warmup-heavy pilots that haven't invited yet. reply_rate / positive_rate are None when nothing has been sent yet.
    - `invites_sent` integer, required
    - `messages_sent` integer, required
    - `replies` integer, required
    - `positive_replies` integer, required
    - `reply_rate_pct` number, nullable, required
    - `positive_rate_pct` number, nullable, required
  - `outreach` OutreachStats, required
    - `invites` InviteStats: Connection requests. ``*_pct`` are None (never 0.0) on an empty base. THREE outcomes, not two (added 2026-08-07 after the first production backfill). An invite we sent is in exactly one of: * **accepted** — ``invite_accepted_at`` is stamped. * **declined** — we looked AFTER inviting and they are still not a connection. "Declined" is shorthand: it also covers ignored. * **unknown** — we have no observation since the invite went out. That third bucket is not a technicality. Relationship distance is only refreshed by the DM gate, which runs when a sequence reaches ``linkedin_followup_1``; ``warmup_view``'s blob is written BEFORE the invite and carries no timestamp at all. So a lead whose follow-up is still sitting in the preview queue has never been re-checked, and folding those into the denominator reports them as rejections. The first prod run showed exactly that: 379 invites, 376 "not 1st-degree", an 0.8% accept rate. Real cold-invite accept rates are 15-40%. Nearly all of that 376 was "we never looked", and dividing by it would have put a catastrophic-looking number in front of clients. So ``accept_rate_pct`` divides by **accepted + declined** — what we actually know — and ``unknown`` is reported alongside so the number can be read with its own confidence attached. The bucket shrinks toward zero once PR 2's ``relation.new`` webhook lands, which is the real fix.
      - `sent` integer
      - `with_note` integer
      - `without_note` integer
      - `accepted` integer
      - `accepted_with_note` integer
      - `accepted_without_note` integer
      - `declined` integer
      - `unknown` integer
      - `judged` integer
      - `judged_with_note` integer
      - `judged_without_note` integer
      - `accept_rate_pct` number, nullable
      - `accept_rate_with_note_pct` number, nullable
      - `accept_rate_without_note_pct` number, nullable
    - `replies` ReplyStats: Messages sent and what came back. ``contacted`` counts SEQUENCES (people) reached by any substantive step, not messages — an invite plus two follow-ups to one lead is one person. ``silent`` is the complement, so positive + neutral + negative + unclassified + silent == contacted.
      - `dms_sent` integer
      - `emails_sent` integer
      - `contacted` integer
      - `replied` integer
      - `reply_rate_pct` number, nullable
      - `positive` integer
      - `neutral` integer
      - `negative` integer
      - `unclassified` integer
      - `silent` integer
    - `comments_sent` integer

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/nudgelink/apis/nudgelink-api.md) · [All operations](https://skmtc.dev/nudgelink/apis/nudgelink-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nudgelink/apis/nudgelink-api/revisions/baa46e6db986?raw)
