Skip to main content

MCP v2.5.0

October 21, 2026

inspect_site sees pixels a tag manager injects — when a browser renderer is configured, inspect_site now also loads the final page once in a real headless browser and merges the ad pixels that actually fired into the report.
  • detection.scan_method is always present: browser when the browser pass ran, static otherwise.
  • Every detection.ad_pixels[] entry gains platform (facebook, google, tiktok, linkedin, bing, x, reddit, pinterest, snapchat, quora, or null).
  • Pixels the browser found carry via: "browser" and matched_by values prefixed browser:. A vendor seen in both the page source and the browser has via: "both" and lists both reasons.
  • detection.tag_managers gains a Google Tag Manager entry when the page source showed none but the browser initialised one.
  • A new top-level browser_scan block is null when no browser pass ran, otherwise { final_url, requests, elapsed_ms, error }.
  • Tags that wait for consent and never fire on load are still not visible. Without a renderer configured, only scan_method: "static" and platform are new.
Business profile in workspace context — get_workspace_context now returns a business object describing the company.
  • business is null until setup step 1 (“About your business”) has been saved. After that it contains summary, type (ecommerce, saas, lead_gen, services, or other), website, platform, lead_destination, uses_native_lead_forms, and ad_platforms.
  • summary is up to three sentences on what the company sells, to whom, and how a customer converts. It is drafted from the website and editable in Setup → step 1.
  • Existing fields are unchanged.

MCP v2.4.0

October 15, 2026

MCP read-only tokens — when you generate an MCP access token under Settings → Integrations → MCP, you can now tick Read-only.
  • A read-only token carries the ability mcp_space:{id}:read instead of mcp_space:{id}. The write tools update_contact, update_company, and update_event are hidden from tools/list, and calling one returns a “Tool not found” error. Every other tool, resource, and prompt works the same.
  • Read-only tokens show a Read-only badge in the token list, count toward the same 25-token limit, and are revoked the same way.
  • Existing tokens keep full access, and a token can’t be converted — generate a new read-only one. OAuth-connected clients are unchanged and always get full access.
See Authentication for details.

v1.5.0

October 16, 2026

All ids are returned as strings — every id, *_id, and *_ids value in every API response and export file is now a JSON string.
  • Ids can exceed 2^53, and JavaScript clients rounded them when they were returned as numbers.
  • Events already documented string ids and now return them. Contacts and Companies ids were documented as integers and are now strings, including export_id, company_id, contact_id, contact_ids, and conflicting_company_id.
  • Path and body parameters accept ids as before.
  • MCP tool outputs are unchanged.

v1.4.1

September 29, 2026

Contacts dataset: tracking_ids column — the Contacts dataset has a new optional column, tracking_ids.
  • tracking_ids is an uncapped JSON array of strings: every distinct tracking_id sent on the contact’s events, including values inherited from contacts merged into it. It’s [] when none, and off by default.
  • It sits in the Identity graph group, next to emails, phones, and comet_tokens.
  • Existing exports are unaffected. Create a new Contacts export with the column enabled to get it.

v1.4.0

September 23, 2026

New endpoint: Update Event — PUT /events/{id} updates fields on an already-ingested event using sparse PUT semantics.
  • amount is the updatable field today: number | null, >= 0; numeric strings like "120.25" are accepted, and null clears the amount. At least one updatable field must be provided.
  • Returns 200 with { "message": "Event updated successfully" }, and 404 when the id does not exist in the caller’s Space.
  • Rate limited at 60 requests per minute per Space, the same bucket as Update Contact and Update Company.
  • New MCP tool update_event mirrors the endpoint. It requires amount and cannot clear it to null.

v1.3.0

September 9, 2026

Company external ID on Create Event — POST /events/track now accepts two new optional fields: company_external_id and company_name.
  • company_external_id groups this contact into a company using your own account or company identifier. It’s trimmed, case-preserved (never lowercased), and stored byte-exact — 1 to 190 characters after trimming. Floats, arrays, and booleans are rejected with a 422.
  • company_name is a display name for the company identified by company_external_id — 1 to 255 characters after trimming, same type and validation rules. Last write wins, and it’s never used for matching: two companies with the same name stay separate. It’s ignored when company_external_id isn’t also sent.
  • Blank strings for either field are treated as absent (null).
  • This is unrelated to tracking_id: tracking_id merges events into a single contact and never groups companies, while company_external_id groups contacts into a company and never merges contacts or takes part in contact matching. Never send a shared account ID as tracking_id.
  • company_external_id is only honored when the Space’s company identity mode is set to External ID in Space Settings. In the default Auto mode (companies grouped by business-email domain), the value is accepted and stored but ignored for grouping.
