Authentication and scope
Send a workspace Organization API key as Authorization: Bearer your_api_key_here. Every response is scoped to the key's workspace. The API returns the same customer projection as the web app; staff-only fields and controls are unavailable. Admins can issue a key with explicit settings or API-key management permission in the web app. Ordinary keys have neither grant.
These endpoints are available at https://beam.lightmeter.io. Use JSON for request and response bodies unless the endpoint returns a PDF or an empty 204 response.
Google Calendar connected calendar
Use /api/v1/settings/calendar-integration/google-calendar. GET returns available, connected, can_manage, connection (email, connected_by and connected_at), last_checked_at, needs_attention, attention_reason and last_failed_at. Credentials are never returned. When unavailable, no connection may be started.
POST /connect returns authorization_url and the disclosure: “Connecting gives access to your Google Calendar events, used only to attribute booked meetings to leads emailed.” Open the URL and grant calendar access. The callback stages an encrypted grant and redirects to Beam with a short-lived state. POST /complete with {"state":"returned-state"} must use the same actor and workspace that started the flow; API keys must complete with that same key. Only completion saves the connection and queues its first check. Expired, replayed or mismatched states save nothing. Google scope consent is required.
POST /sync queues the customer-filtered booking check and returns 202 with the full status object, as does successful completion when its first check is queued. If queueing fails after completion saves the connection, completion returns 200 with the connected status; use Sync now to retry. Repeated requests reuse a pending check. DELETE revokes access best effort, deletes the connection and secret, and retains recorded bookings. Connect, complete and disconnect require settings management permission. Reconnecting replaces the primary calendar account. Google Calendar is offered to every workspace; available is false only while Lightmeter temporarily cannot offer Google Calendar connections. Contact Lightmeter support if it stays false.
Calendly and Cal.com connected calendars
Calendly
GET /api/v1/settings/calendar-integration/calendly returns connected, can_manage, connection (account user_uri, name and email), last_checked_at, last_failed_at, needs_attention and attention_reason. Credentials are never returned.
POST /api/v1/settings/calendar-integration/calendly returns status: user_action_required, action_performed: false and an authenticated settings_url. A workspace admin completes OAuth in the browser. Missing application configuration returns 503. DELETE on the same path deletes stored tokens, attempts revocation and retains recorded bookings; it requires settings management permission.
POST /api/v1/settings/calendar-integration/calendly/sync queues a check and returns HTTP 202 with current status. Any workspace member can request a check. A disconnected source returns 409. The UI checks status for up to one minute after Sync now; a pending check may finish later.
New connections read hosted meetings starting on or after January 1, 2026. Scheduled, canceled and rescheduled bookings use source calendly. Recorded bookings remain after disconnect.
Cal.com
When OAuth is configured, workspace managers can select Connect with Cal.com, or Use an API key instead. GET also returns oauth_available and connection_type (api_key or oauth; api_key when disconnected). OAuth credentials are never included in status.
POST /api/v1/settings/calendar-integration/calcom/oauth/start (also under /authenticated/v1) accepts {"return_path":"/w/workspace/settings/calendars/calcom"} and returns authorization_url. It requires settings management permission and sets a browser-bound authorization cookie. Complete authorization in that same browser. The callback at /v1/settings/calendar-integration/calcom/oauth/callback validates the single-use state, saves the same-account connection, queues a booking check and redirects to settings with a success or error flag. Missing OAuth configuration returns 503; the API-key path remains available.
OAuth access tokens refresh automatically before expiry. A rejected grant shows “Cal.com rejected the connection. Reconnect to resume.” Reconnect keeps the same account; switching accounts requires disconnecting first. Disconnect deletes local tokens and keeps recorded bookings. Cal.com's current OAuth reference does not document a grant-revocation endpoint.
Use /api/v1/settings/calendar-integration/calcom for the workspace's Cal.com connection. GET returns connected, can_manage, last_checked_at (the last completed check, null until the first check completes), and connection (null or an object with user_id, email and username). Status also includes needs_attention, attention_reason, and nullable last_failed_at. A rejected credential shows “Cal.com rejected the API key. Replace the key to resume.” Other read failures show “Cal.com couldn't be checked at the last attempt. It will try again.” A successful check or saving a replacement key clears the failure. No response includes the key.
POST and PUT both save the key, connecting or replacing the key for the same account, using {"api_key":"your_calcom_key"}. Both validate the account with Cal.com before saving an encrypted key. Replacement keeps the same account; disconnect before switching accounts. DELETE disconnects, deletes the stored key and retains recorded bookings. Writes require settings management permission. Connect and key replacement automatically queue a booking check and return 202 with the status object. If queueing fails after the key is saved, they return 200 with the saved connection; use Sync now to retry. Disconnect returns 200 with the status object. Invalid input or Cal.com rejecting the key with 401 or 403 returns 400 (“Could not validate the Cal.com API key. Check the key and try again.”). Other provider failures, including rate limits, server errors, timeouts and transport errors, return 502 (“Cal.com is unavailable. Try again shortly.”). If Lightmeter cannot store the key, POST and PUT return 503 without contacting Cal.com; DELETE is unaffected. Insufficient permission returns 403, and replacing with a different account returns 409.
POST /api/v1/settings/calendar-integration/calcom/sync queues a booking check for the current workspace and returns 202 with the status object. Any workspace member, workspace API key or MCP user with access may trigger it. Requests in the same 30-second period reuse the workspace job. A request in a later period can queue a fresh check while an older one runs. An unconnected workspace returns 409; queue failures return 503. The HTTP request does not wait for the provider. Poll status until last_checked_at or last_failed_at changes; the UI stops waiting after about 60 seconds. A workspace check reads its connected booking sources and refreshes booking attribution.
MCP provides workspace_calcom_sync, workspace_calcom_get and workspace_calcom_disconnect. workspace_calcom_connect and workspace_calcom_replace_key return an authenticated browser settings link. Enter the Cal.com key only in the browser, never in an MCP conversation.
Workspace reads
| Method | Path | Result |
|---|---|---|
| GET | /api/v1/settings/general/reply-forwarding-recipients | List configured addresses with their current mailbox scope. Also included in general settings as reply_forwarding_recipients. |
| POST | /api/v1/settings/general/reply-forwarding-recipients | Add {"email":"name@example.com"} without replacing other recipients. Up to 20 additional workspace-wide addresses can remain configured; existing workspace defaults and mailbox-specific destinations do not count toward that limit. Requires settings-management access and a fresh X-Operation-ID UUID for one verification email, subject to the existing five checks per workspace per hour. |
| DELETE | /api/v1/settings/general/reply-forwarding-recipients | Remove the address supplied in {"email":"name@example.com"} from current and planned forwarding. Other addresses and forwarding mode stay unchanged. Repeating removal is safe. |
| GET | /api/v1/settings/general | Reply forwarding destination and mode, identity generation options, mailbox counts and capability flags. |
| GET | /api/v1/team/members | Members, roles and capabilities. Organization API keys cannot add or manage members. |
| GET | /api/v1/activity/events | Workspace journal events. Supports limit 1–100, offset 0–1,000,000, and the web app's event, actor, source, campaign and date filters. API-key detail fields appear only for keys with the delegated API-key management grant. |
| GET | /api/v1/settings/crm-integration | Customer-visible HubSpot connection and sync state. Provider metadata refresh is reserved for workspace managers. |
| GET | /api/v1/settings/crm-integration/close | Customer-visible Close connection and sync state. |
| GET | /api/v1/billing/overview | Customer-visible balance, credits, invoices, reviews and billing settings. This is a read and creates no charge. |
| GET | /api/v1/billing/platform-notice | Current customer-facing platform billing notice. |
| GET | /api/v1/agreements | Agreements associated with the authenticated workspace. |
| GET | /api/v1/agreements/{agreement_id}/pdf | PDF for a workspace-owned agreement; inaccessible or unknown IDs return the same not-found response. |
| GET | /api/v1/agreements/{agreement_id}/pdf/chunk?document=issued&index=0 | One Base64 chunk of a workspace-owned issued or executed PDF, at most 128 KiB before encoding. The response includes chunk count, total bytes and SHA-256 for assembly and integrity checks. Each read requires current authorization; no bearer document link or expiring cursor is issued, and repeating an index is safe. Unknown and inaccessible agreement IDs return the same not-found response. |
Delegated settings and CRM management
The following writes require a key explicitly issued by a workspace Admin or Owner with can_manage_settings=true. Unprivileged keys receive 403. The browser uses the same handlers and retains its existing role checks, revision checks, validation and provider guards. The SES sending-account and staff account settings remain unavailable.
| Method | Path | Action |
|---|---|---|
| PATCH | /api/v1/settings/general | Change verified reply forwarding destination. Requires X-Operation-ID UUID; while the budget store retains its keys, an ID is rejected for 24 hours and a workspace is limited to five verifications per hour. An uncertain result should be checked with GET before a new ID. |
| PATCH | /api/v1/settings/general/reply-forwarding-mode | Change forwarding mode after current worker/readiness checks. |
| PATCH | /api/v1/settings/general/identity-generation | Change identity-generation market, profiles and style. |
| POST | /api/v1/settings/general/campaign-url-tracking/check | Request a background sending-domain check for this workspace. Requires the settings-management grant. Repeated queued or running requests coalesce. Returns 202 with readiness; 503 means check status or scheduling is unavailable. A check changes no campaign policy and does not repair DNS or certificates. |
| PATCH | /api/v1/settings/general/campaign-url-tracking | Set the campaign creation default and explicit scope with {"enabled":false,"apply_to":"new_campaigns"} or apply_to="new_and_existing_campaigns", in either direction. Omitting scope preserves the legacy apply-to-existing behavior. Returns campaign_url_tracking and changed. Requires the settings-management grant. |
| PATCH | /api/v1/settings/general/walkin-tracking | Change walk-in tracking or the default source tag. Accepts a partial object with enabled, enable_utm_source booleans and/or an HTTP(S) default_redirect_url; at least one is required. Default destination changes atomically update only domains that follow the default. Returns walkin_tracking and changed. Requires the settings-management grant. |
| POST | /api/v1/settings/general/identity-samples | Preview bounded generated identity examples; no saved setting change. |
| PATCH | /api/v1/settings/domain-generation | Change domain-generation industry keywords. |
Request bodies: forwarding destination uses {"reply_forwarding_destination":"name@example.com","overwrite_acknowledged":true}; acknowledge replacement only after reviewing current mailbox destinations. Reply forwarding mode uses {"mode":"off"}, all_replies, or positive_replies. Identity generation and identity-sample preview use market, profile_weights (profile IDs and percentages totaling 100) and given_name_style from the general settings options. Domain generation uses {"industry_keywords":["example"]}, up to the current workspace limit. Read the current settings and allowed options before changing them.
Campaign click tracking
In Create or Edit → Creative, the campaign action menu offers Click tracking: On/Off. Each campaign inherits the workspace default when created and can then override it. New-only workspace changes preserve those choices; an explicit new-and-existing action resets matching existing campaign choices. PATCH /api/v1/campaigns/{campaign_id}/link-tracking accepts {"enabled":true} (or false). campaign_link_tracking_update exposes the same customer-scoped service through MCP. Campaign detail exposes url_tracking_enabled; the authenticated campaign API uses urlTrackingEnabled. Updates journal event108 with actor, source and before/after; prepared bytes and issued redirects are preserved.
In the app, use Settings → Tracking → Click tracking. This workspace setting starts off and currently covers campaign emails. The existing General API routes and MCP action remain unchanged. Actual changes appear in Activity with actor, source and Off/On before/after.
campaign_url_tracking.readiness reports state (first_check_pending, queued, checking, ready, failed or status_unavailable), nullable UTC next_check_at and last_checked_at, check_again_available, and this workspace’s domain outcomes with stable reason codes. Next check time comes from the live API scheduler and is a check time, not a readiness deadline. Lost or stale observations are reported as unavailable. PostgreSQL readiness remains the sending authority. Explicit enabling requests a prompt check through the same deduplicated background mechanism. MCP workspace_campaign_url_tracking_check with payload={} uses the same handler.
General settings returns campaign_url_tracking with enabled (the new-campaign default), scope_supported, existing_enabled_campaigns, existing_disabled_campaigns, managed_domains, ready_domains and unavailable_domains. Tracking defaults off, including missing settings. Campaigns inherit once at creation; clones are new, while retained drafts are existing. New-only scope never changes existing policies. The broader scope explicitly changes all retained non-deleted campaigns that differ, including completed and archived campaigns with attributable issued URLs. A default off while existing campaigns remain on is valid. Counts and settings changes serialize under the customer lock; the response includes the actual changed_campaigns count. A broad change works even if the default is unchanged; a true no-op returns changed=false. Invalid scope returns 400. MCP workspace_campaign_url_tracking_update uses the same payload and handler.
Readiness expires after ten minutes without renewed DNS, routing and HTTPS proof. Opted-in campaigns cannot launch, resume or make a fresh send when tracking is unavailable. Authorization, SMTP handoff and provider-attempt admission enforce this boundary; original-URL fallback is not allowed. Ordinary off sends remain available. Authorized MIME and message identity cannot be rewritten; previously untracked authorizations are held after opt-in until existing-campaign opt-out, while uncertain and accepted sends reconcile their original identity. Issued URLs always retain their saved destinations. Opting out an existing campaign stops future visits and Fingerprint submissions for its old URLs while preserving historical facts. Re-enabling is explicit and does not recover missed visits. Event108 records default and campaign changes, selected scope and actual counts transactionally. After an uncertain write response, read settings before retrying.
Eligible public HTTP and HTTPS links in recipient-rendered campaign messages become short HTTPS URLs on the naked sending domain. Interactive replies, test sends, attachments, protected authentication links and ambiguous prose candidates are excluded. A short URL publicly reveals its destination in the redirect response. Do not include a private bearer destination. Requests are classified as candidate estimates, automation, unknown or non-navigation evidence; neither missing detector data nor an ordinary browser proves a human. See click analytics for units and coverage.
Walk-in tracking
In the app, use Settings → Tracking → Walk-in tracking. These controls are independent of campaign click tracking and its new-campaign default. General settings also returns walkin_tracking: enabled, enable_utm_source, managed_domains, configured_domains, ready_domains and unavailable_domains. Tracking starts disabled. Pausing tracking keeps redirects and configured tags. The separate source preference controls utm_source=lightmeter on participating domains; existing opt-outs are preserved.
Readiness records recent reachability of a participating domain's root route. It expires after ten minutes and is separate from short-URL readiness; it does not gate an arriving redirect. Walk-in requests cannot identify a recipient or prove a human visit. Configure each domain and read coverage, estimates and unknown requests through the walk-in infrastructure API.
HubSpot and Close
Salesforce Revenue: GET /api/v1/settings/crm-integration/salesforce returns connected, oauth_available, can_manage, and, for a connection, integration_id, account_id, configuration_revision and oauth_grant_revision. An invalid grant sets needs_reconnect. Connect through the authenticated browser flow. Salesforce has no sync writes or token-input endpoint.
Use GET or PUT /api/v1/settings/crm-integration/revenue-setup?provider=salesforce for Salesforce Revenue settings. The PUT body contains qualified_stage_ids, won_stage_ids, amount_meaning (deal_value or estimated_gross_profit), timezone, and optional monthly_target_cents. Stage IDs are Salesforce API values. Disconnect with POST /api/v1/settings/crm-integration/salesforce/oauth/disconnect and the current configuration and OAuth grant revisions. Settings-management permission and workspace isolation apply. See Salesforce setup and administrator requirements.
Use /api/v1/settings/crm-integration for HubSpot and /api/v1/settings/crm-integration/close for Close, followed by one suffix below. API-key writes require the settings-management grant. Tokens in create, discover and rotate requests are sensitive; never log or persist them in client diagnostics. OAuth provider consent and callback remain in the browser flow. Status reads return saved state without provider discovery; use /discover for current metadata.
To disconnect an OAuth grant, send POST /api/v1/settings/crm-integration/oauth/disconnect for HubSpot or POST /api/v1/settings/crm-integration/close/oauth/disconnect for Close. Both require a JSON body with the current oauth_grant_revision from the settings read; Close also requires configuration_revision. HubSpot requires sync to be disabled first. A response may report revocation_pending; inspect connection state before retrying if the result is uncertain. API keys need the settings-management grant. OAuth start, pending inspection, completion, provider consent and callback remain bound to the initiating member's browser session.
| Method | Suffix for either provider | Action |
|---|---|---|
| GET | (empty) | Read connection and sync state. |
| POST | (empty) | Create the connection from a provider credential. |
| PUT | (empty) | Update sync settings with current configuration revision. |
| POST | /discover | Inspect provider account and capability metadata before setup. |
| POST | /validate | Validate the saved connection. |
| GET | /test-conversation-preview | Preview a positive-reply setup test without writing to the provider. |
| POST | /test-conversation-operations | Start one bounded, durable positive-reply provider setup test. |
| GET | /test-conversation-operations/{operation_id} | Read a saved or uncertain provider test result without retrying it. |
| POST | /conversations/{conversation_id}/retry | Retry a workspace-owned conversation's pending sync. |
| POST | /blocklist-preview | Review provider blocklist changes before approval. |
| POST | /blocklist-preview/approve | Apply the reviewed blocklist revision. |
| POST | /activate | Activate the configured integration after validation. |
| POST | /capabilities/{capability}/activate | Enable a supported sync capability. |
| POST | /capabilities/{capability}/disable | Disable a sync capability. |
| POST | /rotate-token | Replace the saved private credential. |
| POST | /disable | Disable the integration. |
HubSpot credential requests use {"private_app_token":"..."}; Close uses {"api_key":"..."}. Create includes that credential plus a settings object. Update uses {"settings":{...}} for HubSpot and also requires configuration_revision for Close. Populate the settings object from the matching provider's current GET response and discovered option IDs; do not submit another provider's settings. HubSpot settings include lead pipeline and disqualified stage IDs, selected sync capabilities, source/lead-status mappings, phone block fields, and email subscription IDs. Close settings include selected sync capabilities, Lead status/source mapping, field assignments and optional Opportunity mapping. Preview/retry and blocklist approval use the IDs and revision returned by their corresponding preview/read response.
For Close, email_observation is a separate read capability. Activate it with POST /api/v1/settings/crm-integration/close/capabilities/email_observation/activate and {"configuration_revision":"CURRENT_GET_REVISION"}. An Admin or Owner, or an API key with the settings-management grant, may activate it after the saved account and permissions to read events and emails are checked. Both existing write capabilities keep their current opt-outs. Read integration.capabilities.email_observation.enabled, positive_reply_sync.enabled, and blocklist_sync.enabled from the Close GET response to verify the result. Disable observation with the matching /disable suffix; the original forward cutoff is retained on resumption. Close Notes and emails without native occurrence and exact conversation evidence do not qualify. Observation covers checked Close activity, not every mailbox email.
Close Contact reconciliation reads a current Lead snapshot once across the pending interval. These mutable snapshots cannot certify complete history. Lightmeter stops snapshot paging after the page at offset 10,000; omitted history remains a reported coverage gap. Close may impose a lower endpoint-specific offset limit. Native Event Log reads use cursor paging and have a 30-day retention limit; neither limit is a promise of complete mailbox coverage.
MCP uses the same public handlers: call workspace_crm_capability_activate with provider="close", resource_id="email_observation", and the current configuration_revision in payload. Use workspace_crm_close_get for readback and workspace_crm_capability_disable to pause observation.
For a positive-reply provider setup test, first read GET /test-conversation-preview?conversation_id=.... Then send POST /test-conversation-operations with a new client-generated UUID in operation_id, plus conversation_id, expected_trigger_message_id, and expected_recipient_email from the preview. For Close, also send the preview's expected_trigger_sender and acknowledge_sender_mismatch=true when sender and Contact email differ. Both providers use this suffix under their CRM base path. The request may write to the connected CRM. Reusing the same operation ID and body returns the saved outcome without another provider call. If the response is lost, read GET /test-conversation-operations/:operation_id before any new attempt. running or indeterminate means the provider outcome is not yet confirmed; another public test for that conversation is blocked until it is reconciled. failed_preflight means no provider sync began; use a new operation ID after fixing the input. At most ten new operations may be reserved per integration per hour; excess requests return 429. The provider attempt has a two-minute deadline, and a stale running record reads as indeterminate. Salesforce supports explicit checkpoint-preserving resume via POST /test-conversation-operations/resume with the original operation ID and preview payload. It checks Salesforce for the earlier attempt before writing. Other providers do not automatically replay indeterminate tests. API keys require the settings-management grant.
Revenue attribution setup is available at GET /api/v1/settings/crm-integration/revenue-setup and PUT /api/v1/settings/crm-integration/revenue-setup. PUT requires the settings-management grant. Its JSON body contains qualified_stage_ids, won_stage_ids, amount_meaning, optional monthly_target_cents, and Close's timezone. Select stage IDs from the GET metadata. The former provider_value_period input is accepted but ignored; every native period counts. Revenue report responses include qualified_values and closed_won_values grouped by currency, with one-off, monthly recurring, annual recurring, monthly-equivalent and first-year amounts in fixed hundredths. Existing scalar amount fields use first-year value in the report currency. Other currencies stay separate and make report-currency coverage partial. Currency groups include known_values; unavailable values are grouped by period with a count and nullable amount_cents, rather than listed per deal. HubSpot deal totals count once, preferring its home-currency amount; Close values retain their native period. UI, public API and MCP use the same calculation. The provider-side blocklist round-trip test (/test-blocklist-round-trip) runs only in the browser.
Delegated API-key management
Only keys an Admin or Owner explicitly issued with can_manage_api_keys=true can call these endpoints. API callers cannot grant delegated settings or key-management privileges to newly created keys. An API caller cannot extend itself or another delegated key. Delete a compromised delegated key in the web app or through a different authorized manager.
| Method | Path | Action |
|---|---|---|
| GET | /api/v1/api-keys | List workspace keys and delegated capability flags, never token values. |
| POST | /api/v1/api-keys | Create a normal key with display_name, expiration_option and optional expires_at. The token appears once; responses use Cache-Control: no-store. |
| PATCH | /api/v1/api-keys/{apiKeyID} | Rename or change expiration of a normal workspace key. |
| DELETE | /api/v1/api-keys/{apiKeyID} | Revoke a workspace key. |
Webhook configurations
Use the multi-event configuration contract. The legacy scalar browser routes are not part of this public API. Creating, deleting, rotating or testing a webhook requires the key's explicit settings-management grant. See the web app webhook guide for supported events, delivery formats and payload examples.
| Method | Path | Result |
|---|---|---|
| GET | /api/v1/webhook-configurations | Workspace configurations; signing secrets are omitted. |
| POST | /api/v1/webhook-configurations | Create a configuration with HTTPS url, name, event_types and optional format. A signing secret is returned only at creation when the format uses signed JSON headers. |
| DELETE | /api/v1/webhook-configurations/{id} | Delete a workspace-owned configuration; returns 204. |
| POST | /api/v1/webhook-configurations/{id}/signing-secret/rotate | Replace a signed JSON secret. Update your receiver immediately; the new secret appears once in the response. |
| POST | /api/v1/webhook-configurations/{id}/test | Send sample events to the saved endpoint and record delivery results. Requires a new UUID in X-Operation-ID. While the budget store retains its keys, an ID is rejected for 24 hours and a workspace is limited to 20 test calls per hour. |
| POST | /api/v1/webhook-configurations/test-preview | Test an unsaved public HTTPS url with event_types and optional format. Private, loopback and link-local destinations and redirects are blocked. Requires settings-management permission and a fresh UUID in X-Operation-ID; it shares the saved-test 20 calls per workspace per hour and 24-hour replay limits. This sends sample events externally but creates no configuration or delivery-history row. After an uncertain response, check the receiver before trying another ID. |
| GET | /api/v1/webhooks/deliveries | Delivery history with web app filters, sort, limit 1–100 and offset. |
| GET | /api/v1/webhooks/deliveries/{id} | Details for a workspace-owned delivery. |
Create request
{"name":"Qualified replies","url":"https://example.com/lightmeter-webhook","event_types":["positive_reply"],"format":"standard"}
A test call can contact your configured endpoint and create a test delivery record. On a timeout or uncertain response, inspect delivery history before using a new operation ID. A reused ID returns 409; the hourly budget returns 429 with Retry-After. If the budget store is unavailable, tests fail closed with 503.
AI replies
GET /api/v1/settings/ai-replies returns settings and defaults before setup.
PATCH /api/v1/settings/ai-replies updates supplied fields; omitted fields are preserved. Workspace manager permission is required for updates.
Settings → AI replies → Setup saves the mode only when you press Save. The checklist uses saved Slack, mentions, About, pricing and booking details; it disappears once these are complete and AI replies is on. Slack and the AI-question setting stay editable while AI replies is off.
The settings GET also returns last_delivery: null when there is no recorded result for the current Slack installation, otherwise kind (test or post), at (timestamp), and error_code (empty for success). It is the latest recorded test attempt or successful draft post, not a live Slack health check.
enabled defaults to false. Before AI replies is available, enabling returns HTTP 403 with code ai_replies_not_launched. Turning off remains available to workspace managers. approval only accepts approve; a person must approve sending.
bot_question accepts disclose (default: identify as an AI assistant and offer a person) or person (pass to a person).
Other fields: pricing_text, pricing_disclosure, pricing_qualification, booking_url, allowed_links, handoff_contact and holding_signature. Text fields accept empty strings to clear them. Links must be HTTP or HTTPS without credentials; allowed_links is an array. Settings remain editable while AI replies are off.
GET /api/v1/settings/ai-replies/mentions lists workspace members with member_id, name, email, found_in_slack and selected.
PUT /api/v1/settings/ai-replies/mentions replaces the selection using {"member_ids":["member-id"]}; an empty array clears it without requiring Slack. A missing or null member_ids is refused. Both require manager access. Only members found in the connected Slack workspace may be selected. GET uses stored Slack matches; pass ?refresh=true to resolve members without a stored match. PUT also resolves unmatched members. Revoked Slack access returns HTTP 409 with code slack_revoked and state revoked; reconnect Slack. Other provider failures return errors rather than a missing-member result.
Average customer value
GET /api/v1/settings/customer-value returns {"value":null,"can_manage":false} when unset, otherwise value includes value_cents, period, and effective_from. Never display null as zero.
PUT /api/v1/settings/customer-value accepts {"value_cents":10000,"period":"one_off"}. Use integer USD cents from 1 to 9007199254740991, and period one_off, monthly, or annual. Values are not converted. Each changed value appends a dated row; an unchanged value and period is a no-op. Invalid values return 400; missing settings-management permission returns 403. Organization keys require delegated Settings access. There is no clear action.
MCP: workspace_customer_value_get takes optional workspace_id; workspace_customer_value_set takes the same workspace and the PUT body under payload.
AI replies: Knowledge
Workspace members can read Knowledge for AI replies through these endpoints and MCP. Writes require workspace Settings manager permission. Omit campaign_id, or send null in a save, for All campaigns. Supply a campaign ID for This campaign only. The campaign must belong to your workspace. These operations do not send email.
| Method | Path | Purpose |
|---|---|---|
| GET / PUT | /api/v1/ai-replies/knowledge | Read the latest briefing or save {"body_md":"About our offer","campaign_id":null}. Campaign briefings also support needs_customer_data. body_md is required; an explicit empty string clears it. The maximum is 65,536 UTF-8 bytes; a larger body returns code knowledge_body_too_large. |
| GET | /api/v1/ai-replies/knowledge/history | Read retained revisions, newest first, with version, author, creation time and body. Omit campaign_id for the workspace briefing or supply a campaign ID. Returns data.items and data.next_offset, up to 100 revisions per page; pass offset for the next page. Read-only: this does not restore or change a revision. |
| GET / POST | /api/v1/ai-replies/{resource} | List or create Answers, Rules or Proof points. Resource names are answers, rules and proof-points. |
| GET / PUT | /api/v1/ai-replies/{resource}/{id} | Read or replace an item's content. PUT is a full content save; omitted optional values are cleared. Use the scope action to change Use for. |
| POST | /api/v1/ai-replies/{resource}/{id}/accept | Accept a proposal. An Answer must have answer text before acceptance. |
| POST | /api/v1/ai-replies/{resource}/{id}/dismiss | Dismiss an item while retaining its history. A dismissed proposal cannot be accepted again. |
| POST | /api/v1/ai-replies/{resource}/{id}/retire | Retire an Answer, Rule or Proof point without deleting its history. |
| PUT | /api/v1/ai-replies/{resource}/{id}/scope | For Answers and Rules: save {"campaign_id":null,"scope_reason":"Applies to every campaign"}. Always use the returned item's ID for later edits. |
| GET | /api/v1/ai-replies/gaps and /api/v1/ai-replies/gaps/{id} | List or read Gaps. Gaps belonging to removed leads are excluded. |
| POST | /api/v1/ai-replies/gaps/{id}/answer | Create an Answer and resolve the Gap together. Supply an Answer kind, answer text and Use for scope: null for all campaigns or the Gap's campaign ID. |
| POST | /api/v1/ai-replies/gaps/{id}/dismiss | Dismiss a Gap. |
Successful responses use {"data":...}. Item lists return {"data":{"items":[],"next_offset":null}}. They contain up to 100 items; pass the returned next_offset as ?offset=... for another page. Use ?campaign_id=... to list one campaign's items. Use ?scope=all to include workspace and campaign items, for example all Rules counted toward the workspace limit. Gaps default to this all-campaigns view; other lists default to workspace-only. scope=workspace selects only All campaigns items. Do not combine scope=all or scope=workspace with a campaign ID. An empty workspace briefing is {"data":null}. Missing or foreign items return 404, invalid input 400 and conflicting changes 409. Read the latest state before retrying a conflict.
Content fields
Answers: kind is fact, asset_link, event, objection or reference. Supply question and answer; optional fields are example_questions, valid_until (YYYY-MM-DD or null), and scope_reason. Key facts use kind: "fact" and an optional nonnegative position; they are manually maintained and never learned. Expired Answers remain visible for editing but are not used by drafts. The valid-until date is inclusive through that date in UTC.
Rules: supply kind (do or dont) and text of at most 500 characters. A workspace can have 20 active customer Rules in total, including campaign Rules. Built-in Rules are not returned and do not count toward this limit.
Learned from your replies
When AI replies is on, each reply a person writes or edits in Unibox or Slack can propose Rules and Answers. An AI draft sent unchanged makes no learning call. API and MCP sends do not teach. A discard with feedback can also teach; Handled elsewhere, No reply needed and discards without a reason do not. Historical replay does not learn.
Proposals appear in Knowledge and Rules with Accept and Dismiss, a preset Use for choice and its plain-language reason (scope_reason). Nothing is used before acceptance. At most two proposals are added per reply, with at most 20 waiting across Rules and Answers. Learning pauses at that limit. Dismissed proposals are retained to prevent repeats. Prices, pricing policy and Key facts are never learned. Waiting proposals are considered too, so learning can avoid repeating or contradicting suggestions already awaiting review. A configured booking or allowed link is not learned again as a Rule or Answer.
GET /api/v1/ai-replies/learning returns {"data":{"items":[],"next_offset":50}}. Pass ?offset=50 for the next page; each page has up to 50 entries, newest first, and omits next_offset on the last page. Entries include id, trigger (reply or discard), status, created_at, and current proposals, accepted and dismissed counts for that extraction. Status is queued, running, done, nothing_new_pricing, failed, or skipped_ followed by the reason, such as replay, waiting_cap or unchanged_draft. nothing_new_pricing is shown as “Nothing new: when to share pricing is set in Key facts” when the pricing filter leaves no proposals. Failures are retried automatically, up to three attempts. History includes lead_name, company, thread_id, action (written_by_hand, ai_draft_edited, ai_draft_unchanged or discarded), the member’s why note (discard reason code for discards), and items containing each created item’s id, resource, status and label. The Learning panel links to those items and the current thread. Raw email bodies and private standards are never included. Learning cannot change whether a reply is sent.
Campaign AI replies
The campaign AI replies tab contains Drafts, Knowledge and Settings. Campaigns without drafts open on Knowledge. When AI replies are off, the tab remains available so you can prepare Knowledge. The workspace briefing is read-only and collapsed in campaign Knowledge.
Drafts show the original AI text and its outcome. Filters and summary counts describe the rows loaded. Accept or dismiss learned proposals inline. Save as Answer resolves a Gap using All campaigns or This campaign only; the suggested choice and reason come from the draft. Older Gaps without a suggestion default to All campaigns.
POST /api/v1/campaigns/{campaign_id}/ai-replies/suggest-questions reads saved Creative and past positive replies. It requires at least 20 words of real Creative, excluding template placeholders. One request creates Proposed Answers with empty answers for review. It never sends mail. The response wraps items and creative_words in data. Short Creative returns HTTP 422 with suggest_questions_creative_too_short; generation failures return a named error. Suggest questions allows one running call per workspace and at most 20 calls per workspace per UTC day, including failed calls. Refusals use suggest_questions_in_progress (HTTP 409) or suggest_questions_daily_limit (HTTP 429). Before launch, customer requests return ai_replies_not_launched (HTTP 403). After launch, suggestions remain available while AI replies are off, so Knowledge can be prepared before enabling. The corresponding MCP tool is ai_reply_knowledge_suggest_questions.
For campaign-specific Slack mentions, pass campaign_id to the existing mentions GET/PUT endpoint or the mentions MCP tools. An empty campaign selection restores the workspace default without changing it. Workspace-manager permission is required. Always needs a person is the campaign Knowledge revision's needs_customer_data setting, saved through the existing Knowledge API and MCP writer.
Proof points: supply text and optionally named_company, metric, period, as_of (YYYY-MM-DD or null) and may_name. Naming permission defaults to false. The returned current_customer_in_stripe may be null, meaning unknown; these endpoints do not update billing evidence.
Briefing autosaves by the same person within ten minutes share a revision while no draft references it; other saves create a new revision. Activity records one briefing entry per revision, storing its character count rather than its text. Coalesced autosaves and unchanged saves create no Activity entry. Other items record changed fields, omitting empty defaults on creation. Items remain available while AI replies is off.
GET /api/v1/ai-replies/knowledge/campaign-summary returns one row per campaign with a briefing: campaign_id, latest version and has_content, without briefing bodies.
MCP
The matching tools are ai_reply_knowledge_campaign_summary, ai_reply_knowledge_history, ai_reply_knowledge_list, ai_reply_knowledge_get, ai_reply_knowledge_save, ai_reply_knowledge_accept, ai_reply_knowledge_dismiss, ai_reply_knowledge_retire, ai_reply_knowledge_scope and ai_reply_knowledge_answer_gap. Supply workspace_id when needed, resource (knowledge, answers, rules, proof-points or gaps) and id for an existing item. Save, scope and answer_gap take their content in input. List takes top-level campaign_id, scope and offset. Writes also honour top-level campaign_id; if it and input.campaign_id are both supplied they must agree, including null. Unknown request fields are refused in both transports. The same validation and workspace boundaries apply.
Deal Slack Report
Your weekly Deal Slack Report shows Positive replies and Bookings for the last completed Monday-to-Sunday week, compared with the week before. It includes totals since your first Positive conversation and current Reply needed, Cooling and Gone cold counts. Conversations marked Lost or Not a fit are omitted when no CRM is connected. If no eligible Positive conversations remain, no report is sent. Delivery also stops when workspace Unibox access ends.
After Lightmeter enables delivery, reports arrive on Monday at 09:00 in your report time zone. Set it in Settings → General. UTC is the default. Configure a Slack webhook with the deal_summary event in Settings → Webhooks. Customer delivery requires Lightmeter staff approval.
Open Unibox and See all deals take you to your workspace. Up to five current Reply needed and Cooling conversations are listed, newest first. Imported conversations without a thread have no thread link. Zero Cooling and Gone cold counts are omitted.
API and MCP
GET /api/v1/settings/deal-summary returns report_timezone and can_manage. Workspace managers can PATCH /api/v1/settings/deal-summary with {"report_timezone":"Europe/Berlin"}. Use an IANA time zone. Organization API keys need workspace-settings management permission to write.
MCP provides workspace_deal_summary_get and workspace_deal_summary_update. Pass workspace_id; the update also takes payload with report_timezone.
Learn from your past emails
When AI replies is on and Close or HubSpot is connected, open Settings → AI replies → Setup and choose Learn from your past emails. It defaults to the connected CRM and the newest 1,000 sent emails at most from the last 12 months. Change reveals the UTC dates and, when both CRMs are connected, the CRM choice. From is inclusive and Before is exclusive. Preview reads eligible sent emails available in that CRM for this workspace; it does not start learning. Both providers use the sent date; Close includes older sent emails synced into the CRM later. Unlogged mailbox email is not included.
Before learning starts, the preview shows the newest selected emails out of the full eligible count, CRM, workspace and period. Usually takes a few minutes. Choose Learn from your past emails again to start with that saved selection. Retry resumes it. Emails that cannot be read are skipped and counted. If learning pauses for review, accept or dismiss waiting proposals in Rules and Answers, then choose Carry on. Cancel stops further learning for the import. Workspace admins and API keys with settings-management permission can preview, start, retry, cancel and review; other members can read progress. Proposals remain inactive until you accept them. Review the batch using Accept or Dismiss, then Apply review. Up to 20 active Rules per workspace. Each proposal says From Close or From HubSpot and its source stage: first reply, scheduling, after a call, proposal or follow-up.
Public API: GET /api/v1/ai-replies/crm-imports lists connections and recent imports. POST /api/v1/ai-replies/crm-imports/preview takes integration_id, start and end (RFC3339 timestamps). Poll GET /api/v1/ai-replies/crm-imports/{id} until preview_ready; show the returned email count with its period and scope, and explain that it usually takes a few minutes before the person chooses POST .../{id}/start. Use POST .../{id}/retry for a failed import and POST .../{id}/cancel to cancel. AI replies being off returns ai_replies_disabled; another active import returns ai_reply_import_already_active.
POST .../{id}/review takes {"decisions":[{"resource":"rules","id":"proposal-uuid","action":"accept"}]}. Resources are rules or answers; actions are accept or dismiss. A batch commits together or makes no changes. Normal Rule capacity and workspace permissions apply. GET returns proposals with stage, provider, status and scope reason; provider IDs and scan progress are private.
MCP offers the same operations as ai_reply_crm_import_list, _preview, _get, _start, _retry, _review and _cancel, each with optional workspace_id. Pass preview/review fields in input, and the import UUID in id for get/start/retry/review/cancel. The same preview and person’s start decision are required.