{"version":"v1","entries":[{"date":"2026-09-25","changes":["people_search with connection_degrees ['1st'] and network_filter_mode 'filter' now checks every included source (Super Carl, LinkedIn, Gmail, Calendar, Contacts, X, Instagram) for a current first-degree connection and returns only people at least one source confirms. People no source confirms are left out; when a source cannot be checked, the people only it could confirm are withheld and a first_degree_count_not_fully_verified warning names that source (a source that could be checked for only some people is named as partly checked). Integration-review lists keep their provider membership.","composition_v2 rows pages for that filter no longer include a pool count (count, cohort_count, exportable_people) or the full-list export offer: the indexed total is not a verified count, so the count is unknown rather than zero. mode:'count' reports the verified count with basis qualified_rows, relation exact, or lower_bound when only part of the candidates could be checked. Offsets count confirmed people. Each page checks candidates from the start of the list: at least 200 for a 25-row page, and 25% more than offset + limit on deeper pages, with no upper limit. When those candidates hold too few confirmed people for the page while more candidates remain, the same request fetches one larger list, sized to the share of candidates that were confirmed and at most four times the first list. It does so only when no other ranking or verification step shares that list (for example location, network warmth or context ranking, or a posts or education requirement), so every page of such a search is taken from the same list. Candidates are checked in batches of 1,000 and none is checked twice, so a single request above 1,000 rows is fully checked. If the page still falls short while more candidates remain, it returns the confirmed people it has with has_more false, coverage_status partial_unpageable and a bounded_partial_underfill (or bounded_partial_zero) warning that more connections may exist but could not be checked in this request. A page filled exactly by the last confirmed people the next request could reach closes the same way (with a bounded_partial_unpageable warning) instead of offering a next page that would be empty. When no candidates remain it is a normal last page.","For those results, a first_degree_count_not_fully_verified warning also explains a result with no confirmed connection: how many people were excluded because no included source currently lists them as a first-degree connection, and whether more remain unchecked. linkedin_connected, is_linkedin_connection, supercarl_connected and is_super_carl_connection are null (unknown) when that source was not checked for the person, instead of false. It counts as not connected only people whose sources were checked, and says more remain unchecked only when there are candidates the request did not check. On the legacy people_search response, counts.first_degree_verification now lists only status, relation, the candidate counts, and unchecked_sources and partially_checked_sources by display name, and counts.note describes the result in plain words.","For that filter, a lower_bound first-degree count no longer reports the search's result-count cap (such as cap 10000 with reason result_count_cap): the bound comes from the first-degree check, so count and cohort_count omit cap and give reason lower_bound_reported_by_backend, and the legacy response has result_count_capped false and no result_count_cap. When the search merges several indexed records of one person into a single candidate, those records no longer count as unchecked: if every candidate was fetched and checked, the count is exact (and a rows page ends as a normal last page) instead of a lower bound."]},{"date":"2026-09-24","changes":["Removed the yc and company_sub_stage company filters from MCP search tools; requests that send them now fail validation. yc only added ranking boosts, and company_sub_stage has no indexed data (the company_sub_stage output field is always empty). Use company_tags (or evidence_requirements on company_search) for accelerator membership, and company_stage or funding.stages for stage.","Related company clauses (filters.companies[].where on people_search, jobs_search, posts_search and company_search) now reject department_headcount (which previously failed at execution), job_keyword_hints and yc (which were silently ignored) at validation. department_headcount and job_keyword_hints still work in company_search's own filters.where.","company_search: when filters.where.department_headcount sets min or max, the where may contain only identity, location, industries, categories, company_tags, industry_keywords, company_headcount and preferences, and query must be empty. Other fields now fail with department_headcount_unsupported_siblings (details.unsupported and details.supported list the fields) instead of being silently dropped.","Clarified that company where preferences never change membership or order; they only annotate primary company rows with matched-preference evidence. Inside a company any_of branch, company_tags and categories now combine with OR, as they already did at the top level.","Retired posts_search filters.where.mode: post criteria are always eligibility filters, and keyword ranking follows keyword_match_mode. A sent where.mode is stripped with an omit_retired_where_field entry in request_normalizations instead of being rejected. request_normalizations receipts appear on successful search results and on invalid_search_request errors.","Posts action_types (posts_search and related post clauses) now accept only post, repost and comment; like and reaction never matched indexed activity. Mixed with supported values, like and reaction are stripped with an omit_retired_action_types receipt; sent alone they fail validation. Searches for people who liked or reacted to posts are not supported; reaction-count thresholds are unaffected.","posts_search with a mentioned phrase and keyword_match_mode=hard now requires the mention and at least one additional_context_keywords_core term, instead of silently dropping the core terms. Core terms that repeat the mentioned phrase are ignored, and supporting terms add scoring only when a core term remains.","Range filters no longer count missing data as zero: years_experience and average_role_tenure_months ranges require a positive value, and company revenue ranges (company_search where.revenue and people_search where.company_revenue) exclude companies with no revenue data. Max-only bounds such as under 2 years or under 1M USD revenue now return fewer, accurate rows, and an experience or tenure range whose min exceeds max matches nothing. Applies to MCP and the REST search API.","people_search where.languages.proficiency is now a closed set on MCP: Elementary proficiency, Limited working proficiency, Professional working proficiency, Full professional proficiency, Native or bilingual proficiency. Values in another letter case are canonicalized (canonicalize_language_proficiency receipt); anything else, such as fluent, fails validation (for fluent, send Full professional proficiency and Native or bilingual proficiency). Matching is now case-insensitive on MCP and REST; REST does not validate the value.","Fixed filters that matched almost nothing: education.fields_of_study now also matches degree text, where most majors are stored, and company_status closed (with synonyms such as defunct, shut down, dissolved and inactive) now resolves to the stored value closed. Canonical company statuses are active, acquired and closed.","jobs_search where.job_titles and where.locations are capped at 8 values each. On the primary where, longer lists are cut to the first 8 with a truncate_to_execution_cap receipt whose keys give each omitted entry's index path (for example $.filters.where.locations[8]); related job clauses with more than 8 values fail validation. published_after and published_before must be ISO-8601 dates (YYYY-MM-DD, optionally with a time and zone); use published_within_days for relative windows.","jobs_search now maps retired MCP shapes instead of rejecting them, each with a request_normalizations receipt: filters.hiring criteria move to filters.where when where is empty and hiring.mode is absent or must (move_legacy_hiring_criteria); preview_limit becomes limit, capped at 25 (rename_legacy_control); with_people=true becomes answer_projection=person.warm_paths (map_legacy_with_people); with_people=false and people_per_company are dropped (omit_legacy_default, omit_legacy_control); unsupported ranking.emphasis values are dropped (omit_unsupported_ranking_emphasis, keys naming each dropped entry's index path such as $.ranking.emphasis[0]). preview_limit, with_people and people_per_company are also accepted as strings (\"10\", \"true\", \"false\"), since MCP hosts that no longer see them in the schema send them that way. hiring.mode=boost, other hiring keys, and preview_limit sent together with limit are still rejected. New integrations should send filters.where, limit and answer_projection directly.","people_search where.connected_to and exclude_connected_to accept at most 25 people on MCP (more fails validation; the REST search API still uses the first 25). Searches now fail closed instead of silently widening: if an exclude_connected_to person cannot be resolved, or a hiring mode=must filter with only recency criteria cannot be evaluated, the search returns zero rows with the query degradation exclude_connected_to_unresolved or hiring_must_unresolved_failed_closed. Treat these zeros as inconclusive, not as proof that no one matches.","Fixed exports, project audiences and Google Sheet syncs of searches that use related company, job or post clauses; they previously failed on replay. Saved watches and exports that carry the retired posts where.mode or like/reaction values keep replaying unchanged.","A caller-supplied answer_projection (for example jobs_search person.warm_paths or posts_search person.authors) is now kept when a query is also sent; the query planner previously could replace it. An answer_projection that cannot combine with the planned request fails with invalid_search_request instead of being dropped.","people_search sort_by=last_name orders by the full display name, first name first, in case-sensitive order; there is no surname field (the REST search API also accepts name and full_name for it). An omitted sort_order now defaults to asc (A to Z) for last_name; every other sort key still defaults to desc. Profiles without a name sort last in both directions."]},{"date":"2026-09-23","changes":["MCP send_communication: the channel enum now lists only the seven send channels (supercarl_direct_message, supercarl_invite, supercarl_referral_request, gmail_send, linkedin_send_message, x_send_message, instagram_send_message); filter mode=history with history_channel. A live gmail_send (mode=send, not a dry run) now requires a reviewed recipient_email and otherwise returns recipient_email_required. offset for mode=history on send_communication and communication_read is bounded 0-1000.","send_communication drafts need a target that resolves to a Super Carl person (target_user_id, project_target_id, or a LinkedIn URL or username; recipient_email or an X/Instagram handle works only when it matches an existing person), and a Gmail draft needs subject but not recipient_email. For mcp_session_project_required (409), save a draft first, pass an existing project_id, or reuse agent_session_id from a related call. The 200-character connect_note limit counts expanded links, and longer notes are cut at a word boundary.","POST /api/v1/communications: an invalid channel returns 400 with code=invalid_channel and allowed_channels. For gmail_send, an accepted caller-supplied recipient_email is used first; if it is rejected as undeliverable or stale, the email goes to the person's validated address and the response adds recipient_email_substitution (requested_recipient_email, recipient_email, reason). MCP send_communication returns the same field.","POST /api/v1/communications/history now requires at least one target identifier (target_user_id, assignment_target_id, a LinkedIn/X/Instagram URL or username, or recipient_email) and otherwise returns 400 with code=target_identity_required. When no Super Carl person resolves, has_prior_send is null (unknown, not never contacted) and history_coverage=target_unresolved; with history_fresh=true, linkedin_history.refresh_skipped_reason is target_unresolved. offset is limited to 0-1000, and has_more is false once offset reaches 1000. MCP mode=history returns the same body.","Super Carl communication tools: introduction_read without request_ref now lists your introduction cases (first page only; the listing cursors are null and has_more discloses more). inbox_read, conversation_read and introduction_read page with pagination.next_cursor. communication_action accepts the sc:message: and sc:introduction: refs the reads return, and its receipt is null until the action is dispatched. Descriptions now state the OAuth scope each kind needs, that body length counts UTF-16 code units (emoji count 2), and that max_body_bytes x limit may not exceed 2048 when limit > 1. Body-budget error messages name the snake_case fields; error codes are unchanged.","MCP credits: structuredContent.credits and the Credits: X/Y used this period; Z remaining line now include the returning call's own charges (best effort; settled usage only if pending charges cannot be read), and the LOW BALANCE warning uses that post-call balance. contacts_action enrich with mode=run and export with mode=start are now credit-gated and can return the handled credits_exhausted, organization_search_disabled or credit_status_unavailable results.","MCP output schemas now match what tools return, so strict clients no longer reject valid results. Nullable: project_action project and current_session_project; project_read current_session_project (with new current_session_project_reason); contacts_action export_id, task_id and export; report_feedback feedback_id and signal_type; communication_action receipt. contacts_action action can also be confirm_candidate, reject_candidate, mark_needs_review, ignore_entity or restore_entity. send_communication and communication_read declare their real keys, including delivery_receipt and recipient_email_substitution. Search results declare employer_industry_exclusion.candidate_recall_complete and count.bounded_candidate_count; replay_search_result requires only success; company_search_batch tool_execution_failed errors carry contract_version 2 instead of phase.","Fixed project_read mode=counts, which returned only session_binding; it now returns the counts or cohort preview payload. project_action generate_templates infers template_type from a single supplied template field (default outreach_message_prompt) and returns template_type_required when several are supplied. outreach_intent_type now lists its accepted values, and engagement_mode_schedule_live_duration is an integer from 5 to 240.","bulk_export: Google Sheet exports need a project scope; saved search scopes (source_search_id, source_search_ids) and personalized_message_mode=generate are CSV-only. match_reason_mode requires include_match_reasons=true and professional_email_mode requires include_professional_email=true. total_matches_relation and count_relation can now be unknown (neither exact nor a lower bound). Google Sheet errors now suggest saving the people with project_action mode=add_targets.","watch_signals: removed the competitor_engagement signal type and the watch_list and company source kinds, which the service already ignored. schedule.at must be zero-padded 24-hour HH:MM, and weekday applies only to weekly schedules. message sets exact copy only for a single signal_hit_id; batch promotes get generated drafts. The conversation_watch_already_exists retry template no longer includes conversation_id. Fixed watch_signals_read mode=hits paging with after_cursor, which previously returned the first page again.","discover_employers: filters.where.job_titles now requires mode=must and current_only=true, and locations requires scope=current (defaults removed; other values already failed). next_call.arguments now contains only fields the schema accepts, so it can be replayed verbatim.","contacts_action reconcile now advertises the input bounds the REST API already enforced (row field lengths, list sizes, limit 1-100 (get_candidates 1-25), identity_resolution_limit 0-100). Over MCP, bulk_confirm_candidates takes review_items with entity_id and a reviewed candidate_user_id. The minimal list_review projection (MCP and GET /api/v1/contacts/reconciliation/review with response_verbosity=minimal) no longer returns next_actions. enrich with mode=run and no user_confirmed now returns confirmation_required with a callable contacts_action estimate step instead of a server error.","people_search can now start with only include_user_ids and no query, and jobs_search with only a ranking object. people_search row pages now carry result_replay, including byte-truncated pages; result_replay.recorded_rows is the full recorded page size, which can exceed the rows returned, and replay_search_result re-pages it at no credit cost. replay_search_result experience_detail=full returns up to 12 roles plus experiences_omitted, and people_lookup_batch returns full cached role history for small batches.","MCP search tools now reject inputs beyond the limits execution honors instead of silently truncating or clamping them: people_search additional_context_keywords_core and additional_context_keywords_supporting max 15 each, experience_clauses[].titles max 20, keywords max 64, within_recent_roles 1-20, linkedin_connected_within_days 1-3650; posts_search additional_context_keywords_supporting max 24. The REST search API still applies the same limits silently.","Paging: continue people_search and posts_search with next_page.request sent unchanged. Clarified that company_search and jobs_search return final pages (no offset or next_page); raise limit or refine filters for other rows, and treat has_more as incomplete coverage. applied_request and next_page.request now keep up to 100 list items and 2000-character strings, so replaying them preserves exclusions and identity lists.","jobs_search evidence_terms and evidence_groups require match_mode=posting_text; evidence_groups takes 1-3 OR-groups with 8 phrases in total and cannot be combined with evidence_terms. posts_search: with text criteria, results rank by relevance first and metric sorts only break ties; recent sorts newest first; sort_order applies only to metric sorts.","Sessions: session_binding is attached only to session-aware tools and calls that are actually bound. The unbound-session receipt no longer includes recommended_next_call; omit agent_session_id on the first session-aware call and reuse the returned one. An invalid agent_session_id returns success=false with code=invalid_agent_session and retryable=false. Bound non-search tools also report the session in their text content.","OAuth insufficient_scope step-up challenges now request the caller's current scopes plus the missing ones, so re-authorizing keeps existing grants; structuredContent.required_scopes still lists only the missing scopes.","social_proximity_status intro_path_limit, possible_intro_limit and mutual_connection_limit have a minimum of 1, and 0 or an omitted value returns 1 row per list. Polling research status (MCP or REST) may queue server-side ranking of intro paths already found but never starts or refreshes research. Corrected the documented default intro_path_limit to 1 (max 20).","Error-recovery hints (mode_contract, action_contract, required_next_call, next_actions and retry templates) now name only tools and fields the MCP server accepts. For example, communication_read errors no longer suggest allow_email_enrichment or history_fresh, and its LinkedIn history recheck action targets communication_read and is also returned while linkedin_history.tracking_status is pending or running.","/public/docs/mcp now lists only the tools available to every account. The MCP integration guide in /public/docs/schema and get_product_help answers now teach only accepted call shapes: one people_search with a query or target_name, then inspect request.applied_request and correct with a new search; jobs_search answer_projection=person.warm_paths; posts_search answer_projection=person.authors or company.official_authors; direct lookup with people_lookup_batch; Contacts scoping in filters.where. preview, query_plan_handle, filter_updates and with_people are not part of the MCP search contract."]},{"date":"2026-07-15","changes":["Changed MCP credits_exhausted responses to handled structured results with success=false, error=credits_exhausted, remaining balance, and reset date on the normal result path so MCP hosts do not wrap them as runtime exceptions."]},{"date":"2026-07-09","changes":["Added duplicate-profile collision guards to contacts_reconcile so distinct names with distinct LinkedIn identities are held for review instead of being confirmed onto one shared Carl profile.","Added correct_resolution and bulk_correct_resolutions MCP modes plus matching REST endpoints to reject a wrong profile link, detach it safely, or reassign the contact to a distinct profile or exact stored LinkedIn identity.","Resolution correction now suppresses rejected candidates from review/candidate results and removes stale Contacts edges only when no other confirmed contact entity still uses that profile."]},{"date":"2026-06-30","changes":["Added the REST API-only contacts-delegate-resolve scope.","Added POST /api/v1/contacts/delegate-resolve for resolving up to 100 contact rows from a supplied delegate perspective by Super Carl id or LinkedIn identity.","Documented compact field projections, opt-in evidence persistence, hashed phone/email signal storage, and the explicit exclusion from MCP/OAuth connector scope advertisement.","Added delegated contact resolve billing: dry-run previews charge 0.01 credits per requested contact without persisting evidence, non-dry-run high-confidence resolved rows charge 0.10 credits each, ambiguous/unresolved/delegate-404 rows are free for live resolve billing, cached email projection is free, and successful explicit provider email enrichment charges 0.04 credits each."]},{"date":"2026-06-29","changes":["Added compact/minimal/detailed response projections to contacts_reconcile list_review so agents can page 100 review rows without hydrated metadata overflow.","Added bulk contacts_reconcile review modes and POST /api/v1/contacts/reconciliation/review/bulk for confirming, rejecting, marking needs-review, ignoring, or restoring up to 100 review entities per call.","Updated contact exports so unresolved review tabs include the proposed candidate target id, profile/linkedin URLs, score, and match reason."]},{"date":"2026-06-24","changes":["Added contacts-read and contacts-write API scopes.","Added the contact reconciliation API under /api/v1/contacts/reconciliation for schema discovery, run creation, 100-row preview/apply batches, run status/finalize, and incoming/review parity actions for likely-match confirmation, rejection, needs-review, ignore, and restore.","Added the contacts_reconcile MCP tool, backed by the same public API, so coworking agents can normalize user-supplied contact spreadsheets and safely reconcile rows without silently confirming likely matches.","Updated contact reconciliation read/setup routes so existing MCP connector keys with the legacy search scope can run schema, start_run, preview_batch, status, list_review, and get_candidates. Contact-changing modes still require contacts-write and user_confirmed=true."]},{"date":"2026-05-13","changes":["Updated credit policy docs for the May 15 pricing change: Free now has 5 credits per credit period, Starter is an $8/month tier with 50 credits, Starter Annual is a $6.40/month-equivalent yearly tier with 50 credits, and Pro/Annual/Team remain at 1000 credits.","Clarified that API keys can be created on any plan, including free accounts, and documented that the /mcp endpoint accepts API keys via X-API-Key or Authorization: Bearer carl_<key>."]},{"date":"2026-04-23","changes":["Documented credit enforcement: per-tier 30-day rolling caps, the X-Carl-Credits-* response headers (Tier, Limit, Used, Remaining, Reset-At, Window-Days), the HTTP 402 credits_exhausted body, and the MCP over-limit tool error (isError + structuredContent.error_code). Added GET /api/v1/credits/status (API-key) and GET /users/me/credits/status (session JWT)."]},{"date":"2026-04-03","changes":["Added communications orchestration docs and MCP schemas covering capabilities checks, direct/invite/referral/Gmail/LinkedIn sends, normalized communication status/events, SSE streaming, and artifact retrieval.","Documented LinkedIn profile URL lookup, page-wide enrich behavior, richer experience chunk metadata, exposed public static data-scale metadata for agent integrations, and added a public credit summary endpoint with live rate-card and billing-semantics docs."]},{"date":"2026-01-30","changes":["Initial public Search API, API key management, and MCP schema endpoints."]}]}