Company external_id on the Companies API — Get Company, List Companies, and Update Company now expose external_id, the customer-supplied external ID counterpart to domain.
  • external_id is an identifier, not just a label: it decides which company future events carrying that company_external_id are matched to, the same way domain decides matching by email domain.
  • Update Company now accepts external_id (string | integer | null) with the same semantics as domain: trimmed, but case is preserved (byte-exact — ACCT_1 and acct_1 are different ids), 1 to 190 characters, integers stored as their decimal string, and a blank string treated as null.
  • Setting an external_id that already belongs to another company in the Space is rejected with 409 — { message, field, conflicting_company_id } — and nothing is written. field can now be domain or external_id.
  • Sending external_id: null releases the company’s claim on the identifier; the company keeps its id, history, and contacts.
  • The “at least one field” validation message on Update Company is now “At least one of domain, external_id or name must be provided.”
  • external_id is only honored by event ingestion when the Space’s company identity mode is External ID. In the default Auto mode, the value is stored and returned through this API but ignored for grouping.
New endpoints: Attach / Detach Contact Company — PUT /contacts/{id}/company and DELETE /contacts/{id}/company let you move a contact onto a different company, or off its company entirely, without waiting for another event.
  • A contact belongs to at most one company per Space — attaching moves it off any company it currently belongs to.
  • The contact’s conversions, touchpoints, and visit metadata are re-stamped with the new (or null) company id in the same transaction, so company-level reports and the Companies dataset in the data warehouse follow immediately.
  • Both calls are idempotent: repeating an attach with the contact’s current company id, or detaching an already-company-less contact, re-stamps rows (or no-ops) with a 200 rather than an error.
  • Rate limited at 60 requests per minute per Space, the same bucket as Update Contact.
  • What happens next depends on the Space’s company identity mode: in Auto mode, the tracker only assigns a company to a contact that currently has none, so a manual attach sticks and a manual detach is undone by the contact’s next business-email event; in External ID mode, the next event carrying a different company_external_id re-points the contact again either way.
  • There is no MCP tool for these endpoints yet.
Webhook mapping destinations — Company External ID and Company Name are now available as mapping destination fields on every webhook integration, alongside your existing field mappings. They map to the same company_external_id and company_name keys as Create Event. Company Tracking settings — a new Space Settings → Additional Setup → Company Tracking page holds the company identity mode (Auto, the default, groups companies by business-email domain; External ID groups them by company_external_id alone) alongside the ad-platform conversion identity mode. company_external_id sent on events is only honored in External ID mode. New guide: Account-level attribution for B2B — Account-level attribution for B2B (company external ID) walks through using company_external_id to attribute a conversion by one teammate to an ad another teammate clicked, including webhook/Stripe metadata mapping and the ad-platform conversion identity setting.

v1.2.0

September 3, 2026

Email lookup for List Contacts — GET /contacts now accepts an email query parameter to look contacts up by exact address instead of, or in addition to, a creation-date range. Accepts a single address, a comma-separated list, or a repeated email[] parameter — up to 100 addresses per request.
  • Matching is exact (not partial or fuzzy) and case-insensitive, with surrounding whitespace trimmed. It resolves against the contact’s primary email, all secondary emails, and emails captured on profiles that were later merged into the contact, so an address that only ever appeared on a merged-away profile still finds the surviving contact.
  • start_date / end_date are now optional when email is supplied, but remain required as a pair otherwise — sending only one is a 422 regardless of email.
  • email and a date range can be combined; both conditions AND together.
  • No match returns a normal 200 with an empty data array, never a 404, and several distinct contacts can legitimately share an address — all of them are returned.
  • The rate limit is unchanged at 15 requests per minute per Space, which is why the batch form exists: batch up to 100 addresses into a single call rather than one call per address for bulk reconciliation.
  • The list_contacts MCP tool supports the same email parameter (as an array only — no comma-separated string form).
