Tools
Actions the agent can invoke (tools/call) — search contacts, send messages, create deals, etc.
Pinlyx ships a built-in Model Context Protocol (MCP) server. MCP is an open standard that lets AI agents — Claude Desktop, Cursor, Cline, and any other MCP-capable client — discover and call your CRM’s capabilities through a single, authenticated endpoint.
Once connected, an agent can search your contacts, send Telegram and X (Twitter) messages, manage deals and tasks, read finance summaries, run sequences, and more — all scoped to exactly the permissions on your API key.
The server speaks JSON-RPC 2.0 over HTTP and exposes three kinds of capabilities:
Tools
Actions the agent can invoke (tools/call) — search contacts, send messages, create deals, etc.
Resources
Read-only context the agent can pull in (resources/read) — current user, accounts, pipeline, KPIs.
Prompts
Pre-built prompt templates (prompts/get) — daily briefing, contact summary, pipeline review.
| Endpoint | https://api.pinlyx.com/mcp |
| Methods | POST (JSON-RPC), GET (server-sent stream) |
| Protocol | JSON-RPC 2.0 / MCP |
| Auth | Authorization: Bearer csk_live_… |
| Server version | 1.1.0 |
Authentication uses the same API key as the REST API — a csk_live_… key. Every request must include it as a Bearer token:
Authorization: Bearer csk_live_…Content-Type: application/jsonThe key’s scopes determine which tools, resources, and prompts the agent can use. A request for a capability whose requiredScope your key lacks is rejected. See Authentication to create a key and pick the right scopes.
Beyond the scopes on the API key itself, the connection URL can narrow what one particular client sees. Append toolsets (a comma-separated list of group names) and/or readonly=true as query parameters:
https://api.pinlyx.com/mcp?toolsets=ads,contacts&readonly=trueThat example limits the connection to the ads and contacts groups and drops every tool that writes, regardless of what the underlying key is scoped to. The group names are: feedback, workspace, posts, social, contacts, conversations, deals, tasks, email, finance, sequences, pipelines, webhooks, jobs, ads, agents, accounts, telegram, twitter, analytics.
crm_whoami and the three feedback tools (crm_submit_feedback, crm_list_feedback, crm_reply_feedback) are always kept, no matter what toolsets or readonly you pass: a connection can always identify itself and always report a problem, even one it hit because everything else was filtered away.
This is a second, server-side layer on top of the key’s own scopes, and it composes with the --tools and --read-only flags of the stdio bridge below: the bridge’s local filter narrows what one client process sees, and toolsets/readonly on the URL narrow what the connection itself is allowed to ask for. Use the URL parameters when you connect a client straight to the hosted endpoint; use the bridge flags when the client only speaks stdio.
Create an API key in the panel with the scopes you want the agent to have. Copy the csk_live_… value — it is shown only once. (See Authentication.)
Add the MCP server to your client’s config, pasting the key as the Authorization header. Use the tab for your client below.
Restart the client so it reloads its configuration and performs the MCP initialize handshake.
Verify the tools appear. Your client should list the Pinlyx tools (e.g. crm_search_contacts). If nothing shows up, double-check the endpoint URL and that the Bearer prefix is present in the header.
Some clients cannot talk to a remote MCP endpoint directly. For those, run the first-party stdio bridge, which proxies to this same endpoint and adds local tool filtering and a read-only mode:
{ "mcpServers": { "pinlyx": { "command": "npx", "args": ["-y", "@crmsolid/mcp-server"], "env": { "CRMSOLID_API_KEY": "csk_live_..." } } }}Useful flags: --tools social,posts limits the catalog to one area, and --read-only
hides every tool that writes. Source and full option reference:
github.com/Pinlyx/pinlyx-mcp.
Add the server to claude_desktop_config.json:
{ "mcpServers": { "pinlyx": { "url": "https://api.pinlyx.com/mcp", "headers": { "Authorization": "Bearer csk_live_…" } } }}Config file locations:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Add the server to ~/.cursor/mcp.json (or the project-level .cursor/mcp.json):
{ "mcpServers": { "pinlyx": { "url": "https://api.pinlyx.com/mcp", "headers": { "Authorization": "Bearer csk_live_…" } } }}Any MCP client that supports the streamable-HTTP transport uses the same shape — point it at the endpoint and supply the Bearer header:
{ "mcpServers": { "pinlyx": { "url": "https://api.pinlyx.com/mcp", "headers": { "Authorization": "Bearer csk_live_…" } } }}The server implements the standard MCP method set. Send these as JSON-RPC 2.0 envelopes to POST /mcp.
| Method | Purpose |
|---|---|
initialize | Handshake — first call required |
ping | Keep-alive / health check |
tools/list | Enumerate registered tools |
tools/call | Invoke a named tool |
resources/list | Enumerate available resources |
resources/read | Fetch a resource by URI |
prompts/list | Enumerate registered prompts |
prompts/get | Render a prompt with arguments |
Notifications:
| Notification | Behavior |
|---|---|
notifications/initialized | Sent by server after initialize completes |
notifications/cancelled | Returns HTTP 202; indicates async op cancellation |
Most clients handle these for you, but here is the raw wire format.
tools/list — discover available tools:
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }tools/call — invoke a tool:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "crm_search_contacts", "arguments": { "query": "acme" } }}resources/read — read a resource:
{ "jsonrpc": "2.0", "id": 3, "method": "resources/read", "params": { "uri": "crm://me" } }A full curl call:
curl -X POST https://api.pinlyx.com/mcp \ -H "Authorization: Bearer csk_live_…" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"crm_search_contacts","arguments":{"query":"acme"}}}'142 tools (78 read-only, 64 write), grouped by the scope each one requires. A tool is only callable if your API key holds its requiredScope, and every tool’s own description ends with the sentence Required scope: <scope>. so a client can show it without a second lookup. Call crm_whoami at any time to see the scopes your key holds and every tool it cannot currently call.
| Tool | Description | Scope |
|---|---|---|
crm_search_contacts | Search the user’s CRM contacts by name, username, or phone. Returns up to 25 results sorted by most-recently-contacted. | contacts:read |
crm_get_contact | Fetch a single contact by id, including the last 10 messages exchanged. | contacts:read |
crm_search_twitter_messages | Search the user’s stored Twitter (X) DMs by free-text. Use when the user asks “what did I say to X about Y”. Returns up to 25 most-recent matches. | contacts:read |
crm_list_accounts | List all connected accounts (Telegram + Twitter/X) with id, type, name, status, and most-recent activity. Required before sending any message — gives the agent the right accountId. | contacts:read |
crm_list_recent_conversations | Recently active contacts with their last message preview, ordered by latest activity. Use to surface “who needs a reply?”. | contacts:read |
crm_get_conversation | Full message thread for one contact, paginated newest-first. Pass before (an Id) to fetch the page older than that message. Returns up to 50 messages per call. | contacts:read |
crm_list_tags | List the user’s contact-tag dictionary with how many contacts each tag is attached to. | contacts:read |
crm_get_contact_activity | Fetch a contact’s activity timeline (notes, stage changes, tags, score changes, assignments) newest-first. | contacts:read |
crm_add_contact_note | Append a free-text note to a contact’s Notes field (timestamped). Use to record key facts the agent learned during a conversation. | contacts:write |
crm_update_contact_stage | Move a contact to a different pipeline stage (lead → conversation → proposal → negotiation → won/lost). Use after a meaningful sales event. | contacts:write |
crm_create_tag | Create a tag in the workspace’s contact-tag dictionary. Does not touch any contact; use crm_tag_contact to attach it. Idempotent: an existing tag with the same name is returned unchanged. | contacts:write |
crm_tag_contact | Attach a tag to a contact. Provide tagId, or tagName (created if it doesn’t exist yet). Logs a “TagAdded” activity. Idempotent. | contacts:write |
crm_untag_contact | Detach a tag from a contact. Logs a “TagRemoved” activity. Idempotent. | contacts:write |
crm_set_lead_score | Manually set a contact’s lead score (0–100). Marks it as a manual (non-AI) override and logs a “ScoreChanged” activity. | contacts:write |
crm_assign_contact | Assign a contact to a team member (owner), or unassign by omitting assignedToUserId. Logs an “Assigned”/“Unassigned” activity. | contacts:write |
| Tool | Description | Scope |
|---|---|---|
crm_send_telegram_message | Queue a Telegram outbound message. Specify accountId (one of the user’s connected Telegram accounts) and either contactId or username. Message is sent asynchronously. | telegram:send |
crm_send_twitter_dm | Send a Twitter (X) DM to a contact. Use when the user wants to reach out on X. The contact must already exist with platform=‘twitter’ and an XUserId. Sends synchronously through the user’s connected X session. | twitter:send |
Direct messages across Instagram, Facebook, X, LinkedIn, TikTok, YouTube, Threads, Pinterest, Reddit, Bluesky, Telegram and WhatsApp, in one inbox.
| Tool | Description | Scope |
|---|---|---|
crm_list_social_accounts | List the social accounts connected to this workspace (Instagram, Facebook, X, LinkedIn, TikTok, YouTube, Threads, Pinterest, Reddit, Bluesky, Telegram, WhatsApp) with platform, handle and posting limits. Call this first to learn which accountId to post from. | social:read |
crm_list_social_conversations | List social DM conversations, most-recently-active first, with the participant, unread count and last-message preview. Use to answer ‘who messaged us on Instagram?’ or to find the conversationId for a reply. | social:read |
crm_get_social_conversation | Fetch one social DM conversation with the participant’s details, the bridged CRM contact and the last 10 messages. Use before drafting a reply so the answer fits the thread. | social:read |
crm_list_social_messages | Page through a social DM thread, oldest-first inside the page. Voice notes carry their transcript and translated messages carry both wordings. Pass beforeMessageId to walk further back. | social:read |
crm_social_inbox_summary | One-call state of the social inbox: conversation and unread totals overall and per network, plus the threads still waiting on a reply, oldest first. Use as the opening move for inbox triage. | social:read |
crm_send_social_message | Send a direct message into an existing social conversation. This reaches a real person immediately. The reply is delivered through the account that owns the thread, the AI auto-reply is paused for the linked contact, and the CRM timeline records the send. Platform windows still apply: WhatsApp only allows free-form replies within 24 hours of the customer’s last message. | social:write |
crm_mark_social_conversation_read | Clear a social conversation’s unread badge, on the network as well as in the CRM. Idempotent: marking an already-read conversation changes nothing. | social:write |
| Tool | Description | Scope |
|---|---|---|
crm_list_social_posts | List scheduled and published social posts, newest scheduled time first, with status, published URL and any failure reason. Use to answer ‘what is going out this week?’. | posts:read |
crm_get_social_post | Fetch one social post by id with its full content, media, schedule, status and published URL. | posts:read |
crm_social_post_stats | Publishing volume and outcome over a recent window: totals by status overall and per network, plus the last publish time. Use to answer ‘how is our posting going this month?’. | posts:read |
crm_schedule_social_post | Schedule a post on one or more connected accounts. One post is created per target account, so two platforms means two posts. scheduledAt is required unless publishNow is true, which publishes to a real audience straight away. Per-platform rules are enforced (TikTok and YouTube need a video, Instagram needs media, X caps at 280 characters). | posts:write |
crm_update_social_post | Edit a post that has not gone out yet: its text, media or scheduled time. Only pending posts can be edited; anything already published, in flight, failed or cancelled is rejected. | posts:write |
crm_cancel_social_post | Cancel a scheduled post so it is never published. Idempotent: cancelling an already-cancelled post is a no-op. A post that has already gone out cannot be withdrawn from here. | posts:write |
| Tool | Description | Scope |
|---|---|---|
crm_list_sequences | List the user’s outbound message sequences with status, target counts, and progress. Use to answer “what campaigns are running?”. | sequences:read |
crm_get_sequence_status | Get a deep status report for one sequence: name, status, target/processed/successful/failed counts, message steps, and recent job activity. | sequences:read |
crm_pause_sequence | Pause an active sequence so no more messages are queued. Existing in-flight jobs will still run. Idempotent: pausing a paused sequence is a no-op. | sequences:write |
crm_resume_sequence | Resume a paused sequence so the worker starts queueing messages again. | sequences:write |
| Tool | Description | Scope |
|---|---|---|
crm_list_deals | List sales deals (pipeline) ordered by stage then value, with open-task counts. Use to answer “what’s in my pipeline?”. | deals:read |
crm_get_deal | Fetch one deal with its linked tasks and resolved contact name. | deals:read |
crm_create_deal | Create a new pipeline deal in an active stage. Title is required. Cannot create a deal already won/lost (closing a deal is done from the panel because “won” books revenue). | deals:write |
crm_update_deal_stage | Move a deal between pipeline stages. Allowed: lead, qualified, proposal, negotiation, lost. Moving to “won” is intentionally NOT supported here (it books an income ledger entry — do that from the panel). | deals:write |
| Tool | Description | Scope |
|---|---|---|
crm_list_tasks | List CRM tasks (to-dos / reminders) sorted by due date then priority. Use for “what’s due?” or “what’s overdue?”. | tasks:read |
crm_create_task | Create a task / reminder. Title is required; optionally link it to a contact and/or deal and set a due date and priority. | tasks:write |
crm_complete_task | Set a task’s status. Defaults to marking it done (stamps completion time); pass status to re-open (open/inprogress). | tasks:write |
| Tool | Description | Scope |
|---|---|---|
crm_search_email_threads | Search the user’s email inbox threads by subject/preview, with status/contact/unread filters. Read-only — does NOT send mail. | email:read |
crm_get_email_thread | Fetch one email thread with its messages (plain text, oldest-first) plus any AI summary/lead score. Read-only. | email:read |
crm_set_email_thread_status | Set an email thread’s workflow status (open/pending/closed). Does NOT send mail. | email:write |
crm_assign_email_thread | Assign an email thread to a team member, or unassign it by omitting assignedToUserId. Does NOT send mail. | email:write |
crm_list_email_accounts | List the mailboxes connected to this CRM with their sync status, per-mailbox thread/unread counts and the plan’s remaining mailbox slots. Credentials are never returned. | email:read |
crm_add_email_account | Connect a mailbox over IMAP/SMTP. Host and port autofill for the common providers; IMAP and SMTP are both authenticated first and nothing is saved unless both succeed. | email:write |
crm_test_email_account | Re-authenticate a connected mailbox with the credentials already on file and update its status from the result. Does NOT send mail. | email:write |
| Tool | Description | Scope |
|---|---|---|
crm_finance_summary | Realized income/expense/net per currency plus outstanding (pending) totals and the top expense categories, over a window. Use for “how is the business doing financially?”. Read-only. | finance:read |
crm_list_transactions | List ledger entries (income/expense) newest-first, with optional filters. Read-only — does NOT create transactions. | finance:read |
crm_list_invoices | List invoices newest-first with an outstanding (sent/overdue) summary per currency. Read-only — does NOT create or pay invoices. | finance:read |
crm_revenue_sources_summary | List configured external revenue sources with their last-sync status, total ingested count and last event time. Secrets (keys/credentials) are never returned. Read-only. | finance:read |
| Tool | Description | Scope |
|---|---|---|
crm_list_pipelines | List the user’s pipeline boards with their ordered stage columns and per-stage contact counts. Use to understand how the CRM is organized before moving/reading contacts. Read-only. | pipelines:read |
crm_get_pipeline | Fetch one pipeline board by id with its ordered stages and per-stage contact counts. Read-only. | pipelines:read |
| Tool | Description | Scope |
|---|---|---|
crm_list_webhooks | List the user’s registered webhook endpoints (URL, subscribed event types, health). Signing secrets are NEVER returned — only a short preview. Read-only. | webhooks:read |
crm_list_webhook_deliveries | List recent delivery attempts for one webhook endpoint (status, attempts, last response code, last error) newest-first. Use to debug “why isn’t my webhook firing?”. Read-only. | webhooks:read |
crm_create_webhook | Register a new webhook endpoint. Provide an HTTPS url and optionally a list of event types to subscribe to (default: all). The signing secret is returned ONCE in the response — store it immediately, it cannot be retrieved later. | webhooks:write |
crm_delete_webhook | Permanently delete a webhook endpoint. This stops all future deliveries to it and cannot be undone. | webhooks:write |
| Tool | Description | Scope |
|---|---|---|
crm_list_agents | List the user’s AI agents with a config summary (status, channels, trigger/response mode, model) and a 24h run count. Read-only. | agents:read |
crm_run_agent | Test-run (dry-run) an AI agent against a sample inbound message and return the reply it WOULD send. This is a safe playground — the reply is NEVER delivered to any contact and nothing is mutated. Optionally seed prior turns via history. | agents:run |
| Tool | Description | Scope |
|---|---|---|
crm_list_jobs | List outbound Telegram send-jobs (from crm_send_telegram_message and sequences) newest-first, with status and error visibility. Use to monitor “did my messages go out?”. Read-only. | jobs:read |
crm_get_job | Fetch one outbound message-job by id including its full text, target, status and lastError. Use to diagnose a specific send failure. Read-only. | jobs:read |
| Tool | Description | Scope |
|---|---|---|
crm_dashboard_summary | High-level KPIs for the user’s account: total contacts, messages queued/sent today, connected accounts. Useful as a daily standup for AI agents. | analytics:read |
crm_messaging_stats | Sent/failed/queued message counts over a window (1, 7, or 30 days). Optionally scoped to a single account. Use for “how am I doing this week?” style questions. | analytics:read |
crm_top_contacts | Most-messaged contacts in the last 30 days, ranked by outbound message volume. Useful for “who are my warmest leads?”. | analytics:read |
The four sections below (Google Ads, Meta Ads, TikTok Ads, and Ads Studio/alerts/attribution) share two conventions worth reading once instead of per tool.
Reports state their own window and freshness. Every reporting tool’s result carries window (window.from/window.to in the account’s own time zone; a relative range like LAST_30_DAYS ends yesterday, while TODAY, YESTERDAY and a custom startDate/endDate are also accepted) and freshness (freshness.dataAsOf plus source, either live or cache), so an agent can say precisely which days a number covers and how fresh it is rather than assuming “now”.
Writes are guarded the same way across all three networks. Pass validateOnly: true on a write and the network checks the change and applies nothing, returning what it would have done. Apply a change for real and the result carries a changeId. For Google Ads, crm_google_ads_undo reverts an undoable change by that changeId, within 30 days of it happening; removals, validate-only calls and changes older than that cannot be undone. Meta and TikTok record writes in the same ads change log but revert by calling the original tool again with the previous value, since neither network exposes an undo endpoint the way Google Ads does. Anything that removes or permanently stops something (crm_set_google_ads_status removing an entity, crm_set_meta_ads_status archiving or deleting, a shared negative-keyword list deletion, and similar) additionally requires confirm: true before it applies for real.
52 tools: 26 read, 26 write.
| Tool | Description | Scope |
|---|---|---|
crm_google_ads_account_alerts | Health check of one Google Ads account: everything that stops or throttles its ads, as alerts sorted by severity (critical, warning, info), each with a code, a plain explanation, the entity it concerns and the tool to use next. Checks account status (suspended, cancelled, closed, not enabled), advertiser identity verification, billing (no approved billing setup, account budget used up, ended or ending), disapproved and policy-limited ads (count, top policy topics, example ads), disapproved keywords, enabled campaigns that are NOT_ELIGIBLE, MISCONFIGURED, LIMITED, ENDED, PENDING or LEARNING with Google’s reasons (for example BUDGET_CONSTRAINED, HAS_ADS_DISAPPROVED, BIDDING_STRATEGY_LEARNING), conversion tracking (off, no primary action, or primary actions without conversions in 30 days) and the optimization score. checks lists what was verified; a check Google refuses is reported under warnings instead of failing the report. Start here when an account shows no impressions or no spend. | ads:read |
crm_google_ads_ad_details | Full content and review state of Google Ads ads: responsive search ad headlines and descriptions with their pinned position, final and mobile URLs, display path (path1, path2), tracking template, final URL suffix and custom parameters, display URL of older ad types, approval and review status with policy topics and evidence, ad strength with Google’s suggestions to raise it (actionItems), primary status and reasons. Pass adId (bare id, ‘{adGroupId}~{adId}’ from crm_google_ads_breakdown level=ads, or the resource name) or narrow with adGroupId or campaignId; with no filter the newest ads come first. Removed ads appear only when adId names one. includeAssetPerformance adds every asset’s performance label (BEST, GOOD, LOW, LEARNING, PENDING) and source. Use it to check that ad text matches the keywords and that URLs and tracking are right; pause or enable an ad with crm_set_google_ads_status. | ads:read |
crm_google_ads_ad_preview | Heuristic diagnosis of whether a search could show an ad from this account, built entirely from the account’s own settings (campaign status, budget, schedule, location and language targeting, keywords, negative keywords and ad approval). Google offers no API that runs a real ad preview, so this cannot see the live auction, close keyword variants, audiences or competitors, and an eligible ad still has to win the auction to actually show. verdict is likely_eligible, unlikely or blocked, each with reasons, per campaign checked. For the real, authoritative result, open Google’s own Ad Preview and Diagnosis tool at https://ads.google.com/anon/AdPreview (looking up a search there does not count as an impression). Checks Search campaigns only: campaignId limits the check to one (it must be a Search campaign), otherwise every enabled Search campaign is checked, up to 50. geoTargetId (from crm_google_ads_geo_search) or a free-text place name sets the location context; languageId (an id, a BCP-47 code such as tr, or an English name, also from crm_google_ads_geo_search) sets the language; device is mobile, desktop or tablet. | ads:read |
crm_google_ads_add_keywords | Add keywords to a Search ad group. adGroupId is required unless every keyword comes from fromSearchTerms with its own ad group in the reference. matchType sets the default match type for any keywords or fromSearchTerms item that does not choose its own (falls back to PHRASE for keywords, EXACT for fromSearchTerms, when this is also omitted). cpcBid and finalUrl set the default max CPC (account currency, not micros) and landing page for items that do not give their own; omit cpcBid to use the ad group’s bid. status is ENABLED (default) or PAUSED for every keyword added by this call. A keyword already in the ad group with the same text and match type is skipped, not duplicated (see items); Google’s policy review can still reject new text, reported per keyword. validateOnly checks the change with Google without applying it. Next: crm_update_google_ads_bid to change a bid afterwards, crm_google_ads_update_keyword to change match type or URL. | ads:write |
crm_google_ads_add_negative_keywords | Add negative keywords at the campaign, ad group or shared-list level. level says which: campaign, ad_group or shared_list. When level is omitted it is inferred: shared_list when sharedSetId is given, ad_group when adGroupId is given, otherwise campaign, which is also what a fromSearchTerms-only call gets (each negative then applies at the search term’s own campaign; pass level: ad_group to use the term’s own ad group instead). campaignId, adGroupId or sharedSetId is required for the matching level, unless every item comes from fromSearchTerms (each reference already carries its own campaign and ad group). matchType sets the default match type for any keywords or fromSearchTerms item that does not choose its own (falls back to EXACT when this is also omitted). A keyword already present at the target with the same text and match type is skipped, not duplicated (see items). validateOnly checks the change with Google without applying it. Next: crm_google_ads_negative_keywords to see the result, crm_google_ads_remove_negative_keywords to take one back. | ads:write |
crm_google_ads_apply_label | Create a label, or assign it to, or unassign it from, campaigns, ad groups, ads and keywords. action create needs labelName (must not repeat an existing label’s name) and optionally color, a hex value such as #1A73E8, and description, at most 200 characters. action assign and action unassign need targets. Give labelId, from crm_google_ads_labels, or labelName to say which label; action assign with a labelName that does not exist yet creates that label in the same call. A target that already carries the label (assign) or does not carry it (unassign) is skipped, not an error. validateOnly checks the change with Google without applying it. Next: crm_google_ads_labels to see labels and their assignments. | ads:write |
crm_google_ads_apply_recommendation | Apply or dismiss Google recommendations by id (from crm_google_ads_recommendations). Applying changes the account the way the recommendation describes (for example raises a budget, adds a keyword or switches the bid strategy) and needs confirm: true; dismissing only hides the recommendation. Google has no validate-only mode for recommendations, so validateOnly: true returns a preview of what would be applied or dismissed without sending anything to Google. Up to 100 ids per call; each one succeeds or fails on its own and failures are listed. There is no automatic undo: to reverse an applied recommendation, change the setting back (crm_google_ads_change_history shows what changed). | ads:write |
crm_google_ads_assets | Assets (ad extensions) of a Google Ads account and everywhere each one is linked: sitelinks, callouts, structured snippets, call, price, promotion, image, lead form, business name and logo. Reads account, campaign and ad group links (level, default all; account links serve in every campaign), groups them by field type and gives for each asset its content, approval status and policy topics, and every link with its status, source and primary status (why it is limited or not serving). includePerformance adds each link’s metrics for the window (cost in the account currency, not micros; ctr and conversionRate are fractions 0..1). Filter with campaignId, adGroupId and types. Next: crm_google_ads_create_asset to add an asset, crm_google_ads_link_asset to link or unlink an existing one. | ads:read |
crm_google_ads_auction_insights | Auction insights for Search: which other advertisers (by display domain) competed in the same auctions and how the account compares: their impression share, overlap rate, how often they ranked above (positionAboveRate), their top and absolute top of page rates, and the account’s outranking share. Fractions 0..1 (0.0999 means under 10%). Account level by default, or one campaign or ad group, over the chosen window. Google only serves these metrics to API projects it has allowlisted; otherwise the tool returns the error feature_not_available and the numbers must be read on the Auction insights page in Google Ads. Numbers are never estimated. | ads:read |
crm_google_ads_audiences | Audience lists (user lists) of a Google Ads account, newest first: id, name, type, description, membership status and life span in days, estimated size for Search and Display (exact, or a range for small lists), eligibility for Search/Display, the Customer Match match rate (0-100), upload key type, closing reason, and the status and match-rate range of the latest Customer Match upload. Use it to pick a listId for crm_google_ads_customer_match and, up to 48 hours after an upload, to check how many people Google matched. | ads:read |
crm_google_ads_bidding_strategies | Portfolio (shared) bidding strategies of the account: type, status, targets and limits in the account currency, and which campaigns use each one. Also lists strategies shared from a manager account, when this account is not itself a manager. Attach one to a campaign with crm_update_google_ads_bidding (strategy portfolio, portfolioStrategyId); create a new one with crm_google_ads_create_bidding_strategy. | ads:read |
crm_google_ads_billing | Billing state of one Google Ads account: the billing setup (status, payments account and payments profile), whether the account is on monthly invoicing, its account budgets (approved, proposed and adjusted spending limits, amount served so far, remaining = limit minus served, used fraction, start and end, pending change) and the invoices issued this month and last month (totals, tax, due date, service period, coupon credits). Money is in the account currency, not micros. Promotions such as ‘spend X, get Y’ are not available through the Google Ads API; the answer says so instead of guessing. For a pass/fail health check use crm_google_ads_account_alerts. | ads:read |
crm_google_ads_breakdown | Performance one level below the campaign, with the diagnostics needed to act on it. level: ad_groups (type, max CPC, primary status and reasons, impression share); ads (type, approval and review status, policy topics, ad strength, final URLs; name is the first headline); keywords (match type, serving and approval status, Quality Score with expectedCtr, adRelevance and landingPageExperience, first-page, top-of-page and first-position CPC estimates, bids, impression share incl. exact match; negatives excluded); search_terms (status ADDED = already a keyword, EXCLUDED = already a negative, ADDED_EXCLUDED = both, NONE = neither; matchedKeyword and searchTermMatchType; hiddenTerms = the scope’s Search traffic Google does not itemise); landing_pages and expanded_landing_pages (per URL and campaign, conversion rate, speed score); asset_groups (Performance Max); placements (Display, Video); videos (YouTube views, view rate, CPV, quartiles); products (Shopping and Performance Max items); assets (responsive ad headlines and descriptions with performance label and pin); paid_organic (paid and organic results for the same queries; needs Search Console linked to the Google Ads account). Every row has id, resourceId, resourceName, name, status, effectiveStatus (what really serves given its parents: ENABLED, PAUSED, PAUSED_BY_CAMPAIGN, PAUSED_BY_AD_GROUP, REMOVED…), campaign and ad group id, name and status, and metrics. For ads and keywords resourceId is ‘{adGroupId} | ads:read |
crm_google_ads_budget_pacing | Today’s Google Ads spend against budget for every enabled campaign in one call (or one campaignId): dailyBudget, budgetShared, spentToday, spentYesterday, spentThisMonth, daysElapsed, expectedSpendByNow (the daily budget x the part of today already elapsed in the account time zone), pace (today’s spend / daily budget; for a shared budget, all its campaigns’ spend), monthlyCap (30.4 x daily budget), projectedMonthSpend (this month’s run rate to the month end) and limitedByBudget (Google’s BUDGET_CONSTRAINED status reason, or more than 10% of search impressions lost to budget over the last 7 days), plus account totals that count each shared budget once. Google can spend up to 2x the daily budget on a single day but charges at most 30.4x the average daily budget per month; today’s numbers lag up to about 3 hours. Money is in the account currency (not micros). Answers ‘will we overspend this month?’ and ‘which campaigns are held back by budget?’. Next: crm_update_google_ads_budget to change a budget. | ads:read |
crm_google_ads_bulk | Apply many keyword-family changes in one call. operations is a list of up to 5000 items, each {type, …}; which other fields matter depends on type. set_status changes level campaign, ad_group, ad or keyword to status ENABLED, PAUSED or REMOVED (REMOVED cannot be undone for campaigns, ad groups, ads and keywords; a removed negative keyword can be re-added). set_bid sets cpcBid (account currency, not micros) on level ad_group or keyword, or clear: true to remove a keyword’s own bid. add_keyword adds one keyword to adGroupId (or the ad group named by searchTermRef). add_negative adds one negative keyword at level campaign, ad_group or shared_list, given directly or inferred from campaignId, adGroupId, sharedSetId or a searchTermRef. remove_negative removes one negative keyword by id (a resourceId or resourceName from crm_google_ads_negative_keywords). Each operation is checked and reported on its own in results (applied, skipped or failed) and never blocks the others when partialFailure is true (the default); partialFailure: false is all-or-nothing and then takes at most 1000 operations. Any operation that removes something (status: REMOVED, or type: remove_negative) needs confirm: true to apply for real; validateOnly does not need it and checks every operation with Google without applying anything. Next: crm_google_ads_breakdown or crm_google_ads_negative_keywords to see the result, crm_google_ads_undo to revert the reversible part by changeId. | ads:write |
crm_google_ads_campaign_settings | Live settings of one campaign: status with a plain-English explanation, channel type, the normalized bidding strategy with its target or CPC limit (money in the account currency, ratios as fractions), the daily budget including whether it is shared and with which other campaigns, start and end dates (ISO YYYY-MM-DD), network settings, geo target type, ad schedule and language targets. Read this before changing a budget (crm_update_google_ads_budget), a bidding strategy (crm_update_google_ads_bidding) or targeting (crm_update_google_ads_targeting). | ads:read |
crm_google_ads_campaign_to_draft | Copy a live Google Search campaign into a NEW Ads Studio draft (status Draft, campaign paused) that a person can edit, approve and publish, for example to duplicate it into another connected account or rework it safely. Reads the settings, daily budget, bidding, networks, locations, languages, campaign negative keywords, up to 20 ad groups with up to 200 keywords in total, and the enabled responsive search ads. Creates nothing in Google Ads. Whatever the draft format cannot carry (assets, audiences, ad schedule, pins, bid limits, shared lists…) is listed under notCopied. Next: crm_get_ad_draft, crm_dry_run_ad_draft, crm_submit_ad_draft. | ads:write |
crm_google_ads_campaigns | Campaigns of a Google Ads account with their settings and their performance for a window, including campaigns with no traffic. Each row: status, servingStatus, primaryStatus and primaryStatusReasons (why a campaign is limited or not serving, e.g. BUDGET_CONSTRAINED, BIDDING_STRATEGY_LEARNING, HAS_ADS_DISAPPROVED), channel type, biddingStrategy in the words crm_update_google_ads_bidding accepts (maximize_clicks, manual_cpc…) plus biddingStrategyRaw (Google’s type, e.g. TARGET_SPEND = maximize clicks), cpcBidCeiling (max CPC bid limit), targetCpa, targetRoas, targetImpressionShare, dailyBudget with budgetId, budgetShared (and the other campaigns on it), budgetDeliveryMethod and Google’s recommendedDailyBudget, startDate/endDate (YYYY-MM-DD, endDate left out when open-ended), optimizationScore, the full metric set with invalid clicks, and search impressionShare (search, lostToBudget, lostToRank, top, absoluteTop). Money is in the account currency (not micros); ratios and shares are fractions 0..1. Sorted by cost, highest first, ties by name (sortBy changes it). totals cover every campaign that matched the filters, not only this page; page with limit/cursor. status=all also lists removed campaigns. Next: crm_google_ads_breakdown or crm_google_ads_timeseries with a campaignId, crm_google_ads_budget_pacing for today’s spend against budget. | ads:read |
crm_google_ads_change_history | Who changed what in a Google Ads account, newest first. Merges Google’s change history (the last 30 days: time, user email, where the change was made such as GOOGLE_ADS_WEB_CLIENT, GOOGLE_ADS_API or GOOGLE_ADS_RECOMMENDATIONS, resource type and name, operation, and each changed field with its old and new value; money fields also as amounts) with the changes made through Pinlyx tools (changeId, tool, summary, previous and new value, status, and whether crm_google_ads_undo can still revert it). Use it to connect a change in performance to a settings change. Window: days (1 to 30, default 7, counting today) or startDate/endDate within the last 30 days. | ads:read |
crm_google_ads_conversion_actions | Conversion tracking health of a Google Ads account. Returns the account settings (conversion tracking status, customer data terms, enhanced conversions for leads, auto-tagging) and every non-removed conversion action: category, type, status, origin, primaryForGoal (primary actions feed bidding, secondary ones only report), counting type, default value, attribution model, click-through and view-through windows in days, last tag request and last conversion (account time zone), conversions in the window (optionally for one campaign) and a health verdict: recording (activity in the last 7 days), no_recent_conversions, never_received or inactive. risks[] names dangerous setups such as a PAGE_VIEW action marked primary or a primary action that never recorded. Money is in the account currency. Read this before moving a campaign to conversion-based bidding or uploading offline conversions; change an action with crm_google_ads_save_conversion_action. | ads:read |
crm_google_ads_create_ad_group | Create a new ad group in a Search or Display campaign, optionally with its first keywords, all in one atomic call. name must be unique within the campaign. status is PAUSED (default: nothing serves until it also has an approved ad) or ENABLED. cpcBid sets the ad group’s default max CPC in the account currency, not micros; omit it to leave no default bid (needed before enabling under manual CPC bidding). keywords, Search campaigns only, follow the shape of crm_google_ads_add_keywords; matchType sets their default (falls back to PHRASE). Google’s policy review can reject keyword text; every rejection is reported per keyword and does not block the rest of the ad group. validateOnly checks the change with Google without applying it. Next: crm_google_ads_create_rsa to add a responsive search ad, needed before the ad group can serve, then crm_set_google_ads_status to enable it. | ads:write |
crm_google_ads_create_asset | Create an asset (ad extension) and optionally link it in the same atomic call. type and its fields: sitelink {linkText at most 25, description1 and description2 at most 35 each (both or neither), finalUrl}; callout {text at most 25}; structured_snippet {header from Google’s list such as Services, Brands, Types, Models, Destinations, Courses (Turkish: Hizmetler, Markalar, Türler, Modeller), values: 3 to 10 texts of at most 25}; call {countryCode such as TR, phoneNumber}; price {priceType, priceQualifier?, languageCode such as tr, offerings: 3 to 8 of {header, description (at most 25 each, not equal), price, unit?, finalUrl}}; promotion {promotionTarget at most 20, percentOff (20 means 20%) or moneyAmountOff, occasion?, promotionCode? or ordersOverAmount?, languageCode, startDate?, endDate?, finalUrl}; image {imageUrl: an https JPEG, PNG or GIF of at most 5 MB that Pinlyx downloads}. Money is in the account currency unless currencyCode is given. Any type takes an optional name. linkTo links it at account, campaign or ad group level as SITELINK, CALLOUT, STRUCTURED_SNIPPET, CALL, PRICE, PROMOTION or AD_IMAGE; without linkTo it does not serve until linked (crm_google_ads_link_asset). Every problem is returned at once before anything is sent; policy rejections list each finding. Google Ads cannot delete assets, so crm_google_ads_undo removes the link and the asset stays unused. Supports validateOnly. | ads:write |
crm_google_ads_create_bidding_strategy | Create a portfolio (shared) bidding strategy that several campaigns can use, and optionally attach existing campaigns to it in the same atomic call. name must be unique in the account. Money is in the account currency, ratios are fractions; type and its fields: maximize_clicks (alias target_spend; optional cpcBidCeiling); maximize_conversions (optional targetCpa, optional cpcBidCeiling); maximize_conversion_value (optional targetRoas, optional cpcBidCeiling); target_impression_share (impressionShareLocation, impressionShareTarget and cpcBidCeiling all required); target_cpa (targetCpa required, optional cpcBidCeiling); target_roas (targetRoas required, optional cpcBidCeiling). attachCampaignIds moves those campaigns onto the new strategy immediately, replacing whatever bidding they had; crm_google_ads_undo restores each campaign’s previous bidding where the API allows it, and always removes the created strategy. Attaching campaigns restarts Google’s learning period for them. Next: crm_update_google_ads_bidding to attach more campaigns later, crm_google_ads_bidding_strategies to review it. | ads:write |
crm_google_ads_create_rsa | Create a responsive search ad in a Search ad group. Give 3 to 15 headlines (at most 30 characters each) and 2 to 4 descriptions (at most 90 characters each), each a plain string or {text, pin} to fix it to a position, the https finalUrl, and optionally the display paths path1/path2 (at most 15 characters each; path2 needs path1), a mobile URL, a tracking template and a final URL suffix. Everything is checked first and every problem comes back in one answer (counts, lengths as Google counts them, duplicates, pins, URLs); nothing reaches Google until all pass. The ad is created PAUSED by default: enable it afterwards with crm_set_google_ads_status (level ads, entityId ‘{adGroupId}~{adId}’ from this answer). An enabled ad serves after Google’s policy review, usually within one business day. replaceAdId pauses that ad of the same ad group in the same atomic call. When Google rejects text on policy grounds, the error lists each finding (policy topic, whether an exception can be requested, Google’s wording); Pinlyx never requests exceptions itself. crm_google_ads_undo removes the new ad (and re-enables the replaced one). Supports validateOnly. | ads:write |
crm_google_ads_customer_match | Sync CRM contacts into a Google Ads Customer Match list, so campaigns can target, exclude or find people like existing customers. contactFilter picks the workspace’s contacts (contactIds, tagIds, tagNames, stage, pipelineId, stageId, createdAfter; {} = every contact; limit up to 100000); their emails and phones are normalised and SHA-256 hashed and then added to the list (mode add), removed from it (remove) or made its only members (replace). listName creates a CRM-based email/phone list when none has that name; listId uses an existing one from crm_google_ads_audiences. validateOnly is a dry run that only counts contacts and identifiers and sends nothing. Every real upload needs confirm: true, because it sends customer data to Google. Set consent only as the person states it (default UNSPECIFIED). Google matches within up to 48 hours; check the list with crm_google_ads_audiences. Uploads cannot be undone (run mode remove with the same filter instead). Google accepts this only from API projects that used Customer Match before 2026-04-01; otherwise the error says so. | ads:write |
crm_google_ads_experiments | Campaign experiments (A/B tests that Google Ads runs by splitting a campaign’s traffic): status in plain words, dates, promote status and the arms, meaning which campaign is the control, which is the treatment, the traffic split, and the in-design (draft) campaign of an experiment still in setup. includeMetrics compares treatment with control over the experiment’s own dates: metrics per arm plus the change in CTR, average CPC, conversion rate, cost per conversion and ROAS, with volumes scaled by traffic split so uneven splits compare fairly (money in the account currency; at most 5 experiments per call). With experimentId the answer also carries background errors of a failed schedule or promotion. Next: crm_google_ads_manage_experiment. | ads:read |
crm_google_ads_forecast | Keyword Planner forecast for a new Search campaign with the keywords given: expected clicks, cost and average CPC over the forecast period (default the next 30 days), plus conversions and cost per conversion with maximize_conversions, and per-day averages. Bidding: manual_cpc with maxCpcBid (dailyBudget optional), maximize_clicks with dailyBudget (maxCpcBid then caps the CPC), or maximize_conversions with dailyBudget. Money is in the account currency. The estimate ignores the account’s own history, and Google’s current forecast does not include impressions or CTR. Cached for 1 hour. | ads:read |
crm_google_ads_geo_search | Find Google Ads location ids by name, or look up known ids, for use with crm_update_google_ads_targeting and crm_google_ads_ad_preview. Pass query (one name) or names (several, up to 25 total between the two); a purely numeric entry is read as a geoTargetId and returned with its current name. countryCode (two letters, e.g. TR) narrows a name search to one country. targetTypes filters by kind (Country, Region, City, Postal Code, Airport and other Google-defined kinds); locale controls which language the returned names are in (default en). includeLanguages: true also returns the language id catalog, optionally filtered with languageQuery (a name, a BCP-47 code such as tr, or an exact id). | ads:read |
crm_google_ads_keyword_ideas | Keyword Planner ideas: new keyword ideas from up to 20 seed keywords, a page URL, both, or a whole site, each with average monthly searches, competition (LOW, MEDIUM, HIGH and an index 0..100), the top-of-page bid range (low = 20th, high = 80th percentile, in the account currency) and the last 12 months of search volume, sorted by searches. With historicalOnly: true it returns the same metrics for exactly the keywords given (up to 1000). Set language (for example 1037 or tr for Turkish, 1000 or en for English) and geoTargetConstants (for example 2792 or TR for Turkey) for local numbers; without them Google uses all languages and locations. Results are cached for 12 hours. | ads:read |
crm_google_ads_labels | List the account’s labels: organizational tags with a name and an optional color and description. includeAssignments adds, per label, every campaign, ad group, ad and keyword that carries it (counts has the true totals, each list is capped at limit). labelId reads one label only. Next: crm_google_ads_apply_label to create a label, or assign or unassign one. | ads:read |
crm_google_ads_link_asset | Link an existing asset to the account, a campaign or an ad group under a field type, or remove that link (action unlink, which needs confirm: true). The link is read first: linking what is already linked, or unlinking what is not linked, changes nothing, and a paused link is enabled again. Asset ids and field types come from crm_google_ads_assets or crm_google_ads_create_asset. Unlinking never deletes the asset; it only stops showing there. crm_google_ads_undo reverses either action. Supports validateOnly. | ads:write |
crm_google_ads_manage_experiment | Create and run a campaign experiment on a Search or Display campaign. action create splits baseCampaignId’s traffic between the control and a treatment copy (trafficSplit is the treatment’s percent, default 50) and applies changes to the treatment: biddingStrategy (manual_cpc, maximize_clicks, maximize_conversions, maximize_conversion_value, as in crm_update_google_ads_bidding), cpcBidCeiling (maximize_clicks), targetCpa (maximize_conversions) or targetRoas (maximize_conversion_value, a ratio); money in the account currency. It stays in SETUP until scheduled: scheduleNow schedules right away, and Google refuses to schedule a treatment identical to its control. action schedule starts an experiment in SETUP. end stops it; promote copies the treatment’s changes into the base campaign; graduate turns the treatment into an independent campaign with its own daily budget (dailyBudget, default the base campaign’s); remove deletes it. Those four need confirm: true and have no undo. Every step lands in the change history, and a created experiment can be undone while it is in SETUP. Supports validateOnly. Read progress and results with crm_google_ads_experiments. | ads:write |
crm_google_ads_manage_negative_list | Create, attach, detach, rename or delete a shared negative keyword list (a list of negatives reusable across campaigns). action create makes a new list called name, optionally with initial keywords and campaignIds to attach it to, all in one atomic call; a clashing name is refused together with the existing list’s id. action attach or action detach links or unlinks sharedSetId to or from each of campaignIds (a pair that is already linked, or already not linked, is skipped rather than treated as an error). action rename changes the list’s name (refused if another list already uses it). action delete removes the whole list and its keywords and unlinks it from every campaign first; this cannot be undone and needs confirm: true to apply for real (validateOnly does not need it). The account-level negative keyword list, which applies to every eligible campaign automatically, cannot be attached, detached or deleted here; remove its keywords with crm_google_ads_remove_negative_keywords instead. keywords for action create follow the shape of crm_google_ads_add_negative_keywords; matchType sets their default (falls back to EXACT). Next: crm_google_ads_negative_keywords to see lists and their members, crm_google_ads_add_negative_keywords or crm_google_ads_remove_negative_keywords to change a list’s keywords afterwards. | ads:write |
crm_google_ads_negative_keywords | List negative keywords of a Google Ads account: campaign-level negatives, ad group-level negatives, and shared negative keyword lists together with the campaigns each list is attached to (the account-level list applies to every eligible campaign automatically, without being attached to any). Filter with campaignId (campaign and ad group negatives of that campaign), adGroupId (also resolves its campaign) or sharedSetId (reads that one list only; the campaign and ad group sections are left out). includeListMembers adds each shared list’s own keywords; default is true only when sharedSetId is given, since every list’s members can be a lot of rows otherwise. contains filters by a case-insensitive substring of the keyword text. Each section returns at most limit rows (default 200, max 5000); counts carries the true totals when a section runs longer than that. Next: crm_google_ads_add_negative_keywords to add, crm_google_ads_remove_negative_keywords to remove (ids come from this answer’s resourceId or resourceName), crm_google_ads_manage_negative_list to create, attach, detach, rename or delete a shared list. | ads:read |
crm_google_ads_recommendations | Google’s recommendations for one account (the Recommendations page): type, campaign and ad group, the estimated weekly impact before and after applying (impressions, clicks, cost, conversions, conversion value) and the details Google gives per type (current and recommended budget, keyword with match type and suggested bid, target CPA or ROAS, match type change, bid multiplier). Also returns the account and campaign optimization scores (0..1). Sorted by estimated extra conversions, then clicks. Filter by campaignId or types; dismissed ones are hidden unless includeDismissed is true. Apply or dismiss with crm_google_ads_apply_recommendation using the id. | ads:read |
crm_google_ads_remove_negative_keywords | Remove negative keywords at the campaign, ad group or shared-list level. ids are resourceId or resourceName values from crm_google_ads_negative_keywords (a bare resourceId is looked up across every level; pass level to narrow an ambiguous one, or use the full resourceName to remove any doubt). Removing a negative keyword can let the searches it blocked start matching and triggering ads again, so applying this for real needs confirm: true; without it the call answers with exactly what would be removed and changes nothing. validateOnly checks the removal with Google without applying it and does not need confirm. Next: crm_google_ads_add_negative_keywords adds the same text and match type back if this was a mistake (crm_google_ads_undo does the same automatically while the change is recent). | ads:write |
crm_google_ads_save_conversion_action | Create a Google Ads conversion action (omit conversionActionId) or change one. Create: name and category are required; type defaults to UPLOAD_CLICKS, the type offline imports with crm_google_ads_upload_conversions need (Google accepts uploads to it about 6 hours after creation). Update: pass only what changes. status ENABLED or HIDDEN (HIDDEN stops recording); primaryForGoal false makes the action secondary so bidding ignores it; countingType ONE_PER_CLICK suits leads, MANY_PER_CLICK suits sales. defaultValue is in currencyCode (default: the account currency). The current values are read first and returned as previousValue; crm_google_ads_undo with the returned changeId reverts an update and removes a created action. Supports validateOnly. Verify with crm_google_ads_conversion_actions. | ads:write |
crm_google_ads_segments | Google Ads performance split by one dimension, for the account, one campaign or one ad group: device, network (Google Search, search partners, Display, YouTube…), hour_of_day, day_of_week, slot (top of the page or other positions), country, region (first-level division: province, state or region, whichever the country uses), city, location_type, age, gender or conversion_action. Rows carry the full metric set and their share of cost and clicks, highest cost first. country, region and city report where people physically were; on a country row targetedLocation=false means people who were outside the targeted locations at the time (reached through ‘presence or interest’ targeting, or because they are regularly in a targeted location). location_type reports how the location targeting matched (LOCATION_OF_PRESENCE or AREA_OF_INTEREST). conversion_action rows carry conversion metrics only, because Google does not split cost or clicks by conversion action. Hours and days are in the account time zone. Money is in the account currency (not micros); ratios and shares are fractions 0..1. Answers ‘mobile or desktop?’, ‘which hours waste money?’, ‘are clicks coming from outside the targeted country?’. | ads:read |
crm_google_ads_summary | Account-level Google Ads performance for a window: spend, impressions, clicks, CTR, average CPC, interactions, conversions, conversion rate, cost per conversion, conversion value, ROAS, all conversions and invalid clicks; search impression share (won, lost to budget, lost to rank) with topRate / absoluteTopRate (the fraction of the account’s own impressions shown above the organic results / in the first position; top and absolute-top impression SHARE exist per campaign in crm_google_ads_campaigns); and the account optimization score. compareTo=previous_period or same_period_last_year adds the same metrics for that window and the fractional change per metric (0.25 = up 25%, left out when the earlier value is 0). includeConversionsByAction splits conversions by conversion action. Money is in the account currency (not micros); ratios and shares are fractions 0..1. Google reports shares under 10% as 0.0999 and over 90% as 0.9001. Answers ‘how did Google Ads do this month, compared with last month?’. A manager (MCC) account has no metrics: use one of its client accounts. Next: crm_google_ads_campaigns for the per-campaign split, crm_google_ads_timeseries for the trend. | ads:read |
crm_google_ads_targeting | Full targeting of one campaign: locations (included, excluded, their bid modifiers, and proximity/radius targeting), the location option (Presence or Presence-or-interest), languages, ad schedule, device bid modifiers, and audiences and demographics with their mode (observation only adjusts bids and reports; targeting restricts who sees the ads). includeAdGroups also reads ad-group-level audiences and demographics (an extra query). Negative keywords are not part of targeting: use crm_google_ads_negative_keywords. Next: crm_update_google_ads_targeting to change any of this. | ads:read |
crm_google_ads_timeseries | Google Ads performance over time for the account, one campaign or one ad group: a point per day, week (starting Monday), month, or hour (date and hour, windows up to 14 days), or a profile by hour_of_day or day_of_week, in the account time zone. Every period of the window is present (periods without traffic show zeros), so the series can be charted as it is; a week or month cut by the window edges is marked partial. compareTo=previous_period or same_period_last_year adds comparison.points aligned by position (points[i] against comparison.points[i]) and the change of the totals. metrics narrows each point to some fields, e.g. [“cost”,“clicks”,“conversions”]. Limits: day series up to 400 days, hour series up to 14 days; ALL_TIME is not accepted because Google needs a bounded date range whenever results are split by date, and Google keeps day, week and hour data for 37 months. Money is in the account currency (not micros); ratios and shares are fractions 0..1. Use it to see when impressions started or stopped, spending pace, or the effect of a change. | ads:read |
crm_google_ads_undo | Revert a Google Ads change made through Pinlyx tools, by the changeId that write returned (also listed by crm_google_ads_change_history). Updates are set back to the values from before the change, even if something changed them since; things the change created are removed. Removals, validate-only calls and changes older than 30 days cannot be undone. Supports validateOnly. | ads:write |
crm_google_ads_update_ad | Edit an existing ad in place; it keeps its id and history. Editable: finalUrls, finalMobileUrls, path1, path2, trackingUrlTemplate, finalUrlSuffix, and for responsive search ads the headlines and descriptions. A headlines or descriptions list replaces the whole current list, so read the current text first (crm_google_ads_breakdown level=ads). Only the fields you pass are touched; an empty string (or an empty finalMobileUrls list) clears an optional field. The resulting ad is checked with the same rules as crm_google_ads_create_rsa and every problem is returned at once. Changed text goes back to Google’s policy review and the ad may not serve until approved; URL-only edits keep serving. Passing values the ad already has changes nothing. crm_google_ads_undo sets the previous values back. Supports validateOnly. | ads:write |
crm_google_ads_update_ad_group | Rename an ad group and/or change its tracking template or final URL suffix. Only the fields given are touched; an empty string clears trackingUrlTemplate or finalUrlSuffix. name must stay unique within the campaign. Status changes go through crm_set_google_ads_status, bids through crm_update_google_ads_bid, keywords through crm_google_ads_add_keywords; none of those are touched here. Passing values the ad group already has changes nothing. validateOnly checks the change with Google without applying it. | ads:write |
crm_google_ads_update_keyword | Change a keyword’s match type and/or its own final URL. keywordId is the criterion id, or the composite ‘{adGroupId}~{criterionId}’ as crm_google_ads_breakdown level=keywords returns it; a bare criterion id that exists in more than one ad group is refused together with the candidates, so pass adGroupId or the composite id to say which one. finalUrl replaces the keyword’s own landing page, overriding the ad’s URL; an empty string clears it back to the ad’s URL; omit finalUrl to leave it unchanged. Match type cannot be edited in place: Google needs the old keyword removed and a new one created with the same text, so changing matchType gives the keyword a new id (returned as newKeywordId), resets its serving history, leaves the old statistics with the removed id, and does not copy its labels over (re-apply them with crm_google_ads_apply_label). Passing values the keyword already has changes nothing. This does not work on negative keywords, only on positive ones. validateOnly checks the change with Google without applying it. Next: crm_update_google_ads_bid for the bid. | ads:write |
crm_google_ads_upload_conversions | Send offline conversions (for example won CRM deals) to an UPLOAD_CLICKS conversion action of the workspace’s own Google Ads account, so Smart Bidding learns from real results. Each conversion needs a click id (gclid, gbraid or wbraid) or an email/phone (matching on those needs enhanced conversions for leads and the customer data terms), plus conversionTime and optionally value, currency and orderId. contactId fills email, phone and the ad click the CRM recorded for that contact; dealId fills value, currency, the won time, the contact and orderId ‘pinlyx-deal-{id}’, so uploading the same deal twice is rejected instead of counted twice. Emails and phones are normalised and SHA-256 hashed before sending and are never returned. The answer lists each conversion as uploaded (valid when validateOnly), failed with Google’s reason and a hint, or skipped with why, and the identifier types sent. At most 2000 per call. Uploads cannot be undone, so try validateOnly first. Google accepts this call only from API projects that already used it before 2026-06-15; otherwise the error says so. | ads:write |
crm_list_google_ads_accounts | List the Google Ads accounts connected to this workspace and whether each one can be used: Google’s account status (ENABLED, CANCELED, SUSPENDED, CLOSED, or NOT_ENABLED / UNREACHABLE when Google refuses it), isManager with the manager’s client accounts (clients; connected=true when a client is connected too), testAccount, canReport (enabled and not a manager), connection status, currency, time zone, and an issue code with a hint when something is wrong. Also returns today’s Google Ads request allowance (quota: used, limit, remaining, reset time and the shared deployment allowance). Call this first: every other Google Ads tool needs a customerId from here, and only accounts with canReport=true have campaigns and metrics. Account details are cached for about 6 hours; refresh=true reads them from Google again (one request per account). | ads:read |
crm_set_google_ads_status | Pause, enable or remove one or more Google Ads campaigns, ad groups, ads or keywords in a single call. Pausing stops spend immediately; enabling resumes it; removing is permanent and cannot be restored, so it needs confirm: true (use validateOnly: true first to see what would happen without confirm). Pass a single id in entityId or several in entityIds (same level, at most 100 total); entityId accepts a bare id, the composite ‘{adGroupId}~{id}’ as crm_google_ads_breakdown returns it, or a full resource name. For level ads or keywords, a bare id that exists in more than one ad group is refused with code ambiguous_id and the candidates listed; pass adGroupId or use the composite form to disambiguate. A status an entity already has changes nothing (idempotent). Next: crm_google_ads_undo reverts an enable or a pause, but never a removal. | ads:write |
crm_update_google_ads_bid | Set or clear a manual max CPC bid on an ad group or a keyword, in the account currency, not micros. level ad_group needs entityId as the ad group id and cpcBid greater than 0 (an ad group always keeps a bid, so there is no clear for it). level keyword needs entityId as the keyword (its criterion id, or the composite ‘{adGroupId}~{criterionId}’; adGroupId narrows an ambiguous bare id), and either cpcBid greater than 0 or clear: true to remove the keyword’s own bid so it uses its ad group’s bid again. Passing the bid the entity already has changes nothing. A campaign bidding automatically (Maximize Clicks, Maximize Conversions, Maximize Conversion Value, Target CPA, Target ROAS, or a portfolio strategy) ignores ad group and keyword CPC bids while that strategy stays on; the bid is still stored and only takes effect if the campaign moves to manual CPC, and the answer’s warning says so when it applies. validateOnly checks the change with Google without applying it. Next: crm_update_google_ads_bidding to change the campaign’s own bidding strategy. | ads:write |
crm_update_google_ads_bidding | Switch a campaign’s bidding strategy or change its current target, in the account currency (not micros) with ratios as fractions. strategy manual_cpc: no target (bids come from ad group and keyword bids; Enhanced CPC is retired and not offered). maximize_clicks: optional cpcBidCeiling, the maximum CPC Google will bid. maximize_conversions: optional targetCpa. maximize_conversion_value: optional targetRoas (3 means 300 percent). target_impression_share: impressionShareLocation (ANYWHERE_ON_PAGE, TOP_OF_PAGE or ABSOLUTE_TOP_OF_PAGE), impressionShareTarget as a fraction (0.8 means 80 percent) and cpcBidCeiling; all three are required the first time a campaign switches to it, and can be changed individually afterwards. portfolio: portfolioStrategyId only, from crm_google_ads_bidding_strategies (create one first with crm_google_ads_create_bidding_strategy). clearTarget removes the current limit or target of maximize_clicks, maximize_conversions or maximize_conversion_value instead of setting a new one; do not combine it with the matching value field. A strategy switch restarts Google’s learning period (roughly one to two weeks, or about 50 conversions). Setting the strategy and target already in effect changes nothing (idempotent). Read the current strategy first with crm_google_ads_campaign_settings; crm_google_ads_undo reverts most switches, but not every previous strategy can be re-applied through the API (for example a video or hotel strategy), which the response notes. | ads:write |
crm_update_google_ads_budget | Set the daily budget of a Google Ads campaign, in the account currency (not micros). Takes effect immediately. Google can spend up to about twice the daily budget on a single day, but not more than about 30.4 times it in a month. When the budget is shared with other campaigns, the change moves all of them and needs confirmShared: true; without it the call is refused and lists which campaigns share it. Setting the amount already in effect changes nothing (idempotent). Read the current amount first with crm_google_ads_campaign_settings. | ads:write |
crm_update_google_ads_targeting | Change a campaign’s locations, languages, ad schedule or device bid modifiers; several kinds can change in one atomic call. Read the current targeting first with crm_google_ads_targeting. locationOption and excludedLocationOption: PRESENCE or PRESENCE_OR_INTEREST, how included and excluded locations reach people. addLocations adds included locations (a geoTargetId string, or {geoTargetId, bidModifier}; bidModifier is a multiplier, 1 = no change, 1.2 = +20 percent). excludeLocations adds excluded locations (geoTargetIds). removeLocations stops targeting or excluding locations (criterion ids or geoTargetIds from crm_google_ads_targeting); moving a location from included to excluded, or back, needs it in removeLocations and the new side in the same call. Dropping every included location needs confirm: true, because the campaign would then show everywhere. locationBidModifiers changes the bid modifier of an already-included location. Location ids: crm_google_ads_geo_search. languages replaces the whole language set (an empty array clears it, meaning every language); addLanguages and removeLanguages change it incrementally instead; do not combine languages with either. Language ids, codes (tr) or English names: crm_google_ads_geo_search with includeLanguages: true. adSchedule replaces the whole schedule, at most 6 non-overlapping windows per day (day MONDAY..SUNDAY, startHour/endHour 0..24, startMinute/endMinute 0, 15, 30 or 45, optional bidModifier); an empty array clears it, meaning every hour of every day. deviceModifiers sets {mobile, desktop, tablet}, each a multiplier from 0.1 to 10, or 0 to exclude the device entirely. Values already in effect are left unchanged (idempotent); validateOnly checks without applying. crm_google_ads_undo reverts most of this; criterion types it cannot re-create (for example proximity/radius targeting) are named in the response. | ads:write |
7 tools: 5 read, 2 write. Meta covers Facebook and Instagram together, since Meta’s Marketing API reports and manages both through the same ad account.
| Tool | Description | Scope |
|---|---|---|
crm_list_meta_ad_accounts | List the Meta (Facebook and Instagram) ad accounts connected to this workspace: account id, name, currency, time zone, connection status and any issue that stops it from being used (expired or revoked authorization, the Meta account disabled, a spending limit reached). checkLive also reads each account from Meta itself (account status, amount spent, spend cap), capped at the first 10 connected accounts; otherwise accounts are described from what was stored when connected or last checked. Call this first: every other Meta Ads tool needs an accountId from here (or can be called without one when only one Meta account is connected). | ads:read |
crm_meta_ads_breakdown | Meta ad sets or ads: for ad sets, status, optimization goal, bid, budget, learning phase and targeting (locations, ages, genders, placements, audiences); for ads, status, creative (headline, text, image or video, call to action, link) and review status (disapproval reasons). Both carry performance for the window and flag likely creative fatigue (frequency above 3 with CTR down at least 20% from the previous period). Scope to one campaign with campaignId or one ad set with adsetId; without either, every ad set or ad of the account is read. breakdown instead splits the SAME level’s metrics by age, gender, country, region, publisher_platform, platform_position or device_platform (segments only, no settings or creative). Next: crm_set_meta_ads_status or crm_update_meta_ads_budget to act on an id from this list. | ads:read |
crm_meta_ads_campaigns | Meta campaigns with status, objective, bid strategy, budget and performance for a window. A campaign that delivered in the window stays listed even if it was archived or deleted since, so totals match crm_meta_ads_summary. includeArchived also lists archived campaigns with no recent delivery; activeOnly limits the list to campaigns Meta currently serves. sort orders the list (default spend, highest first; cpc is cheapest first, rows without clicks last). Next: crm_meta_ads_breakdown level=adsets with a campaignId for its ad sets, crm_set_meta_ads_status or crm_update_meta_ads_budget to act on one. | ads:read |
crm_meta_ads_summary | Account-level Meta Ads performance for a window: spend, impressions, reach, frequency, clicks, link clicks, ctr and link ctr (fractions 0..1), cpc, cost per link click and cpm (account currency), the top conversion actions Meta reports (purchases, leads and the rest, ranked; never add them up, Meta counts one purchase under several action types at once), purchase value and ROAS. compareTo adds the same metrics for an earlier period plus the percent change (previous_period or same_period_last_year; ALL_TIME has no comparison period). Next: crm_meta_ads_campaigns for the campaigns behind these numbers, crm_meta_ads_breakdown for ad sets, ads, ages, genders or placements, crm_meta_pixel_status to check whether the conversions being counted are trustworthy. | ads:read |
crm_meta_pixel_status | Health of the Meta pixels (website conversion tracking) shared with an ad account: whether each is firing, when it last fired, event counts by type over the window, whether server-side events (Conversions API) are seen alongside browser events, and automatic advanced matching. Flags a pixel that never fired, went stale, or receives traffic but no Purchase or Lead event. Checks up to the first 5 pixels shared with the account. Use before trusting the purchase or lead numbers crm_meta_ads_summary reports. | ads:read |
crm_set_meta_ads_status | Set a Meta campaign, ad set or ad to ACTIVE or PAUSED, or to ARCHIVED / DELETED, which stop delivery for good and cannot be reactivated (need confirm: true). Reads the current status first; setting the same status changes nothing. ACTIVE also needs the parent campaign and ad set active and the ad approved to actually deliver, see effectiveStatus in crm_meta_ads_campaigns or crm_meta_ads_breakdown. validateOnly asks Meta to check the change (Marketing API execution_options validate_only) without applying it. Recorded in the ads change log; an ACTIVE/PAUSED change can be reverted by calling this tool again with the previous status. | ads:write |
crm_update_meta_ads_budget | Change the daily or lifetime budget of a Meta campaign or ad set, in the account’s currency as major units (for example 50.00 means 50.00 TRY; Meta’s own API takes minor units internally, this tool converts for you). Pass exactly one of dailyBudget or lifetimeBudget, matching what the campaign or ad set already uses; Meta does not switch an existing one between daily and lifetime. Reads the current budget first; raising it more than 3x needs confirm: true. validateOnly asks Meta to check the change without applying it. A change of more than about 20% can send an ad set back into the learning phase. Recorded in the ads change log with a revert argument set to the previous amount. | ads:write |
5 tools: 3 read, 2 write.
| Tool | Description | Scope |
|---|---|---|
crm_list_tiktok_ad_accounts | List the TikTok advertiser accounts connected to this workspace: account id, name, currency, time zone, connection status and any issue (revoked or unreadable authorization, the last call to TikTok failing). checkLive also reads each account from TikTok (name, currency, time zone, and whether it answers at all), capped at the first 10 connected accounts. Call this first: crm_tiktok_ads_summary, crm_tiktok_ads_campaigns and the write tools need an accountId from here (or can be called without one when only one TikTok account is connected). | ads:read |
crm_set_tiktok_ads_status | Set a TikTok campaign to ACTIVE (ENABLE) or PAUSED (DISABLE). Reads the campaign’s current status first from the account’s campaign list; setting the same status changes nothing. TikTok’s API has no validate-only mode: validateOnly only checks the campaign id and the requested status locally and never calls TikTok, so it cannot catch every reason TikTok might later reject the real change. Recorded in the ads change log; call this tool again with the previous status to revert. | ads:write |
crm_tiktok_ads_campaigns | TikTok campaigns with status (ACTIVE/PAUSED), daily budget and performance (spend, impressions, clicks, conversions, conversion value, ROAS) for a preset window, in the account currency. Includes campaigns with no spend in the window so status and budget stay visible for all of them. sort orders the list (default spend, highest first). Next: crm_set_tiktok_ads_status or crm_update_tiktok_ads_budget with a campaign id from this list. | ads:read |
crm_tiktok_ads_summary | Advertiser-level TikTok Ads performance for a preset window: spend, impressions, clicks, ctr (fraction 0..1), cpc, conversions, conversion value and ROAS, in the account currency. TikTok’s reporting API accepts only the listed preset ranges here, no custom start or end dates; ranges are computed on the UTC calendar day, not the advertiser’s own time zone. Results are cached for about 15 minutes. Next: crm_tiktok_ads_campaigns for the campaigns behind these numbers. | ads:read |
crm_update_tiktok_ads_budget | Change the daily budget of a TikTok campaign. Give the amount in the account’s currency as major units, for example 50.00 for 50.00 TRY: TikTok’s own API takes major units directly here, unlike Meta’s, which takes minor units internally (both this tool and crm_update_meta_ads_budget always take and show major units, this note is only about what each network’s raw API expects). Reads the campaign’s current budget first from the account’s campaign list; raising it more than 3x needs confirm: true. TikTok’s API has no validate-only mode: validateOnly only checks the campaign id and amount locally and never calls TikTok. Recorded in the ads change log with a revert argument set to the previous amount. | ads:write |
9 tools: 4 read, 5 write. Ads Studio is where a campaign is drafted and approved by a person before any tool can publish it, across all three networks; the two alert tools configure and read the webhook-delivered monitor that watches connected Google Ads accounts; and the attribution report is the only tool that joins ad spend on any network to what actually happened in the CRM.
| Tool | Description | Scope |
|---|---|---|
crm_ads_alerts | Ad account alert settings and status. Returns: the current settings with defaults filled in (enabled, which of the five ads.* events are watched, the budgetExhaustedPct and spendAnomalyPct thresholds, and any customerIds allow-list); which of the five events have at least one active webhook endpoint subscribed to them and which do not; the connected Google Ads accounts that would be checked on the next run, and why any other connected account is skipped (revoked, a manager account, not enabled, or outside the customerIds allow-list); when the monitor last ran, its last error, and an estimate of the next run; and the most recent alerts it raised. The monitor checks connected accounts on a schedule, about every 30 minutes on an unlimited plan and less often on a plan with a small daily Google Ads allowance, and only when the workspace has alerts enabled AND at least one active webhook endpoint is subscribed to an ads.* event; alerts are only ever delivered as webhooks, never returned by this tool as they happen. Change the settings with crm_configure_ads_alerts; create a receiving endpoint with crm_create_webhook. | ads:read |
crm_ads_attribution_report | Ad spend joined with CRM results, per campaign or per network: spend, clicks, impressions and platform conversions from Google Ads (every connected account that can report, or customerIds) and, when the window allows, Meta and TikTok; next to them the CRM leads (contacts created in the window) and deals won in the window, attributed from the ad source the CRM recorded for each contact. A contact maps to a campaign by its gclid (found in Google’s click report, clicks of the last 90 days), else by a utm_campaign or utm_id equal to a campaign id or name, else only to a network (click id or utm_source). Returns crmLeads, dealsWon, crmRevenue, costPerLead, crmRoas (revenue / spend, only in the same currency) and the evidence behind each number, plus network-only and unattributed leads and revenue (with lead sources). Currencies are never converted or added together. Meta and TikTok are included only for LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, THIS_MONTH or LAST_MONTH. | ads:read |
crm_configure_ads_alerts | Turn ad account alerts on or off and choose what they watch. events is a subset of: ads.ad.disapproved (an enabled ad in an enabled ad group and campaign was disapproved), ads.budget.exhausted (today’s spend reached the configured share of a daily budget), ads.spend.anomaly (spend so far today is far above the usual pace for this time of day, or a campaign that spends every day has spent nothing today), ads.billing.problem (no approved billing setup, an account budget that is exhausted or has ended, or an account that is suspended, cancelled or no longer enabled), and ads.campaign.status_changed (a campaign’s primary status changed, for example ELIGIBLE to LIMITED). Omit events, or pass [’*’], to watch all five; an empty array also means all five. thresholds.budgetExhaustedPct is the percent of a daily budget today’s spend must reach to raise ads.budget.exhausted (default 95, so 95% of the budget; range 50-200). thresholds.spendAnomalyPct is how far above the usual pace, in percent, today’s spend must run to raise the overspend_pace kind of ads.spend.anomaly (default 100, meaning at least double the 7-day average for this time of day; range 25-1000). Fields left out keep their current value; the first call establishes the defaults. customerIds optionally limits monitoring to specific connected Google Ads accounts (every id must already be connected; check with crm_list_google_ads_accounts); omit to leave unchanged, or pass an empty array to monitor every connected account again. The monitor runs about every 30 minutes and alerts are always delivered as webhooks, so every event enabled here also needs an endpoint subscribed to it with crm_create_webhook, or its alerts have nowhere to go (the response says which of the chosen events still need one). Read the result at any time with crm_ads_alerts. | ads:write |
crm_dry_run_ad_draft | Ask the ad network to validate a draft without creating anything (Google: the whole campaign tree in one validate-only request). Answers valid true/false with the network’s own field-level issues and what a publish would create. Works in any status; without an ad account on the draft only the local rules are checked. Uses about one Google Ads operation per resource. Run it before submitting and again before publishing. | ads:write |
crm_get_ad_draft | One Ads Studio draft in full: the campaign spec exactly as it would be published (budget, bidding, targeting, negative keywords, ad groups with keywords and ads), its local validation issues (field paths point into the spec), the reviewer’s note, and the publish result (campaign id, created resources, last error). Money is in the ad account’s currency, not micros. To change the draft, edit the spec and send it back with crm_save_ad_draft. | ads:read |
crm_list_ad_drafts | Ads Studio campaign drafts (Google, Meta, TikTok), most recently updated first. Each row gives the status, ad account, daily budget (in the account currency), what the campaign would create (ad groups, keywords, ads, locations), whether it passes local validation, and nextStep: edit, submit, wait for a person to approve it in Ads Studio, dry run then publish, or the published campaign id. Statuses: Draft, PendingApproval (alias in_review), Approved, Rejected, Publishing, Published, Failed. Read one draft in full with crm_get_ad_draft. | ads:read |
crm_publish_ad_draft | Publish an Approved draft into its ad account. On Google the whole campaign (budget, campaign, locations, languages, negatives, ad groups, keywords, ads) is created in one atomic request, paused, so nothing spends until it is enabled with crm_set_google_ads_status. Refused unless a person approved the draft in Ads Studio. Returns the campaign id, every created resource, and a changeId: crm_google_ads_undo with it removes the new campaign again. | ads:write |
crm_save_ad_draft | Create an Ads Studio draft (network + spec, accountId optional) or change one (draftId + spec). The spec is the campaign object crm_get_ad_draft returns: name, objective (traffic, leads, sales, awareness…), budget {daily}, campaignType (Google: search), bidStrategy (manual_cpc, maximize_clicks, maximize_conversions, maximize_conversion_value), targeting {geoInclude [{type: ‘platform’, code: ‘<geo target id>’} or {type: ‘country’, country: ‘TR’}], geoExclude, languages [‘<language constant id>’]}, negativeKeywords, adGroups [{name, status, cpcBid, keywords [{text, matchType: broad|phrase|exact, negative}], ads [{headlines (3-15, max 30 chars), descriptions (2-4, max 90 chars), url, path1, path2}]}]. Unknown fields are refused with the list of allowed ones. With merge: true the spec is a partial patch applied to the stored one (objects merge, arrays replace, null removes). Drafts saved here always publish paused. Saving over a PendingApproval, Approved, Rejected or Failed draft sends it back to Draft, so it must be submitted and approved again. Nothing reaches the ad network; next: crm_dry_run_ad_draft, then crm_submit_ad_draft. | ads:write |
crm_submit_ad_draft | Submit a Draft or Rejected draft for approval; its status becomes PendingApproval. The spec must pass local validation first, otherwise the answer is validation_failed with every issue. A person must then approve it in Ads Studio (https://app.pinlyx.com/ads-studio); assistants cannot approve drafts. Once it is Approved, publish it with crm_publish_ad_draft. | ads:write |
4 tools, scoped any: they work regardless of which scopes your API key holds, and the connection-narrowing described in Scoping a connection can never filter them out.
| Tool | Description | Scope |
|---|---|---|
crm_list_feedback | Feedback this account has sent to the Pinlyx team, through this server or from the Pinlyx panel, with the team’s replies. Without feedbackId: one row per thread, latest activity first: id, source (mcp or panel), category, toolName, excerpt, createdAt, resolved, replyCount, lastReplyAt, lastReply (who wrote it and an excerpt), awaitingYourReply (the team wrote last and the thread is still open) and unread (a team reply the person has not opened in the panel yet). With feedbackId: the whole thread in order, each message marked author ‘you’ or ‘Pinlyx team’. Reading here marks nothing as read. Answer a thread with crm_reply_feedback. | any |
crm_reply_feedback | Write back in one of this account’s feedback threads, for example to answer a question from the Pinlyx team or to add detail to a report. The reply reaches the team’s support inbox and shows in the panel under Feedback > My conversations. Replying to a resolved thread reopens it. The same text sent again within 10 minutes is not posted twice; at most 20 replies an hour. Never include passwords, API keys, tokens or personal data. | any |
crm_submit_feedback | Tell the Pinlyx team (the people who build this server) about a tool that is missing, misleading, slow or returns something wrong, an error message that did not help, a task that needed a workaround, or something that worked well. It is filed in the same support inbox as feedback sent from the Pinlyx panel; the team reads every report and can reply. Replies show up in crm_list_feedback and in the panel under Feedback > My conversations; answer them with crm_reply_feedback. Put the problem in message, the tool in toolName and, for a wrong result, what you expected and what came back. Never put passwords, API keys, tokens or personal data (names, emails, phone numbers of contacts) in any field. The same message about the same tool within 10 minutes returns the first report instead of filing a copy; at most 20 reports an hour. Returns feedbackId. | any |
crm_whoami | Describe this connection. workspace: the account the key belongs to (userId, owner name and email, plan, reporting time zone, language, currency). auth: API key or OAuth app, its id and name, the scopes it holds, when it was created, expires and was last used. client and server: names and versions. tools: how many tools this connection can call, and every tool it cannot call with the scope that tool needs (missingScopes groups them). links: where the person manages API keys and connected apps. Call it at the start of a session, or after a ‘requires scope’ error, to tell the person exactly which scope to add. Never returns secrets. | any |
21 read-only resources the agent can pull in for context via resources/read. All return application/json. Resources respect your key’s scopes at read time.
| URI | Name | Description |
|---|---|---|
crm://me | Current user | Identity, plan, and connected-account summary for the API key holder. |
crm://accounts | Connected accounts | All connected Telegram and Twitter (X) accounts with type, status, and last activity. Pre-loaded so the agent can pick the right accountId without calling crm_list_accounts first. |
crm://sequences | Active sequences | Outbound message sequences (campaigns) and their current status, daily limit, and target progress. |
crm://recent-conversations | Recent conversations | Last 20 active contacts with name, platform, last-message preview, and unread flag — gives the agent immediate context on who needs attention. |
crm://plan | Subscription plan | Current subscription plan, period, daily-message limits, and remaining seats. Use to answer billing/quota questions before queueing more sends. |
crm://kpis/7d | 7-day KPIs | Sent/failed/queued message counts for the last 7 days plus a per-day breakdown — useful for trend-spotting without calling crm_messaging_stats. |
crm://finance/summary | Finance summary (30d) | Realized income/expense/net per currency for the last 30 days — a quick read on financial health without calling crm_finance_summary. |
crm://deals/pipeline | Deals pipeline | Deal count and total value per pipeline stage — the shape of the sales funnel at a glance. |
crm://tasks/today | Tasks due today / overdue | Open tasks that are due today or already overdue, ordered by due date — surfaces what needs action now. |
crm://inbox | Open email threads | Up to 20 open email inbox threads with subject, preview and unread count — who is waiting on a reply. |
crm://pipelines | Pipelines & stages | All contact pipelines (boards) with their ordered stages and the live contact count sitting in each stage — the shape of every funnel at a glance. |
crm://jobs/recent | Recent outbound jobs | The last 20 outbound message-sending jobs with status, target, account, and a trimmed error summary for any failures — quick visibility into delivery without calling a tool. |
crm://finance/invoices | Outstanding invoices | Open invoices (sent or overdue) summarized per currency, plus the most-overdue ones — money still owed to the business. |
crm://tasks/overdue | Overdue tasks | Open tasks whose due date has already passed (strictly before now), ordered oldest-first — distinct from crm://tasks/today which also includes today. |
crm://agents | AI agents | The user’s AI auto-reply agents with status, channels, response mode and rate limits (no secrets/persona text) plus a 7-day run count — what is currently automating replies. |
crm://webhooks | Registered webhooks | Outbound webhook endpoints with their subscribed event types, active flag and recent delivery health. Signing secrets are NEVER included. |
crm://deals/open | Open deals | Open deals (not Won or Lost) ordered by value, with stage, win probability and expected close date — the live opportunity list ranked by size. |
crm://social/accounts | Connected social accounts | Every connected social network account (Instagram, Facebook, X, LinkedIn, TikTok, YouTube, Threads, Pinterest, Reddit, Bluesky, Telegram, WhatsApp) with handle, timezone and daily post limit. Pre-loaded so the agent can pick an account without calling crm_list_social_accounts first. |
crm://social/inbox | Social inbox | Unread totals per network plus the 20 most-recently-active social DM conversations with participant, preview and unread count: who is waiting for a reply right now. |
crm://social/posts/scheduled | Scheduled social posts | Posts queued to go out, soonest first, with network, scheduled time and content preview: the upcoming content calendar. |
crm://social/posts/published | Published social posts | The most recently published posts with their live URLs, plus any that failed and why: what actually went out. |
15 pre-built prompt templates exposed via prompts/get. Each renders a ready-to-run prompt by pulling the relevant CRM data. Arguments marked with a * are required.
| Prompt | Title | Description | Arguments | Scope |
|---|---|---|---|---|
summarize-contact | Summarize a contact | Summarizes the relationship with a CRM contact and proposes a concrete next step. Pulls the latest 10 messages exchanged with the contact. | contactId* | contacts:read |
draft-followup-message | Draft a follow-up message | Drafts a Telegram follow-up message tailored to the contact’s stage and recent conversation. Optional tone selector. | contactId*, tone | contacts:read |
daily-briefing | Daily CRM briefing | Builds a “morning standup” digest from today’s queued/sent/failed jobs and the user’s contact pipeline. | — | analytics:read |
audit-account-health | Audit a connected account | Pulls the last 7 days of job stats for a connected Telegram/X account and asks for a risk assessment (rate-limit pressure, error spikes, etc.). | accountId* | analytics:read |
weekly-finance-report | Weekly finance report | Builds a weekly finance report from the last 7 days of realized (completed) income/expense, grouped per currency. | — | finance:read |
deal-next-step | Suggest a deal’s next step | Given a deal’s stage, value, probability and open tasks, recommends the single best next action to move it forward. | dealId* | deals:read |
summarize-email-thread | Summarize an email thread | Summarizes an email inbox thread and surfaces the customer’s open question plus one recommended next action. Does not draft or send a reply. | threadId* | email:read |
triage-inbox | Triage the inbox | Pulls the most recently active contacts (unread first) and asks the model to rank who to reply to first and why. | — | contacts:read |
pipeline-review | Review the deal pipeline | Pulls open deals grouped by stage with value and probability, then asks for a weighted forecast and the 3 deals most at risk. | — | deals:read |
task-prioritize | Prioritize today’s tasks | Pulls overdue tasks plus those due in the next 48 hours and asks for a single prioritized action list for today. | — | tasks:read |
outreach-plan | Plan next week’s outreach | Summarizes active sequences with their target progress and asks for next-week outreach focus and one improvement per under-performing sequence. | — | sequences:read |
lost-deal-postmortem | Lost-deal post-mortem | Given a lost deal’s data and its task history, asks for the likely root cause and a concrete re-engagement play. | dealId* | deals:read |
social-inbox-triage | Triage the social inbox | Pulls the social DM conversations still waiting on a reply across every connected network (Instagram, WhatsApp, Facebook, X, LinkedIn and the rest) and asks the model to rank who to answer first and why. | — | social:read |
weekly-content-plan | Plan next week’s social posts | Combines the connected accounts, what is already scheduled and how the last 30 days of posting performed into a concrete posting plan for the coming week. | — | posts:read |
dm-reply-draft | Draft a social DM reply | Drafts a reply to a social DM conversation using the real thread history, the participant’s language and the platform’s length conventions. Drafts only, never sends. | conversationId*, tone | social:read |
Prompt argument details:
draft-followup-message → tone (optional): Voice for the draft: 'friendly' (default), 'professional', or 'urgent'.dm-reply-draft → conversationId (required): from crm_list_social_conversations. tone (optional): same three voices.The ads tools (Google Ads, Meta Ads, TikTok Ads, Ads Studio, alerts, attribution) answer a failed call with a structured JSON error instead of a bare sentence, so an agent can branch on code rather than parsing text:
{ "error": { "code": "rate_limited", "message": "...", "hint": "...", "retryable": true, "retryAfterSec": 30, "googleErrorCode": null, "requestId": "..." }}code is a stable identifier, for example manager_account_no_metrics, customer_not_enabled, permission_denied, rate_limited, quota_exceeded, validation_failed, confirmation_required, ambiguous_id, or not_connected. retryable says whether trying again can succeed at all, retryAfterSec is present alongside a rate or quota code, hint is a plain-English suggestion of what to change, and googleErrorCode carries Google’s own error code when the failure came from the Google Ads API.
requiredScope for it. Add the scope to the key (or create a new key) in Authentication.401 Unauthorized — the Authorization header is missing, malformed, or the key was revoked. Ensure the value is Bearer csk_live_… (note the space).isError: true: the call reached the tool but the operation failed (bad arguments, not-found id, etc.). The error payload inside result explains why; for an ads tool, that payload is the structured error object above.https://api.pinlyx.com/mcp and restart the client to re-run initialize.@crmsolid/mcp-server — the stdio bridge, with per-client setup guides and tool recipes.