add_crm_contact_to_pipeline
ChatGPTPipelines: add a contact to a native pipeline at a stage (ids from get_crm_pipelines), creating a pipeline record. Call it again after the contact's previous record in that pipeline closed to start a new cycle. Team-scoped operators must pass assignmentTeamId. Configured pipeline automations may run.
add_crm_product_price
ChatGPTProducts: add a new immutable price to a product. amount is a decimal string in major units ("19.95") in the given ISO currency.
add_crm_team_member
ChatGPTTeams: add an admitted workspace member (userId from get_crm_teams) to a team, using the team's current revision.
archive_crm_pipeline_automation
ChatGPTPipeline automations: archive an automation rule so it stops acting on records, using its current revision from get_crm_pipeline_automations.
archive_crm_product
ChatGPTProducts: archive a product (productId from get_crm_commerce). Quotes and sales keep their immutable price snapshots.
archive_crm_tag
ChatGPTTags: archive a contact tag so it can no longer be assigned. Existing assignments are kept, and restore_crm_tag restores it. expectedRevision is the tag's timestamp revision from list_crm_tags.
archive_crm_team
ChatGPTTeams: archive a team, using its current revision from get_crm_teams. Records the team owns may block archiving; restore_crm_team restores it.
assign_crm_owner
ChatGPTOwnership: assign a conversation or pipeline record (subject) to a team, a person or both. ONLY_IF_UNASSIGNED keeps existing ownership; FORCE replaces it and, like outsideTeamOverride, needs extra permission and an assignmentReason. expectedRevision comes from get_crm_assignment (0 when nothing is assigned yet).
associate_whatsapp_direct_numbers
ChatGPTQueue one or more allowed customer phone numbers for Cortex WhatsApp direct routing. The gateway forwards the request to mk1-tasks, which normalizes the numbers, checks whether any number already belongs to another influencer, and enqueues the association task when there are no conflicts. Returns { status: "queued", taskId } on success or { error: "phone_number_conflict", requested_influencer_id, conflicts: [...] } when a number is already mapped elsewhere.
bootstrap_discord_channel
ChatGPTQueue mk1-tasks bootstrap for the influencer's Discord operator channel. This creates or repairs the stored Discord mapping asynchronously through mk1-tasks. The downstream bootstrap creates the role, private channel, and permanent invite when needed. Returns { status: "queued", taskId } on success.
claim_crm_ownership
ChatGPTOwnership: claim a conversation or pipeline record (subject) for the signed-in user. expectedRevision comes from get_crm_assignment (0 when nothing is assigned yet). Human claims are protected from ordinary automation.
close_crm_pipeline_record
ChatGPTPipelines: close a pipeline record, with an optional outcome (SUCCESS or FAILURE) and closeReason, using the record's current revision. The closed record stays in history; add_crm_contact_to_pipeline starts a new cycle.
configure_crm_airtable_sync
ChatGPTExternal CRM sync: map a connected Airtable account to a base and contacts table so Ninjo contacts sync there. Run refresh_crm_sync with airtableBaseId first to get table and field ids. fieldMappings needs the Ninjo contact id and first-name columns; stageFieldId must be a single-select field and monetaryValueFieldId a numeric one. Replaces any existing mapping and re-registers the Airtable webhook.
create_agent
ChatGPTCreate a new Ninjo agent with its initial system prompt. Creates the Agent, AgentConfig, and first AgentPromptVersion atomically, with safe humanization defaults (message chunking on, MEDIUM delay split, 2–6s response delay — all overridable). Returns { agent_id, agent_config_id, prompt_version_id, completeness }. completeness is the deterministic build/wiring audit of the new agent: a fresh agent reports critical gaps by design (no terminal stop, not linked to a connected account) — wire them with scaffold_agent_activation before treating it as done.
create_connect_link
ChatGPTMint a one-time magic-link the account owner opens in a browser to authorize an integration: Instagram / Facebook, a CRM ('gohighlevel_crm', 'hubspot_crm', 'kommo_crm'), booking ('gohighlevel_booking', 'calendly') or the Google Calendar the agent books into ('google_calendar'). Connecting requires human OAuth consent at the provider — this tool cannot complete it. Hand the returned URL to the user and ask them to open it and authorize; do NOT open it yourself. The link needs no prior Studio login (it mints a short-lived, influencer-bound session on redeem), is single-use and expires after a few minutes. NEVER ask the user for an API key, token or password for these — none of them is used by this flow (in particular a GoHighLevel private-integration token is NOT needed). GoHighLevel has TWO separate integrations: 'gohighlevel_crm' (contact/opportunity sync, Studio screen automation/crm-sync) and 'gohighlevel_booking' (call tracking, Studio screen integrations/gohighlevel). Ask which one the user means instead of guessing. After the user authorizes, poll get_connection_status. Booking is NOT finished at that point — it reports pending_step:"select_calendars", so continue with list_booking_calendars + set_booking_calendars. CRM needs nothing more (pipelines/stages matter only when wiring a property action). Google Calendar ('google_calendar') is NOT booking tracking and has no calendars to select — never call list_booking_calendars / set_booking_calendars for it. It is the calendar the agent itself reads and books into (v5 agents only), one per workspace. After consent get_connection_status reports pending_step:"enable_for_agent_in_studio": finish it with set_google_calendar_agent for each agent that should book (the user can also do it in Studio at /studio/{influencer_id}/integrations/google-calendar). Then have them review the booking rules on that screen — left unset they default to Monday–Friday 9:00–18:00, 30-minute slots and a video call, which is wrong for most in-person businesses. ManyChat is not supported here: it has no OAuth. Send the user to /studio/{influencer_id}/integrations/manychat, where THEY fill in four things: the channel (WhatsApp / Instagram / Facebook), the API key, a shared webhook secret, and then they must COPY the webhook URL that screen shows them and paste it into ManyChat itself. Never ask for or echo the API key. Warn them that the last step happens inside ManyChat, so Ninjo cannot confirm it — get_connection_status only sees the first three. Returns { provider, url, expires_at }.
create_crm_contact
ChatGPTCreate contact: add one native contact with Studio's validation and duplicate detection; returns contactId. Fill the identity fields you know, then set properties with set_crm_contact_property and tags with replace_crm_contact_tags. After a timeout, look the contact up before retrying.
create_crm_pipeline_automation
ChatGPTPipeline automations: create a rule that moves, adds or transfers pipeline records when a record enters a stage or a contact property changes. Read get_crm_pipeline_automations for stages, property definitions and operators first. actionReason is recorded on the records it acts on. Enable only the configuration you intend.
create_crm_product
ChatGPTProducts: create a product with its first price. amount is a decimal string in major units ("19.95") in the given ISO currency.
create_crm_property
ChatGPTCreate property: add a typed property (string, integer, boolean, datetime or option) in a fact scope (contact, conversation or pipeline record). Scoped facts need the workspace rollout. Options are comma-separated labels; defaults and evaluation settings are validated. The codename is generated.
create_crm_quote
ChatGPTQuotes: create a quote for a contact. Lines use either immutable productPriceId versions or productId with a custom unitAmount in minor units, all lines the same way. It does not message the contact.
create_crm_routing_rule
ChatGPTRouting: create an assignment routing rule that assigns matching conversations or pipeline records to a team or person. Read get_crm_routing for criteria, targets and options first. Pass a fresh createRuleId and reuse it with the same payload when retrying. FORCE needs forceReason and permission.
create_crm_sync_trigger
ChatGPTExternal CRM sync: create a stage trigger that sets a contact property when the contact reaches a stage in the external CRM. syncConnectionId and stageId come from get_crm_sync; customPropertyId must be a GENERIC property (list_crm_properties); value is the text to set, after delayMinutes (0 to 525600). It keeps acting on live contacts until deleted with delete_crm_sync_trigger.
create_crm_tag
ChatGPTTags: create a reusable contact tag with a name and an optional six-digit hex color (for example #336699). Assign it to contacts with replace_crm_contact_tags.
create_crm_team
ChatGPTTeams: create a team with a name and an optional description. Repeating the same create is deduplicated; reload get_crm_teams for its id and revision.
create_document
ChatGPTUpload a context document for a Ninjo agent. If file_base64 is provided, uploads to S3 at agents/{influencer_id}/context/{uuid}/{file_name}. Returns the created document row.
create_feedback_upload_url
ChatGPTStep 1 of reporting feedback (optional, only when you want to attach the agent session). Returns a short-lived presigned S3 PUT URL + s3_key. Write the full agent session to a file and PUT it to upload_url (no special headers needed) — the bytes never pass through the tool-call payload or model context. Then call report_feedback with the returned s3_key as session_s3_key. Returns { upload_url, s3_key }.
create_messaging_channel
ChatGPTCreate a messaging channel on a connected GoHighLevel or Kommo account, so a Ninjo agent can answer conversations that live inside the CRM. WHEN THIS IS THE RIGHT ANSWER: a WhatsApp number can only be connected in ONE place at a time. If the number already lives in GoHighLevel/Kommo, it CANNOT also be connected directly to Ninjo — this channel is how you get around that: the number stays in the CRM and Ninjo replies THROUGH the CRM. For Instagram and Facebook you usually do NOT need this: they can be in the CRM and in Ninjo simultaneously, so create_connect_link with 'instagram'/'facebook' is the better path. PREREQUISITES, in order: 1. The CRM account is connected — create_connect_link with 'gohighlevel_crm' or 'kommo_crm'. 'gohighlevel_booking' does NOT work for this; it is a different integration on a different table. 2. The channel ALREADY EXISTS inside the CRM. Ninjo attaches to a channel that is set up in GoHighLevel/Kommo; it does not create one there. If it doesn't exist yet, the user must add it in the CRM first. There is NO manual webhook step in either CRM — do not ask the user to paste a webhook URL anywhere, and never ask for an API key or private-integration token. third_party_whatsapp (GoHighLevel + WHATSAPP only): set true when the number reaches GHL through an EXTERNAL provider (a WhatsApp QR/app integration) rather than GoHighLevel's own official WhatsApp. GHL rejects official-WhatsApp sends for those numbers, so a wrong value silently breaks outbound. ASK the user which of the two they have; do not guess. If it turns out wrong afterwards, fix it with set_messaging_channel_whatsapp_provider — the channel cannot simply be recreated. The channel is created ENABLED. Pass agent_id here to route it in one step; assigning later via set_agent_crm_channel needs a user JWT and fails for API-key callers. Common failures: 409 "already exists" (one channel per type per account), 409 asking for connected_account_id (more than one account of that CRM — take it from a list_crm_connections row for that provider, NOT from list_connected_accounts, which lists Meta sub-accounts from another table), 409 telling you to reconnect (the CRM account predates OAuth). A connected_account_id from the wrong table comes back as "No GoHighLevel account connected" — that error means the id did not match, not that the CRM is unconnected, so re-read it before telling the user to reconnect anything. Returns { channel, webhook_registered? }. On Kommo, webhook_registered: false means the channel exists but receives nothing — retry with register_messaging_channel_webhook before telling the user it is live.
create_resource_upload_url
ChatGPTStep 1 of uploading an agent-sendable audio/image clip. Returns a presigned S3 PUT URL + s3_key — the file bytes are NOT sent through this tool. AUDIO must be M4A/AAC (MP3 rejected); IMAGE must be JPG/PNG/GIF. Next: PUT the file to upload_url with the same Content-Type header (e.g. curl -T file.m4a -H 'Content-Type: audio/mp4' '<upload_url>'), then call register_creator_resource with the s3_key. Returns { upload_url, s3_key }.
create_thread
ChatGPTCreate a new Cortex thread (conversation between the influencer and their AI agent). Returns the new conversation object with id, title, status, created_at. Uses JWT for RLS when available; with API key/admin, pass influencer_id.
create_trigger
ChatGPTCreate a trigger for a Ninjo agent. type selects the variant and which fields apply: • keywords — DM keyword trigger: keyword (required), match_mode (KEYWORD_ONLY|ANYWHERE), allow_typo. • all-messages — fires on every DM or comment: keyword must be ALL_DM or ALL_COMMENTS; prompt_evaluator optional. • comments — comment keyword trigger: keyword (required), match_mode, allow_typo, responses (public reply templates). • ads — ad referral trigger: ad_id (required). • outgoing-messages — fires on an outgoing message keyword: keyword (required), assign_unpaused. • instagram-story — story reply trigger: story_id (required), story_created_at. Returns the created trigger row.
create_whatsapp_template
ChatGPTCreate a new WhatsApp message template and submit it to Meta for review (via mk1-chat). This SENDS NOTHING — it registers a template that can be broadcast later, once Meta approves it. Creation is asynchronous, so plan for the wait: 1. Call this tool. It returns { templateId, status } — status is normally PENDING, which means NOT usable yet. 2. Meta review usually takes minutes but can take up to 24h. Poll list_whatsapp_templates with includeAllStatuses:true and find this template by name/templateId: watch its status go PENDING → APPROVED. (The default listing shows APPROVED only, so on that path the template simply appears once approved — but includeAllStatuses:true lets you see it the whole time, including while PENDING.) 3. If it comes back REJECTED, the same includeAllStatuses:true listing carries its rejectedReason (why Meta rejected it) — no need to wait for Meta's email. Fix the wording that reason points at and create it again under a NEW name (a rejected name stays taken). 4. Once APPROVED, MARKETING/UTILITY can be broadcast the normal way: preview_whatsapp_template_recipients → confirm with the user → send_whatsapp_template. headerType decides which header field travels with it, and the two must agree: TEXT needs headerText, IMAGE needs headerImageUrl, the default NONE takes neither. A mismatch (an image URL on a NONE/TEXT header, a headline on a NONE/IMAGE one) is refused here before the call leaves, because headerType is what builds the template — a stray headerImageUrl would otherwise be dropped and the template created with no picture at all. For an IMAGE header, the headerImageUrl passed here is the sample Meta reviews. When you broadcast, pass the SAME headerImageUrl to send_whatsapp_template — that is what the contacts actually receive. AUTHENTICATION uses preset wording and a COPY_CODE OTP button. Omit bodyText/bodyExamples/headers/footerText/buttons; use authentication options for security disclaimer, expiry minutes and optional button label. After approval, your authentication backend sends one code per login attempt through POST /api/n8n/send-template with template.variables: [code] and a new idempotencyKey. send_whatsapp_template is a broadcast tool and cannot deliver authentication codes. The backend generates, expires and verifies codes. A template lives inside one WhatsApp Business Account, so pass fromWhatsAppAccountId (from list_whatsapp_templates) when the influencer has more than one number connected, and send it later from that same account. Returns { ok, influencerId, templateId, status, name, languageCode, category }.
deactivate_crm_product_price
ChatGPTProducts: deactivate a product price (productPriceId from get_crm_commerce) so it can no longer be used. Existing quotes and sales keep their price snapshots.
delete_agent
ChatGPTPermanently delete a Ninjo agent and all its associated data (triggers, prompt versions, documents, workflow relations, config). Cannot delete agents with active conversations — will return an error with the count. Returns { success: true }.
delete_contact_limit
ChatGPTDelete a contact limit by id. Returns { success: true }.
delete_creator_resource
ChatGPTDelete a creator resource (removes the S3 object and the DB row). Returns { deleted, resource_id }.
delete_crm_property
ChatGPTDelete property: permanently delete a property after reviewing preview_crm_property_delete. Can remove stored values; this is not archiving. Dependency blockers still apply.
delete_crm_sync_trigger
ChatGPTExternal CRM sync: delete a stage-to-contact-property trigger (triggerId from get_crm_sync). Values it already set on contacts are kept.
delete_custom_notification
ChatGPTDelete a custom notification by id. Returns { success: true }.
delete_custom_property
ChatGPTDelete a custom property by id. Returns { success: true }.
delete_document
ChatGPTDelete a context document from a Ninjo agent. If the document has an S3 file_key, deletes it from S3 as well. Returns { success: true }.
delete_notification_destination
ChatGPTDelete a notification destination by id. Returns { success: true }.
delete_property_action
ChatGPTDelete a property action by id. Its subtype row (http / crm_*) is removed too. Returns { success: true }.
delete_thread
ChatGPTDelete a Cortex thread and all its messages.
delete_trigger
ChatGPTDelete a trigger by ID and type. type must be one of: keywords, all-messages, comments, ads, outgoing-messages, instagram-story. Cascades to trigger_negative_config if present. Returns { success: true }.
delete_trigger_negative_config
ChatGPTRemove the negative config from a trigger. The trigger itself is not affected.
delete_whatsapp_template_definition
ChatGPTDelete a WhatsApp template definition by id (via mk1-chat). Refused with 409 if any notification destination still references it (detach or delete those first) — the definition is never silently orphaned. Returns { ok, influencerId, id }.
delete_workflow
ChatGPTDelete a workflow by id. Returns { success: true }.
deploy_agent_sdk
ChatGPTDeploy the Cortex SDK (system.md + the 8 v5Config fields) to a Ninjo agent in one correct-by-construction call. Bakes the multi-step deploy the cortex skills enforce but the raw tools don't: (1) update the prompt column if system changed, (2) merge changed v5Config fields, (3) re-sync trigger_keywords whenever keywords is provided — so keyword changes are always dual-written (v5Config context AND what actually fires) and system never lands in v5Config. Diffs each provided field against the live config and only calls what changed; omitted fields are left untouched (PATCH semantics — there is no set-to-null). Then re-fetches and verifies (version bumped, fields match, no v5Config↔trigger_keywords drift). On verified=false or partial=true the deploy did NOT fully succeed: pass rollback_version_id to restore_prompt_version to revert both prompt and config. Returns the deploy report. IMPORTANT: this ships the agent's MESSAGES only (prompt + v5Config). It does NOT create the contact limits, custom notifications, or follow-up workflows that turn a prompt into a working agent — build those separately (upsert_contact_limit / upsert_custom_notification / upsert_workflow), gated on your custom properties. verified=true means the messages are live, not that the system is complete. The result also carries a completeness report (the same deterministic build/wiring audit as diagnose_agent mode=quick) run AFTER the deploy — resolve its critical/warn findings (or run scaffold_agent_activation) before treating the agent as done.
diagnose_agent
ChatGPTAudit a live agent and return ranked defects, each with the exact fix tool. An agent is a SYSTEM, not a prompt: this is the "definition of done" as code. mode="quick" (default) — DETERMINISTIC tier only. Free, fast, reproducible: run it after every iterate. Service-role checks: no terminal contact limit, an active agent not linked to a connected account, ungated follow-ups, string-typed gating properties, hand-made properties duplicating an auto one (e.g. agendo_llamada ↔ call_booked), inert properties, missing conversion notification, robotic cadence (humanization off), and v5Config↔trigger_keywords drift. score/complete come from this tier. mode="full" — also runs two LLM-graded tiers (costs model calls — run pre-deploy or periodically, NOT every iteration): - behavioral: samples recent low-quality conversations (bad/stuck/low-happy) and grades them server-side — filter leak, NO_RESPONSE paraphrase, reasoning leak, premature booking. Needs a JWT-scoped token. Returns the sampled transcripts too. - prompt_audit: grades the deployed SDK (system.md + v5Config) against the Best-Practices rubric BP-2…BP-10 (fetched live from the wiki) — contradictions, example coverage, unguarded actions, voice drift, stale CTAs. Returns { agent_id, checked_at, mode, score (0–100, deterministic), complete, findings, behavioral, prompt_audit }. Resolve every critical/warn finding (across all tiers) before treating the agent as done.
disable_crm_payment_link
ChatGPTPayment links: disable a quote's payment link at its payment provider (paymentLinkId and provider from get_crm_contact_commerce or list_crm_commerce_records). Calls the provider.
disconnect_crm_sync
ChatGPTExternal CRM sync: disconnect a connected CRM account (accountId from get_crm_sync). Its sync connections stop syncing and are marked disconnected; messaging channels on the same account and historic opportunities are kept.
expire_crm_quote
ChatGPTQuotes: expire a quote now (quoteId from get_crm_commerce or get_crm_contact_commerce).
export_crm_contacts
ChatGPTContacts export: one filtered page of the contacts table as CSV, with its totalCount. Requires the export:contacts permission. Iterate pages for larger exports. Spreadsheet formulas are neutralized.
export_crm_opportunities
ChatGPTDeals export: export up to 50 selected opportunities (quote ids with their current revisions) to CSV with Studio's export authorization.
generate_image
ChatGPTGenerate an image using Gemini AI (gemini-3-pro-image-preview). Pass a prompt and an optional background image as base64. Returns { image_base64, mime_type }.
generate_synthetic_conversations
ChatGPTGenerate synthetic conversations for an agent by invoking the replicant Lambda. Two mutually-exclusive modes: pass personas for AI-simulated leads (user generated by an LLM), or pass scripted_scenarios to replay fixed user messages with no user-side inference (only the agent responds). Fan-out across the chosen items and return conversations in both structured and markdown formats. Returns { conversations, test_run_ids, lambda_invocations, lambda_errors, conversations_fetched, conversations_filtered, elapsed_seconds, warning }. min_turns defaults to 1 in scripted mode and 3 with personas; warning is non-null when every fetched conversation was dropped by min_turns (returned 0), suggesting a lower min_turns. influencer_id is inferred from the JWT when using an influencer-scoped token — only required when using admin or API key auth.
get_agent_config
ChatGPTGet the full configuration snapshot for a Ninjo agent: agent metadata, system prompt, and AgentConfig settings. Requires an influencer-scoped JWT. Returns { agent, config }.
get_agent_insights
ChatGPTFetch operational insights snapshot for an agent: quick stats (24h activity), hot leads waiting for follow-up, stalled leads by objection type, funnel transition rates, and content source performance. Returns: - quick_stats: { new_conversations_24h, qualified_leads_24h, bookings_sent_24h } - hot_leads: leads with funnel≥2, lead_score≥3, last message INBOUND 24–72h ago (up to 20) - stalled_by_objection: leads stalled 1–3 funnel, grouped by objection (MONEY/TRUST/TIMING/PRIORITY/UNKNOWN) - funnel_transitions: conversion rates between funnel stages for the lookback period - content_sources: per-source (Organic DM / Story Reply / Ad) conversion performance influencer_id is inferred from the JWT when using an influencer-scoped token.
get_agent_metrics
ChatGPTCalculate performance metrics for one or all agents. Includes engagement, funnel, lead score, booking rates, happy path, nurturing quality, monotonicity of funnel progression, and relative risk scores (z-scores). Returns { days, min_leads, agents: [{ influencer_id, influencer_username, leads, avg_engagement_score, avg_funnel, avg_lead_score, funnel_to_lead_score_ratio, bookings_sent, booking_send_rate, call_booked_observed_leads, calls_booked, call_book_rate_total, call_book_rate_per_lead_observed, call_book_rate_per_booking_observed, pct_calls_booked_low_lead_score, avg_happy_path_score, avg_nurturing_score, pct_happy_lt_60, pct_nurture_lt_60, pct_lead_score_eq_1, pct_funnel_ge_4, premature_rate_refined, stages_compared, monotonic_violations, worst_drop, lead_score_monotonic_non_decreasing, risk_raw, risk_score_0_100 }] }.
get_connection_status
ChatGPTReport, per integration, whether it is authorized AND whether it is actually finished: Instagram, Facebook, the CRMs ('gohighlevel_crm', 'hubspot_crm', 'kommo_crm'), booking ('gohighlevel_booking', 'calendly'), 'google_calendar' and 'manychat'. Use this to poll after handing the owner a connect link, and to verify setup instead of asking the user whether it worked. Read setup_complete, not connected. oauth_ok:true with setup_complete:false is a real state — booking is fail-closed, so an authorized calendar account with nothing selected tracks zero bookings. pending_step says what to do next: "select_calendars" → set_booking_calendars; "paste_api_key_in_studio" → send the user to /studio/{influencer_id}/integrations/manychat to set the channel AND the API key (never ask for the key); "authorize_with_connect_link"/"reconnect" → create_connect_link; "enable_for_agent_in_studio" (Google Calendar) → set_google_calendar_agent, which finishes it without leaving the chat. For 'manychat', setup_complete:true means everything Ninjo can SEE is configured (channel + key). It cannot see whether the user pasted Ninjo's webhook URL into ManyChat, which is what makes messages actually arrive — so remind them of that step rather than declaring the integration live. Returns { influencer_id, channels: { <provider>: { connected, invalid_token, oauth_ok, setup_complete, pending_step, name } } }. Only requested channels are present (pass provider to narrow).
get_contact
ChatGPTEverything the platform knows about ONE contact: native fields, the value of every custom property defined on the account, and the contact's conversations. This is the tool for "why did nothing happen for this person" — follow-ups, contact limits and notifications all gate on custom-property values, and this is the only way to read them for a given contact. Identify the contact with EXACTLY ONE of: contact_id (from search_contacts), whatsapp_number, instagram_username, email, phone. Passing two is rejected rather than silently AND-ed. If an identifier matches more than one contact row (which happens after a partial merge), the call fails with the count and asks you to use contact_id — it never picks one for you. READ is_set BEFORE DRAWING ANY CONCLUSION. Every property the influencer defines comes back, including ones this contact has never been given: - is_set: true → value holds the stored value (typed: boolean, number, option text, or string). This is what the automations see. - is_set: false → the evaluator has NEVER written this property for this contact, and value is null. That is NOT "false" and NOT "empty". A contact limit gated on compra_realizada behaves the same whether the property is false or unset, but the first means the evaluator ran and said no, and the second means it never ran — opposite fixes. Custom properties are written by the post-hoc evaluator agent, never by the conversational agent, so a wrong value is an evaluator question, not a prompt question. conversations lists the contact's conversations (newest first, up to 20) with conversation_id for get_conversation_messages / get_conversation_decisions, plus agent_conversation so you can see at a glance whether an agent was ever attached. whatsapp_identity explains a null whatsapp_number: bsuid means the lead hid their number in WhatsApp's privacy settings. That is not lost data and there is nothing to backfill — the number cannot be recovered, the team cannot call them, but WhatsApp messages and templates still reach them. comment_post_url, comment_media_id and commented_at describe the contact's first public comment (the post it was left on); null when they never commented. Returns { contact_id, first_name, last_name, email, phone_number, whatsapp_number, whatsapp_identity, is_whatsapp_subscribed, instagram_username, picture_url, created_at, comment_post_url, comment_media_id, commented_at, properties: [{ codename, label, type, is_set, value, selected_options, updated_at }], properties_set_count, conversations: [{ conversation_id, type, agent_conversation, agent_id, last_message_at }] }.
get_contact_limits_context
ChatGPTFetch context data required to configure contact limits: available agents and custom properties with options. Returns { agents, customProperties }.
get_conversation_decisions
ChatGPTExplain why a lead saw no reply. Returns the platform's own recorded decisions for one conversation: NO_RESPONSE events, contact-limit events (a limit fired and muted the conversation permanently) and send failures (kind send_failed: the agent DID reply, the channel rejected it, the lead never saw the text that is still in the transcript; detail is <error_code>: <description>, e.g. THREAD_OWNER_MISMATCH = another Meta app such as ManyChat owns the Instagram thread, MESSAGE_WINDOW_EXPIRED = outside the 24h window, INVALID_TOKEN = reconnect the account). READ THE DETAIL, not just the kind: NO_RESPONSE alone means the agent chose silence (prompt-side); NO_RESPONSE: last_message_not_user means there was nothing to reply to and is benign; NO_RESPONSE - cot_filter_blocked means the chain-of-thought filter suppressed a leaking message (a platform safety net, see knowledge/reasoning-leak.md); NO_RESPONSE - <text> is the agent's own stated reason. Only the first is a prompt problem. Call this FIRST whenever an operator says the agent did not answer a specific lead, or that a lead stopped answering, before reading the prompt — an empty transcript looks identical whether the agent chose silence or the message never arrived, and a transcript with agent text looks identical whether it was delivered or rejected; this is the only way to tell. An empty result means none of those fired, so the cause is upstream (routing, trigger, connected account) — work knowledge/runbooks/agent-not-answering.md. Note NO_RESPONSE on a comment trigger suppresses BOTH legs, the public reply and the private DM.
get_conversations
ChatGPTFetch real production conversations from influencer_conversation_rollup_view_rls + messages table. Returns conversation metadata and full message history. Modes: - recent: latest conversations with ≥3 messages - booking: booking link was shared with the lead - high-funnel: funnel stage ≥ 4 - high-score: Lead Score > 3 - bad: funnel ≥ 4 but lead score ≤ 3 (high funnel, low quality) - low-happy: happy_path_score < 60 - high-happy: happy_path_score ≥ 80 - stuck: agent sent ≥ 6 messages but funnel < 3 influencer_id is inferred from the JWT when using an influencer-scoped token. Returns { influencer_id, mode, count, conversations: [{ conversation_id, contact_id, contact_username, meta: {...}, messages: [{direction, sent_at, content}] }] }. The contact_id can be passed to the WhatsApp template preview/send tools.
get_crm_assignment
ChatGPTOwnership: read who owns one exact conversation or pipeline record, its assignment history, eligible teams and people, and your capabilities, including the current revision. Use cursor for older history.
get_crm_booking_conversions
ChatGPTBooking won/lost outcomes: read the Booking Link manual won/lost records (at most one per outcome) for one contact. Requires read:pipelines and read:contacts. These legacy records are separate from native sales and quote opportunities (deals).
get_crm_commerce
ChatGPTCommerce: read the product and price catalog, quotes, configured payment providers and commerce capabilities. Prices and quote snapshots are immutable versions. Filter with productQuery and quoteQuery; use get_crm_contact_commerce for one contact and list_crm_commerce_records for older records and line items.
get_crm_contact
ChatGPTContact 360: one contact's identity, tags, visible conversations, scoped properties (facts), pipeline records and commercial history. History pages are bounded; use get_crm_contact_history for older pages. Contacts have no owner of their own: ownership belongs to exact conversations or pipeline records (get_crm_assignment).
get_crm_contact_commerce
ChatGPTContact commerce: read one contact's quotes, sales, payments, refunds, No Sale outcomes and imported commercial history, with available products and provider capabilities. Page with historyCursor and importedHistoryCursor.
get_crm_contact_edit_context
ChatGPTContact edit snapshot: read a contact's editable identity and document identity before replace_crm_contact. Copy every identity field you want to keep into the replacement; empty strings clear values.
get_crm_contact_history
ChatGPTContact 360 history: page through a contact's facts, conversations or pipeline timeline after get_crm_contact. Facts and conversations need the returned next cursor; the pipeline timeline may omit it for its first page. Keep the opaque cursor and the exact contact. Results and conversation links obey record scope.
get_crm_contact_tags
ChatGPTContact tags: read one contact's tags and the active tags available to add.
get_crm_overview
ChatGPTStart here for native Ninjo CRM: contacts, tags, properties, pipelines and stages, deals (opportunities), products, quotes, sales, payment links, teams, routing and external CRM sync. Returns your permissions in the workspace, the rollout flags per area, an index of the CRM tools grouped by area, and workflow guidance. Native pipelines are not the external-CRM mirrors of list_crm_pipelines and list_crm_stages.
get_crm_pipeline_automations
ChatGPTPipeline automations: read the rules that move, add or transfer pipeline records when a record enters a stage or a contact fact changes, with active stages, contact fact definitions and options, and recent runs. Ownership routing is separate (get_crm_routing).
get_crm_pipeline_draft
ChatGPTPipeline draft preview: read a saved pipeline configuration draft and recompute its publish preview without changing it: current revisions, blockers and the fingerprint publish_crm_pipeline_draft needs. Requires read:pipelines and manage:workspace-settings.
get_crm_pipelines
ChatGPTNative pipelines: read Ninjo pipelines, their ordered stages and records (deals in a stage). Filter by pipelineId, status and stageId; page with after; pass recordId for one record's detail and history. These ids are not the external-CRM mirror ids of list_crm_pipelines and list_crm_stages. Use get_crm_pipeline_draft for a draft and its publish preview.
get_crm_property
ChatGPTProperty definition: read one property's full edit state and dependency context before replace_crm_property or a deletion.
get_crm_routing
ChatGPTRouting rules: read the automatic assignment rules with their typed fact criteria and options, eligible targets, revisions and recent outcomes. Routing picks the human owner; pipeline automations move records.
get_crm_sync
ChatGPTExternal CRM sync: read the connected external CRM accounts with their sync settings, mirrored pipelines, stage-to-property triggers and Airtable mappings. Never returns provider tokens, webhook secrets or event URLs. Use create_connect_link to authorize or reconnect a provider. Mirrored pipelines belong to the external CRM; native Ninjo pipelines are in get_crm_pipelines.
get_crm_teams
ChatGPTTeams: read teams, their members, eligible workspace users and team revisions. Teams do not grant workspace access. Read before changing membership.
get_discord_invite
ChatGPTReturn the stored Discord invite for the influencer's mapped operator channel (invite_url + metadata). Throws if no invite is stored — run bootstrap_discord_channel first. influencer_id is inferred from an influencer-scoped JWT; admin/API-key auth must pass it.
get_instagram_posts
ChatGPTFetch the influencer's recent Instagram posts via Meta Graph API. influencer_id from auth when available; from param when admin.
get_instagram_profile
ChatGPTFetch the influencer's Instagram profile via Meta Graph API. influencer_id from auth when available; from param when admin.
get_knowledge
ChatGPTFetch a specific platform knowledge document by slug. Use list_knowledge first to discover available slugs.
get_me
ChatGPTReturn the current authenticated context: influencer_id (the one active for this request), user_id, scope (single-influencer | multi-influencer | admin), available_influencer_ids (selectable via X-Influencer-Id when the token carries a user_id; multi-influencer + admin tokens), and influencers (map of influencer_id → Instagram handle — identify a creator by handle but pass the influencer_id to tools). 'scope' is the selection mode, NOT a DB role, and does not limit which tools you can call. Same shape as GET /api/v1/me.
get_peer_managed_files
ChatGPTReturns managed files (e.g. changelog.md) from peer influencers that share the same use_case or vertical as the requesting influencer. influencer_id from auth when available; from param when admin. At least one of use_case or vertical must be provided. Returns { peers: [...], total }.
get_playbook_doc
ChatGPTFetch one playbook, template, or worked-example SDK by an id from get_playbook_index. For sample SDKs, call with no section to get the file manifest, then pass section to select a file (e.g. system, examples, objections, keywords, meta). Large docs paginate: when has_more is true, call again with the returned next_cursor.
get_playbook_index
ChatGPTCall this FIRST before creating, iterating, analyzing, or answering any question about a Ninjo agent or the cortex SDK. Returns the catalog of operating manual, knowledge base, prompt-architecture templates, and worked-example SDKs; fetch the relevant ones with get_playbook_doc before drafting. A Ninjo agent is a SYSTEM (system prompt + the 8 v5Config fields + triggers + automation), not just a prompt — the playbook is how you build the whole system instead of a bare prompt.
get_self_serve_data
ChatGPTFetch self-serve onboarding data from MongoDB for an influencer. Returns data from four collections: - influencer_bio: IG profile processed by GPT (bio, audience, content formats, engagement patterns) - instagram_post: Posts with metrics and video transcriptions - instagram_conversation: DM conversations with followers - creator_input: Self-serve onboarding form (program details, lead magnets, style, use case) Missing sources are listed in missing_sources — expected for incomplete onboarding. Returns { influencer_id, sections: [{ source, count?, data }], missing_sources: string[] }.
get_synthetic_conversations
ChatGPTFetch synthetic conversations from MongoDB by one or more test_run_ids. Use this to retrieve results after a generate_synthetic_conversations call or to re-fetch existing runs. Returns { conversations, count }.
get_thread_messages
ChatGPTGet message history for a Cortex thread, ordered chronologically. Supports cursor-based pagination via the before parameter (ISO timestamp). Returns { messages: [{ id, role, content, created_at }] }.
get_trigger_negative_config
ChatGPTGet the negative config (temporary block) of a trigger. When enabled and now < expires_at, the trigger is suppressed even if it would otherwise match. Returns { negative_config } which is null if none is set. trigger_type: keywords | all-messages | comments | ads (outgoing-messages and instagram-story are not supported).
get_workflow_activity
ChatGPTGet workflow activity snapshot (fires/evaluations) for the last N days. Returns { days, since, activity }.
import_crm_contacts
ChatGPTImport contacts: create or update contacts from a CSV (at most 250 KB) with Studio's importer; returns per-row created/updated/skipped/error results. Use the native headers from the import guidance; an optional bulk property value applies to every row. Does not change subscription consent or accept non-contact facts. Review the counts before repeating a partial import.
list_agent_channels
ChatGPTList every messaging channel a Ninjo agent answers, from BOTH sources, in one unified view. Returns { channels, count }; each channel carries source: "direct" (a Meta account — Instagram/WhatsApp — connected directly in Ninjo) or "crm" (a CRM sync connection — GoHighLevel, Kommo, HubSpot, Airtable — that RELAYS its messages to this agent). Use this to tell whether an agent is a free Meta agent or is dedicated to a CRM channel: a source:"crm" channel means the agent is NOT connected to Instagram directly — it answers the messages that arrive from GHL/Kommo through that channel. channel_type is the account type (direct) or the CRM provider (crm); connected is the single 'is this channel live' flag (direct: the Meta token is valid; crm: the connection is enabled and not disconnected). Metadata only — no access tokens or webhook secrets are returned.
list_agent_tools
ChatGPTList all tools/skills assigned to a Ninjo agent, including their enabled status, settings, and prompt.
list_agents
ChatGPTList all agents belonging to the authenticated influencer. Returns { agents: AgentRow[], count: number }. Useful to resolve an agent_id when only the influencer identity is known.
list_booking_calendars
ChatGPTList the GoHighLevel calendars (or Calendly event types) on the connected booking account, flagging which ones Ninjo currently tracks. This is step 3 of connecting booking: create_connect_link → the owner authorizes → list_booking_calendars → set_booking_calendars. Read the names back to the user and let them pick; the ids are opaque provider ids (a Calendly id is a URI) and must never be guessed. connected:false means the platform was never authorized — send a connect link instead. load_failed:true means the list could not be read (expired token / provider down), so an empty list is NOT evidence the account has no calendars. Returns { platform, connected, load_failed, calendars: [{ id, name, selected }], count }.
list_connected_accounts
ChatGPTList connected Meta sub-accounts linked to a Ninjo agent. Returns { accounts, count }. Metadata only — no access tokens or secrets are returned.
list_contact_limits
ChatGPTList configured contact limits for an influencer. Returns { contactLimits: ContactLimit[] } including related agents and propertyConditions.
list_creator_resources
ChatGPTList the influencer's agent-sendable resources (audio/image clips sent mid-conversation). Filter by type (IMAGE | AUDIO) and agent_usable_only. Returns { resources: [{ id, name, type, agent_usable, agent_usage_context, ... }], count }.
list_crm_commerce_records
ChatGPTCommerce history: page through native products, prices, quotes and quote lines, sales and sale lines, payments and payment events, payment links and No Sale records beyond the bounded snapshots of get_crm_commerce and get_crm_contact_commerce. Pick one entity with its parent id, then follow nextCursor until hasMore is false, keeping the same selection. Money is in minor-unit strings. Provider secrets, error bodies and hidden conversation provenance are never returned.
list_crm_connections
ChatGPTList the influencer's CRM connections (GoHighLevel, Kommo, HubSpot, Airtable). This is the ROOT of CRM discovery — it returns the sync_connection_id you pass to CRM property actions, to list_crm_pipelines / list_crm_fields, and to set_messaging_channel_enabled. Unlike list_agent_channels (which shows only connections routed to a given agent), this shows ALL of the influencer's connections. Returns { connections, count }. Metadata only — no tokens or webhook secrets. It returns TWO different kinds of row, distinguished by event_name: a row WITHOUT a '.messaging.' event_name is the CRM SYNC connection (contacts, opportunities, fields — one per connected account); a row whose event_name contains '.messaging.' (e.g. 'gohighlevel.messaging.whatsapp', 'kommo.messaging.instagram') is a MESSAGING CHANNEL that relays conversations from the CRM to a Ninjo agent. They are not interchangeable: property actions and pipelines belong to the sync row, while set_messaging_channel_enabled and set_agent_crm_channel act on the messaging rows. Read enabled here before toggling a channel.
list_crm_contacts
ChatGPTContacts table: list native contacts with typed properties and tags, using filters, sorting and page/pageSize, with totalCount. Iterate pages to read everything. Use get_crm_contact for one contact's full 360 view.
list_crm_fields
ChatGPTList a CRM connection's custom fields, fetched LIVE from the CRM. entity picks which object's fields — 'contact' or 'opportunity' — because CRM fields hang off a specific object. Each field's id is the crm_external_field_id you pass to a CRM_FIELD_UPDATE property action. Returns { fields, count }.
list_crm_opportunities
ChatGPTDeals (opportunities): list quote-based opportunities with stage, owner, won/lost, follow-up and payment state, and valid filter options. One row per quote. Page with after; the API reports filter issues. Commerce stays authoritative for money and quote status.
list_crm_pipelines
ChatGPTList the CRM pipelines synced for an influencer (optionally narrowed to one sync_connection_id). Use this to find the pipeline that holds the stage you want for a CRM_STAGE_TRANSITION property action. Pipelines come from the local synced mirror — if a connection has never synced they come back empty. Returns { pipelines, count }.
list_crm_properties
ChatGPTProperties: list native property definitions with their scope (CONTACT, CONVERSATION and PIPELINE_RECORD facts are distinct), type, options, defaults and evaluation settings. Tags are managed separately.
list_crm_stages
ChatGPTList the stages of a CRM pipeline (from list_crm_pipelines). Each stage's id is the crm_target_stage_id / crm_stage_id you pass to a CRM_STAGE_TRANSITION or CRM_PUSH_CONTACT property action. Stages come from the local synced mirror. Returns { stages, count }.
list_crm_tags
ChatGPTTags: list the workspace's reusable contact tags, including archived ones, with colors, assigned counts and timestamp revisions (the expectedRevision for update_crm_tag, archive_crm_tag, restore_crm_tag and remove_archived_crm_tag_assignments).
list_custom_notifications
ChatGPTList custom notifications for an influencer. Includes linked destinations. Returns { customNotifications }.
list_custom_properties
ChatGPTList custom properties for an influencer. Includes rich metadata and options. Returns { customProperties }.
list_documents
ChatGPTList all context documents (agent_document_contents) for a Ninjo agent. Returns { documents, count }.
list_influencer_connected_accounts
ChatGPTList ALL connected Meta sub-accounts that belong to the influencer (Instagram, WhatsApp, etc.), whether or not they are linked to an agent. Use this to DISCOVER the connected_account_id to pass to set_connected_account when linking a fresh agent — list_connected_accounts only shows accounts already linked to a given agent, so it is empty for a new agent. Returns { accounts, count }. Metadata only — no access tokens or secrets are returned.
list_knowledge
ChatGPTList all available platform knowledge documents (playbooks, templates, strategy guides, platform docs). Returns slug, category, and title for each doc. Use get_knowledge with a slug to fetch the full content.
list_notification_destinations
ChatGPTList custom notification destinations for an influencer. Optional channel filter. Returns { notificationDestinations }.
list_property_actions
ChatGPTList the property actions configured for an influencer. A property action is a side-effect that fires when a custom property reaches a value: an HTTP_REQUEST (webhook) or one of the CRM actions — CRM_STAGE_TRANSITION (move an opportunity to a stage), CRM_FIELD_UPDATE (write a CRM field), CRM_TASK_CREATE (open a task), CRM_PUSH_CONTACT (push the contact into the CRM), CRM_CONTACT_TAG (write a tag on the CRM contact, or on its Kommo lead). Each item carries its condition (the operator + value that triggers it) and exactly one populated subtype block (http / crm_stage_transition / crm_field_update / crm_task_create / crm_push_contact / crm_contact_tag) matching its action_type. Use this to see how a custom property is wired to downstream automation and to CRM channels. Returns { propertyActions, count }. Metadata only — no secrets.
list_schedules
ChatGPTList the influencer's real bookings from the schedules table — who booked, when, from where, and their status. This is the ground-truth booking record, distinct from calls_booked on get_agent_metrics (an LLM-inferred custom-property estimate read from the conversation, not this table). Filters (all optional, combined with AND; status/source are OR'd internally): status (ACTIVE | CANCELLED | SHOWED | NO_SHOW), source (GO_HIGH_LEVEL | CALENDLY | ESCULPE_CRM | AGENT | GOOGLE_CALENDAR | AGENDAPRO | IMPORT; AGENDAPRO = synced from the workspace's AgendaPro account; agent_id is always null; IMPORT = a past visit imported from the workspace's historical records: status SHOWED, the date is real but the time is a 12:00 local placeholder, created_at equals the visit time, name lists the services, agent_id is always null), agent_id, contact_id, has_agent, scheduled_after/scheduled_before (on the appointment datetime), booked_after/booked_before (on when the booking was created), search (contains, on the contact's name/phone/email). TIMEZONE — read this before quoting any hour to anyone. Pass timezone (an IANA name, e.g. "America/Argentina/Buenos_Aires") and the tool does all the conversion for you: every returned datetime/created_at comes back in that zone with its offset attached ("2026-08-01T16:00:00.000-03:00", i.e. a 4pm call), and bare dates in the filters are read as local days — scheduled_after/booked_after as 00:00 local, scheduled_before/booked_before as the end of that local day, so "bookings in August" is just booked_after "2026-08-01" + booked_before "2026-08-31". Never add or subtract hours yourself; set timezone and quote the wall clock you get back. The response echoes the zone it used in its top-level "timezone" field. Omit timezone and everything stays UTC with a Z — correct, but then 19:00Z is a 4pm call for a UTC-3 workspace and it is on you to say so. Where to get the zone: the agent's own config already has one — call get_agent_config and read its "timezone" field (the same value the agent's native get_current_time tool uses). That is the operator's business zone and the right thing to pass here. If the agent has none set, or the question spans several agents, ask the operator which zone they work in — never infer it from a contact's phone number, and never assume UTC-3 because most workspaces are. Filters also accept full ISO 8601 instants with a zone at any time; a bare date without timezone is rejected rather than assumed to be UTC midnight. Three things you MUST get right when reading the response: 1. agent_id credits the booking to a Ninjo agent; a null agent_id does not by itself mean the contact never talked to one. AGENT and GOOGLE_CALENDAR bookings carry the agent that booked them in the conversation. GO_HIGH_LEVEL, CALENDLY and ESCULPE_CRM bookings carry the agent of the contact's most recent agent conversation when the booking first arrived, so null there means there was none yet (direct link, web form, manual entry). AGENDAPRO bookings are never attributed: their agent_id is always null, whether or not the lead talked to an agent. IMPORT rows are past visits imported from the workspace's historical records and are never attributed either. Any booking's agent_id becomes null when its agent is deleted, and bookings made before mid-March 2026 have no attribution at all. Use has_agent:true/false to split attributed from unattributed bookings, and do not filter by agent on bookings made before mid-March 2026 expecting it to mean anything. 2. datetime ≠ created_at. scheduled_after/scheduled_before answer "what's on the calendar" (the appointment); booked_after/booked_before answer "who booked recently" (when the row was created). They are not interchangeable — pick the one that matches the question. 3. form_data is raw and its shape depends on source. GO_HIGH_LEVEL rows carry [{id, value}] with GoHighLevel's internal field id, not the question text; it's inspectable but not interpretable without the CRM's field dictionary. AGENDAPRO rows carry an agendaProScheduleSync object (AgendaPro sync provenance), a…
list_threads
ChatGPTList Cortex threads for an influencer, ordered by most recently updated. Each item includes id, title, status, last_message, created_at, updated_at.
list_trigger_audios
ChatGPTList the audios attached to a trigger, ordered by order ascending. type selects which trigger family: keywords (DM keyword trigger) or ads (ad referral trigger). Each audio references a CreatorResource (type=AUDIO) played in rotation when the trigger matches. Returns { audios }.
list_trigger_canned_responses
ChatGPTList the canned text response variants configured on a trigger, ordered by order ascending. On the FIRST trigger match in a conversation, mk1-chat sends one variant at random instead of invoking the LLM (saving agent cost); follow-up messages are handled by the normal agent. type selects the trigger family: keywords | all-messages | comments | ads | instagram-story (outgoing-messages is not supported). Returns { canned_responses }.
list_triggers
ChatGPTList all triggers for a Ninjo agent, grouped by type: keywords (DM keyword triggers), all_messages (ALL_DM / ALL_COMMENTS), comments (comment keyword triggers), ads (ad referral triggers), outgoing_messages, instagram_story. Keyword and ad referral triggers include audios when configured.
list_whatsapp_template_definitions
ChatGPTList the influencer's stored WhatsApp template definitions (via mk1-chat). A template definition is the persisted binding that a WHATSAPP_TEMPLATE notification destination points at (whatsappTemplateDefinitionId). Use this to obtain that UUID when wiring upsert_notification_destination, or to inspect the current variable values. Returns { ok, influencerId, definitions: [{ id, templateId, templateName, languageCode, variableMappings: [{ id, name, value, locations }] }], count }.
list_whatsapp_templates
ChatGPTList the influencer's Meta-approved WhatsApp message templates (via mk1-chat). Use this first when the user wants to start a WhatsApp conversation outside the 24-hour customer-service window — only APPROVED templates can be sent. Returns { ok, influencerId, templates: [{ templateId, name, language, status, components }], count }.
list_workflows
ChatGPTList workflows for an influencer. Optional filters: type and customNotificationId. Returns { workflows }.
mark_crm_opportunities_lost
ChatGPTDeals (opportunities): mark up to 50 selected opportunities lost with a lostReason, each with its current revision from list_crm_opportunities. Changes CRM state only; quotes and payments are untouched. Check per-row results for partial failures.
mark_crm_opportunity_won
ChatGPTDeals (opportunities): mark one opportunity won, with its current revision from list_crm_opportunities. Changes CRM state only; it never sends quotes or moves payments.
mark_crm_quote_sent
ChatGPTQuotes: mark a quote as sent, advancing its status. It does not message the contact; share the quote with the messaging tools.
move_crm_opportunities_to_stage
ChatGPTDeals (opportunities): move up to 50 selected opportunities to a stage of a pipeline, each with its current revision from list_crm_opportunities. Check per-row results for partial failures.
move_crm_pipeline_record
ChatGPTPipelines: move a pipeline record to another stage of its pipeline, using the record's current revision. History is preserved and configured pipeline automations may run. To move it to another pipeline use transfer_crm_pipeline_record.
pause_conversation_agent
ChatGPTPause the agent on a specific conversation. The agent will stop responding to inbound messages in that conversation until resumed. Identify the conversation by the contact's platform identifier (Instagram username, Facebook ID, or WhatsApp phone number).
preview_crm_property_delete
ChatGPTProperty delete preview: read a property's dependencies and usage before delete_crm_property. Changes nothing.
preview_whatsapp_template_recipients
ChatGPTResolve candidate contact ids server-side before sending a WhatsApp template. Contacts without a WhatsApp number or unsubscribed from WhatsApp are excluded. ALWAYS call this before send_whatsapp_template: show the eligible sample and counts to the user and obtain their explicit confirmation. Then send with the SAME contactIds you previewed. Returns { ok, influencerId, requestedCount, eligibleCount, excludedCount, eligibleSample, eligibleSampleTruncated, eligibleSampleLimit, excludedContactIds }.
publish_crm_pipeline_draft
ChatGPTPipeline setup, step 2: publish exactly the reviewed draft preview, with its draft revision, the current configuration revision (null for a new pipeline) and previewFingerprint. Stale previews and unsafe stage removals or archives fail; reload and review a new preview before retrying.
record_crm_booking_conversion
ChatGPTBooking won/lost: record a contact's Booking Link outcome as won (with a positive amount in major currency units) or lost, and push it to connected CRMs. Requires write:opportunities. One record per contact and outcome: repeating overwrites amount and note and may repeat the external push. Currency defaults to USD on creation and is kept on updates. Read get_crm_booking_conversions first. Does not create a native sale or close a quote.
record_crm_no_sale
ChatGPTSales: record a No Sale outcome for a contact with an uppercase reasonCode such as NOT_INTERESTED, PRICE, TIMING or OTHER, and an optional note.
record_crm_outside_payment
ChatGPTSales: record a payment received outside Ninjo against a contact's sale. amountMinor is an integer string in minor units (USD 19.95 is "1995"). Records evidence only; it never charges through a provider.
record_crm_outside_refund
ChatGPTSales: record a refund made outside Ninjo against a contact's payment. amountMinor is an integer string in minor units (USD 19.95 is "1995"). Records evidence only; it never refunds through a provider.
record_crm_outside_sale
ChatGPTSales: record a sale paid outside Ninjo for a contact, optionally against a quote. Lines use either productPriceId versions or productId with a unitAmount in minor units. Records evidence only; it never charges through a provider.
refresh_crm_sync
ChatGPTExternal CRM sync: refresh a connected provider's pipeline mirror and health/setup metadata through the existing integration. Calls the provider, may refresh its tokens and overwrites the synced mirror. For Airtable setup, pass airtableBaseId to discover table and field ids. Returns safe account metadata and setup choices, never credentials.
register_creator_resource
ChatGPTStep 2 of uploading: after PUTting the file to the presigned URL, register the DB row pointing at s3_key and make it agent-usable. usage_context is required when agent_usable is true (the default) — a concrete sentence telling the agent WHEN to send it. Returns { resource }.
register_messaging_channel_webhook
ChatGPTRe-register the Kommo account webhook for an existing messaging channel. Kommo only — GoHighLevel needs no per-channel webhook and is rejected. Use this when create_messaging_channel came back with webhook_registered: false. That channel exists but receives NOTHING: Kommo does not know where to deliver its messages, so the agent stays silent and the symptom looks like a broken agent rather than a setup step. This is the recovery path — without it the only fix is re-saving the channel in Studio. Safe to call more than once: the destination and secret are unchanged, so Kommo upserts rather than adding a duplicate. It is also harmless on a channel that is already registered. Returns { channel, webhook_registered }. If webhook_registered is still false the retry failed too — tell the user the channel is not receiving messages yet instead of reporting the channel as live; a repeated failure usually means the Kommo account's token is stale and needs a reconnect.
remove_archived_crm_tag_assignments
ChatGPTTags: permanently remove an archived tag from every contact it was assigned to. Requires write:contacts. Archiving alone keeps the assignments; this cannot be undone. expectedRevision is the tag's timestamp revision from list_crm_tags.
remove_crm_team_member
ChatGPTTeams: remove a member from a team, using the team's current revision from get_crm_teams. Records the member owns may block the removal.
replace_crm_contact
ChatGPTReplace contact identity: overwrite a contact's complete editable identity (names, notes, phone, email, WhatsApp, Instagram, verification flags). Read get_crm_contact_edit_context first and resend every value you keep: all fields are required and empty strings clear them. Verification and attested-identity protections still apply. Gender and country use update_crm_contact_attributes.
replace_crm_contact_tags
ChatGPTSet contact tags: replace a contact's complete set of active tags. To add or remove one tag, read get_crm_contact_tags and resend every tag you keep; [] clears them all. Archived tags cannot be newly added. Tag facts, routing and automations react to the change.
replace_crm_product
ChatGPTProducts: replace a product's name, description and SKU; an empty description or SKU clears it. Prices are immutable versions: change pricing with add_crm_product_price and deactivate_crm_product_price.
replace_crm_property
ChatGPTReplace property definition: overwrite a property's editable definition. Read get_crm_property first and resend every field you keep. The scope cannot change here; option and dependency protections still apply.
replace_objectives
ChatGPTReplace all objectives for a Ninjo agent. Deletes existing objectives and inserts the provided array. Pass an empty array to clear all objectives. Returns { success: true }.
report_feedback
ChatGPTReport a problem to the Ninjo developers when you cannot complete a task (missing tool/skill/playbook/info, a bug, or a feature request). Files an issue in Linear (Cortex-ops project, label by type: ERROR→Bug, FEATURE_REQUEST→Feature, MISSING_INFO→Improvement) and pings the devs Slack channel with the ticket + affected client. Provide what you were trying to do (operation), what went wrong (problem), and the type. To attach the full session, first call create_feedback_upload_url, upload the session, and pass its s3_key as session_s3_key. Returns { ok, issue_id, issue_identifier, issue_url, slack_posted }. slack_posted may be false (partial success) even when the issue was created.
reset_crm_airtable_sync
ChatGPTExternal CRM sync: reset a connected Airtable account's setup, removing its webhook and field mappings. Configure it again with configure_crm_airtable_sync after refresh_crm_sync.
restore_crm_tag
ChatGPTTags: restore an archived contact tag so it can be assigned again, with the assignments it kept. expectedRevision is the tag's timestamp revision from list_crm_tags.
restore_crm_team
ChatGPTTeams: restore an archived team, using its current revision from get_crm_teams.
restore_prompt_version
ChatGPTRestore a previous prompt version. Sets the agent's active prompt to the specified version and updates current_prompt_version_id.
resume_conversation_agent
ChatGPTResume the agent on a previously paused conversation. The agent will start responding to inbound messages again. Identify the conversation by the contact's platform identifier (Instagram username, Facebook ID, or WhatsApp phone number).
save_crm_pipeline_draft
ChatGPTPipeline setup, step 1: save a full pipeline configuration (name, default flag, ordered stages with colors and success/failure outcomes) as a draft for a NEW pipeline, an EXISTING one (current configuration revision) or an existing DRAFT (current draft revision). Keep existing stage ids; omit ids only for new stages. Returns a preview: review its blockers, then publish_crm_pipeline_draft with the exact returned fingerprint and revisions.
save_image
ChatGPTUpload a base64 image to S3 (ninjo-prod-content, key: amplify/campaigns/{campaign_id}/{sequence}.{ext}) and update campaign_sections.image_url in the database. Returns { cdn_url }.
scaffold_agent_activation
ChatGPTWire the standard activation kit onto an agent, correct-by-construction. diagnose_agent DETECTS missing activation infra; this REMEDIATES it. The gateway can't infer an agent's conversion property or motion, so you supply the intent and this guarantees correct wiring: - ensures terminal_property exists as a BOOLEAN (string properties gate unreliably), - an enabled contact limit gated on it, so the agent stops messaging contacts who converted, - (followup) a FOLLOW_UP gated on not-converted (+ optional interest) — never ungated, - (notify) a conversion notification (workflow + custom notification) on an existing destination. Idempotent: re-running reuses any piece already wired for this agent instead of duplicating it. Returns what was created vs reused, plus a fresh completeness report. NOTE: if terminal_property is not a recognized terminal codename (call_booked / purchased / …), diagnose may still report no_terminal_stop — recognized_terminal in the result tells you.
search_contacts
ChatGPTSearch the influencer's contact directory with composable AND filters and pagination — the same audience picker behind the studio contacts/templates page. Returns each contact's contact_id, which you pass to preview_whatsapp_template_recipients and send_whatsapp_template. Native filters (all optional): name (partial, first or last), email, phone, whatsapp_number, instagram_username, is_whatsapp_subscribed, has_whatsapp_number, created_after / created_before (ISO 8601). Ad attribution: from_ads (true → only contacts who came from a Meta ad — at least one inbound Instagram/Facebook message carries an ad referral; false → only contacts with no ad referral on any inbound), ad_id (only contacts with an inbound referral for that exact Meta ad id; implies from_ads). When either is set, each contact is enriched with its first-touch ad metadata — the earliest ad-tagged inbound — (referral_ad_id, referral_source, referral_type, referral_ref, ad_title, ad_post_id, ad_photo_url, ad_video_url, post_url); otherwise those fields come back null. Custom-property filters (custom_properties[]): each { codename, ... } is resolved to the property's type and matched accordingly: - boolean → equals_boolean - integer → min and/or max - option → value (the option's text, case-insensitive) - string → value (case-insensitive contains) Get codenames from list_custom_properties. Pagination: limit (default 25, max 100), page (default 1). To target a WhatsApp template send: filter here (often is_whatsapp_subscribed: true + has_whatsapp_number: true), collect contact_id values, then preview before sending. Preview re-applies eligibility server-side, so search is for audience selection, not the final eligibility gate. Returns { influencer_id, filters_applied, total_count, page, total_pages, pages_remaining, count, contacts: [{ contact_id, first_name, last_name, email, phone_number, whatsapp_number, is_whatsapp_subscribed, instagram_username, created_at, referral_ad_id, referral_source, referral_type, referral_ref, ad_title, ad_post_id, ad_photo_url, ad_video_url, post_url }] }.
search_conversations
ChatGPTSearch real production conversations from influencer_conversation_rollup_view_rls + messages table using composable AND filters, with pagination. Returns conversation metadata and full message history. Unlike get_conversations (curated modes), this has NO implicit minimum message count — pass min_messages: 3 to reproduce the "recent" behavior. Omitting all filters returns every agent conversation for the influencer. Filters (all optional, combined with AND): - conversation_id: exact match — returns that single conversation - contact_username: case-insensitive partial match on the contact identifier (instagram/tiktok handle, phone, whatsapp) - messages/funnel: min_messages, max_messages, min_agent_messages, min_funnel, max_funnel - scores: min_lead_score, max_lead_score, min_happy_path, max_happy_path, min_nurturing, max_nurturing, min_engagement, max_engagement - booleans: has_booking_link, is_lead, call_booked, open_conversation - date ranges (ISO 8601): last_message_after, last_message_before, first_message_after, first_message_before - pagination: limit (default 10, max 100), page (default 1) influencer_id is inferred from the JWT when using an influencer-scoped token. Returns { influencer_id, filters_applied, total_count, page, total_pages, pages_remaining, count, conversations: [{ conversation_id, contact_id, contact_username, meta, messages }] }. The contact_id can be passed to the WhatsApp template preview/send tools.
search_playbook
ChatGPTSearch the playbook for relevant passages instead of fetching whole docs; returns ranked snippets with the id (and section for samples) you can pass to get_playbook_doc to read more. Use get_playbook_index first to understand the catalog.
send_thread_message
ChatGPTSend a message to a Cortex thread. The request is accepted immediately (202) and processed asynchronously — the agent response is inserted once OpenClaw responds. Returns { message_id }.
send_whatsapp_template
ChatGPTSend a Meta-approved WhatsApp template to one or more contacts (via mk1-chat). HIGH IMPACT: this delivers real WhatsApp messages, billed by Meta. MANDATORY workflow — never skip a step: 1. list_whatsapp_templates — discover APPROVED templates 2. preview_whatsapp_template_recipients — resolve eligible recipients 3. Show the user the eligible sample/counts and ask for explicit confirmation 4. Call this tool with userConfirmed: true and the SAME contactIds you previewed Returns { ok, influencerId, templateId, createdCount, skippedCount, totalContacts }.
set_agent_crm_channel
ChatGPTRoute a CRM sync connection (GoHighLevel, Kommo, HubSpot, Airtable) to a Ninjo agent, or unroute it. Pass agent_id to make that agent answer the messages this CRM channel relays into Ninjo; pass agent_id: null to unroute the channel from any agent. Unlike Meta sub-accounts (many-to-many via set_connected_account), a CRM sync connection routes to a SINGLE agent, so routing it to a new agent replaces the previous one. Use list_agent_channels first to see which sync connections exist and where they point. Returns { success: true }.
set_agent_status
ChatGPTEnable or disable a Ninjo agent by setting is_active. Requires an influencer-scoped JWT. Returns { success: true }.
set_booking_calendars
ChatGPTChoose which GoHighLevel calendars / Calendly event types Ninjo tracks bookings from. BOOKING IS FAIL-CLOSED: with NO calendars selected, NOT A SINGLE booking is tracked — OAuth alone leaves the integration connected but dead. So never report booking as ready before this call succeeds, and never leave the selection empty by default. calendar_ids REPLACES the whole selection (it is not additive), so include every calendar that should stay tracked. Every id must come from list_booking_calendars — an invented id is rejected rather than silently disabling tracking. Passing [] switches tracking off entirely; only do it when the user explicitly asks. Returns { platform, selected, count, calendars }. Confirm back by name, not by id.
set_connected_account
ChatGPTLink or unlink a connected Meta sub-account to/from a Ninjo agent (many-to-many). Pass connected_account_id to ADD a link (leaves existing links intact), or null to unlink ALL sub-accounts from this agent. Returns { success: true }.
set_crm_auto_sync
ChatGPTExternal CRM sync: turn automatic contact sync on or off for one sync connection from get_crm_sync. When turning it on, stageId optionally picks the destination stage (from get_crm_sync, null for none); turning it off clears the stage.
set_crm_contact_property
ChatGPTSet contact property: set or clear one CONTACT-scoped property value with the typed writer. Read the definition first: options take the option UUID, booleans "true"/"false", integers integer strings, dates ISO timestamps; "" clears. May fire configured property actions and external CRM hooks. Never use it for conversation or pipeline-record facts.
set_crm_opportunities_next_action
ChatGPTDeals (opportunities): set the next follow-up date and note on up to 50 selected opportunities, or clear them with null, each with its current revision from list_crm_opportunities. Check per-row results for partial failures.
set_crm_opportunities_owner
ChatGPTDeals (opportunities): set the owner of up to 50 selected opportunities, or clear it with null, each with its current revision from list_crm_opportunities. Check per-row results for partial failures.
set_google_calendar_agent
ChatGPTSwitch the workspace's connected Google Calendar ON or OFF for one agent. This is the last step of connecting it — the one get_connection_status reports as pending_step:"enable_for_agent_in_studio". A consented calendar books NOTHING until an agent is linked to it: the four runtime tools (get_google_calendar_availability, book_google_calendar_event, cancel_google_calendar_event, reschedule_google_calendar_event) are loaded only for a linked agent. So never report Google Calendar as ready before this call succeeds. There is ONE calendar per workspace and it is shared — this only decides which agents may use it. Order matters: create_connect_link(provider:'google_calendar') → the owner authorizes in the browser → this. Calling it first fails with "no Google Calendar connected". v5 agents only — an older engine is refused rather than linked, because it would arm the legacy scheduler (UTC, none of the booking rules). Switching an agent ON also lets it CANCEL and RESCHEDULE, whether or not the prompt mentions those tools. Say so when the operator only asked for booking. Then have them review the booking rules at /studio/{influencer_id}/integrations/google-calendar (calendar, hours per weekday, duration, minimum notice, days ahead, in person with address or video call) — left unset they default to Monday–Friday 9:00–18:00, 30-minute slots and a Google Meet link. enabled:false unlinks only this agent: the connection, its booking rules and every other agent are untouched. Returns { agent_id, enabled, agents: [{ id, name, enabled }], enabled_count }. Confirm back by name. enabled_count:0 means the calendar is connected and dead.
set_messaging_channel_enabled
ChatGPTPause or resume a GoHighLevel / Kommo messaging channel without deleting it. Reversible; deleting a channel is not exposed here (do that in Studio). A channel is created already enabled, so there is NO need to call this after create_messaging_channel — use it to pause a channel while the user reconfigures something in the CRM, and to turn it back on. Get sync_connection_id from list_crm_connections (or list_agent_channels), picking a row whose event_name contains '.messaging.'. A row with a provider and no messaging event_name is the CRM SYNC connection, not a channel — this tool refuses those, since pausing it would stop contact sync for the whole account. Returns { channel }.
set_messaging_channel_whatsapp_provider
ChatGPTSwitch an existing GoHighLevel WhatsApp channel between GoHighLevel's official WhatsApp and an external provider (a WhatsApp QR/app integration registered inside GHL). Use this when create_messaging_channel was called with the wrong third_party_whatsapp value — the symptom is that inbound messages arrive but Ninjo's replies never send. The channel cannot simply be recreated (one WhatsApp channel per account), which is why this exists. Only applies to GoHighLevel WHATSAPP channels; Kommo and every other channel type are rejected. Returns { channel, third_party }. Check third_party, not channel: the flag lives on the connected account, so channel is byte-identical before and after — third_party is read back from the account after the write and is the only confirmation the flip landed.
sync_keyword_triggers
ChatGPTReconcile the agent's DM keyword triggers with the provided list using a diff: existing keywords are preserved (created_at untouched), match_mode is patched when it differs, new keywords are inserted, and keywords absent from the input are deleted. Inputs are lowercased + trimmed + deduplicated before diffing. match_type values (SDK format): any_mention/anywhere → ANYWHERE, isolated_word/keyword_only → KEYWORD_ONLY. Returns { deleted, created, updated, keywords } where keywords is the final state sorted alphabetically.
sync_trigger_audios
ChatGPTReconcile the audios attached to a trigger with the provided list: kept audios preserve their row (and created_at), reordered audios get their order patched, new ones are inserted, and ones absent from the input are deleted. type selects the trigger family: keywords or ads. Input is deduplicated by resource_id. Each resource_id must reference a CreatorResource of type AUDIO owned by this influencer — creation/upload of CreatorResources is handled elsewhere. If order is omitted for an item it defaults to the item's index. Returns { deleted, created, updated, audios } where audios is the final list sorted by order.
sync_trigger_canned_responses
ChatGPTReplace the canned text response variants of a trigger with the provided list, via diff by id: items WITH an existing id update that row in place (text/order), items WITHOUT an id are inserted as new variants, and existing variants absent from the input are deleted. Pass an empty list to remove all variants. To edit safely, call list_trigger_canned_responses first and resend items with their ids. Max 10 variants per trigger; each text is trimmed, must be non-empty and at most 950 characters. If order is omitted for an item it defaults to the item's index. Rejected (400) while the trigger's negative config is enabled — negative triggers cannot carry canned responses. type: keywords | all-messages | comments | ads | instagram-story. Returns { deleted, created, updated, canned_responses } with the final state sorted by order.
toggle_crm_routing_rule
ChatGPTRouting: switch an assignment routing rule between enabled and disabled, using its current revision from get_crm_routing. Read the rule again before changing it once more.
transfer_crm_pipeline_record
ChatGPTPipelines: atomically close a pipeline record and continue the contact in another pipeline at destinationStageId, with an optional outcome and transferReason. Uses the source record's current revision; ids come from get_crm_pipelines.
trigger_fetch_info
ChatGPTEnsure MongoDB has the influencer's Instagram data by triggering the fetch-info Step Function if needed. Workflow: 1. Checks if influencer_bio already exists in MongoDB → returns status: skipped if yes (unless force=true) 2. Verifies Instagram is connected (access token present in Postgres) 3. Starts the fetch-info Step Function and polls until completion (up to timeout_seconds) 4. Returns the final status Returns { status: "skipped"|"no_ig_connected"|"no_sf_arn"|"succeeded"|"failed"|"timed_out", reason?, execution_arn?, bio_existed? }.
unassign_crm_owner
ChatGPTOwnership: clear the team and person that own a conversation or pipeline record (subject), with an optional unassignReason, using the current revision from get_crm_assignment.
update_agent
ChatGPTUpdate basic fields on a Ninjo agent: name and/or description. Requires an influencer-scoped JWT. Returns { success: true }.
update_agent_config
ChatGPTUpdate AgentConfig settings. All fields are optional. model, temperature, conversation_summary_enabled, should_respond_check_enabled, is_test_agent, response_filter go into the config JSON. set_on_conversation goes to the agents table. All other fields update agent_configs directly. response_filter tunes the CoT reasoning-leak filter (config.responseFilter): { enabled, extra_patterns (extra JS-regex patterns to strip, additive), disabled_defaults (default patterns to drop for this agent) } — PATCH-merged, so pass only what you change.
update_agent_mode
ChatGPTUpdate a Ninjo agent's mode and workflow relations. For non-INDIVIDUAL modes, workflow_agents is required. Each workflow_agent must be a valid UUID and cannot be the same as agent_id. Returns { success: true }.
update_agent_voice
ChatGPTUpdate voice reply configuration for a Ninjo agent. All fields are optional and merged into the existing voiceReply config JSON. Returns { success: true }.
update_creator_resource
ChatGPTUpdate an existing creator resource's name or agent metadata (agent_usable, usage_context, caption_guidance). PATCH semantics — omitted fields are left untouched. Returns { resource }.
update_crm_contact_attributes
ChatGPTContact attributes: partially update a contact's native gender and countryCode. Omitted attributes are kept; null clears one. Read get_crm_contact first; other identity fields use replace_crm_contact. Contact identity is shared, but CRM sync effects stay within the selected workspace.
update_crm_pipeline_automation
ChatGPTPipeline automations: replace an automation rule's complete configuration, using its current revision from get_crm_pipeline_automations. actionReason is recorded on the records it acts on.
update_crm_routing_rule
ChatGPTRouting: replace an assignment routing rule's complete configuration, using its current revision from get_crm_routing. FORCE needs forceReason and permission.
update_crm_tag
ChatGPTTags: rename or recolor a contact tag (optionId from list_crm_tags). name replaces the current name; an empty color clears it and an omitted color keeps it. expectedRevision is the tag's timestamp revision from list_crm_tags.
update_crm_team
ChatGPTTeams: replace a team's name and description (an empty description clears it), using the team's current revision from get_crm_teams.
update_managed_file
ChatGPTWrite a managed file to influencer_managed_files. influencer_id from auth when available; from param when admin. filepath is relative (e.g. 'changelog.md'). Returns { filepath, content_sha256, updated_at }.
update_prompt
ChatGPTUpdate the system prompt for a Ninjo agent. Automatically creates a new prompt version and sets it as current. Returns { agent_config_id, prompt_version_id, version }.
update_resource_sending
ChatGPTEnable/configure the agent sending creator-uploaded audio/image clips mid-conversation (config.resourceSending). enabled toggles the feature; allowed_types is a subset of [IMAGE, AUDIO] (only these are deliverable); max_per_conversation caps how many times the same resource is sent per conversation. PATCH semantics — omitted fields are left untouched. This does NOT create a new prompt version. Returns the merged resourceSending config.
update_tool
ChatGPTUpdate an agent tool. Only allowed fields: enabled (boolean), settings (object), prompt (string). credentials are never modifiable via this tool. Returns { success: true }.
update_trigger
ChatGPTUpdate an existing trigger. type selects the variant: keywords (keyword, match_mode, allow_typo) or outgoing-messages (keyword, assign_unpaused). Only provided fields change. NOTE: for keyword changes that must stay in sync with v5Config, prefer deploy_agent_sdk or sync_keyword_triggers — a single-row keyword edit here does not update v5Config.keywords. Returns { success: true }.
update_v5_config
ChatGPTUpdate the v5Config (Cortex SDK) for an agent. Each field is a text blob that maps to an SDK file (knowledge_base.md, examples.md, etc.). Only the keys you provide are merged; others are preserved. Returns the merged config.
upsert_contact_limit
ChatGPTCreate or update a contact limit — the lever that STOPS an agent from messaging a contact once a terminal state is reached (e.g. they booked a call or purchased). Gate it on a custom property via propertyConditions: this is how you silence the agent after a conversion so the operator stops babysitting DMs by hand. Pass id to update an existing limit; omit id to create a new one. Returns { success: true, contactLimit }.
upsert_custom_notification
ChatGPTCreate or update a custom notification — alerts the operator the moment something happens (e.g. a lead booked a call). Pair it with a workflow (type CUSTOM_NOTIFICATION) or a contact limit, gated on the custom property that marks the event, so the operator is pinged automatically instead of watching DMs by hand. Pass id to update; omit id to create. Returns { success: true, customNotification }.
upsert_custom_property
ChatGPTCreate or update a custom property. Pass id to update, omit id to create. A property is INERT on its own: an external evaluator fills its value, but nothing happens until a contact limit, custom notification, or workflow CONSUMES it via a propertyCondition — defining the property is only half the job. For any property you will gate automation on (a booking flag, a funnel stage), use a boolean or number type, NOT a string: "true"/"false" string values compare unreliably in conditions. Returns { success: true, customProperty }.
upsert_notification_destination
ChatGPTCreate or update a notification destination. Pass id to update; omit id to create. Returns { success: true, notificationDestination }.
upsert_property_action
ChatGPTCreate (omit id) or update (pass id) a property action — a side-effect that fires when a custom property reaches a value. Set action_type: HTTP_REQUEST for a webhook (needs http_url), or CRM_STAGE_TRANSITION / CRM_FIELD_UPDATE / CRM_PUSH_CONTACT / CRM_CONTACT_TAG to act on a CRM (needs crm_sync_connection_id; CRM_STAGE_TRANSITION also needs crm_target_stage_id, CRM_CONTACT_TAG needs crm_tag_name). A CRM_CONTACT_TAG only works on a contact already pushed to the CRM — pair it with a CRM_PUSH_CONTACT action if the contacts are not synced yet. The action fires when the property's value satisfies operator against the value_* you set. For HTTP_REQUEST, read the http_body_template description before writing a body: it takes {{contact.first_name}}-style tokens from a fixed vocabulary, and an unrecognised token renders as an empty string with no error rather than failing. Use list_property_actions to see existing actions and list_crm_connections / list_crm_stages / list_crm_fields to discover the CRM ids. Returns { success: true, id, action_type }.
upsert_trigger_negative_config
ChatGPTCreate or update the negative config (temporary block) of a trigger. The trigger is suppressed while enabled=true AND now < expires_at. A null or past expires_at means the block is effectively inactive even if enabled; for an 'indefinite' block, pass a far-future expires_at (mk1-chat UI uses +100 years). Setting enabled=false clears activated_at. user_timezone is informational (IANA tz). Returns the upserted config.
upsert_whatsapp_template_definition
ChatGPTCreate or update a WhatsApp template definition and its variable bindings (via mk1-chat). Returns the UUID consumed by upsert_notification_destination (whatsappTemplateDefinitionId), closing the workflow-driven outbound WhatsApp path end-to-end via MCP. Identity is the natural key (templateId, influencerId): omit id to create-or-update by that key; pass id to assert you are updating a specific existing definition. mk1-chat rebuilds the full template structure (components/buttons) from the live Meta template — you only supply variable values via variableMappings (an id→value map). templateName/languageCode default to the Meta template when omitted. To discover the variable ids of a new template, call this once with no/partial variableMappings and read them from the returned definition.variableMappings, then call again with the id→value map. Returns { ok, influencerId, created, definition: { id, templateId, templateName, languageCode, variableMappings } }.
upsert_workflow
ChatGPTCreate or update a workflow — scheduled automation that runs OFF custom properties. The most common use is re-engaging stalled leads: type FOLLOW_UP with a propertyCondition on a funnel/stage property re-nudges contacts who went quiet (a prompt alone never follows up). Other types: CUSTOM_NOTIFICATION (alert the operator), SCHEDULE_REMINDER, CUSTOM_ACTION. Pass id to update; omit id to create. Returns { success: true, workflow }.
void_crm_quote
ChatGPTQuotes: void a quote (quoteId from get_crm_commerce or get_crm_contact_commerce).
void_crm_sale
ChatGPTSales: void a contact's recorded sale (saleId from get_crm_contact_commerce). Payments and refunds recorded against it are preserved.
associate_whatsapp_direct_numbers
Claudebootstrap_discord_channel
Claudecreate_agent
Claudecreate_document
Claudecreate_feedback_upload_url
Claudecreate_resource_upload_url
Claudecreate_thread
Claudecreate_trigger
Claudedelete_agent
Claudedelete_contact_limit
Claudedelete_creator_resource
Claudedelete_custom_notification
Claudedelete_custom_property
Claudedelete_document
Claudedelete_notification_destination
Claudedelete_thread
Claudedelete_trigger
Claudedelete_trigger_negative_config
Claudedelete_whatsapp_template_definition
Claudedelete_workflow
Claudedeploy_agent_sdk
Claudediagnose_agent
Claudegenerate_synthetic_conversations
Claudeget_agent_config
Claudeget_agent_insights
Claudeget_agent_metrics
Claudeget_contact_limits_context
Claudeget_conversations
Claudeget_instagram_posts
Claudeget_instagram_profile
Claudeget_knowledge
Claudeget_me
Claudeget_peer_managed_files
Claudeget_playbook_doc
Claudeget_playbook_index
Claudeget_self_serve_data
Claudeget_thread_messages
Claudeget_trigger_negative_config
Claudeget_workflow_activity
Claudelist_agent_tools
Claudelist_agents
Claudelist_connected_accounts
Claudelist_contact_limits
Claudelist_creator_resources
Claudelist_custom_notifications
Claudelist_custom_properties
Claudelist_documents
Claudelist_influencer_connected_accounts
Claudelist_knowledge
Claudelist_notification_destinations
Claudelist_threads
Claudelist_trigger_audios
Claudelist_trigger_canned_responses
Claudelist_triggers
Claudelist_whatsapp_template_definitions
Claudelist_whatsapp_templates
Claudelist_workflows
Claudepause_conversation_agent
Claudepreview_whatsapp_template_recipients
Clauderegister_creator_resource
Claudereplace_objectives
Claudereport_feedback
Clauderestore_prompt_version
Clauderesume_conversation_agent
Claudesave_image
Claudescaffold_agent_activation
Claudesearch_contacts
Claudesearch_conversations
Claudesearch_playbook
Claudesend_thread_message
Claudesend_whatsapp_template
Claudeset_agent_status
Claudeset_connected_account
Claudesync_keyword_triggers
Claudesync_trigger_audios
Claudesync_trigger_canned_responses
Claudetrigger_fetch_info
Claudeupdate_agent
Claudeupdate_agent_config
Claudeupdate_agent_mode
Claudeupdate_agent_voice
Claudeupdate_creator_resource
Claudeupdate_managed_file
Claudeupdate_prompt
Claudeupdate_resource_sending
Claudeupdate_tool
Claudeupdate_trigger
Claudeupdate_v5_config
Claudeupsert_contact_limit
Claudeupsert_custom_notification
Claudeupsert_custom_property
Claudeupsert_notification_destination
Claudeupsert_trigger_negative_config
Claudeupsert_whatsapp_template_definition
Claudeupsert_workflow
Claude