New endpoint: Get Contact by Email — GET /contacts/by-email/{email} and GET /contacts/by-email?email= look up a single contact by address, for when you expect exactly one match. The response is identical to Get Contact, including all of its optional query parameters (include_comet_tokens, include_events, hide_direct_touchpoints, use_custom_field_labels, include_browsing_session_data).
  • Resolution uses the same rules as the email filter above: exact, case-insensitive, whitespace-trimmed, spanning the contact’s primary email, secondary emails, and emails from merged-away profiles.
  • Returns 404 when no contact matches, and 409 with contact_ids when more than one contact matches — mirroring the 409 on Delete Contact PII. Use the List Contacts email filter to see all matches, or request one of the returned contact_ids via GET /contacts/{id}.
  • Rate limited at 30 requests per minute per Space — the same bucket as Get Contact, not the 15/minute limit on List Contacts.

MCP v2.3.0

September 2, 2026

Personal access tokens (PATs) are now available for server-side and headless MCP agents. If you’re running a CI job, backend service, or any script without a browser, you no longer need to work around the OAuth flow. Generate a token directly from Settings → Integrations → MCP under MCP Access Tokens, name it, and send it as Authorization: Bearer like any other MCP token. Key details:
  • A personal access token behaves exactly like an OAuth-issued token: tied to your user account, working for a single Space, with your Space access re-checked on every request.
  • Tokens don’t expire. Revoke them when the agent is decommissioned.
  • You can generate tokens until you hold up to 25 MCP tokens for a Space; tokens issued to OAuth clients count toward that number.
  • All MCP tokens, OAuth- and PAT-issued alike, are listed and revocable from the same Settings → Integrations → MCP page.
See Authentication for the full flow and a .mcp.json config example.

v1.1.1

September 2, 2026

Company identity rebuild — a company’s stable identity is now its numeric id, matched via lookup tables keyed on an email domain and/or a customer-supplied external ID (each unique per Space). This changes domain semantics across the Companies endpoints:
  • domain is now nullable on Get Company and List Companies. It’s null for a company identified only by an external ID, with no associated email domain.
  • Update Company: domain is an identifier, not just a label — changing it moves the company’s claim on that domain. Values are trimmed and lowercased before storing (a blank string is treated as null), matching ingestion. Sending domain: null releases the company’s claim on its domain: the company keeps its id, history, and contacts, but future events from that domain will create or match a different company. If the new domain already belongs to another company in the Space, the request is now rejected with 409 Conflict — { message, field: "domain", conflicting_company_id } — and nothing is changed.
  • name: null is now rejected. The tracker’s name column is required, so sending name: null on Update Company now returns 422 (“The name must be a string and cannot be null.”) instead of clearing the value. Omit the key to leave name untouched.
  • Companies dataset (Data Warehouse): domain is no longer a locked column — it’s optional and nullable, matching the API. A new optional external_id column is available (the customer’s own company identifier). id and created_at remain locked.
external_id is not yet exposed on the Companies API responses — that’s tracked separately.

v1.1.0

August 7, 2026

Delete Contact PII endpoint — Added DELETE /contacts/{id}/pii and DELETE /contacts/pii?email={email} for permanently scrubbing a contact’s personally identifiable information. Exactly one of id or email must be provided. The request validates and resolves the target contact synchronously, then queues the scrub and returns 202 Accepted with { contact_id, status: "queued", message } — call Get Contact afterward to confirm the fields have cleared.
  • Deleted: all emails, phones, names, locations, devices, IPs, tracking IDs, and comet tokens for the contact (including data inherited from merged profiles), all raw browsing-session hits, and the contact’s own name, email, phone, location, city, state, country, device_type, os, browser, language, and all 30 custom fields.
  • Kept: the contact record (id, created_at), its events and journey, and its merge history. Event metadata (webhook payloads, URL query strings) can still contain PII — delete individual events via Delete Event if needed.
  • Returns 404 if the id or email doesn’t resolve to a contact in your space, and 409 with contact_ids if email matches more than one distinct contact — nothing is deleted in that case. Unlike Delete Event, this endpoint is not idempotent on missing targets.

MCP v2.2.0

June 18, 2026

OAuth Client ID Metadata Documents (CIMD) are now supported and are the preferred registration path for new custom MCP clients. Instead of calling the registration endpoint, you host a JSON metadata document at a stable https:// URL and use that URL as your client_id — no Dynamic Client Registration call required. Cometly fetches, validates, and caches the document on the first /authorize request. Key details:
  • The document must include client_id (equal to its own URL), client_name, redirect_uris, and token_endpoint_auth_method: "none".
  • Redirect URIs must be loopback or same-origin https (same scheme, host, and port as the client_id URL). Cross-origin https and custom URI schemes are not accepted for CIMD clients — use DCR for custom schemes.
  • The document is cached up to 24 hours (respecting Cache-Control: max-age; default window 15 minutes).
  • Support is advertised as client_id_metadata_document_supported: true in the authorization server metadata. DCR remains available as a fallback.
See Authentication for the full specification and a document example.

MCP v2.1.2

June 10, 2026

Major hosted MCP clients now complete OAuth Dynamic Client Registration out of the box, with no operator configuration required. Claude (claude.ai), ChatGPT, Cursor, VS Code for the Web, Grok, Gemini, and Perplexity are all accepted by default. See Authentication for the full host list.

MCP v2.1.1

June 3, 2026

Dynamic Client Registration now accepts a partial redirect_uris array. Previously, if any single URI in the redirect_uris array failed the redirect URI policy, the entire registration was rejected with 400 invalid_redirect_uri. Now the endpoint registers only the valid subset and drops the rest — a 201 response’s redirect_uris field reflects the accepted URIs, which may be fewer than you submitted. The registration is only rejected outright when none of the supplied URIs are valid. The per-URI validation rules (loopback, allowlisted https host, approved custom scheme, reverse-DNS scheme) are unchanged. See Authentication for the full policy table.

v1.0.8

May 26, 2026

Bug fixes and behavioral improvements for custom_field_filters on List Contacts and List Events:
  • Age operators on date fields now work. age_greater_than, age_equal_to, and age_less_than were documented but incorrectly rejected with a 422 when passed a whole-number day count. The validator now accepts numeric values for these operators on date fields (profile_field_26–profile_field_30).
  • Date filter comparisons are timezone-aware. equal_to, greater_than, less_than, and between on date fields now evaluate against your space’s configured timezone. equal_to expands to a full midnight-to-midnight range for the given day; greater_than compares against end-of-day. Previously these operators compared raw strings, which would miss column values with a stored time component.
  • Numeric any / unknown semantics. For numeric fields, any matches contacts where the value is greater than 0; unknown matches contacts where the value is 0 or unset.
  • not_equal_to and not_contains no longer include unset values. Previously these operators could return contacts where the field was NULL or empty. If you need those contacts, add a separate unknown condition ANDed alongside.
  • Text filter literals. The _ and \ characters in contains, starts_with, ends_with, and contains_word filter values are now treated as literal characters instead of LIKE wildcards.

MCP v2.1.0

May 21, 2026

Removed the four export tools — request_event_export, request_contact_export, request_company_export, and get_export_status. Bulk extraction is better handled by the Public API V1 export endpoints (programmatic) or the in-app CSV export buttons (interactive). Routing the rows through an MCP turn just consumed tool slots and added a polling round-trip without giving the agent any analytical leverage. Use query_events_aggregated, query_contacts_aggregated, or the various query_ad_metrics_* tools when the agent needs to reason about large datasets — not export them. The MCP catalog is now 50 external tools across 14 toolsets (down from 54 / 15).

MCP v2.0.0

May 15, 2026

Major expansion of the Cometly MCP server — from 7 read-only tools to 54 external tools across 15 toolsets, plus the first MCP Resources and Prompts. Backwards compatible: every v1 tool kept its original input/output shape, with format: "csv" | "json" | "yaml" added as an opt-in. New toolsets (49 new tools): Resources (read-only, subscribable):
  • cometly://workspace/context
  • cometly://catalog/metrics
  • cometly://catalog/attribution-models
  • cometly://catalog/dimensions
  • cometly://catalog/custom-events
Prompts (slash-command templates):
  • analyze_performance
  • compare_attribution_models
  • weekly_review
  • find_underperformers
Cross-cutting improvements:
  • Custom event label resolution — analytics tools accept either custom_event_2 or the configured label (“Deal Created”) in their inputs. Output rewrites slot ids to labels with a # label_map: footer for round-tripping.
  • Empty-state hints — analytics tools annotate suspicious all-zero results with hints like “No facebook_ads account is connected to this space” or “Last google_ads sync was 3 days ago”.
  • Token-budget pagination — responses cap around ~6,000 tokens with a truncated_at_token_budget: true footer + opaque next_cursor.
  • CSV default for new tools — ~50% fewer tokens than JSON for tabular results. Legacy v1 tools keep JSON as default.
  • DST caveat — query_ad_metrics and resolve_date_range surface a DST advisory when the requested window crosses a transition.
  • Honest forecasting language — softened “anomaly detection” / “forecast” claims in tool descriptions to “directional reads” — we don’t run statistical models, the agent does threshold math.
  • external: false filtering — tools that only make sense in-app (chat history, file attachments) are hidden from external MCP clients via a server-level shouldRegister filter.

v1.0.7

May 14, 2026

  • Update Contact endpoint — Added PUT /contacts/ for updating an existing contact’s emails, phones, names, locations, and custom_fields. Uses sparse PUT semantics: any field you include replaces the existing collection in full; any field you omit is left untouched. Empty arrays ([]) wipe a collection; providing custom_fields clears every key not in the object.
  • Update Company endpoint — Added PUT /companies/ for updating a company’s domain and name. Uses sparse PUT semantics — only the fields you include are modified.
  • name field on Get Company — The Get Company response now includes name alongside id and domain. This is an additive change; existing fields are unchanged.
  • custom_field_filters parameter on List Contacts — Added custom_field_filters to the List Contacts endpoint. Accepts an array of AND-joined conditions (max 10) for filtering contacts by their custom profile field values. Each condition takes { field, operator, value } (or { field, operator, start, end } for the between operator). The field must reference a profile_field_N slot configured with a label in your space; operator vocabulary depends on the field’s type (text / number / date).
  • custom_field_filters parameter on List Events — Same parameter added to the List Events endpoint, narrowing results to events whose owning contact matches the conditions. Same shape and operator vocabulary as List Contacts.

v1.0.6

April 20, 2026

  • include_browsing_session_data parameter on Get Contact — Added include_browsing_session_data to the Get Contact endpoint. When set to 1, the response includes a browsing_session_hits array with up to the last 1000 raw browsing hits (page views) for the contact, ordered by most recent first. Each hit includes event_url (full URL), referrer_host, source, country, device_type, browser, os, event_name, and event_time_utc.

v1.0.5

April 7, 2026

  • include_events parameter on Get Contact — Added include_events to the Get Contact endpoint. When set to 1, the response includes an events array containing the contact’s full journey — all conversions and touchpoints sorted by most recent first. Conversion events include event_name, amount, event_url, order_id, order_name, channel (browser/server), and integration. Touchpoint events include source, touchpoint_url, referrer_url, and the full ad hierarchy (ad_name, adset_name, campaign_name, account_name).
  • hide_direct_touchpoints parameter on Get Contact — Added hide_direct_touchpoints (default 1) to the Get Contact endpoint. When include_events=1, direct touchpoints are excluded by default. Set to 0 to include them.

v1.0.4

March 19, 2026

  • use_custom_field_labels parameter — Added use_custom_field_labels to the List Contacts and Get Contact endpoints. When set to 1, custom field keys use user-defined labels (e.g. "Customer Age") instead of raw column names (e.g. "profile_field_1"). Fields without a configured label retain their raw column name.

v1.0.3

February 27, 2026

  • Ad hierarchy fields on List Events — Added ad_name, adset_id, adset_name, campaign_id, campaign_name, account_id, and account_name as requestable fields on the List Events endpoint. These fields require sources to be provided and return the ad, ad set, campaign, and account data from the attributed touchpoint.

v1.0.2

February 19, 2026

  • include_all_emails parameter — Added include_all_emails to the List Contacts and Create Contact Export endpoints. When set to 1, returns all email addresses associated with a contact, including emails from merged profiles.

v1.0.1

February 17, 2026

  • Custom fields on Create Event — The Create Event endpoint now accepts custom profile fields (profile_field_1 through profile_field_30) as root-level properties. Fields 1-15 accept text, 16-25 accept numbers (string or number), 26-30 accept dates.
  • event_url field — Added event_url as a requestable field on the List Events and Create Event Export endpoints. Returns the full URL where the event occurred.

v1.0.0

Initial release