# Macha - Full Documentation > Macha is an AI copilot platform that connects to the tools your team already uses and gives you AI agents that read data, draft replies, and take action with your approval. This file is the full prose content of every Macha documentation page, concatenated for LLM ingestion. Canonical site: https://www.getmacha.com OpenAPI spec: https://dashboard.getmacha.com/api/v1/openapi.json --- # What is Macha — AI Copilot for Your Tools Source: https://www.getmacha.com/docs/macha > Macha is an AI copilot that connects to the tools your team already uses — Zendesk, Freshdesk, Gorgias, Front, Shopify, Slack, and more — and gives you AI agents that read data, draft replies, and take action with your approval. ## What Macha is Macha is an AI copilot platform for support, e-commerce, and operations teams. You connect the tools your team already uses — Zendesk, Freshdesk, Gorgias, Front, Shopify, Stripe, Slack, Confluence, Notion, Google Workspace — and Macha turns each connected tool into a set of capabilities your AI agents can use. Agents read data from your workspace, draft replies, update records, and take action on your behalf, with confirmation gates on anything customer-facing. The model under the hood matters less than what the agent is allowed to *do*. Macha is built around the tool surface, not the chat box: every agent is configured with a specific set of tools (read, write, knowledge), specific instructions (the rules you write), and an optional trigger (the event that wakes it up). The model just executes the policy you've written. ## The core idea Most AI products are a chat box pointed at a generic large language model. Macha is different in two ways: - **Tools, not just chat.** Every agent has a specific tool surface — search Zendesk tickets, read a Google Doc, look up a Stripe customer, post a public reply to a Front conversation. The agent decides which tool to call when, but it can only call tools you've enabled. - **Your rules in writing.** Each agent has an instructions field where you write the policy in plain English: how to triage, what to escalate, what tone to use, what's off-limits. The agent obeys those instructions on every conversation. The result is an agent that behaves like a junior teammate who knows your tools — not a chatbot that guesses. ## What you can build with Macha Most customers fall into one of four shapes: - **Support automation.** A triage agent reads incoming tickets and tags / prioritizes / routes them. A reply assistant drafts customer responses. An escalation manager catches the urgent ones. Each works off your existing helpdesk (Zendesk, Freshdesk, Gorgias, Front) and uses the helpdesk's native concepts — tags, priorities, custom fields, internal notes. - **E-commerce ops.** Order lookup agents resolve "where is my order?" by reading Shopify. Refund handlers verify eligibility from Stripe before processing. Product recommenders search your catalog. Macha doesn't replace your store — it gives your support team an AI that can read it. - **Internal Q&A.** Knowledge agents answer team questions using uploaded docs, Confluence, Notion, or Google Drive. The "where do I find X?" question gets a direct answer with a link to the source. - **Multi-agent flows.** A parent agent classifies an incoming ticket and hands off to specialist sub-agents (one for refunds, one for shipping, one for technical) — each sub-agent has its own narrower toolset. The parent handles routing; the children handle the work. ## Key concepts Five primitives compose every Macha workflow. Once you know these, the rest of the platform is configuration. ### Agents An agent is a configured AI that has a name, a handle (used to `@mention` it), instructions (the rules it follows), a model (which AI runs it), a set of tools, and optionally a trigger. You can create agents manually or with Sidekick — describe what you want and Sidekick builds it. See [Agents](/docs/agents). ### Tools Tools are the actions an agent can take. They come from two places: **connectors** (Zendesk, Shopify, etc. — pre-built tool sets) and **custom tools** (any HTTP API you connect via the Custom Tools builder). Each tool is either a *read* (safe — fetches data) or a *write* (mutates external state — needs confirmation in chat, runs immediately in autonomous mode). ### Connectors Connectors are the integrations Macha ships with — currently 14, including all major helpdesks (Zendesk, Freshdesk, Gorgias, Front), e-commerce (Shopify), payments (Stripe, Razorpay), messaging (Slack), docs (Confluence, Notion, Google), and a few more. Each connector shows up with its full tool surface the moment you connect it. See [Connectors](/docs/connectors). ### Triggers Triggers are the events that wake an agent up without a human typing. A Zendesk "new ticket" trigger fires the agent every time a customer files something. A Slack `app_mention` trigger fires when someone `@mentions` the bot. A custom webhook trigger lets you call Macha from anywhere. Triggers are how agents go from "interactive chat" to "autonomous worker." See [Triggers](/docs/triggers). ### Data sources Data sources are the knowledge an agent reads from. Upload PDFs, point at a website to crawl, or hook up live sources like Google Docs or Confluence. The agent searches across them on every conversation. Different from connectors: connectors give the agent *actions*, data sources give the agent *context*. See [Data Sources](/docs/data-sources). ## How Macha is different from a generic chatbot Three things, mostly: - **Macha is multi-tool by default.** A single Macha agent typically has 8–20 tools active across multiple connectors. The model decides which one to call. Generic chatbots either have no tools or one at a time. - **Macha enforces your rules at the platform level.** Write tools always pause for confirmation in chat. Connector-disabled tools are invisible to the agent at runtime. Plan limits apply uniformly. You don't have to trust that the LLM will read your instructions correctly — the platform ensures it can't even attempt the things you've turned off. - **Macha grades itself.** The [Agent Evaluation](/docs/agent-evaluation) feature runs an AI judge over every past conversation and scores how well the agent followed its instructions. You don't have to guess whether a prompt change helped — measure it. ## Who Macha is for Macha is built for teams who have one or more of these problems: - **Support volume that's growing faster than headcount.** Triage and reply assistants take the routine work off your queue so humans focus on the hard tickets. - **Multiple tools that don't talk to each other.** Macha is the layer that does — your support agent can look up a Stripe payment, search a Confluence runbook, and post the reply in Zendesk in one workflow. - **An expanding ops team that needs internal answers fast.** Sidekick + connected docs means "where do I find X?" gets a sourced answer in seconds. - **A product where the support experience matters.** Macha's confirmation gates, evaluation scores, and per-agent permissions are built around the assumption that bad replies are worse than slow replies. If your stack is "just a chat box" or "just an Excel file," Macha is probably overkill. If your stack is "Zendesk + Shopify + Confluence and we're drowning in tickets," this is exactly what we built. ## How to get started - [Create an account](https://dashboard.getmacha.com/signup) — free trial, no card required. - Walk through onboarding — pick your tools, pick up to three pre-built agents, connect your integrations. - Land in the welcome conversation — Macha has already pulled real items from your workspace and shows what it found. This first chat is on us (zero credits). - Activate the agents you picked. Test them in chat first, then add a trigger when you trust them. For a deeper walkthrough see [Getting Started](/docs/getting-started). For best practices on writing instructions, picking models, and avoiding common pitfalls, the [Building Effective Agents](/building-effective-agents) guide is the field manual. --- # Sidekick — The In-Product AI Helper Source: https://www.getmacha.com/docs/sidekick > Sidekick is the AI helper built into the Macha dashboard. Ask it to build an agent from a description, wire up a custom API tool, list which connectors broke this week, or answer any question about how Macha works — without leaving the page. ## What Sidekick is Sidekick is the AI copilot built into the Macha dashboard, a full-screen workspace you can open from anywhere in the app. It's separate from the agents you build for your team: those agents work on your *data* (Zendesk tickets, Shopify orders, Slack messages); Sidekick works on *Macha itself*. It can build an agent from a description, wire up a custom API tool, audit how your existing agents are performing on real conversations, debug a tool that isn't behaving, render charts of your usage, search the web for vendor docs, and read files you attach. You'll find Sidekick in the sidebar footer (look for the rotating mascot). Click it, or hit `⌘K` on Mac / `Ctrl K` on Windows or Linux from any page. The overlay covers most of the dashboard with a backdrop blur, and your session keeps its place if you close and reopen. ## When to use Sidekick (and when not to) The split is mostly about *what data the question is about*: - **Use Sidekick** for questions about Macha: how to set up X, what plan you're on, why a connector is in the wrong state, building a new agent from scratch, hooking up a custom tool, debugging why a trigger isn't firing, auditing how your refund agent did this week. - **Use one of your own agents** for questions about your business data: "summarize ticket #12345", "find recent refund requests", "draft a reply to this customer". Sidekick can't read your tickets or your Stripe data directly, that's what the agents you've built are for. (Sidekick *can* read past *conversations* your agents have had, which is how it audits performance.) A useful mental model: Sidekick is the Macha team member sitting next to you, not the customer support rep. Ask it the meta questions about your workspace. ## What Sidekick can do Six things Sidekick is particularly good at: ### 1. Build an agent from a description Describe the agent you want in plain English (*"I need an agent that reads new Zendesk tickets, decides if they're about refunds, tags them, and posts an internal note for the support team"*) and Sidekick walks you through it: confirms the use case, recommends a ranked list of tools from the connectors you have connected (with a picker you can adjust), drafts the instructions, suggests a trigger, and creates the agent. You review before anything saves. This uses the `build-agent` playbook internally. Sidekick fetches the playbook step-by-step instructions on demand, so the same agent-creation pattern works whether you start with a one-line description or a long brief. Available on **every plan**, including trial. ### 2. Edit an existing agent Open Sidekick and say *"add a refund tool to the triage agent"*, or *"change the support agent's model to GPT-5.4 Mini"*, or *"add a scheduled trigger to the daily-digest agent that runs every morning at 9am"*. Sidekick looks up the agent, makes the change, and tells you what it did. Available on every plan. ### 3. Build and debug a custom API tool If you want your agents to call an HTTP API that isn't a built-in connector (your internal CRM, a logistics provider, a niche SaaS), Sidekick can configure it as a custom tool. Paste the API docs (or a curl command), tell Sidekick what it does, and it builds the tool: URL, method, parameters, auth, body template. It tests the endpoint live before saving so you know it works. For tools that already exist, ask *"is my Postmark template-list tool working?"* and Sidekick will run it with sample args, show you the request, response, and timing, and explain what's broken if anything is. This uses the `build-custom-tool` playbook. Custom tools are a **Professional and Enterprise feature**; Sidekick will tell you if you're not on a qualifying plan. ### 4. Audit how your agents are doing Sidekick can read past conversations your agents have run and judge them against the agent's own instructions. Ask *"how did the refund agent do this week?"* or *"find any conversations where the support agent tagged a ticket but the customer wasn't actually angry"* or *"score the last 20 runs of the triage agent for instruction-following"*, and Sidekick searches the conversation log, opens each one, and gives you a verdict, often with a chart of the result. This uses the `evaluate-agent` playbook. Available on every plan. ### 5. Answer questions about Macha Anything covered in these docs, Sidekick can answer directly. It has the Macha docs indexed as a knowledge base and searches them on every question. *"How do I set up a Zendesk custom webhook?"*, *"What's the difference between a trigger and a schedule?"*, *"How does instruction-following evaluation work?"* Quick sourced answers with links to the relevant doc page if you want to go deeper. For things outside Macha's docs (third-party API specs, vendor pricing, current events), Sidekick falls back to a built-in **web search** with inline citations. This uses the `answer-questions` playbook. Available on every plan. ### 6. Surface workspace status & render charts Sidekick can read your workspace state and answer questions about it: - *"What plan am I on?"* - *"How many credits do I have left?"* - *"Which connectors are broken?"* - *"List all my inactive agents."* - *"Show me a bar chart of credits used per agent this month."* - *"Plot conversations per day for the last 14 days."* Bar, line, and donut charts render inline using `render_chart`, with a View Data table for the underlying numbers. No PII passes through, these are platform-level metadata queries. ## How you talk to Sidekick Sidekick is designed to feel like Claude Code or a senior teammate working at your shoulder, not a one-line chatbot. A few patterns to know: - **Pickers, not "A or B?".** When Sidekick needs to clarify something, it shows you a list of options with number-key shortcuts. Hit `1`, `2`, or `3` to pick, or use `↑/↓` and `Enter`. There's always a "Chat about this" freeform option if none of the choices fit. - **Confirmation cards before destructive actions.** Sidekick won't delete an agent, change a trigger, or commit a configuration write without showing you a card summarizing what it's about to do. - **Reasoning is exposed.** Every assistant turn has a Reasoning pill; click it (or any italic narrator line between tool calls) to open the Reasoning drawer with the model's chain-of-thought streaming in. Useful when you want to know *why* Sidekick made a call. - **Ghost-text suggestions.** When Sidekick has a high-confidence guess at what you might want to say next, it shows it as ghost text in the composer. Press `Tab` to accept. - **History rail.** Past sessions are auto-titled and grouped Today / Yesterday / Older. Toggle the rail open from the chat header. ## Attaching files and using voice - **Files.** Click the paperclip or drag any file onto the panel. Sidekick reads images, PDFs, text, CSV, JSON, Markdown, and DOCX natively, up to 20MB per file and 5 files per message. PDFs are capped at 100 pages. Quote relevant sections back to Sidekick if you want it to focus on a specific part. - **Voice.** Tap the microphone to dictate. Sidekick transcribes with Groq Whisper and auto-sends when you stop talking. Useful when you're describing an agent end-to-end and don't want to type a paragraph. ## What Sidekick can NOT do Two important boundaries: - **Sidekick can't read your live customer data.** It doesn't connect to Zendesk, Stripe, Front, etc. to fetch tickets or customers in real time. That's by design, Sidekick is the meta-agent for working with Macha, not for working with your customers. Build your own agents for that, and they'll have the appropriate tool access. (Sidekick *can* read past conversations your agents have already had, which is how the audit flow works.) - **Sidekick can't change billing or invite teammates.** Anything that touches money, identity, or your organization's structure stays in the Settings UI on purpose. Sidekick can *tell you* what your plan is and link you to the billing page, but it won't upgrade or cancel for you. ## How Sidekick decides what to do When you send a message to Sidekick, it doesn't just answer, it picks a *playbook*. Each playbook is a multi-step script for a major task (build an agent, edit an agent, build a custom tool, evaluate an agent, answer a question) that Sidekick loads on demand. The playbook tells Sidekick: what tools to use, what order to use them in, what to confirm with the user before saving anything. This is why Sidekick stays consistent. Agent creation always follows the same flow, custom tool creation always tests the endpoint before saving, doc answers always cite the source. You're never surprised by what it does because the patterns are baked in, not improvised per conversation. ## Conversations and credits Each Sidekick session is its own conversation, persisted in your Macha account. The history rail in the chat header lets you scroll back through prior sessions, grouped by Today / Yesterday / Older, with auto-generated titles. Sidekick runs on a dedicated key with its own usage tracking, separate from the credits your customer-facing agents spend. Long sessions are **compacted automatically**: once a conversation crosses a token threshold, Sidekick summarizes the middle of the thread (keeping the first user message and the last 12 messages intact) so context stays fresh without you losing the thread. ## Privacy Sidekick conversations are stored on your Macha account, the same way agent conversations are, and follow a 7-day TTL on the internal log. Files you upload are attached to OpenAI's Files API for the duration of the session so the model can read them; they're not used for training. Credentials passed to Sidekick during custom-tool building (e.g., test API keys you paste in the chat) are encrypted at rest using the same key infrastructure as connector credentials. Once a custom tool is saved, the credentials live on the tool record, never visible in the Sidekick conversation history afterwards. ## Plan availability Sidekick is available on **every plan**: trial, starter, professional, and enterprise. The agent-building, editing, evaluation, and Q&A flows are open to all. Custom tool building is gated to **Professional and Enterprise** because custom tools themselves are a paid feature; Sidekick will tell you if you try to build one on a lower plan. --- # Getting Started with Macha Source: https://www.getmacha.com/docs/getting-started > Create your account, walk through onboarding, connect your first integration, and set up your workspace in minutes. ';this.style.cursor='default'"> What is an AI Agent on Macha An AI agent on Macha is a workflow you can configure with three things: instructions (what you want it to do), tools (the actions it can take inside your connected apps), and triggers (the events that kick it off). You point it at the data sources it should reference, give it the right capabilities, and the agent decides on its own how to handle each situation it sees. Anytime the agent wants to make a change in chat — update a ticket, post a reply, edit a field — it pauses and asks you to confirm. In autonomous mode (running off a trigger), it acts immediately without that confirmation step. ## Creating an Account Getting started with Macha takes just a few minutes. Head to the [signup page](https://dashboard.getmacha.com/signup) and enter your name and email address. You do not need to create a password — Macha uses passwordless authentication for better security. ### OTP Verification After submitting your email, you will receive a one-time passcode (OTP) delivered to your inbox. On the verification screen you will see six individual input boxes — one for each digit of the code. Type or paste the code and it will auto-submit once all six digits are filled in. A few things to note: - Each box auto-advances to the next as you type. - Press **Backspace** to move back to the previous box. - You can paste the full 6-digit code and all boxes will fill at once. - The code expires after a short window, so enter it promptly. Tip If you already have an account, use the [login page](https://dashboard.getmacha.com/login) instead. The login page will let you know if the email is not recognized and point you to sign up. ## Onboarding Walkthrough When you create a new organization, Macha walks you through a three-step onboarding flow so your workspace is ready to go from the start. ### Step 1: Select Your Tools You will see a grid of available integrations — Zendesk, Freshdesk, Gorgias, Front, Shopify, Slack, Stripe, Google Workspace, Notion, Airtable, and more. Helpdesks are listed first since they're the most common starting point. Select the tools your team uses; this helps Macha recommend the right agents and templates for your workflow. ### Step 2: Recommended Agents Based on the tools you selected, Macha suggests pre-built agent templates. These are ready-made configurations for common workflows like ticket triage, customer support replies, escalation handling, and pulling docs context from Confluence. You can pick up to **three agents** to start with — keeping the first run focused beats trying to enable everything at once. You can build more agents anytime after onboarding. ### Step 3: Connect Integrations For each tool you selected, you will be prompted to connect it. Depending on the integration, this is either an OAuth authorization flow (you click a button and approve access) or an API key entry (you paste credentials from the external service). You can skip any integration and connect it later from the Connectors page. Tip You can skip the entire onboarding if you prefer to set things up manually. Click "Skip" at any point and you will be taken to your workspace. ## The welcome conversation Once you finish onboarding with at least one connector connected, Macha drops you straight into a **welcome conversation** , not a static "you're all set" screen. Macha has already used your connected tools to pull a few real items (e.g. recent Zendesk tickets, recent Stripe payments, recent Front conversations) and the assistant message you see streams in with concrete references to what was found in your workspace. Below the welcome message, three suggestion chips appear , AI-generated, tailored to the agents you just picked and the data you actually have. Click a chip and the suggested question sends as your first message; ignore them and just type your own. The conversation carries a small **"This chat costs no credits"** badge near the model picker so it's clear this run is on the house. The badge disappears the moment you start a new conversation , only this one welcome chat is credit-free. Why a free welcome chat? The discovery reads and the streamed assistant message all use credits internally , Macha is covering them so you can see what the platform can actually do with your data before any of your plan credits get spent. One welcome conversation per organization. ## Workspace Overview Once onboarding is complete, you land in your Macha workspace. The sidebar on the left gives you access to everything you need: - **New Chat** — Start a conversation with any of your agents. - **Agents** — View, create, and configure your AI agents. - **Sources** — Manage knowledge bases, file uploads, and connected data sources. - **Connectors** — Connect and manage integrations with external tools. - **Custom Tools** — Build your own API-based tools for agents to use. - **Templates** — Browse pre-built agent configurations for common workflows. Each section is designed to be self-contained — you can set up connectors independently of agents, and then wire them together when you are ready. ## Quick Start: Your First Agent Here is the fastest path from signup to a working AI agent: - **Build with AI (recommended).** Go to the Agents page and click "Build with AI." Describe what you want — for example, "Create an agent that triages incoming Zendesk tickets." The AI will configure the name, instructions, tools, and trigger automatically based on your connected integrations. - **Or create manually.** Click "Create Agent" to set up an agent step by step. Give it a name, write instructions, pick a model, and assign connectors and tools. - **Start a conversation.** Click "New Chat" in the sidebar, select your agent, and type your first message. The agent will respond using the instructions and tools you configured. From here you can iterate — refine the instructions, add data sources for the agent to reference, assign additional connectors, or set up triggers for automation. Each of these topics is covered in detail in the following pages. ';this.style.cursor='default'"> Build an AI Agent — Full Walkthrough If you want to see the whole flow end-to-end — Build with AI, reviewing and editing the draft, adding tools, attaching a trigger, testing in chat — the walkthrough above runs through it on a real ticket-summarizer agent. A few takeaways from the video worth flagging: - **Always review what Build with AI generates.** The AI gives you a strong starting point, but read through the instructions and tool list before saving. It does not know about your custom ticket fields or organization-specific rules — those you add yourself. - **The AI builder does not add triggers automatically.** You decide when the agent should run. After the agent is configured, go to Triggers and pick the event that should kick it off (e.g., ticket closed, new comment, custom webhook). - **For complex instructions, draft them in ChatGPT or Claude first** — paste your existing instructions, ask the model to tighten them, then copy the result back into Macha. Instructions are plain text, so this works well. - **Test before you go live.** Use Chat to run the agent against a real or test ticket, watch what it does, then turn the trigger on once you're confident. --- # Creating and Configuring AI Agents Source: https://www.getmacha.com/docs/agents > Create AI agents manually or with the AI builder. Configure instructions, choose models, assign tools, and connect knowledge sources. ';this.style.cursor='default'"> How to Create AI Agents Manually ## What Are Agents Agents are the core of Macha. An agent is an AI copilot configured with specific instructions, tools, and knowledge to help your team with a particular job. Think of each agent as a specialist — one might handle customer support tickets, another might look up order information, and a third might triage incoming requests. Every agent has its own personality, capabilities, and access permissions. You control exactly what each agent can do by choosing its model, writing its instructions, and assigning the connectors and data sources it needs. ## Creating a New Agent There are three ways to create an agent: - **Build with AI** , Click the "Build with AI" button and describe what you want in plain language. The AI will configure the agent's name, instructions, tools, triggers, and sub-agents based on your connected integrations. This is the fastest way to get started. - **Create manually** , Click "Create Agent" to start with a blank configuration and set everything up yourself. - **Start from template** , Browse pre-built templates for common workflows like ticket triage and customer replies. You can also edit any existing agent with AI by clicking "Edit with AI" on the agent's configuration page. ';this.style.cursor='default'"> Build AI Agents with the AI Agent Builder ### Name & Handle Give your agent a clear, descriptive name that reflects its purpose. For example: "Zendesk Support Agent," "Billing Specialist," or "Order Lookup Assistant." The name is visible to your team when they select an agent to chat with. Each agent also has a **handle** used for @mentions in chat (e.g., `@ticketTriageAgent`). The handle auto-generates in camelCase from the name as you type. You can also edit it manually. ### Instructions Instructions are the system prompt that shapes how your agent behaves. This is the single most important part of agent configuration — it tells the AI who it is, how it should respond, and what rules to follow. ### Model Selection ';this.style.cursor='default'"> How to Pick the Right AI Model Macha supports multiple AI models from different providers. Each model has different strengths: - **OpenAI GPT-5.4** — Most capable model. Best-in-class reasoning and accuracy for complex, multi-step workflows. - **OpenAI GPT-5** — Powerful and cost-effective. The default model — great balance of quality and credit cost for most agents. - **OpenAI GPT-5.4 Mini** — Fast and affordable. Ideal for high-volume agents handling everyday tasks. - **Anthropic Claude** — Strong at nuanced writing, careful reasoning, and following complex instructions. Great for tasks requiring attention to detail. - **Groq (Llama)** — Extremely fast inference. Ideal for high-volume, straightforward tasks where low latency is the priority. Tip Different models consume different amounts of credits per response. More capable models cost more. Check the credit cost shown next to each model when making your selection. ## Writing Effective Instructions The quality of your agent depends heavily on the instructions you write. Here are guidelines for getting the best results: ### Be Specific About the Role Start by clearly defining who the agent is and what it does. Instead of "Help with support," write something like: "You are a Tier 1 support agent for Acme Corp. Your job is to handle incoming Zendesk tickets, look up customer orders, and provide helpful responses." ### Define the Persona Set the tone and style. Should the agent be formal or casual? Brief or detailed? For example: "Respond in a friendly, professional tone. Keep replies concise — no more than 2-3 paragraphs unless the customer's question requires a detailed explanation." ### Set Boundaries Tell the agent what it should **not** do. This is just as important as telling it what to do. For example: "Never promise refunds without checking with the billing team. Do not share internal notes with customers. If you are unsure about a policy, say so rather than guessing." ### Describe the Workflow If the agent should follow a specific process, spell it out step by step. For example: "When a new ticket arrives: 1) Read the ticket and any previous conversation. 2) Look up the customer's order history. 3) Draft a reply addressing their issue. 4) If the issue requires escalation, tag the ticket as 'needs-escalation' and add an internal note." ### Reference Available Tools If the agent has access to specific tools, mention them in the instructions so the AI knows when and how to use them. For example: "Use the search_tickets tool to find related tickets before responding. Use add_public_reply to send the response directly." ## Assigning Connectors and Tools Connectors give your agent the ability to interact with external services. When you assign a connector to an agent, you then choose which specific tools from that connector the agent can use. For example, if you assign a Zendesk connector, you might enable tools like **get_ticket**, **search_tickets**, and **add_public_reply** — but leave out **update_priority** if you do not want the agent changing ticket priority. Some tools are marked as requiring confirmation. These are typically write operations (like sending a reply or creating a refund) where you want a human to approve the action before it executes. When an agent tries to use a confirmation-required tool, the chat pauses and asks you to approve or reject. ### When a tool has been disabled at the connector level Connectors can have specific tools turned off at the org-wide level — see [Disabling tools at the connector level](/docs/connectors). When that happens, any agent that previously had those tools enabled will show them in a clear warning state instead of silently letting them appear active: - The tool's pill in the flow summary turns amber-dashed with a small warning icon. Hover for a tooltip explaining the situation. - In the **Add Tool** modal, the row is greyed out, the toggle is replaced with a **Manage** button. - In the right-side enabled-tools list, the card shows an amber warning band and a **Manage connector** link. Each "Manage" link opens the connector's settings modal directly on the agent page so an admin can re-enable the tool and the agent's list updates live. The agent silently can't call a connector-disabled tool at runtime — these visual cues exist so nobody wastes time toggling tools the platform won't actually run. ## Assigning Data Sources Data sources give your agent access to knowledge — uploaded documents, website content, or live data from connected services like Google Docs and Notion. See the [Data Sources](/docs/data-sources) documentation for full details on how this works. When you add a data source to an agent, you can choose whether the agent has access to all documents in that source or only specific ones you select. ## Prompt Suggestions Each agent can have a set of prompt suggestions — starter messages that appear when a user opens a new chat with that agent. These help users understand what the agent can do and give them a quick way to get started. Prompt suggestions are auto-generated based on the agent's instructions and capabilities. They are designed to showcase the agent's most useful features. You can regenerate them at any time if you update the agent's configuration. ## Credit System Every time an agent produces a response, it consumes credits. The number of credits varies by model — more capable models cost more per response. Credits are deducted once per complete assistant response, not per message or per tool call. Key details about credits: - Credit costs are defined per model and shown in the model selection dropdown. - Your organization has a credit balance that all agents share. - You will receive email alerts when your credits reach 50%, 80%, and 90% usage. - Enterprise plans bypass credit limits entirely. You can monitor your credit usage on the [Billing](/docs/billing) page. ## Deleting and restoring agents Delete is reversible. When you delete an agent, it moves to a **Trash** tab on the Agents page for 30 days. You can restore it any time within that window and all its triggers, instructions, sub-agent links, and tool configuration come back intact. After 30 days it's permanently deleted. Trash mechanics worth knowing: - **Triggers are paused, not deleted.** When an agent is trashed, its triggers are deactivated so they stop firing, but their webhook secrets and configuration are preserved. Restoring the agent brings the trigger configuration back; you re-enable them when you're ready. - **The Trash tab shows time remaining.** Each trashed agent displays how long ago it was trashed and how many days remain before automatic purge. One-click restore per row. - **Sidekick respects the trash flow.** If you ask the dashboard's Sidekick to delete an agent for you, it uses the same soft-delete path, with the same 30-day restore window. Tip If you're cleaning up a workspace and want to keep an agent's configuration as a future reference, trashing is a low-cost way to archive it. Restore only if you actually need it back. --- # Pre-Built Agent Templates Source: https://www.getmacha.com/docs/agent-templates > Browse pre-built agent configurations for common workflows like ticket triage, customer replies, and escalation handling. ';this.style.cursor='default'"> Create AI Agents from Templates ## What Are Templates Agent templates are pre-built configurations that let you create a fully functional agent in one click. Each template comes with a name, description, detailed instructions, a recommended set of connectors, and pre-selected tools — all designed for a specific workflow. Templates are the fastest way to get started with Macha. Instead of writing instructions from scratch and figuring out which tools to assign, you pick a template that matches your use case and it handles the setup for you. ## Available Template Categories Macha offers templates across a range of common workflows. Here are some of the categories you will find: ### Customer Support Available across all four supported helpdesks (Zendesk, Freshdesk, Gorgias, Front). Each template uses the connector-specific tools — e.g. the Gorgias triage template reaches for macros, the Front triage template reaches for inboxes — so the agent feels native to whichever platform you've connected. - **Ticket / Conversation Triage** — Reads incoming tickets (or conversations, on Front), categorizes them by type and urgency, and assigns priority, tags, and routing. Variants: *Zendesk Triage* , uses ticket fields, tags, and groups for routing. - *Freshdesk / Gorgias Triage* , mirrors the Zendesk pattern with helpdesk-native field names. - *Front Conversation Triage* , uses Front's inboxes, tags, and teammate assignment instead of a priority field (Front doesn't have one natively). - **Customer Reply Assistant** — Drafts helpful responses to customer inquiries using ticket context, message history, and knowledge sources. Variants per helpdesk; the Gorgias version is wired to *search macros* so the agent can adapt canned responses, and the Front version posts an internal comment with contact + inbox context before drafting the reply. - **Escalation Handler** — Identifies tickets that need human attention, adds internal notes (or comments, on Front) with context, and routes to the appropriate team. - **Conversation + Docs Context** — Cross-connector template that pairs any helpdesk with Confluence. When a ticket / conversation comes in, the agent searches Confluence for relevant docs and posts an internal note with links. Available as Zendesk + Confluence, Freshdesk + Confluence, Gorgias + Confluence, and Front + Confluence. ### E-Commerce - **Order Lookup** — Helps customers check order status, shipping details, and delivery timelines using Shopify or Stripe data. - **Refund Assistant** — Walks through the refund process, checks order eligibility, and initiates refunds with human confirmation. ### Internal Operations - **Knowledge Base Assistant** — Answers internal questions using uploaded documents and connected data sources. - **Data Lookup** — Searches across Airtable, Google Sheets, or other connected data to answer team queries. Tip The templates shown to you are filtered based on which connectors your organization has set up. If you connect a new integration, new templates may become available. ## Creating from a Template To create an agent from a template: - Navigate to the **Templates** page from the sidebar. - Browse the available templates. Each card shows the template name, a brief description, and the connectors it requires. - Click on a template to see its full details — including the instructions it will use and the tools it will enable. - Click "Use Template" to create the agent. Macha will set up the agent with the template's configuration and take you to the agent editor. The agent is created immediately and is ready to use. You can start chatting with it right away, or customize it first. ## Customizing After Creation A template is just a starting point. Once the agent is created, it is a fully independent agent that you can modify however you like. Nothing is locked to the template. ### Common Customizations - **Edit instructions** — Tailor the agent's behavior to your company's specific processes, tone, and policies. The template gives you a solid base, but you will likely want to add details specific to your team. - **Change the model** — Templates come with a default model selection, but you can switch to a different one based on your needs. For example, swap to a faster model for high-volume use or a more capable model for complex reasoning. - **Add or remove connectors** — Templates pre-select connectors, but you can add more (like giving a support agent access to Shopify in addition to Zendesk) or remove ones you do not need. - **Adjust tool access** — Fine-tune which specific tools the agent can use. You might want to disable write operations until you are confident in the agent's behavior. - **Add data sources** — Connect knowledge bases, uploaded documents, or live data from Google Docs and Notion to give the agent more context. - **Set up triggers** — Configure the agent to run automatically in response to events. See [Triggers](/docs/triggers) for details. Tip If you are new to Macha, start with a template and iterate from there. It is much easier to refine a working agent than to build one from scratch. --- # Multi-Agent Delegation with Sub-Agents Source: https://www.getmacha.com/docs/sub-agents > Let agents delegate tasks to specialist agents. Build multi-agent workflows with automatic routing and hierarchical delegation. ';this.style.cursor='default'"> Using Sub-Agents — Multi-Agent Delegation ## What Are Sub-Agents Sub-agents let one agent delegate tasks to another agent. When you assign a sub-agent to a parent agent, the sub-agent appears as a callable tool during conversations. The parent agent can decide when to call the sub-agent, pass it a task, receive the response, and incorporate it into its own reply. This creates a hierarchy of specialists. Instead of building one agent that tries to do everything, you can build focused agents that each handle a specific domain and let a coordinator agent route tasks between them. ## When to Use Sub-Agents Sub-agents are most useful when your workflows involve multiple distinct areas of expertise. Here are some common scenarios: ### Specialist Routing A general-purpose support agent receives all incoming questions. Instead of configuring it with every possible tool and knowledge base, you give it access to specialist sub-agents — one for billing, one for technical issues, one for account management. The parent agent reads the question, decides which specialist to call, and delegates accordingly. ### Complex Multi-Step Workflows Some tasks require actions across multiple systems. For example, processing a customer refund might involve checking the order in Shopify, issuing the refund in Stripe, and updating the support ticket in Zendesk. You can build a sub-agent for each system and have the parent agent orchestrate the full workflow. ### Separation of Concerns Different tasks may require different AI models or instruction sets. A data analysis sub-agent might use a model that excels at reasoning over numbers, while a customer-facing reply agent might use one optimized for natural, empathetic writing. Sub-agents let you mix and match. ## Setting Up Sub-Agents To configure sub-agents: - **Create the specialist agents first.** Each sub-agent is a normal agent with its own instructions, model, connectors, and data sources. Build and test them individually before wiring them together. - **Open the parent agent's configuration.** Navigate to the Agents page and edit the agent you want to serve as the coordinator. - **Assign sub-agents.** In the agent configuration, you will find a section for sub-agents. Select the agents you want the parent to be able to call. - **Update the parent's instructions.** Tell the parent agent about its sub-agents and when to use them. For example: "You have access to a Billing Specialist agent. Delegate any billing-related questions to it." Tip Always describe the sub-agents in the parent's instructions. The parent agent needs to know what each sub-agent does in order to route tasks correctly. Be explicit about when to delegate and when to handle things directly. ## How Delegation Works When a parent agent has sub-agents assigned, each sub-agent appears as a tool the parent can call during a conversation. Here is how the process works: - A user sends a message to the parent agent. - The parent agent reads the message and decides if it should handle the task itself or delegate to a sub-agent. - If it delegates, it calls the sub-agent tool with a description of the task. - The sub-agent processes the task using its own instructions, tools, and knowledge. - The sub-agent returns a response to the parent agent. - The parent agent incorporates the sub-agent's response into its own reply to the user. From the user's perspective, this is seamless — they are chatting with one agent and receiving unified responses. The delegation happens behind the scenes. ### What the Parent Agent Controls - **Whether to delegate** — The parent decides if a sub-agent is needed based on its instructions and the user's message. - **What to pass** — The parent formulates the task description sent to the sub-agent. - **How to use the response** — The parent can use the sub-agent's response verbatim, summarize it, combine it with other information, or even discard it if it is not helpful. ### What the Sub-Agent Controls - **How to execute the task** — The sub-agent uses its own instructions, model, connectors, and data sources. It operates independently within the scope of the delegated task. - **Which tools to call** — The sub-agent can use any tools assigned to it, including making API calls to external services. ## Example: Support Agent with a Billing Specialist Here is a concrete example of how sub-agents work in practice: ### Setup **Billing Specialist Agent** - Connected to Stripe (tools: search_customers, get_invoices, get_subscription) - Instructions: "You are a billing specialist. Look up customer billing information, explain charges, and check subscription status. Be precise with numbers and dates." **Support Agent (Parent)** - Connected to Zendesk (tools: get_ticket, search_tickets, add_public_reply) - Sub-agent: Billing Specialist - Instructions: "You are a frontline support agent. Handle general inquiries yourself. When a customer asks about billing, charges, invoices, or their subscription, delegate to the Billing Specialist agent." ### Conversation Flow **User:** "Customer on ticket #4521 is asking why they were charged twice this month." The Support Agent reads the ticket, sees it is a billing question, and delegates to the Billing Specialist. The Billing Specialist looks up the customer in Stripe, reviews their invoices, and returns a detailed explanation. The Support Agent then drafts a customer-friendly reply combining the billing details with the appropriate support tone, and sends it via Zendesk. ## Viewing Sub-Agent Runs When a parent agent delegates to a sub-agent, the sub-agent's run is captured automatically and appears inline in the chat. You'll see a card under the parent's reply with the sub-agent's avatar, handle, model, connector logos, and tool count, plus a green "Handed off" badge so you can tell at a glance that delegation happened. Click the card to expand it. Inside, you'll see the full sub-agent conversation rendered with the same chat styling as the main panel , the handoff message the parent sent, every tool call the sub-agent made with its arguments, every tool result, and the sub-agent's final reply. Click the card again to collapse. ### What's Captured - **The handoff message** , The exact text the parent's reasoning crafted to brief the sub-agent. Useful for understanding what context the sub-agent had to work with. - **Every tool call and result** , Including arguments and full response bodies. You can see exactly what the sub-agent looked up and what came back. - **The sub-agent's final reply** , The text the sub-agent returned to the parent. This is what the parent sees as the tool result and uses in its own response. - **Model and timing** , The model the sub-agent ran on and the duration of the sub-agent's full run. Sub-agent runs are kept for 45 days under the standard conversation retention policy. They are not counted toward your conversation count in History; they live alongside the parent run that spawned them. Tip Inline sub-agent cards work the same way for chat-driven and trigger-driven flows. Whether you opened a conversation with a parent agent or a webhook fired the parent automatically, the sub-agent cards appear in both places , making it easy to audit autonomous runs after the fact. ## Permissions & Safety Sub-agents have different permissions depending on how the parent agent is running: - **Interactive chat:** Sub-agents are **read-only**. They can fetch data and search, but cannot execute write operations (like sending replies or updating records). This ensures a human is in the loop for any actions that modify external systems. - **Autonomous mode (triggers):** When the parent agent is running automatically via a trigger, sub-agents **can execute write operations**. Since there is no human present, the sub-agent inherits the autonomous context and can take actions like replying to tickets or updating records. Additional safety guardrails: - **Depth limit:** Sub-agents can nest up to 3 levels deep (A calls B calls C). Beyond that, the call is blocked. - **Circular reference prevention:** If Agent A is a sub-agent of Agent B, you cannot also make Agent B a sub-agent of Agent A. This is checked when saving and at runtime. ## Using the AI Builder The AI Agent Builder can automatically assign sub-agents when creating a new agent. If you describe a workflow that involves delegation, the builder will suggest existing agents as sub-agents and wire them up. You can also use the AI editor on an existing agent to add sub-agents through conversation. Tip Start simple. Begin with one parent agent and one or two sub-agents. Once you are comfortable with how delegation works, you can build more complex hierarchies. --- # Connecting Your Tools and Integrations Source: https://www.getmacha.com/docs/connectors > Connect your tools — Zendesk, Freshdesk, Shopify, Stripe, Slack, Google Workspace, Notion, and more. Each connector gives your agents read and write access to external services. ';this.style.cursor='default'"> Connectors, Tools & Triggers Explained ## What Are Connectors Connectors are integrations that give your agents access to external tools and services. When you connect an integration like Zendesk, Freshdesk, Gorgias, Front, or Shopify, Macha creates a set of tools that agents can use to read data, perform actions, and interact with those services on your behalf. Each connector exposes a specific set of tools. You control which tools each agent has access to, so you can give a support agent full Zendesk access while restricting a reporting agent to read-only tools. ## Read Tools vs Write Tools ';this.style.cursor='default'"> Connectors Explained — Read Tools vs Write Tools Every tool a connector exposes is either a **read tool** or a **write tool**. The distinction matters because it changes how safe a tool is to hand to an agent — especially one running autonomously. ### Read Tools Read tools fetch information without changing anything in your connected app. Examples: - Shopify — search products, search orders, get a customer record, look up an order - Zendesk — get ticket, search tickets, read attachments, search help center articles - Google Workspace — read a Doc, read a Sheet These are safe. The agent can use them freely without needing to ask you for anything. ### Write Tools Write tools make changes in your connected app — adding a public reply, updating a ticket status, posting an internal note, editing a custom field, creating a refund. These actually mutate data on the third-party tool. In **interactive chat**, the agent always pauses and asks for confirmation before running a write tool. You see the proposed action, review it, and click confirm. In **autonomous mode** (when the agent is running off a trigger), there is no human in the loop. Write actions execute immediately, with no confirmation step. This is by design — but it means you need to be deliberate about which write tools an autonomous agent can access. Tip Tools that post public replies to customers show a clear warning when you switch them on. Don't enable customer-visible write tools on an autonomous agent unless you've thoroughly tested it in chat first. ## Disabling tools at the connector level Every connector has its own tool list inside the connector's settings modal. You can switch off any tool there to disable it **across every agent in the organization**, regardless of whether individual agents had it enabled. Useful when a team admin wants to ringfence what's possible at the platform level — say, blocking `zendesk_update_ticket_tags` for the whole org while letting one team's agents keep using everything else. Connector-level disables are enforced at runtime: when an agent tries to use a tool that's been disabled at the connector level, Macha silently skips it — the agent never sees the tool, can't call it, and can't be tricked into thinking it has access. ### What this looks like inside the agent builder If a connector tool is disabled while an agent has it enabled, the agent builder flags it visibly in three places so nobody wastes time toggling a tool the platform won't actually run: - **Flow pill summary** (the compact tool list on the left of the agent flow) — the affected pill turns amber with a dashed border and a warning icon. Hover for a tooltip explaining what's happening. - **"Add Tool" modal** — the locked tool row is greyed out, the toggle is replaced by a "Manage" button, and clicking the row does nothing. - **Enabled-tools card** on the right of the Tools section — the card gets an amber warning band with text explaining the agent can't actually call this tool, plus a "Manage connector" link. Each of those "Manage" links opens the relevant connector's settings modal *in place* on the agent page. Re-enable the tool and save — the agent's tool list updates immediately, no reload needed. ## Available Integrations ### Zendesk Full-featured integration with 17 tools for ticket management, image reading, custom fields, messaging, and help center content. Zendesk connects via OAuth or API key. - **Ticket management** — Get ticket details, search tickets, update status, priority, type, subject, tags, and custom fields. - **Custom fields** — Read all custom field values on a ticket with labels resolved from the field schema. Cached per connector. - **Replies and notes** — Send public replies to customers or add internal notes for your team. - **Image vision** — Read image attachments (JPEG, PNG, GIF, WebP) using AI vision. The agent downloads the image, encodes it, and sends it to a vision-capable model. Works with GPT-5, GPT-5.4, GPT-5.4 Mini, and Claude Sonnet. - **Attachments** — Extract text from PDF, DOCX, XLSX, CSV, and TXT attachments. - **Messaging** — Read and respond to Zendesk messaging (SunCo) conversations. - **Help Center** — Search knowledge base articles with live webhook sync. - **Users and groups** — Search Zendesk users by name, email, or role; list groups to route tickets to the right queue. Assign tickets to a specific agent, a group, or both. ### Freshdesk Comprehensive support platform integration with 15 tools. Freshdesk connects via API key and subdomain. - **Tickets** — Get ticket details (including conversations and attachments), search tickets with filter-based query syntax. - **Contacts** — Search and look up customer contact information. - **Knowledge Base** — Search help center articles. - **Actions** — Add public replies (the agent's configured Freshdesk signature is appended automatically), add internal notes, update priority, status, tags, and custom fields, assign tickets. - **Team** — List agents and groups for assignment workflows. - **Attachments** — Read attachment contents (supports PDF, DOCX, XLSX, CSV, and TXT text extraction). ### Gorgias E-commerce support platform integration with 15 tools. Gorgias connects via Basic auth — your account email plus the API key from Settings -> REST API, along with your subdomain. - **Tickets** — Get ticket details with the full message thread, search tickets by full-text query. - **Customers** — Search customers by email, phone, or name. - **Macros** — Search canned responses (Gorgias's pre-written reply library). - **Custom fields** — List custom ticket fields defined in your Gorgias account. - **Actions** — Send public replies via the ticket's channel (email, chat, etc.), add internal notes, update status (open / pending / resolved / closed), update priority (low / normal / high / urgent), set tags, update custom fields. - **Team** — List users (agents) and teams for assignment workflows. Assign tickets to a specific user, team, or both. - **Attachments** — Extract text from PDF, DOCX, XLSX, CSV, and TXT attachments. - **Triggers** — Custom-webhook triggers for ticket created, ticket updated, and new message added. Configure in Gorgias under Settings -> Integrations -> HTTP integrations. ### Front Shared-inbox platform integration with 15 tools. Front connects via a Bearer API token (generated in Settings -> Developers -> API tokens). Note: Front's primary object is the **conversation** rather than the ticket — tool names and labels reflect that. - **Conversations** — Get conversation details with the full message + comment thread, search conversations by full-text query. - **Contacts** — Search contacts by handle (email, phone, twitter, etc.) or by name. Handle-based lookup is exact and fastest. - **Tags** — List the tags available in your workspace so the agent can pick valid options. - **Custom fields** — List custom fields defined across conversations, contacts, inboxes, and teammates. - **Actions** — Send public replies via the conversation's channel, post internal comments with `@mention` support, update status (archive / reopen / trash), set tags (smart diff — add and remove computed automatically), update custom fields. - **Routing** — Assign or unassign a teammate. List teammates, teams, and inboxes for routing decisions. - **Attachments** — Extract text from PDF, DOCX, XLSX, CSV, and TXT attachments. - **Triggers** — Custom-webhook triggers for conversation created, new message added, and conversation assigned. Configure in Front under Settings -> Rules with the "Send a webhook" action. **Note:** Front conversations do not have a native priority field — teams typically use tags for urgency. To prioritize, use *Update tags* with a tag like `priority-high` instead of looking for a priority dropdown. ### Shopify E-commerce integration for products, orders, customers, and more. Shopify connects via OAuth through the Macha AI app. - **Products** — Search your product catalog with variants, pricing, and inventory data. - **Orders** — Get order details, search orders by various criteria, and view order history for specific customers. - **Customers** — Look up customer profiles and their order history. - **Discounts** — View active discount codes and promotions. - **Refunds** — Create refunds (requires human confirmation before executing). ### Slack Messaging integration for team communication. Slack connects via OAuth. - **Messaging** — Send messages to channels and respond to conversations. - **App mentions** — Agents can respond when mentioned in Slack channels. - **Direct messages** — Handle direct messages sent to the Macha Slack app. ### Stripe Payment and billing integration. Stripe connects via API key. - **Customers** — Search and look up customer records. - **Payments** — View payment history, charges, and payment methods. - **Invoices** — Retrieve invoice details and payment status. - **Subscriptions** — View subscription details and status. ### Google Workspace Integration with Google Docs and Sheets. Google connects via OAuth. Documents are selected using Google Picker — you choose which files your agents can access. - **Read Google Doc** — Read the full content of a Google Doc. - **Read Google Sheet** — Read data from a Google Sheet, all sheets or a specific range. ### Confluence Integration with Atlassian Confluence for searching and managing documentation. Confluence connects via API token. - **Search Pages** — Search Confluence pages by keyword across spaces. - **Get Page** — Read the full content of a Confluence page. - **List Spaces** — List available Confluence spaces. - **Get Page Children** — Navigate page hierarchies. - **Create Page** — Create a new page in a space (with confirmation). - **Update Page** — Update an existing page (with confirmation). - **Add Comment** — Add a comment to a page (with confirmation). **Note:** Confluence API tokens expire. When connecting, enter the expiry date you chose in Atlassian. Macha will notify you 30 days before it expires so you can regenerate it. ### Notion Knowledge management integration. Notion connects via OAuth. - **Pages** — Read Notion page content. - **Search** — Search across your Notion workspace. ### Airtable Database and spreadsheet integration. Airtable connects via API key or OAuth. - **Records** — Read, search, and manage records in Airtable bases. - **Tables** — Access table structure and metadata. ## OAuth vs. API Key Setup Connectors use one of two authentication methods: ### OAuth (Authorization Flow) Used by: Zendesk, Shopify, Slack, Google Workspace, Notion. With OAuth, you click an "Authorize" button that redirects you to the external service. You log in there (if not already), review the permissions Macha is requesting, and click "Allow" or "Approve." You are then redirected back to Macha with the connection established. No API keys or credentials to copy. ### API Key / Credentials Used by: Freshdesk, Stripe, Airtable. With API key authentication, you enter credentials directly in Macha. Each connector's setup form includes step-by-step instructions on where to find the required keys in the external service. For example, Freshdesk requires your API key (found in Profile Settings) and your subdomain. Tip When connecting via API key, follow the setup guide shown below the form fields. It tells you exactly where to find your credentials in the external service, what permissions to grant, and what format to use. ## Multi-Instance Connectors ';this.style.cursor='default'"> Connect Multiple Accounts of the Same App Your organization can connect multiple instances of the same connector type. For example, you might run two Google Workspace accounts — one for the main company and one for a separate team — or two Zendesk accounts (production and sandbox), or separate accounts for different product lines. You can connect both and let your agents use either one. ### How It Works - Each connector instance has a unique name within your organization (e.g., "Production Zendesk" and "Sandbox Zendesk", or "Google Main Company" and "Google Europe Team"). - When you assign multiple instances of the same connector type to an agent, Macha automatically disambiguates the tool names. A tool like `zendesk_get_ticket` becomes `zendesk_get_ticket__production` and `zendesk_get_ticket__sandbox`. Similarly, a single `read_google_doc` becomes two distinct tools — one per connected Google account. - Tool descriptions are also prepended with the account name (e.g., "[Account: Production]") so the AI model knows which instance to use. This disambiguation is automatic — you do not need to configure anything beyond giving each connector instance a distinct name. ### Name Your Connectors Clearly The clearer your connector names are, the more reliably your agent picks the right one. Avoid generic names like "Google Workspace 1" and "Google Workspace 2" — instead use meaningful names that describe what the account is for ("Google Main Company", "Google Europe Team", "Production Zendesk", "Sandbox Zendesk"). You can also reference these names directly in your agent's instructions. For example: "Always use *Google Main Company* for internal documents and *Google Europe Team* for anything related to that team. If unsure, search both." ## Built-In Connectors Some connectors are always available without any setup or authentication. ### File Tools The File Tools connector is built into Macha and requires no connection. It gives agents the ability to generate files on demand: - **Create Spreadsheet** — Generates an Excel (.xlsx) file. - **Create CSV** — Generates a CSV file. - **Create PDF** — Generates a PDF document. - **Create Document** — Generates a Word (.docx) document. Each tool creates the file and returns a download URL. You will see the File Tools connector on your Connectors page with a purple "Installed" badge instead of a "Connect" button. ## Connector Setup Guides Every connector in Macha includes a built-in setup guide visible in the connection modal. Here is a brief overview of what each connector requires: - **Zendesk** — OAuth authorization. Click "Connect" and authorize through your Zendesk admin account. - **Freshdesk** — API key (found in your Freshdesk profile under "Your API Key") and your subdomain (e.g., `yourcompany` from `yourcompany.freshdesk.com`). - **Gorgias** — API key (found under Settings -> REST API), the email you log in with, and your subdomain (e.g., `yourcompany` from `yourcompany.gorgias.com`). - **Front** — API token from Settings -> Developers -> API tokens. Tokens are JWTs that start with `eyJ`. No subdomain needed — Front uses a single global endpoint. - **Shopify** — OAuth authorization via the Macha AI app. You will need to enter your store domain first (e.g., `your-store.myshopify.com`), then authorize through Shopify. - **Slack** — OAuth authorization. Click "Connect" and authorize through your Slack workspace. - **Stripe** — Restricted API key. Create one in your Stripe Dashboard under Developers > API Keys with read-only permissions for the resources you need. - **Google Workspace** — OAuth authorization. Click "Connect" and authorize with your Google account. Grant access to the services you want (Docs, Sheets, Drive, Calendar). - **Notion** — OAuth authorization. Click "Connect" and select which Notion pages and databases to share with Macha. - **Airtable** — Personal access token. Create one at airtable.com/account with access to the bases you need. Tip After connecting a connector, assign it to an agent and select the specific tools you want that agent to use. A connector on its own does not do anything until it is wired to an agent. --- # Adding Knowledge and Data Sources Source: https://www.getmacha.com/docs/data-sources > Give your agents knowledge by uploading documents, crawling websites, or connecting live data from Google Docs, Notion, and Confluence. ';this.style.cursor='default'"> What Are Knowledge Sources (Explained in 50 Seconds) ## What Are Data Sources Data sources give your agents access to knowledge — documents, files, websites, and live data from connected services. While connectors let agents take actions in external tools, data sources let agents reference information to provide better, more accurate responses. For example, you might upload your company's return policy as a PDF, connect a Google Doc with your product FAQ, or index your website's help pages. When a customer asks a question, the agent can look up the answer in these sources rather than relying solely on its training data. On the Sources page, the top of the screen has three add options — **Upload documents** (PDFs, Word docs, spreadsheets, CSVs), **Add a website** (crawl and index an entire site), and **Add a web page** (a single URL). Below that is your source list with everything you've connected so far. ### Source Status: Live vs Ready Each source displays a status badge so you know what kind of data it is: - **Live** — The source pulls content in real time directly from a connected app (e.g., Google Workspace, Confluence, Notion). The agent always reads the current version. - **Ready** — The source has been indexed and is good to go (e.g., uploaded files, Zendesk Help Center, indexed websites). The agent searches the indexed content. ## Knowledge Source vs Tool — Which One Should Your Agent Use? ';this.style.cursor='default'"> Knowledge Source vs Tool — Which Should Your Agent Use? One of the most important decisions when setting up an agent is choosing the right kind of source. It comes down to one question: **is your content static or does it change?** - **Static content** (rarely changes) — policy documents, FAQs, product manuals, your Zendesk Help Center articles. Add these as a **static source** — upload the file directly or connect your website. Macha indexes it once and your agent searches through it. - **Dynamic content** (updates regularly) — pricing sheets, escalation matrices, on-call rosters, anything that changes weekly. Add a **live connector source** like Google Workspace, Notion, or Confluence. Macha automatically attaches the right read tool (e.g., `google_read_doc`, `google_read_sheet`), and the agent reads the live version every time — not a snapshot from last week. Both approaches are data sources. The difference is whether the agent gets a frozen-in-time copy or a live read. Pick based on how often the underlying content changes. ## File Uploads ';this.style.cursor='default'"> How to Upload Documents to Your Knowledge Base If you have static content you want your agent to reference — internal documents, policy files, support guides — upload them directly into Macha. Limits: up to **10 files at a time**, each up to **20 MB**. Once uploaded, Macha starts indexing immediately. It reads the content, breaks it into chunks, and makes it searchable. Depending on the file size, indexing usually takes anywhere from a few seconds to a couple of minutes. When it's finished, the source appears under your upload list and the agent can start searching it. Tip If you update an original document, Macha won't auto-refresh — you need to delete the old version and re-upload. For content that changes frequently, use a live connector source (Google Workspace, Notion, Confluence) instead of a static upload. ### Supported Formats - **PDF** — Product manuals, policy documents, contracts, reports. - **CSV** — Customer lists, product catalogs, pricing tables. - **XLSX** — Spreadsheets with structured data. - **DOCX** — Word documents with procedures, guides, or reference material. - **TXT** — Plain text files. ### How Files Are Processed Macha processes uploaded files differently depending on their size and type: #### Small Spreadsheets (2,000 rows or fewer) CSV and XLSX files with 2,000 rows or fewer are **injected directly** into the agent's context. This means the entire file content is available to the agent at all times — no searching required. The agent can reference any row or column immediately. This is the fastest and most reliable way for an agent to work with structured data. #### Large Files Files that exceed the injection threshold — large spreadsheets (more than 2,000 rows), PDFs, DOCX files, and other documents — are processed differently. Macha **chunks** the content into smaller segments and creates **embeddings** (vector representations) for semantic search. The agent then searches this knowledge base using the `search_knowledge` tool and retrieves specific document sections with the `get_document` tool. For spreadsheets, chunking is row-aware: each chunk contains approximately 75 rows with the header row preserved, so the agent always knows what each column represents. Tip If your spreadsheet has fewer than 2,000 rows, it will be injected directly and the agent will always have full access to the data. For larger datasets, consider splitting the file into smaller, focused spreadsheets if possible. ## Website Sources ';this.style.cursor='default'"> How to Index a Website or Webpage for Your Agent For website content, Macha gives you two options — pick based on how much of the site you need: ### Add Website (Crawl Everything) **Add Website** crawls the entire site. Macha follows links it finds, discovers every page, and indexes all of them. Use this when you want your agent to access an entire documentation site, an entire knowledge base, or all the pages on your website. There's a **system limit of 200 pages** — Macha will only add the first 200 pages it finds. As Macha discovers pages, you'll see them listed in real time. Depending on the site, indexing usually completes in a few minutes. When done, the source shows a **Ready** status. ### Add Web Page (Single URL) **Add Web Page** is for when you just need one specific page — a single blog post, a specific FAQ, one product page. No crawling. It just adds that one URL, indexed and ready. Tip Macha doesn't monitor your website for changes automatically. If you update content on the site, hit the **Resync** button on the source to pull the latest version. A resync also cleans out pages that have been removed. Website sources are processed the same way as large files — the content is chunked, embedded, and made available through the `search_knowledge` and `get_document` tools. ## Connector Sources In addition to static file uploads, you can connect live data from Google Docs and Notion. These sources stay up to date because the agent reads the content directly from the service every time it needs it, rather than working from a static copy. ### Google Docs When you add Google Docs as a data source, the agent reads documents live using the `google_read_doc` tool. Every time the agent references a document, it fetches the current version — so if someone updates the Google Doc, the agent immediately sees the changes. ### Notion Pages Notion works the same way. The agent reads pages live using the `notion_get_page` tool, always getting the most current content. ### Auto-Linking Tools and Connectors When you add a connector-based source (Google or Notion) to an agent's data sources, Macha **automatically adds the required read tools and connector instance** to the agent. You do not need to manually assign the Google or Notion connector — it happens for you. For Google sources, Macha auto-adds: `google_read_doc`, `google_read_sheet`, and `google_list_drive_files`. For Notion sources, Macha auto-adds: `notion_search` and `notion_get_page`. These auto-added tools are locked — you cannot remove them while the data source is linked. If you want to remove the tools, remove the data source first. Tip Connector sources are ideal for documents that change frequently. Instead of re-uploading files every time they are updated, let the agent read the live version from Google Docs or Notion. ## Scope Filtering When you add a data source to an agent, you can control which documents the agent has access to. Each source row shows an inline toggle with two options: - **All documents** — The agent can access every document in the source. As new documents are added to the source, the agent automatically gains access to them. - **Selected** — The agent can only access the specific documents you choose. Clicking "Selected" automatically expands the document picker so you can choose which ones to include. Scope filtering works across all source types — file uploads, websites, Google Docs, and Notion pages. ## How Agents Access Knowledge ';this.style.cursor='default'"> Adding Knowledge Sources — Full Walkthrough Understanding how your agent reads data sources helps you configure them effectively. There are three modes of access: ### Injected Documents Small CSV and XLSX files (2,000 rows or fewer) are injected directly into the agent's system prompt. The agent always has this data available — no tool calls needed. This is the fastest and most reliable access mode, but it uses context window space. ### Searchable Documents Large files, PDFs, DOCX files, and website content are stored as searchable knowledge. When the agent needs information from these sources, it: - Calls the `search_knowledge` tool with a query to find relevant document chunks. - Reviews the search results to identify the most relevant sections. - Calls the `get_document` tool to retrieve the full content of specific chunks. This two-step process lets agents work with very large knowledge bases efficiently — they only load the parts they need. ### Live Connector Documents Google Docs and Notion pages are read live using their respective tools (`google_read_doc` or `notion_get_page`). The agent calls the tool with the document ID and gets back the current content. This ensures the agent always works with the latest version of the document. Tip You can mix all three types in a single agent. For example, inject a small product pricing spreadsheet, add a large policy PDF as searchable knowledge, and connect a live Google Doc with your latest FAQ — all on the same agent. --- # Automating Agents with Triggers Source: https://www.getmacha.com/docs/triggers > Run agents automatically in response to events — new tickets, Slack messages, custom webhooks, or recurring schedules. ';this.style.cursor='default'"> What is a Trigger? (Explained in 30 Seconds) ## What are triggers? Triggers let your agents run automatically in response to external events. Instead of manually starting a conversation, a trigger fires when something happens — a new support ticket, a Slack mention, a custom webhook from any system — and your agent handles it on its own. This is how you move from reactive chat to proactive automation. An agent with a trigger can triage tickets the moment they arrive, respond to Slack mentions instantly, or run a daily summary without anyone lifting a finger. ## Event triggers Event triggers fire when something happens in a connected tool. Each connector supports a specific set of events. ### Zendesk events - **ticket.created** — a new ticket is submitted - **ticket.comment_added** — a comment is added to an existing ticket - **ticket.status_changed** — a ticket's status changes (e.g., open to pending) - **ticket.priority_changed** — a ticket's priority is updated - **ticket.assigned** — a ticket is assigned to an agent or group - **ticket.closed** — a ticket is closed - **messaging.customer_message** — a customer sends a message via Zendesk Messaging For Zendesk, most event triggers are set up automatically. When you create a trigger, Macha creates a corresponding webhook in your Zendesk account. You just need to create a Zendesk trigger rule that points to it. When you delete the trigger in Macha, the webhook is cleaned up automatically. ### Freshdesk events - **ticket.created** — a new ticket is created - **ticket.updated** — a ticket is updated (status, priority, assignment, etc.) Freshdesk triggers use the custom webhook pattern. After creating a trigger in Macha, you'll get a webhook URL and instructions for setting up an automation rule in Freshdesk that sends data to that URL. ### Slack events - **app_mention** — someone mentions your Macha app in a Slack channel - **direct_message** — someone sends a direct message to your Macha app ';this.style.cursor='default'"> Using Custom Triggers for AI Agents ## Custom webhooks Custom webhooks let you trigger an agent from any external service, even ones Macha doesn't have a dedicated connector for. When you create a custom webhook trigger, Macha generates a unique URL and a signing secret. You then configure your external service to send HTTP requests to that URL. The signing secret lets you verify that incoming requests are authentic. The payload from the webhook is passed to your agent as context, so it knows what happened and can act on it. This is useful for connecting services like GitHub, Linear, HubSpot, or any internal tool that supports outgoing webhooks. Ticket-aware conversation titles For Zendesk and Freshdesk custom webhooks, if your payload includes `ticket_id` (and ideally `ticket_subject` — the setup modal recommends both), Macha uses those values in the conversation title shown in agent history. So instead of every autonomous run showing up as "Custom Webhook", you'll see "1234 — Refund request" or similar — same shape as the named ticket events. If the payload doesn't include them, the title falls back to "Custom Webhook" as before. ## Macha custom triggers Macha custom triggers are a universal webhook type that doesn't require any connector. They appear under the "Macha" group in the triggers modal. Like custom webhooks, they generate a URL you can call from anywhere — but they're not tied to a specific integration. Use these when you want to trigger an agent from a script, a CI/CD pipeline, or any arbitrary HTTP request. ## Scheduled triggers ';this.style.cursor='default'"> How to Schedule Your AI Agents Scheduled triggers run your agent automatically on a recurring schedule. Instead of waiting for an external event, the agent runs at fixed intervals — useful for daily reports, periodic data checks, or routine maintenance tasks. ### How scheduling works - Set an interval in hours (minimum 1 hour between runs) - Choose a start time for the first run - Macha's scheduler checks every 60 seconds for triggers that are due to run ### Guardrails and limits - **Minimum interval:** 1 hour — you cannot schedule an agent to run more frequently - **Daily cap:** 24 runs per trigger per day — prevents runaway schedules - **Concurrency cap:** 3 simultaneous scheduled runs per organization - **Auto-disable:** After 5 consecutive errors, the trigger is automatically disabled and you receive an email notification - **Stale lock cleanup:** If a run takes longer than 30 minutes, the lock is released so the next run can proceed - **Credit check:** Your organization must have sufficient credits before each scheduled run ### Plan limits for scheduled triggers - **Trial / Starter:** Not available - **Professional:** Up to 3 scheduled triggers - **Enterprise:** Up to 20 scheduled triggers ## Debounce settings Some events fire in rapid succession — for example, a flurry of customer messages in a Zendesk Messaging conversation, or several ticket updates landing back-to-back. Debounce settings let you batch these rapid events so your agent processes them as a single context instead of running once per event. ### How debounce works Configure a debounce window (in seconds) per trigger. When the first event arrives, Macha starts a timer. If more events come in during that window for *the same entity* (same ticket, same Slack channel, etc.), the timer resets and the new events are added to the batch. Once the window finally closes without a new event, the agent runs once with the combined context. This is a "trailing edge" debounce — the agent fires *after* the conversation goes quiet, not after a fixed delay. So if a customer keeps typing every 10 seconds with a 15-second window, the agent waits for them to stop before responding. ### Which triggers can use debounce Debounce is available on every **event-driven** trigger that fires per entity — every Zendesk and Freshdesk ticket event, every Slack mention or DM, every messaging event. Each of those triggers shows a small **Debounce** chip on its card in the agent's Triggers section; click the chip to open the popover and set the delay in seconds. - Default for new event-driven triggers: **0 seconds (off)**. The agent fires on every event individually unless you opt in. - **Zendesk messaging tickets** default to **15 seconds**. Customers type in bursts; this gives them time to finish before the agent responds. - **Slack direct messages** default to **10 seconds** for the same reason. - **Scheduled (cron) triggers** and **universal Macha webhooks / custom-webhook triggers without a clear per-entity grouping field** don't show the debounce chip — debouncing a clock-based or generic-payload trigger doesn't make sense. ### Safeguards Two automatic safeguards protect against runaway event streams that would otherwise hold the agent forever: - A bucket is force-fired once it accumulates **25 events**, even if more keep arriving. Bounds memory and ensures the agent eventually runs on busy entities. - A bucket is force-fired after a total wait of **10× the debounce window** (capped at 2 minutes), so events that arrive in a steady stream don't postpone the agent indefinitely. Tip For messaging triggers, the default 15-second window works well. For ticket events (ticket.created, comment_added, status_changed, etc.), start with 0 (off). Turn it on only if you're getting a noisy stream of updates on the same ticket and you want them batched. ## Setting up a trigger ';this.style.cursor='default'"> How to Set Up a Trigger on Your AI Agent - Navigate to the agent you want to automate - Open the **Triggers** tab - Click **Add trigger** - Select the connector and event type (or choose a Macha trigger for custom webhooks and schedules) - Configure any conditions or debounce settings - Save the trigger For connector-based triggers, follow the setup instructions shown in the modal. For Zendesk, the webhook is created automatically. For Freshdesk and custom webhooks, you'll need to configure the external service to send requests to the provided URL. To verify the trigger is firing, take an action that should trigger it (e.g., change a ticket's status, send a Slack mention) and then go to the agent's **History** tab. You should see the run appear there with all the steps the agent took. Tip Make sure your agent's instructions cover what it should do when triggered automatically. The agent won't have a human in the loop, so its instructions need to be thorough enough to handle the event independently. ## Pausing an agent without breaking your Zendesk setup When you toggle an agent **off**, Macha doesn't delete its Zendesk webhooks or Zendesk Triggers — it sets their status to *inactive* on Zendesk's side. When you turn the agent back on, the same webhook + Zendesk Trigger are re-activated, with the same resource IDs. That matters most for **custom webhook** triggers. If you've built a Zendesk Trigger in your own Admin Center that calls Macha's webhook, that Zendesk Trigger references our webhook by its resource ID. If we deleted and recreated the webhook every toggle cycle (the old behavior), your Zendesk Trigger would silently break — pointing at a webhook that no longer exists. The soft-toggle preserves the resource ID so your Zendesk Trigger config keeps working untouched across pause/resume cycles. Deleting a trigger from Macha (rather than just toggling it off) *does* delete the underlying Zendesk webhook + Zendesk Trigger fully — that's an explicit action, and the assumption is you really meant to clean up. ## Trigger best practices ';this.style.cursor='default'"> Trigger Best Practices for AI Agents ### Avoid overfiring triggers Pick the most specific trigger that matches your workflow. A broad trigger like "every customer message on a ticket" fires on every new comment — and consumes a credit each time. If your agent only needs to act on certain conditions, use a more targeted Zendesk trigger or a custom webhook with conditions baked in. ### Name your triggers clearly You can have multiple triggers feeding the same agent. Name each one so it's obvious what tickets it sends through and which agent is on the receiving end. A name like *"New high-priority tickets → Bug Triage Agent"* reads better than *"Trigger 3"* when you come back six weeks later. This also makes it easier to debug when something fires unexpectedly. ### Custom webhooks: keep things organized externally When you add a custom webhook trigger on Zendesk, Macha automatically creates the webhook on your Zendesk instance — you just search for it and select it inside Zendesk's trigger setup. For custom webhooks from external (non-Zendesk) systems, Macha generates a webhook URL — make sure you keep clear notes on which event maps to which trigger so future-you isn't guessing. ### Always test before going live Simulate the trigger event manually in chat first. Make sure the agent does exactly what you expect before turning the trigger on for real tickets. Once it's running autonomously, mistakes execute immediately with no confirmation step. --- # Building Custom API Tools Source: https://www.getmacha.com/docs/custom-tools > Connect any HTTP API as a tool for your agents. Build tools manually or let the AI Tool Builder configure them from a conversation. ';this.style.cursor='default'"> How to Add Custom API Tools ## What are custom tools? Custom tools let you give your agents the ability to call any HTTP API endpoint. If your agent needs to look up data in an internal system, create a record in a CRM, or call a third-party API that Macha doesn't have a built-in connector for, you can define a custom tool for it. Each custom tool is an organization-level resource. You create it once, then assign it to any agents that need it. When an agent uses a custom tool, it makes an HTTP request to the endpoint you configured, passes the right parameters, and gets back the response. ## Creating a tool manually To create a custom tool, go to the **Custom Tools** page and click **New tool**. You'll configure the following: ### Basic information - **Label:** A human-readable name for the tool (e.g., "List Postmark Templates"). This should include the service name and resource to be clear about what it does. - **Description:** Tell the AI what this tool does and when to use it. A good description helps the agent decide when to call the tool. - **Type:** Choose **Read** for tools that only fetch data, or **Write** for tools that create, update, or delete data. Write tools require user confirmation before execution in chat. ### Request configuration - **Method:** GET, POST, PUT, PATCH, or DELETE - **URL:** The endpoint URL. Use `{{param}}` placeholders for dynamic values (e.g., `https://api.example.com/users/{{userId}}`) ### Authentication Choose how the tool authenticates with the API: - **None:** No authentication required - **API Key:** Sends a key in a custom header (e.g., `X-API-Key: your-key`) - **Bearer Token:** Sends a token in the Authorization header (`Authorization: Bearer your-token`) - **Basic Auth:** Sends a username and password as HTTP Basic Authentication Credentials are encrypted at rest and never exposed to the AI model. ### Parameters Define the parameters the AI should provide when calling the tool. Each parameter has: - **Name:** The parameter identifier (used in URL and body placeholders) - **Type:** String, number, boolean, etc. - **Description:** Helps the AI understand what value to provide - **Required:** Whether the parameter must be provided ### Body template For POST, PUT, and PATCH requests, you can define a JSON body template with `{{param}}` placeholders that get replaced with the AI's parameter values: ``` { "name": "{{customerName}}", "email": "{{customerEmail}}", "priority": "{{priority}}" } ``` ### Response mapping Use dot-path notation to extract specific data from the API response. For example, if the API returns: ``` { "data": { "results": [...] } } ``` Setting the response mapping to `data.results` means the agent only sees the results array, keeping things clean and focused. ## Tool groups Organize related tools under a group with a shared name, emoji, and color. For example, you might group all your Postmark tools under a "Postmark" group with a mail emoji. Tool groups also appear as custom connectors on the Connectors page, giving your team a visual overview of all connected services — both built-in and custom. You can upload a custom square icon for any tool group by clicking the group icon on the Custom Tools page. ## Testing tools Before assigning a tool to an agent, test it to make sure it works. Open the tool's edit modal and use the **Test** button. Enter sample values for each parameter, run the test, and verify the response. This helps catch authentication issues, incorrect URLs, or malformed body templates before they affect your agents. ';this.style.cursor='default'"> Build Custom Tools with the AI Tool Builder ## AI Tool Builder If you'd rather not configure tools manually, the AI Tool Builder can do it for you. This feature is currently available in **Macha Experiment Labs**. ### How it works - Click **Build with AI** on the Custom Tools page (available in both the header and the empty state) - Describe the API you want to connect to and paste your credentials - The AI discovers available endpoints and tests your credentials - It proposes a set of tools with proper authentication, parameters, and descriptions - Review and confirm — the tools are created and grouped automatically The Tool Builder uses a conversational interface, so you can ask it to adjust tools, add more endpoints, or change groupings as you go. Tip The AI Tool Builder works best when you provide the API documentation URL or paste in a few example endpoints. The more context you give it, the better the tools it creates. ## Assigning tools to agents Once a tool is created, assign it to agents via the agent's **Tools** tab. Custom tools appear alongside built-in connector tools. An agent can only use tools that have been explicitly assigned to it. ## Plan limits Custom tool limits are based on assignment slots — assigning the same tool to 3 different agents counts as 3 slots. - **Trial / Starter:** Not available - **Professional:** 5 tool assignment slots - **Enterprise:** 20 tool assignment slots --- # Studies — AI Analysis Across Your Records Source: https://www.getmacha.com/docs/studies > Run an AI analysis across thousands of records — Zendesk tickets, support history, and more. Define the columns you want, get a structured results grid, export to CSV, or push back as a knowledge source. ## What Studies are Studies — also called **AI Analysis** in the sidebar — let you run an AI analysis across a list of records and get structured results back. Instead of opening one ticket at a time and asking an agent for an answer, you point a Study at a set of records, define the columns you want filled in, and Macha analyses every record in parallel and writes the answers back into the grid. The end result is a spreadsheet-shaped grid of insights: one row per record, one column per field you defined. You can browse it, filter it, export it to CSV, or push it back into Macha as a knowledge source for your agents to search. Studies are the right tool when you have a question that needs an answer across *many* records — auditing the last 5,000 tickets for refund mentions, classifying support volume by root cause, finding every ticket where the customer raised a billing concern. Doing that by hand is hours of work; doing it through chat would mean opening a conversation per record. A Study runs the same extraction over every record at once. ## How a Study is shaped Every Study has four parts: - **An input source** — where the records come from. Today that's Zendesk tickets matched by a search query and an optional date range. More record sources are coming. - **Input fields** — the parts of each record you want the AI to see. Picking only what's necessary keeps the prompt small and costs predictable. - **A schema** — the columns you want filled in. Each column has a type (boolean, single select, multi select, number, short text, long text), a label, and optional guidance for the AI on how to fill it. - **A model** — which LLM does the extraction. The model you pick sets the credit cost per record. The model reads the input fields you selected, follows your instructions and per-column guidance, and returns a value for each column. One record in, one row out. ## Creating a Study Studies live in the sidebar under their own section. To create one: - Open the **Studies** page and click **New Study**. - Give it a name and an optional description. - Pick the input source — for example, *Zendesk Tickets*. - If the source needs a connector, pick the connected instance. Multi-instance accounts (e.g. two Zendesk accounts) each show up separately. - Configure the input — add a search query and/or a date range to scope the records you want. - Pick the input fields you want the AI to read. - Define the schema — add a column for each piece of information you want extracted. - Choose a model and save. You don't have to run the Study right away. It's a saved configuration you can re-run any time — useful for monthly audits or recurring classification. ## The input source: Zendesk Tickets The first input source available is Zendesk Tickets. It pulls tickets that match a Zendesk search query, optionally bounded by a date range. ### Configuring the query - **Search query** — any Zendesk search expression (the same syntax you'd use in the Zendesk search bar). Examples: `status:open priority:urgent`, `tags:refund`, `brand_id:1234 form:billing`. Leave it empty to match all tickets in the date range. - **From / To** — restrict to tickets created in a date range. Useful for "last quarter" or "since the new policy went live" audits. Tip The estimate Macha shows before you run a Study is calculated from the exact same query that the run will use — so the number you see is what you'll process. If it's higher than you expected, tighten the query before running. ### Ticket fields you can include You choose which fields the AI sees for each ticket. The more you include, the more context the model has — but also the larger the prompt and the slower the run. Available fields: - **Subject** — the ticket subject line - **Description** — the customer's first message - **Status, Priority, Type, Tags** — ticket metadata - **Created at, Updated at** — timestamps - **Requester ID, Assignee ID, Group ID** — identifiers - **Custom fields** — every populated custom field with its human-readable label and resolved value. Flagged as *expensive* because it requires fetching the field schema. - **Full comment thread** — the complete public + internal conversation. Flagged as *expensive* because it adds an extra API call per ticket and significantly grows the prompt. For most extractions, *Subject* and *Description* are enough. Add the comment thread only when the answer genuinely needs the full conversation. ## Defining the schema The schema is the heart of a Study. Each entry is one column in the final results grid. You can have as many columns as you need. ### Column types Each column has an answer type that defines the shape of the value the model returns. The Study editor shows a short hint under the Answer-type selector explaining what each type returns — useful when you're picking the right shape for the question. - **Boolean** — yes/no. Best for "is this a refund request?" or "did the customer mention a competitor?" - **Single select** — one value from a list you define. Best for categorical classification: *billing / shipping / product / other*. - **Multi select** — zero or more values from a list. Best for tags: *which issues are mentioned*. - **Number** — a numeric value. Best for counts, scores, or amounts the model can read from the record. - **Short text** — a brief free-text answer. Best for things like "what is the customer's main concern in one sentence?" - **Long text** — multi-line free text. Best for summaries, suggested replies, or extracted quotes. For **single select** and **multi select**, you add the allowed values as tags — type each option and hit Enter, or paste a comma-separated list and Macha splits it for you. Click the × on a tag to remove it. The model is constrained to pick from this fixed set, so spelling matters: pick the labels you want to see in the final grid. ### Writing good guidance Each column has an optional *guidance* field. This is where you teach the model what you actually want. The guidance is included in the extraction prompt for that column, so be specific: - For a single-select column "Root cause", spell out what each option means and how to disambiguate edge cases. - For a boolean "Refund requested", clarify the difference between asking about a refund and actually requesting one. - For a short-text "Customer's main concern", say how long it should be ("one sentence") and what voice it should use ("describe the issue, not the customer's emotion"). Treat guidance like instructions you'd give a new analyst. The clearer the rules, the more consistent the output. Tip When the answers come back inconsistent, the fix is almost always in the guidance, not the model. Tighten the column definition, add examples in the guidance, and run a test on a small batch before re-running the full set. ## Choosing a model Studies use the same model lineup as agent chat. The model you pick drives the credit cost per record — which compounds across the whole run, so it matters a lot more here than in a one-off chat. The Study editor shows a *credits / record* badge next to the Model selector and again at the top of every run page, so the cost is visible at every step. A few rules of thumb: - For simple classification, boolean extraction, or short field lookups, a mini model is plenty. - For nuanced multi-column extractions, long-form summaries, or judgement calls (e.g. "did this agent handle the ticket well?"), step up to a more capable model. - When in doubt, run a *test* on 10–20 records first with the model you're considering. Look at the output. If it's good enough, keep the model. If not, step up — the cost difference at small scale is tiny, and you'd rather know now than after burning credits on 5,000 records. ## Estimate and the pre-run gate Before any run starts, Macha shows you a **Review** screen with: - The number of records the input is going to match - The credit cost per record (based on the model) - The total estimated credits for the run - Your remaining credits You can't accidentally run a 10,000-ticket study without seeing the cost first. If the estimate is uncomfortable, go back, narrow the query, or switch to a cheaper model. Clicking **Run study** opens a second confirmation modal that re-shows the record count, the estimated credits, and the model — you have to explicitly confirm before any work actually starts. Test runs ("Test on 3") skip this second step since they're small by definition. If you're short on credits at this stage, you can **buy a top-up pack** directly from the Review screen — top-up credits never expire and they're consumed automatically after your monthly allowance runs out. ## Test runs Before committing to a full run, do a test. A test run takes a small sample (typically 10–50 records) and runs the same extraction on it. Use it to: - Sanity-check that the schema produces the answers you actually want. - Tune the per-column guidance. - Make sure the model is capable enough for the task before scaling up. Test runs are marked as previews in the UI so they don't clutter your real history. They still cost credits (you're paying for real model calls), but only for the sample size. ## Running, progress, and cancelling When you start a real run, Macha kicks off a background worker that streams records from the source and processes them with bounded concurrency — multiple records run in parallel, but never so many that we'd overwhelm the source API or your model quota. The run page shows progress live: how many records processed, how many succeeded, how many errored, and how many credits have been spent so far. You can **cancel** a run at any time. Cancellation is graceful — the worker finishes the records it has in flight, then stops. You only pay for what was actually processed; nothing is charged for records that never ran. ### How a run stops A run can finish in one of several ways: - **Completed** — every record in the input was processed. - **Cancelled** — you stopped the run from the UI. - **Out of credits** — your balance hit zero mid-run. The worker stops gracefully and reports the stop reason on the run. - **Cap reached** — the run hit the platform's hard ceiling. Studies are capped at **20,000 records per run**. To go bigger, split into multiple runs with date-range filters. - **Failed** — a fatal error (e.g. the connector disconnected mid-run). Whatever was processed before the failure is preserved. ## Reviewing results When a run completes, its results page shows a table — one row per record, one column per schema field, plus a status column. Each row links back to the source record (e.g. the Zendesk ticket URL) so you can verify the extraction against the original. The results table is Excel-shaped: click any column header to sort (ascending → descending → off), and use the **search box** in the toolbar to filter loaded rows by free text across every column. Click a row to open the full record in a side drawer; J/K keys move to the next/previous row, Esc closes. Useful things you can do from the results page: - **Sort and search** — click any header to sort, type in the search box to filter the loaded rows. - **Group by a field** — pick a column and Macha computes bucket counts you can click to filter the table. - **Open a row** — see the full record in the side drawer. - **View report** — open the run's [analytics view](#the-report-view) (see below). - **Use as knowledge source** — push the results back into Macha as searchable knowledge (see further below). - **Export to CSV** — download the whole result set as a spreadsheet. - **Push to a Knowledge Source** — see below. ### Frozen snapshots Every run keeps a copy of the input config, schema, and model it ran with — frozen at the moment the run started. Editing the parent Study later doesn't rewrite history. Past runs always reflect the configuration they ran under, so audit trails stay clean. ## The Report view The results table is great for reading individual rows. The **Report view** is for reading the run as a whole — how many tickets fell into each category, what the distribution looks like, where the outliers are. From a completed run, click **View report** in the toolbar to open it. The report has three layers: ### Top-of-page stat callouts Four big-number cards summarise the run at a glance: - **Records processed** — the total record count. - **Credits spent** — with the average credits per record shown beneath. - **Errors** — turns red if anything failed. - **Reportable columns** — how many of your schema columns produce charts. Number columns are also called out separately because they get histograms. ### Per-column aggregation cards Every column whose answer type is **Yes/No**, **Single choice**, **Multiple choice**, or **Number** gets its own card. Short-text and long-text columns don't get a card — they're too free-form to chart meaningfully. - **Yes/No, Single choice, Multiple choice** render as horizontal bar charts. Each bar shows the bucket label, the count, and the percentage of the answered set. Click any bar to drill into the rows that fall into that bucket. - **Number columns** render as histograms. The card shows summary stats at the top — min, mean, median, max — and a bin chart below. If a number column has 10 or fewer unique values, each value becomes its own bin (good for integer counts like "comments per ticket"). With more unique values, Macha bins automatically into ~10 equal-width ranges. ### Drilldown modal Clicking a bar opens a modal listing the records that match that bucket. The modal uses the same results table you see on the main run page — same columns, same record drawer when you click a row — so navigating from a chart into the underlying rows feels continuous. Use the link at the bottom of the modal to jump to the full results table if you need to see every match. Coming soon The report page also includes an **Ask Sidekick** bar at the top, currently shown as a "Coming soon" preview. Once Study-scoped query tools land, you'll be able to ask the Sidekick questions about a specific run ("how many tickets mention billing this month?", "what's the most common root cause for tickets that got escalated?") and it'll answer using the run's data directly. The bar is intentionally disabled until then so it doesn't return misleading answers. ### Plan availability The Report view is a **Professional and Enterprise feature**. Trial and Starter plans see an upgrade card with a link to billing instead of the dashboard. The underlying Study itself can run on any plan that has Studies enabled, but the analytics view is gated. ## Pushing results into a Knowledge Source Studies don't just produce a static spreadsheet — they can feed your agents. From a completed run's results page, you can export the results as a new **knowledge source**. Each row becomes a document, composed from the columns you choose, and indexed via the same embeddings pipeline that powers the rest of Macha's knowledge. This is how Studies become operational instead of one-off analyses. Run a Study to extract structured insights from your last 5,000 tickets, push the results to a knowledge source, and now your support agent can search those insights when handling new tickets. You choose which fields end up in each document and which one is used as the title. From there it behaves like any other knowledge source — assign it to an agent, set scope, and the agent's *search_knowledge* and *get_document* tools can pull from it. ## Credits and pricing Studies use the same credit system as the rest of Macha. The cost per record is the credit cost of the model you picked — so a Study on a mini model costs less per record than the same Study on a top-tier model. - Credits are deducted **per successful record**, not up front. - Errored records don't cost anything. - Cancelled records (ones that never ran) don't cost anything. - Monthly plan credits are used first; once those are spent, top-up credits kick in automatically. Top-up credits never expire. - Enterprise plans bypass per-record credit checks. ## Plan availability - **Trial** — Studies are not available on trial. - **Starter** — not available; upgrade to Professional to use Studies. - **Professional** — full access. - **Enterprise** — full access, with credit checks bypassed. ## Best practices ### Start narrow, then widen The first time you build a schema, run it against a small date range or a tight query first. Look at the results. Iterate on the schema and guidance. Once you're happy, re-run against the full set. ### One question per column A column is meant to answer one question. If a column tries to do two things at once ("category and severity"), split it into two columns. Single-purpose columns are easier for the model to answer consistently and easier for you to filter on later. ### Use single-select over short-text when you can Single-select forces the model to pick from your taxonomy, which makes the column easy to group, sort, and chart. Short-text leaves it free-form, which is useful for genuine free-text answers but bad for anything you want to count. ### Don't pull comments unless you need them The full comment thread roughly doubles or triples the prompt size and adds an API call per ticket. If the answer is in the subject and description, leave comments off. ### Run smaller batches across longer windows If you want to study "the whole year" but it's 60,000 tickets, run four quarterly Studies instead of one giant one. You stay under the 20,000-record cap, you can review intermediate results, and you can iterate the schema between runs if something looks off. ### Push high-value runs to a knowledge source If a Study's results would help your agents (e.g. a classified backlog of past resolutions, or a clean list of known issues), don't just export to CSV. Push it to a knowledge source so your agents can search it during real conversations. Tip A Study is just a saved configuration — it costs nothing until you run it. Iterate on the schema freely; only test runs and real runs use credits. --- # Agent Evaluation — Evaluate How Your Agents Perform Source: https://www.getmacha.com/docs/agent-evaluation > Evaluate how your agents actually performed on past conversations. An AI judge runs a checklist over every chat, trigger run, and sub-agent handoff and gives you a percentage-followed score, per-conversation verdicts, and a one-line reason for each call. ## What Agent Evaluation is Agent Evaluation is a built-in way to evaluate how your agents are actually performing — not whether they ran, but whether they did the right thing. You set up a checklist once (or have Macha build it from the agent's own instructions), and an AI judge runs that checklist over every past conversation the agent has had: chat sessions, autonomous trigger runs, sub-agent handoffs, embedded chatbot conversations. You get back a clear view of how often the agent followed its instructions, where it slipped, and a short reason for each verdict so you can audit the call without re-reading the whole conversation. It lives under the **Agent Evaluation** tab on every agent's detail page, alongside Configuration, Chat, Analytics, and History. ## When to use it Three situations where Evaluation pays off: - **You've changed the agent's prompt** and want to know whether that change actually helped, hurt, or made no difference. Run the evaluation before and after — the percentage-followed score and per-conversation verdicts tell you immediately. - **You're onboarding a new sub-agent** into an existing routing flow and need to make sure the parent agent is handing off correctly. Evaluation checks the handoff messages, the routing decisions, and any forbidden actions in one pass. - **You're rolling out an agent to a new team or use case** and want a baseline quality score before going wider. Set the evaluation up once, run it weekly, and you have a quality trend line. Evaluation is *not* a live moderator — it evaluates past conversations, not in-flight ones. For real-time guardrails, use the agent's own instructions or a confirmation gate on write tools. ## How an Evaluation is shaped Every Evaluation has four parts: - **An agent** — the one whose past conversations you want to evaluate. The Evaluation tab lives on the agent's detail page, so the agent is preselected; you can't accidentally run an evaluation across the wrong one. - **A scope** — which slice of that agent's conversations to evaluate. The Scope step shows a **Filter conversations** card where you set a date range and (optionally) restrict to conversations the agent ran on a specific AI model — useful when you've migrated the agent from one model to another and want to compare. By default the last 7 days are evaluated. - **Which version of the AI's instructions to evaluate against** — agents have version history, so you choose: the instructions that were *live when each conversation actually ran* (the honest "did this agent do its job at the time?" view), *the AI instructions you have right now* (the "would today's prompt have passed?" view), or a *specific saved version* (for A/B comparisons between prompt iterations). - **A set of evaluation fields** — the checklist of fields the AI judge fills in for every conversation. Two fields are added for you automatically and can't be removed: *Instructions followed* (Yes / Partially / No) and a short *Why* explanation. You add the rest of the checks — for example "Right tool called", "Tone was empathetic", "Refund granted only when policy allowed". ## Creating an evaluation Open any agent and click the **Agent Evaluation** tab. The first time you open it you'll land on a zero state explaining the feature with a primary **Create your first evaluation** button. After that it shows a table of the evaluations you've already run. Click **New evaluation** (or **Create your first evaluation**) and you'll see a three-step wizard: - **Scope — "What should we evaluate?"** Pick the date range, optionally restrict by AI model used for the conversation, and choose which version of the AI's instructions the judge should evaluate against. - **Extract — "What should the AI judge evaluate?"** Define the checklist. Two paths here: **Build with AI** (recommended) — Macha reads this agent's instructions and proposes a set of evaluation fields automatically, one per rule it finds. You can edit, remove, or add to anything it proposes before running. - **Add manually** — define each field yourself: field name, field type (Yes/No, Single choice, Multiple choice, Short text, Long text, Number), and per-field guidance telling the judge how to decide. Use this when you have a very specific rubric in mind. - **Review** — see what's about to be evaluated, get a cost estimate (one credit per evaluated conversation, with the judge model you picked), then start the run. If your filters return zero conversations, the Test and Run buttons are disabled with a one-click link back to widen the Scope step. The wizard runs entirely inside the agent's tab — the URL stays on the agent page the whole time, so you don't lose context if you flip away mid-flow. ## The two mandatory fields Every Agent Evaluation includes two fields automatically: - **Instructions followed** — a Yes / Partially / No verdict on whether the agent followed its instructions on this conversation. Yes means every required step was carried out correctly; Partially means it mostly followed them but made a notable mistake (wrong tag, wrong template, skipped step); No means the agent took the wrong action or didn't follow the instructions at all. - **Why** — a one-to-two sentence explanation of the verdict, pointing to a specific moment in the conversation. This is the audit trail: a reviewer can scan the percentage score, click into a row, and immediately see *why* the AI judge reached that verdict without reading the whole conversation. Both fields show up as the first two columns on the results grid, and the verdict drives the green/amber/red colour coding used everywhere else (the compliance pill on the table, the donut chart on the report, the headline percentage on the evaluation list). ## Building the rest of the checklist with AI When you pick **Build with AI**, Macha: - Reads the current instructions for the agent you picked (or the specific version you pinned). - Identifies the rules and constraints in those instructions — what the agent must do, what it must not do, how it must classify things. - Proposes one evaluation field per rule. Each field comes with a field name, the right field type, options where relevant, and judge guidance. - Streams the proposals into the wizard one at a time, so you can watch it work. This usually produces a sensible 3–7 field checklist in under thirty seconds. You can edit any field before running, or delete it and add your own. ## Running an evaluation and seeing results Click **Start run** on the Review step. The run evaluates every conversation in your scope using the judge model you picked (defaults to GPT-5). You'll see a live "0 of N processed" counter and rows appearing in real time. Cancel mid-run if you want — credits already spent stay billed, but no new ones get charged. Once it's done you get three views: - **Results table** — one row per conversation, one column per evaluation field. The Instructions followed column shows the Yes/Partially/No pill (green/amber/red); the Why column has the short reasoning; the rest of your custom fields fill in next to them. Click a row to open the full record drawer with the original conversation and every field's value. - **Report view** — click **View report** from the results page. You get a summary card per evaluation field. The Instructions followed card is rendered as a three-segment donut chart (green/amber/red) with a centre percentage and a clickable legend. Other fields show as bar lists. - **Evaluation list** — back on the agent's tab, the list view shows one row per evaluation with the headline % followed pill, the judge model, the status, the count of evaluated conversations, and the timestamp. The headline percentage is computed as: *Yes count + ½ × Partially count*, divided by the total evaluated. Partial credit for partial work — so a run that's 60% Yes and 40% Partially scores 80% followed, not 60%. ## Re-running and iterating From the evaluations list you can hit **Run again** on any past evaluation. This reopens the same wizard with the original config loaded — you can keep the scope and just re-run against the latest conversations, or change the instructions-source from "as run" to "latest" to see whether your newer prompt would have done better on the same conversations. Common iteration loops: - **Weekly quality check** — same evaluation, same scope = last 7 days. Watch the trend. - **Before-and-after prompt change** — run once against the old version (pin "instructions in effect at the time"), edit the agent's prompt, run again against "latest" over the same date range, compare the two pills. - **Regression catch** — run on a fixed historical window after every prompt change to make sure you didn't break something the old prompt got right. ## What you don't have to set up A few things people often ask about — Agent Evaluation handles them automatically: - **The agent is already locked in**. You don't pick an agent on the Scope step — you're evaluating the agent you're already looking at. - **The Instructions field on Step 2 (Extract) is hidden**. The judge already evaluates against the agent's actual configured instructions via the *Instructions followed* field, so an extra "guidance for the judge" textbox would just be noise. - **Sub-agent runs are evaluated as part of the parent conversation**. The judge sees the full delegation tree — every tool call, every sub-agent reply — so a routing agent gets evaluated on whether its handoff was correct, not just on whether it called the right tool. - **The judge sees the full conversation transcript by default**. There's no "What the AI sees per record" picker on the Scope step for evaluations — instructions, transcript, tool calls, and metadata are all in scope, capped at the model's context budget. ## Plan availability Agent Evaluation is available on the **Professional** and **Enterprise** plans. Each evaluated conversation costs one credit at the judge model's per-record rate (e.g. 2 credits/record on GPT-5). You see the estimate before starting the run. --- # Chatting with Your AI Agents Source: https://www.getmacha.com/docs/chat > Chat with your AI agents, attach files, view tool calls in real time, confirm write operations, and manage conversations. ';this.style.cursor='default'"> Chatting with Your AI Agents ## Two modes: interactive chat vs autonomous ';this.style.cursor='default'"> Autonomous Mode vs Interactive Chat — What's the Difference? Every agent on Macha can run in two ways: - **Interactive chat** (this page) — you're in the loop the entire time. The agent reads your message, decides what to do, and pauses before any write action to ask for confirmation. You review what it wants to do and approve it, then it executes. This is the safest mode and the right place to test a new agent before automating it. - **Autonomous mode** — kicks in once you attach a trigger to the agent. As soon as the trigger fires, the agent reads the event, decides on the next steps, and executes write actions immediately. There's no human in the loop and no confirmation step. See [Triggers](/docs/triggers) for setup. The recommended flow is: configure your agent's instructions, tools, and data sources → test it in chat to see how it behaves → only then attach a trigger to make it autonomous. Testing in chat first is the easiest way to catch a wrong response, an incorrect public reply, or a bad ticket-field update before it goes live. ## Starting a conversation To chat with an agent, click on the agent from your dashboard or select it from the sidebar. You'll see a welcome screen with the agent's name, description, and suggested prompts to get you started. Type your message in the input field and press **Enter** or click the send button. If you already have an active conversation and want to start fresh, click the **New chat** button that appears next to the tabs. This clears the current conversation and returns you to the welcome screen. ## Sending messages Type your message in the input field at the bottom of the chat. Press **Enter** to send, or click the send button. The agent will process your message, potentially use its connected tools to gather information, and respond. Responses stream in as the agent generates them, so you can start reading before the full response is complete. ## Attachments You can attach files to your messages for the agent to analyze. Click the **paperclip icon** in the message input to open the file picker, or simply **drag and drop** files onto the input area. A dashed border will appear when you're dragging files over the input to confirm the drop zone. ### Supported file types and limits - **Images** (PNG, JPG, etc.) — up to 5 MB. Sent as visual content, so the agent can see and describe what's in the image. - **Documents** (PDF, DOCX, CSV, XLSX, TXT) — up to 10 MB. Text is extracted from the file and included in your message, so the agent can read and analyze the contents. - **Audio** — up to 25 MB. The file is stored and available for processing. You can attach up to **3 files per message**. Tip For spreadsheets, the agent gets the full text content, so it can answer questions about specific rows, columns, or calculations. Try asking it to summarize, filter, or compare data from your uploaded files. ## Tool confirmations When an agent needs to perform a write operation — like updating a ticket, creating a record, or sending a message — it will ask for your confirmation before proceeding. You'll see a confirmation card showing what the agent wants to do and with what parameters. Click **Confirm** to let the agent proceed, or **Cancel** to stop the action. This safety mechanism ensures the agent never makes changes without your explicit approval. Read-only operations (fetching data, searching, looking things up) run automatically without confirmation. ## Markdown in responses Agent responses support rich formatting including: - **Bold** and *italic* text - Bullet and numbered lists - Code blocks with syntax highlighting - Links - Tables — wide tables scroll horizontally within the chat, so the page layout stays intact ## File generation Agents with the File Tools connector can generate files on your behalf and return download links directly in the chat. Supported formats include: - **Spreadsheets** (.xlsx) — structured data with multiple sheets, formatting, and formulas - **CSV files** — simple comma-separated data - **PDF documents** — formatted reports and documents - **Word documents** (.docx) — rich text documents Just ask your agent to create a file. For example: "Create a spreadsheet with this month's sales data" or "Generate a PDF report of the open tickets." Tip File Tools are always available — they're a built-in connector that requires no setup. Any agent can generate files as long as File Tools is assigned to it. ## Conversation management Your past conversations are accessible from the sidebar. Click on any previous conversation to continue where you left off. Each conversation maintains its full history, so the agent remembers the context from earlier messages. To start a new conversation with the same agent, click the **New chat** button that appears next to the Chat tab when you have an active conversation. --- # Zendesk Setup & Best Practices Source: https://www.getmacha.com/docs/zendesk-best-practices > Pick the right trigger for your Zendesk workflow, set up custom Zendesk webhooks, avoid infinite loops on tickets, and understand the Zendesk tools that need explaining. This page collects the Zendesk-specific guidance that doesn't fit cleanly into the general docs — choosing the right trigger for your workflow, setting up custom Zendesk webhooks, avoiding infinite loops, and the handful of Zendesk tools that need a closer look. If you're running Macha agents on Zendesk, this is the page to read after you've gone through Connectors, Data Sources, and Triggers. ## Choosing the right trigger for your Zendesk workflow ';this.style.cursor='default'"> Choosing the Right Trigger for Your Zendesk Workflow Picking a Zendesk trigger comes down to three questions. Walk through them in order: ### 1. Should this run automatically, or does a human kick it off? If a teammate is going to open Macha and chat with the agent, you don't need a trigger at all — that's just chat. Triggers are specifically for when you want the agent to start on its own when something happens in a connected app. If a human is in the loop, skip the trigger entirely. ### 2. Which connected app does the event live on? Pick the trigger from the right connector. For Zendesk, you'll see options like *new ticket*, *every customer ticket message*, *ticket status changed*, *ticket priority changed*, *ticket assigned*, *ticket closed*, *customer message on messaging*, and more. Each one corresponds to a specific Zendesk event. ### 3. How specific can you be? This is the most important question. **Be as specific as possible.** If you turn on a broad trigger like "every customer ticket message," it fires on every customer comment across every ticket — and consumes a credit for each one. You'll burn through credits without meaning to. Pick the trigger that matches the exact moment that matters, not the broadest one available. For maximum specificity, use a **custom Zendesk webhook trigger**. With that, you set up the actual conditions inside Zendesk (e.g., "new ticket" + "high priority" + "from VIP customer") and only tickets that satisfy those conditions get sent to the agent. Tip When you switch on a high-volume trigger, Macha shows a warning ("this trigger fires on every new ticket — it will consume a credit per ticket") and asks you to confirm. Pay attention to those warnings — they exist precisely because broad triggers are easy to misuse. ## Setting up a custom Zendesk webhook trigger ';this.style.cursor='default'"> How to Set Up a Custom Zendesk Webhook Trigger Custom Zendesk webhook triggers give you the most precise control over when an agent runs. The flow is: - **In Macha:** open your agent → Triggers → Add trigger → select **Custom Webhook**. Macha automatically creates a webhook on your Zendesk instance. - **In Zendesk:** go to the admin panel and create a new ticket trigger. Set up the conditions for which tickets should be sent to your agent (e.g., "ticket has new public comment" + "commenter is end user" + "ticket status is less than solved"). - **Add an action** to that Zendesk trigger: *Notify by → Active webhook*, then select the Macha webhook from the dropdown. It'll be named after your agent (e.g., "Macha AI Ticket - Auto Classifier"). - **Copy the JSON payload** Macha gave you in the popup and paste it into the Zendesk webhook body field. Click **Create trigger**. From this point on, every Zendesk ticket that meets your trigger conditions will be sent to your Macha agent — and only those tickets. To verify it's working, create a test ticket that satisfies the conditions, then go to your agent's **History** tab. You should see the run appear there. Tip If something isn't firing, screenshot what you've set up so far on both sides (Macha trigger config + Zendesk trigger conditions + webhook action) and either ask ChatGPT/Claude to help debug or open a support ticket with us. Most issues are conditions on the Zendesk side that don't actually match any tickets. ## Stopping infinite loops on Zendesk tickets ';this.style.cursor='default'"> Stop Your AI Agent from Infinitely Looping on Zendesk Tickets This is a classic Zendesk problem: an agent processes a ticket → updates it → that update fires the same trigger → which sends the ticket back to the agent → and so on. The fix is simple but easy to miss when you're setting things up. ### The pattern: tag-and-exclude Inside the Zendesk trigger that calls your Macha webhook, do two things: - **Add a tag in the trigger's actions.** Alongside the webhook action, add an *Add tags* action with a unique tag name (e.g., `ai_classified_v1`). Every ticket that gets sent to your agent will now be tagged. - **Exclude that same tag in the trigger's conditions.** Add a condition: *Tags → Contains none of the following → ai_classified_v1*. Tickets that already have the tag are skipped. The result: each ticket flows through the agent exactly once. The first time the trigger fires, the ticket gets tagged and sent. The next time the same trigger evaluates that ticket, the tag check excludes it. Tip Use a versioned tag name like `ai_classified_v1` or `ai_summarized_v2`. If you ever change the agent's logic and want it to reprocess every ticket, just bump the version (`v2`) — the new tag won't match any existing tickets, so they'll all flow through once with the updated logic. ## Zendesk tools that need explaining ';this.style.cursor='default'"> Zendesk Tools in Macha — The Ones That Actually Need Explaining Most Zendesk tools in Macha do exactly what their name says. A few are easy to confuse with each other or are more powerful than they look — those are worth a closer read. ### The three "get" tools that confuse everyone - **Get Ticket** — fetches the core ticket: subject, description, status, requester, comments. This is the main tool you'll use for most workflows. - **Get Ticket Custom Fields** — fetches the actual *values* on a specific ticket for its custom fields. If you have a custom field called "Issue Category," this is how you read what's in it on a given ticket. - **Get Ticket Fields** — fetches the field *definitions* — the structure of your Zendesk account: which custom fields exist and what their IDs are. Agents use this to understand your overall setup. (Different from Custom Fields, which reads values on one ticket.) ### Search Tickets is more powerful than it looks Search Tickets supports Zendesk's full search syntax. You can search by status, assignee, tags, date ranges, custom fields, and more. If you want the agent to find a specific group of tickets — not just one — this is the tool to use. Worth giving the agent if it ever needs to do bulk lookups or reporting-style work. ### Add Internal Note vs Add Public Reply An **internal note** is private — only your support agents see it. A **public reply** goes directly to the customer. Pick the right one for the job. If your agent runs autonomously, double-check this before going live — autonomous mode means the agent will post whatever you've configured without confirmation. ### Update Ticket Fields writes custom fields too Update Ticket Fields lets the agent write values into *custom* fields, not just system fields like status or priority. If you have custom dropdowns, text fields, or checkboxes, this is how the agent fills them. ### Read Attachment Easy to miss but very useful. If a customer attaches a file to a ticket, the agent can read it. Attachments can be images, PDFs, or documents — the agent extracts the content and uses it as context when forming a response or looking up customer information. Tip The rest of the Zendesk tools are pretty self-explanatory. If anything else is unclear, send us an email — we're happy to walk through it. --- # Team Management and Roles Source: https://www.getmacha.com/docs/team > Invite team members, assign admin or member roles, and collaborate across your organization. ## Inviting team members To add someone to your organization, go to **Settings** and open the **Team** section. Enter their email address, select a role, and send the invitation. They'll receive an email with instructions to join your workspace. Once they accept the invitation and log in, they'll have access to your organization based on the role you assigned. ## Roles Macha has two roles that control what members can do within your organization. ### Admin Admins have full access to everything in the organization: - Create, edit, and delete agents - Connect and manage integrations - Create and configure custom tools - Set up and manage triggers - Invite and remove team members - Manage billing and subscription - Access organization settings - Use agents and chat ### Member Members can use the platform but cannot change its configuration: - Use agents and chat - View agents, connectors, and tools (read-only) - Cannot create, edit, or delete agents, connectors, tools, or triggers - Cannot manage team members or billing Tip Assign the Member role to people who only need to interact with agents. Reserve Admin access for team leads or operations staff who manage the setup. ## Managing members From the Team section in Settings, you can: - **Change a member's role** — switch between Admin and Member at any time - **Remove a member** — revoke their access to the organization Removing a member does not delete their Macha account. They lose access to your organization, but they can still log in to any other organizations they belong to. ## Multi-organization support A single Macha account can belong to multiple organizations. This is useful if you work across teams, companies, or client accounts. When you log in, you'll be asked to select which organization to work in. You can switch between organizations at any time from the app. Each organization has its own agents, connectors, tools, data, and billing — nothing is shared between them. Tip If you're a consultant or agency managing AI agents for multiple clients, multi-org support lets you keep each client's workspace completely separate while using a single login. --- # Billing, Plans, and Credits Source: https://www.getmacha.com/docs/billing > Manage your subscription, monitor credit usage, configure alerts, and handle payments. ## Plans overview Macha offers four plans to match different usage levels. Each plan determines your limits for connectors, agents, data sources, triggers, and custom tools. ### Trial A free plan with limited access to explore the platform. Try out agents, connect a few tools, and see how Macha works for your team. No credit card required. ### Starter For individuals and small teams getting started with AI agents. Includes basic limits for connectors, agents, and data sources. ### Professional For growing teams that need more power. Includes higher limits across the board, plus access to scheduled triggers (up to 3) and custom tools (up to 5 assignment slots). ### Enterprise For organizations that need the highest limits and priority support. Includes up to 20 scheduled triggers, 20 custom tool assignment slots, and credit check bypass so your agents never stop due to usage limits. Tip Not sure which plan is right for you? Start with Trial to explore, then upgrade as your needs grow. You can change plans at any time. ## Credits system ';this.style.cursor='default'"> Understanding Credits & Choosing the Right AI Model Macha uses a credit-based system for AI usage. Each time an agent completes a response, credits are deducted from your organization's balance. ### How credits work - Credits are deducted **once per complete assistant response** — not per tool call, not for every step in the agent's instructions. If an agent makes several tool calls before responding, you're only charged once for the final response. - The credit cost depends on which AI model the agent is configured to use. More capable models cost more credits per response. - You set the model on a per-agent basis, so a high-volume triage agent can run on a cheap model while a complex reasoning agent runs on a more capable one. ### Choosing the right model for the job You don't need to use the most powerful model for everything. Picking the right model per agent is the easiest way to control credit spend without sacrificing quality: - **GPT-5.4 Mini (1 credit/response)** — fast and affordable. Great default for most Zendesk workflows: triage, drafting replies, summarizing tickets, updating fields. If you're running high-volume support automation, make this your default. - **GPT-5 (2 credits/response)** — strong quality at a reasonable cost. Use this when an agent has long, complex, multi-step instructions that Mini struggles with. This is the platform default and a good balance for most agent workflows. - **GPT-5.4 (3 credits/response)** — most capable model in the OpenAI family. Best for nuanced human-facing replies, conditional policy logic, and multi-step reasoning where even GPT-5 is occasionally indecisive. Recommended when reliability matters more than cost. - **Anthropic Claude / others** — explore these if the OpenAI models aren't giving you the quality you need on a particular agent. You can pick any model when configuring an agent. If you're not sure, click the **"Which model should I use?"** link on the configuration screen for quick guidance. Tip Match the model to the task complexity, not the agent's importance. A simple summarizer that runs 10,000 times a month is much cheaper on Mini than on GPT-5 — and the output quality is identical for that kind of work. ### What doesn't count toward your credits A few specific things don't draw from your plan's credit balance: - **The welcome conversation.** When you finish onboarding, Macha drops you into a one-time welcome chat that introduces what it can do with your connected tools. That conversation carries a small "This chat costs no credits" badge near the model picker, and every message you send inside it is on us , we want you to see Macha working with your data before any of your plan credits get spent. Only this one conversation per organization is credit-free; every other chat draws from your balance as normal. - **The internal Macha Sidekick agent.** Questions you ask Macha-the-product (from the Sidekick widget in the dashboard) don't deduct credits. - **Cancelled study runs.** If you cancel a study mid-run, credits already spent on processed records stay billed, but no new ones get charged for the cancelled remainder. ### Enterprise credit bypass Organizations on the Enterprise plan bypass all credit checks. Your agents will always run regardless of credit balance, ensuring uninterrupted service. ## Top-up credits If you burn through your monthly allowance ahead of schedule — or just want a buffer for a one-off project like a large [Study](/docs/studies) — you can buy a one-time top-up pack instead of upgrading your plan. ### Available packs - **1,000 credits** , $99 ($0.099 per credit) - **5,000 credits** , $449 ($0.090 per credit) , *most popular, ~9% saving* - **10,000 credits** , $799 ($0.080 per credit) , *best value, ~19% saving* ### How top-up credits behave - **They never expire.** Unlike monthly credits, top-ups don't reset at the end of your billing cycle , they roll over until they're used. - **Monthly credits are spent first.** Top-ups only kick in once your monthly allowance is exhausted, so you never have to choose which bucket to draw from. - **Both buckets are shown separately** on the Usage card in Settings -> Billing. - **One-time payment, no auto-renew.** Top-ups are bought through Chargebee's one-time checkout in an in-page popup , no subscription change, no surprise charges next month. ### Who can buy top-ups The Top up credits section appears on the Billing page for active **Starter** and **Professional** subscriptions. Trial accounts can't buy top-ups , upgrade to a paid plan first. Enterprise plans already bypass credit checks, so top-ups aren't surfaced there. Tip Running a one-off Study against a large ticket backlog? Buy a top-up first instead of upgrading your plan , the pack covers the spike, your subscription stays where it is, and any unused credits roll forward. ## Usage alerts Macha sends email notifications to all organization admins when your credit usage reaches certain thresholds: - **50% used** — a heads-up that you're halfway through your credits - **80% used** — a warning that credits are running low - **90% used** — an urgent alert to top up or upgrade before agents stop working These alerts are sent once per threshold, so you won't receive duplicate emails. ## Plan limits Each plan includes limits on the following resources: - **Connectors** — the number of integrations you can connect - **Data sources** — uploaded documents and connected data - **Agents** — the number of agents you can create - **Scheduled triggers** — cron-based automated agent runs (Trial/Starter: 0, Pro: 3, Enterprise: 20) - **Custom tool slots** — tool-to-agent assignments for custom API tools (Trial/Starter: 0, Pro: 5, Enterprise: 20) - **Studies - AI Analysis** — batch AI analysis over records (Trial/Starter: not available, Pro & Enterprise: included, no run-count limit beyond the 20,000-records-per-run cap) ## Managing your subscription To upgrade, downgrade, or manage your subscription, go to **Settings** and open the **Billing** section. From there you can: - **Upgrade your plan** — click the upgrade button and complete checkout. The checkout opens directly within Macha (no external redirect). - **Downgrade your plan** — switch to a lower plan. The change takes effect at the end of your current billing period. - **View your current plan** — see your plan name, credit balance, and usage. Tip If you downgrade and your current usage exceeds the new plan's limits, existing resources won't be deleted — but you won't be able to create new ones until you're within the limits. --- # Account and Organization Settings Source: https://www.getmacha.com/docs/settings > Configure your profile, organization details, privacy preferences, and data management options. ## Profile settings Your profile settings control how you appear across the platform. - **Display name** — your name as shown to other team members. You can update this at any time. - **Email** — the email address you use to log in. This cannot be changed after account creation, as it's tied to your authentication. ## Organization settings Organization settings apply to all members and agents within your workspace. - **Default AI model** — set the AI model that new agents will use by default. Individual agents can override this in their configuration. Macha supports models from OpenAI, Anthropic, and Groq. ## Team management Invite team members, manage roles, and control who has access to your organization. See the [Team](/docs/team) documentation for full details on roles, invitations, and multi-organization support. ## Billing View your current plan, credit balance, and manage your subscription. See the [Billing](/docs/billing) documentation for information on plans, credits, usage alerts, and payments. ## Privacy settings Macha gives you full control over your data and account. Privacy settings are accessible from the Settings page. ### Download your data Request a full export of your data in JSON format. This includes your profile information, conversations, and any other data associated with your account. The export is generated and made available for download. ### Delete your account If you decide to leave Macha, you can request account deletion. Here's how it works: - Account deletion is **scheduled for 30 days** after the request - During this 30-day window, you can **cancel the deletion** and restore your account - After 30 days, your account and all associated data are permanently removed Tip If you belong to multiple organizations, deleting your account removes your access to all of them. Make sure to transfer any admin responsibilities before requesting deletion. ### Delete organization Organization deletion is available to admins only. Like account deletion, it follows a 30-day scheduled process: - The deletion is scheduled and can be cancelled within 30 days - All organization data is permanently removed after the grace period — agents, connectors, conversations, documents, triggers, and custom tools - All members lose access to the organization ### Policies For details on how Macha handles your data, review our policies: - [Privacy Policy](/privacy-policy) - [Terms of Service](/terms-of-service) - [Cookie Policy](/cookie-policy) - [Data Processing Agreement](/data-processing-agreement) - [Refund Policy](/refund-policy) --- # API Keys — Authenticating to the Macha REST API Source: https://www.getmacha.com/docs/api-keys > Generate, scope, and rotate API keys for the Macha REST API. Covers scopes, rate limits, the Authorization header, and security hygiene for production use. ## What API keys are for API keys let your own code call the Macha REST API. They live on your servers (never in client-side JavaScript or mobile apps that ship to end users) and they authorize every request to `/api/v1/*`. Use them to embed Macha agents into your own product, sync agent configuration from a source of truth, push conversation data into your own analytics stack, or trigger Macha from any system that can send an HTTP request. Each key is bound to a single organization. A key issued for Org A cannot read, write, or even discover data in Org B, regardless of what IDs you put in the URL or body. See the [API Reference](/docs/api) for the full endpoint list. ## Generating a key Keys are managed from **Settings -> API Keys** in the dashboard. Only organization admins can create or revoke keys. - Click **Create API key**. - Give it a **label** that describes what it's used for (e.g. *"Production sync job"*, *"Internal CRM webhook"*). The label is visible in the key list and in audit logs. - Pick the **scopes** the key needs (see below). Default is read-only. - Optionally set an **expiry date**. Keys without an expiry never auto-expire; you have to revoke them manually. - Click **Generate**. The full key is shown **once**, in a one-time reveal modal. Copy it immediately and store it somewhere secure (a password manager, your secrets vault, a CI variable). Macha cannot show it again. One-time reveal The raw key value is only visible at the moment you create it. Macha stores a bcrypt hash, not the key itself, so we can verify a key on every request without ever being able to retrieve it back. If you lose a key, the only recovery is to revoke it and generate a new one. ## Using a key Every API request must include the key as a Bearer token in the `Authorization` header: ``` curl https://dashboard.getmacha.com/api/v1/conversations \ -H "Authorization: Bearer mka_live_..." ``` All keys start with the prefix `mka_live_`. The prefix is a useful tripwire for secret scanners (GitHub, GitGuardian, your own CI) to flag committed keys before they hit production. Responses are standard JSON with HTTP status codes. `200` on success, `401` if the key is missing or revoked, `403` if the key doesn't carry the required scope, `429` if you've hit the rate limit, and `4xx`/`5xx` for the usual reasons. Error responses always include a structured `{ code, message }` body so your client can branch on the code. ## Scopes Scopes are per-resource and per-action. A key carries an explicit list, and the match is exact: a key with `agents:read` does **not** automatically gain `agents:write`. This makes a key's privileges fully visible from its scope list alone. - **agents** — `agents:read`, `agents:write`, `agents:delete` - **conversations** — `conversations:read`, `conversations:write`, `conversations:delete` - **connectors** — `connectors:read`, `connectors:write`, `connectors:delete` - **custom tools** — `custom_tools:read`, `custom_tools:write`, `custom_tools:delete` - **sources** — `sources:read`, `sources:write`, `sources:delete` - **chatbots** — `chatbots:read`, `chatbots:write`, `chatbots:delete` - **triggers** — `triggers:read`, `triggers:write`, `triggers:delete` - **team** — `team:read`, `team:write`, `team:delete` - **analytics** — `analytics:read` - **org** — `org:read` The dashboard creation modal offers convenient "tick all read" and "tick everything" shortcuts so you don't have to click each box individually for the common cases. For production credentials, prefer the minimum scopes the job actually needs, not the convenient maximum. What's not in the API v1 covers the read and write surface for agents, conversations, connectors, custom tools, sources, chatbots, triggers, and team. Running a chat turn through an agent (the SSE streaming chat loop) and billing actions are dashboard-only by design. Studies and Sidekick are not exposed via API. ## Rate limits Limits are applied per API key, not per organization. Two windows run in parallel: - **1,000 requests per minute** - **10,000 requests per hour** When you hit a limit you'll get a `429 Too Many Requests` response with a `Retry-After` header indicating how many seconds until the window resets. Back off, then retry. The limits are generous for normal automation; if you're hitting them consistently you're likely better off batching or moving to a streaming/webhook pattern. Because limits are per-key, one noisy integration in your workspace can't starve another. Issue a separate key per integration so you can isolate rate-limit blame. ## Plan availability API keys are available on every paid plan. Trial accounts can generate keys for testing; production usage requires an active subscription. Plan-level limits (agent count, scheduled triggers, custom tools, etc.) apply identically whether you're hitting Macha from the dashboard or the API. ## Security hygiene The usual rules apply, but the ones worth calling out for Macha specifically: - **Never commit a key to a repository.** Use environment variables, a secrets manager, or your CI's encrypted variable store. The `mka_live_` prefix is recognised by most secret scanners. - **Rotate keys quarterly** at minimum, or immediately on any suspected leak. Revoke first, then generate a replacement, then update consumers. - **One key per integration.** Don't share a single "admin key" across services. Per-integration keys mean a leak only affects one surface, and you can rotate without coordinating outages across teams. - **Set an expiry on keys you give to short-lived projects.** Auto-expiring credentials beat remembering to revoke. - **Server-side only.** Never put a Macha API key in a browser bundle, a mobile app, or a public-facing JavaScript file. If you need browser-side access to Macha data, route it through your own server with its own auth. ## Revoking a key From **Settings -> API Keys**, click the menu next to any key and select **Revoke**. Revocation takes effect immediately — the next request with that key will return `401`. There's no grace period and no undo, so update consumers first (or have the replacement key ready) before revoking the old one. Revoked keys remain in the audit list so you can see when they were last used and by whom they were created. They cannot be reactivated; generate a new key if you need to restore access. ## Audit log Each key shows its label, prefix, scopes, creator, creation date, and the timestamp of its most recent use. The "last used" timestamp updates on every successful request and is the easiest way to spot abandoned keys that should be cleaned up. If you're tracking down which key did what, the prefix (the first 8 characters after `mka_live_`) is shown on every audit row and is the same prefix that appears in any logs we keep server-side. Match on prefix, not on the full key — Macha never logs the full key. --- # Getting Started with the Macha API Source: https://www.getmacha.com/docs/api/getting-started > Make your first authenticated request against the Macha REST API in under five minutes. This guide walks you through your first authenticated request against the Macha API. By the end you'll have listed your organization's agents from your terminal, understood the response envelope, and know where to read next. The API base URL is: ```http https://dashboard.getmacha.com/api/v1 ``` Every endpoint lives under this prefix. Every request needs an `Authorization` header. Every response is JSON. ## Step 1, Generate an API key Sign in to the Macha dashboard and head to [Settings -> API Keys](https://dashboard.getmacha.com/settings/api-keys). Click **Create API Key**, give it a label that identifies the integration, and pick the scopes it needs. Macha API keys look like this: ```bash mka_live_jbUaWzqeKB004Gr8FIHpRPoyVOq2Yzx9 ``` The structure is intentional, the `mka_live_` prefix lets us narrow lookups before doing the bcrypt compare on the suffix. The whole token is bcrypt-hashed at rest, so we cannot show it back to you after creation. **Save it somewhere safe immediately.** ⚠ Lost keys are gone If you forget to save the token at creation, Macha cannot recover it. Bcrypt hashing is one-way. Revoke the key and create a new one. ### Picking scopes Macha API keys are scope-restricted. Every endpoint requires a specific scope like `agents:read` or `conversations:write`. There is no super-scope, a key with every capability still has to list each scope individually. For your first integration, start with read-only scopes: ```bash agents:read conversations:read connectors:read org:read ``` You can always create a second key with broader scopes later. Macha never auto-elevates an existing key. ## Step 2, Make your first request Pass the key in the `Authorization` header with the `Bearer` scheme. Everything else is standard JSON-over-HTTPS. ```bash curl https://dashboard.getmacha.com/api/v1/agents \ -H "Authorization: Bearer mka_live_YOUR_KEY_HERE" ``` If the key is valid and has the `agents:read` scope, you'll get back a paginated list of your agents: ```json { "data": [ { "id": "agent_64f1c0ef2ec711ef6dc1dcf", "handle": "ticketTriage", "name": "Triage", "description": "Routes incoming Zendesk tickets...", "model": "gpt-5.4", "is_active": true, "color": "#000000", "avatar": "🚦", "tools_count": 2, "sub_agents_count": 4, "created_at": "2026-06-10T04:07:44.871Z", "updated_at": "2026-06-17T07:29:29.408Z" } ], "meta": { "request_id": "req_a0b88aa084bac0f7", "next_cursor": "agent_..." } } ``` ### What if it didn't work? Common first-request failures and what they mean: | Status | Code | What to do | | 401 | unauthorized | Header missing, malformed, or the token is wrong / revoked. Check you copied the full token including the mka_live_ prefix. | | 403 | insufficient_scope | The token is real but doesn't have the scope this endpoint needs. Create a new token with agents:read. | | 404 | | Wrong URL. Check the path matches /api/v1/agents exactly. | | 429 | rate_limited | You blew through the per-minute or per-hour limit. See Rate Limits. | ## Step 3, Understand the response envelope Every successful Macha API response uses the same shape: ```json { "data": , "meta": { "request_id": "req_a0b88aa084bac0f7", "next_cursor": "agent_..." } } ``` Three rules: - `data` is always the payload. For list endpoints it's an array; for single-resource endpoints it's an object. - `meta.request_id` is always present. It's also returned in the `X-Request-ID` response header. Log it, if you ever need support, this is what we'll ask for. - `meta.next_cursor` appears only on paginated list endpoints, and is `null` when there's no next page. Errors use a different shape, also consistent across every endpoint: ```json { "error": { "code": "agent_not_found", "message": "Agent not found.", "request_id": "req_..." } } ``` Customers code against the `code` field, not the `message`. The message is human-friendly; the code is stable. See the [Errors reference](/docs/api/errors) for every code we emit. ## Step 4, Make a write request Read endpoints don't change state, so retries are safe. Write endpoints (`POST`, `PATCH`, `DELETE`) can change state, so Macha supports the `Idempotency-Key` header for retry safety. Pass any unique string and Macha will replay the cached response on retry within 24 hours. ```bash curl -X POST https://dashboard.getmacha.com/api/v1/agents \ -H "Authorization: Bearer mka_live_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "handle": "myFirstAgent", "name": "My First Agent", "instructions": "Answer questions politely and concisely." }' ``` Response: ```json { "data": { "id": "agent_...", "handle": "myFirstAgent", "name": "My First Agent", "model": null, "is_active": true, "tools_count": 0, "sub_agents_count": 0, "created_at": "2026-06-24T10:42:00.000Z", "updated_at": "2026-06-24T10:42:00.000Z" }, "meta": { "request_id": "req_..." } } ``` Retry the exact same request with the same `Idempotency-Key` and you'll get the cached response, no duplicate agent. See [Idempotency](/docs/api/idempotency) for the full spec. ## Step 5, What to read next - [Authentication](/docs/api/authentication), key lifecycle, full scope catalog, what each auth failure means - [Errors](/docs/api/errors), every error code Macha emits, with retry guidance - [Pagination](/docs/api/pagination), cursor model for list endpoints - [Idempotency](/docs/api/idempotency), safe retries for write requests - [Rate Limits](/docs/api/rate-limits), per-minute and per-hour caps with header semantics - [Agents](/docs/api/agents), full CRUD for the agent resource 📘 Machine-readable spec If you prefer to skip the prose, the full OpenAPI 3.1 specification is served at [`/api/v1/openapi.json`](https://dashboard.getmacha.com/api/v1/openapi.json). Point an SDK generator at it and get a typed client. { "@context": "https://schema.org", "@type": "HowTo", "name": "Get started with the Macha API in five minutes", "description": "Generate an API key, make your first authenticated request, understand the response envelope, and make a write request safely with idempotency.", "totalTime": "PT5M", "supply": [ { "@type": "HowToSupply", "name": "Macha account with API access" } ], "tool": [ { "@type": "HowToTool", "name": "curl or any HTTP client" } ], "step": [ { "@type": "HowToStep", "position": 1, "name": "Generate an API key", "text": "Sign in to the Macha dashboard, head to Settings then API Keys, click Create API Key, give it a label, and pick the scopes it needs. Keys look like mka_live_ followed by 32 random characters. The full token is shown once and bcrypt-hashed at rest." }, { "@type": "HowToStep", "position": 2, "name": "Make your first authenticated request", "text": "Send the API key in the Authorization header as a Bearer token. Example: curl https://dashboard.getmacha.com/api/v1/agents -H 'Authorization: Bearer mka_live_YOUR_KEY'. A successful response returns a JSON envelope with data and meta fields." }, { "@type": "HowToStep", "position": 3, "name": "Understand the response envelope", "text": "Every success response has the shape {data, meta}. The data field is your payload (object or array). The meta field includes request_id (always present, also returned in X-Request-ID header) and next_cursor (for paginated list endpoints). Errors use {error: {code, message, request_id}} instead." }, { "@type": "HowToStep", "position": 4, "name": "Make a write request with idempotency", "text": "POST and PATCH requests honor an Idempotency-Key header. Send any unique string as the value; Macha replays the cached response on retry within 24 hours. Use a UUID v4 per logical operation." }, { "@type": "HowToStep", "position": 5, "name": "Continue with the full reference", "text": "Read the Authentication, Errors, Pagination, Idempotency, and Rate Limits pages for the full contract. Each resource (Agents, Conversations, Connectors, Custom Tools, and others) has its own reference section with per-endpoint detail." } ], "audience": { "@type": "Audience", "audienceType": "Developers" }, "isAccessibleForFree": true, "inLanguage": "en" } --- # Authenticating with the Macha API Source: https://www.getmacha.com/docs/api/authentication > Generate API keys, choose the right scopes, and authenticate requests with Bearer tokens. The Macha API authenticates every request with a Bearer token. Tokens are organization-scoped, scope-restricted, revocable, and never reused. There is no OAuth flow today, just static API keys that you generate from the dashboard. ## Token format API keys have a fixed prefix that identifies them as Macha tokens, followed by 32 characters of random entropy: ```bash mka_live_jbUaWzqeKB004Gr8FIHpRPoyVOq2Yzx9 └── 9 ──┘└────────── 32 ──────────────────┘ prefix random suffix ``` The prefix is what Macha uses to narrow the key lookup before doing the bcrypt compare on the suffix, this keeps key validation under a millisecond at any scale. The whole token is bcrypt-hashed at rest with a cost factor that's adjusted as compute gets cheaper. Even with full database access, Macha cannot recover the original token. ## Passing the token Send the full token in the `Authorization` header on every request: ```http GET /api/v1/agents HTTP/1.1 Host: dashboard.getmacha.com Authorization: Bearer mka_live_jbUaWzqeKB004Gr8FIHpRPoyVOq2Yzx9 Accept: application/json ``` Sending the token via query string, request body, or cookie is not supported and never will be. Bearer header only. ### Example: curl ```bash curl https://dashboard.getmacha.com/api/v1/agents \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ### Example: Node.js (fetch) ```javascript const res = await fetch('https://dashboard.getmacha.com/api/v1/agents', { headers: { 'Authorization': `Bearer ${process.env.MACHA_API_KEY}`, }, }); const json = await res.json(); ``` ### Example: Python (requests) ```python import os, requests r = requests.get( 'https://dashboard.getmacha.com/api/v1/agents', headers={'Authorization': f'Bearer {os.environ["MACHA_API_KEY"]}'}, ) data = r.json() ``` ## Scopes Every API key has a list of scopes that restrict what it can do. Scopes follow a `{resource}:{action}` naming convention. There is no super-scope, a key with every scope still has to list each one explicitly. ### Full scope catalog | Resource | Read | Write | Delete | | Agents | agents:read | agents:write | agents:delete | | Conversations | conversations:read | conversations:write | conversations:delete | | Connectors | connectors:read | connectors:write | connectors:delete | | Custom tools | custom_tools:read | custom_tools:write | custom_tools:delete | | Sources | sources:read | sources:write | sources:delete | | Chatbots | chatbots:read | chatbots:write | chatbots:delete | | Triggers | triggers:read | triggers:write | triggers:delete | | Team | team:read | team:write | team:delete | | Analytics | analytics:read | | | | Organization | org:read | | | `analytics` and `org` are read-only resources by design, analytics is computed from underlying data (no write surface), and org settings stay dashboard-managed for now (billing, branding, etc.). ### Per-endpoint scope Each endpoint's required scope is listed in its reference page. As shorthand: | HTTP method | Scope required | | GET | {resource}:read | | POST / PATCH | {resource}:write | | DELETE | {resource}:delete | The OpenAPI spec exposes the exact scope under `x-required-scope` on each operation, so SDK generators and MCP servers can warn customers about missing scopes before making the call. ## Authentication failures Two distinct failure modes: | Status | Code | Meaning | Fix | | 401 | unauthorized | Missing, malformed, revoked, or unknown key. | Check the token. If revoked, create a new one. | | 403 | insufficient_scope | Valid key, but it lacks the scope this endpoint requires. | Create a new key with the missing scope. | A `403` means "this key is real, but you didn't grant it permission", not a bug in your code. Fix it by creating a new key with broader scopes (or asking the org admin to). ## Key lifecycle ### Create In the dashboard at [Settings -> API Keys](https://dashboard.getmacha.com/settings/api-keys). The full token is shown *once* at creation time. Macha cannot show it again, copy it immediately into your secret store. ### Use Passed as a Bearer token on every request. Macha updates the key's `last_used_at` timestamp asynchronously so the dashboard can show stale-key warnings, but this is fire-and-forget, your request latency is not affected. ### Revoke Click revoke in the dashboard. The key is marked inactive immediately; any further requests get `401 unauthorized`. The audit history of what the key did is retained. ### Rotate Macha doesn't support in-place rotation today. The rotation pattern is: - Create a new key with the same scopes as the old one - Update your integration to use the new key - Verify the new key is working (check logs / dashboard's `last_used_at`) - Revoke the old key This is overlap rotation, both keys are valid during the transition, then the old one is cut. Cleaner than in-place rotation; harder to lock yourself out. ## Security best practices - **Use environment variables.** Never commit a key to source control. Macha scans public GitHub for the `mka_live_` prefix and will revoke leaked keys automatically. - **One key per integration.** Don't share a key across multiple services, if one leaks, you can revoke without breaking the others. - **Smallest scope that works.** An "agent reader" integration shouldn't have `agents:write`. Scope keys tightly. - **Log `request_id` on errors.** Macha can trace any request by its ID. Support is impossible without it. - **Rotate regularly.** Six months is a reasonable cadence. The overlap rotation pattern above makes it cheap. ## What Macha sees Every authenticated request is associated with the API key's organization. The key does *not* impersonate a user, resources created via the API show up in audit logs as "created via API key " rather than tied to a specific person. If you need per-user attribution, create one key per user and label it accordingly. Macha treats each key as a distinct identity for audit purposes. 🔒 Treat keys like passwords Anyone with your key has full org-level access at the scopes you granted. Store keys in a proper secrets manager (1Password, AWS Secrets Manager, Doppler, etc.), not in `.env` files checked into Git. --- # Error Codes and Response Shape Source: https://www.getmacha.com/docs/api/errors > Every Macha API error returns a stable code your code can switch on. Reference for every code we emit. Every Macha API error follows the same shape, with a stable `code` string you can switch on. We never repurpose codes, if a new error condition arises, we give it a new code rather than overload an existing one. ## Error response shape ```json { "error": { "code": "agent_handle_taken", "message": "Agent with handle @ticketTriage already exists", "request_id": "req_a0b88aa084bac0f7" } } ``` ### Field semantics | Field | Stability | Use for | | code | Stable. Never changes between releases without a v-bump. | Branching logic. Switch on this to decide what to do. | | message | Human-friendly. May be reworded between releases. | Logging, surfacing to end users. Never machine-parse. | | request_id | Per-request. Also returned in the X-Request-ID header. | Log it. Macha support needs it to trace anything. | ## HTTP status semantics Macha follows RFC 7231 strictly. We don't return `200` on errors. The HTTP status alone tells you the rough category; the `code` tells you the exact reason. | Status | Category | Should you retry? | | 400 | Bad request | No, fix the request. | | 401 | Authentication failed | No, check the key. | | 403 | Authorization failed (scope or policy) | No, the key needs different scopes. | | 404 | Resource doesn't exist | No, check the ID. | | 409 | State conflict (uniqueness, idempotency reuse) | Sometimes, depends on the code. See below. | | 422 | Validation failed | No, the input is invalid. | | 429 | Rate limited | Yes, honor Retry-After. | | 500 | Server error | Yes, with exponential backoff. Use an Idempotency-Key. | | 503 | Service unavailable | Yes, with exponential backoff. | ## Error code registry These are the codes Macha v1 currently emits. Adding new codes is non-breaking (additive). Removing or renaming a code is breaking and would require v2. ### Authentication & authorization | Code | HTTP | Meaning | | unauthorized | 401 | Missing, malformed, revoked, or unknown API key. Verify the Authorization: Bearer ... header. | | insufficient_scope | 403 | Valid key, lacks the required scope for this endpoint. | | forbidden | 403 | Org-level block, e.g. deletion-scheduled org, suspended subscription. | ### Validation & not-found | Code | HTTP | Meaning | | bad_request | 400 | Malformed input that isn't a domain-validation issue (e.g. invalid JSON). | | validation_failed | 422 | Required field missing, value out of range, enum mismatch, etc. message names the offending field. | | not_found | 404 | Generic. Used for unknown nested resources. | | agent_not_found | 404 | Agent ID doesn't exist (or has been soft-deleted past the trash window). | | conversation_not_found | 404 | Conversation ID unknown or belongs to another org. | | custom_tool_not_found | 404 | Custom tool deleted or never existed. | | source_not_found | 404 | Source deleted or never existed. | ### Conflicts | Code | HTTP | Meaning | | agent_handle_taken | 409 | Trying to create or rename an agent to a handle that already exists in the org (case-insensitive). | | custom_tool_name_taken | 409 | Custom tool with this generated name already exists. | | upload_source_exists | 409 | POST /sources with type=upload, the Uploads source is a per-org singleton and is already provisioned. | | idempotency_key_reused | 409 | Same Idempotency-Key seen within 24h with a different request body. Generate a fresh key for a different operation. | | plan_limit_exceeded | 422 | The action would exceed your plan's resource cap. Returned at write time, never read time. | ### Throttling & server | Code | HTTP | Meaning | | rate_limited | 429 | Per-key rate limit exceeded. Inspect Retry-After and X-RateLimit-* headers. | | internal_error | 500 | Unhandled server exception. Log the request_id, if it persists, contact support. | | service_unavailable | 503 | Provider unreachable, queue full, or planned maintenance. Retry with backoff. | ## Retry guidance The boring rule: retry `5xx` and `429`, never retry `4xx`. Slightly less boring rule: retries on write endpoints should always carry an `Idempotency-Key` header. Otherwise you may end up with duplicate resources if the original request actually succeeded but the response got lost on the wire. ### Recommended retry pattern ```javascript async function callMacha(path, init) { const url = `https://dashboard.getmacha.com/api/v1${path}`; const headers = { 'Authorization': `Bearer ${process.env.MACHA_API_KEY}`, ...(init?.headers || {}), }; let lastError; for (let attempt = 0; attempt setTimeout(r, backoff)); lastError = res; } return lastError; // give up after 5 tries } ``` 📘 Never retry without an Idempotency-Key on POST/PATCH If the original POST actually succeeded but the response was lost, a naive retry creates a duplicate. With `Idempotency-Key` set, Macha returns the cached original response on the retry, no duplicate. See [Idempotency](/docs/api/idempotency). ## Logging for support When something goes wrong and you need Macha to look at it, capture: - The request URL (with query string) - The HTTP method - The response status code - The response `error.code` - The `request_id` (from response body or `X-Request-ID` header) - The timestamp That's enough for us to trace the exact request through our logs in seconds. Without the `request_id`, support takes minutes-to-hours. --- # Cursor-Based Pagination Source: https://www.getmacha.com/docs/api/pagination > List endpoints page through results using opaque cursors. Reliable across inserts, no offset drift. Every list endpoint in the Macha API is cursor-paginated. You walk a list by passing the previous response's `next_cursor` back as a query parameter. Cursors are opaque strings, treat them as bytes, don't try to parse them. ## Why cursors, not offsets Offset pagination (`?page=3&per_page=50`) is what you've seen in older APIs. It breaks under two conditions Macha cares about: - **Inserts during traversal.** If a new conversation lands while you're paging, every subsequent page either skips a record or duplicates one. - **Deep pagination.** `OFFSET 50000` means the database has to count past 50,000 rows. Slow. Cursor pagination uses the last-seen record's ID as the boundary, so each page query is "give me 50 things older than `conv_X`." This is fast (indexed) and stable under concurrent inserts. ## Request List endpoints accept two query params: | Param | Type | Default | Range | | cursor | string | none (start at newest) | opaque | | limit | integer | 25 | 1-100 | The first request omits `cursor`: ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?limit=50' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` The server returns up to 50 items, sorted newest-first, plus a `next_cursor` if there's more: ```json { "data": [ /* ...up to 50 conversations... */ ], "meta": { "request_id": "req_...", "next_cursor": "conv_6a28f567ba502f55d177bb50" } } ``` Pass that cursor back for the next page: ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?limit=50&cursor=conv_6a28f567ba502f55d177bb50' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` When there's no next page, `next_cursor` is `null`: ```json { "data": [ /* ...last batch of items... */ ], "meta": { "request_id": "req_...", "next_cursor": null } } ``` ## Walking the full list The standard loop is straightforward: ```javascript async function listAll(resource) { const all = []; let cursor = null; while (true) { const params = new URLSearchParams({ limit: '100' }); if (cursor) params.set('cursor', cursor); const res = await fetch( `https://dashboard.getmacha.com/api/v1/${resource}?${params}`, { headers: { Authorization: `Bearer ${process.env.MACHA_API_KEY}` } }, ); const body = await res.json(); all.push(...body.data); if (!body.meta.next_cursor) break; cursor = body.meta.next_cursor; } return all; } const allAgents = await listAll('agents'); ``` ### Python equivalent ```python import os, requests def list_all(resource): out, cursor = [], None while True: params = {'limit': 100} if cursor: params['cursor'] = cursor r = requests.get( f'https://dashboard.getmacha.com/api/v1/{resource}', headers={'Authorization': f'Bearer {os.environ["MACHA_API_KEY"]}'}, params=params, ) body = r.json() out.extend(body['data']) cursor = body['meta'].get('next_cursor') if not cursor: break return out ``` ## Ordering Default sort order is **newest first**, rows are returned in descending order of their internal ID, which corresponds to creation time. This is stable across paginated requests unless explicitly documented otherwise. The exception is the conversation messages endpoint (`GET /conversations/:id/messages`), which returns messages in **ascending** order, oldest first, because that's the natural reading order for a chat thread. ## Cursor opacity rules Macha cursors today look like prefixed IDs (`conv_...`, `agent_...`). Don't write code that assumes this. Treat the cursor string as a black box: ⚠ Don't parse cursors Cursors may switch from prefixed IDs to base64-encoded tokens or other formats without a version bump. The contract is "round-trip this string verbatim", nothing more. Things you can rely on: - Cursors are URL-safe strings. No special encoding needed. - Cursors are stable for the lifetime of the listed resource, pausing for an hour mid-traversal and resuming is fine. - Passing an invalid cursor returns `422 validation_failed`. ## Limit caps Server enforces `1 ≤ limit ≤ 100`. Asking for more than 100 returns `422 validation_failed`. Asking for 0 or negative returns the same. If you need everything, set `limit=100` and loop. Don't try to bypass the cap. ## Counting The Macha API **does not return total counts** on list endpoints, no `total`, no `has_more`. We don't compute the count because doing so requires scanning the full result set, which is precisely what cursor pagination is built to avoid. If you need a count for display, walk the list once and count. For "page X of Y" UIs, redesign, cursor pagination doesn't have stable page numbers. ## Filter + pagination Filter params (e.g. `?source=autonomous`, `?model=gpt-5-mini`) compose freely with `cursor` and `limit`. The cursor is filter-aware: pulling page 2 with the same filters returns the next 50 matching items, not the next 50 items globally. ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?source=autonomous&model=gpt-5-mini&limit=50' \ -H "Authorization: Bearer $MACHA_API_KEY" # next page, same filters: curl 'https://dashboard.getmacha.com/api/v1/conversations?source=autonomous&model=gpt-5-mini&limit=50&cursor=' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` Don't change filters mid-traversal, the cursor was scoped to the original filter set. Restart from scratch (no cursor) when you change the filter. --- # Safe Retries with Idempotency Keys Source: https://www.getmacha.com/docs/api/idempotency > Send write requests safely. An Idempotency-Key header makes POST and PATCH retryable without duplicates. Network calls fail. The original request might have succeeded but the response was lost on the wire, leaving the client unsure whether to retry. Naive retries create duplicates, two agents instead of one, two refunds, two emails. The fix is the `Idempotency-Key` request header. Pass any unique string with your `POST` or `PATCH` request, and Macha will replay the cached response on retry within 24 hours instead of running the operation twice. ## How it works - You send a `POST`/`PATCH` with `Idempotency-Key: `. - Macha computes a fingerprint from the request method, path, and body. It checks if it has seen this key before. - **First request:** no cached record. Macha runs the operation, stores `(key, request_hash, status, response_body)`, and returns the response. - **Retry with the same key and same body:** Macha finds the cached record, verifies the hash matches, and returns the stored response. The operation does NOT run again. - **Retry with the same key but a different body:** hash mismatch. Macha returns `409 idempotency_key_reused`, you've used the same key for a different operation, which is almost certainly a bug. Cached responses live for **24 hours**, then drop out via a TTL index. Reusing the same key after 24h is fine, it'll execute fresh. ## Where it applies | Method | Honors Idempotency-Key? | | GET | No, reads are naturally idempotent. | | POST | Yes. | | PATCH | Yes. | | DELETE | No, delete-the-thing operations are naturally idempotent (second call returns 404). | ## Picking a key Macha doesn't care what the string looks like, as long as it's: - Unique per logical operation - 1-128 characters of ASCII - Generated and stored by you (so retries can reuse it) The standard choice is a UUID v4: ```bash Idempotency-Key: 7f6c8a3e-7c5b-4d2c-aa3e-1a9b3d2e7f1a ``` Other reasonable choices: - Your own business event ID (e.g. `order-12345-create-agent`) - A hash of (user ID + timestamp + action) - A monotonic ID from your queue system ### Anti-patterns ⛔ Don't reuse keys across logical operations A single `Idempotency-Key` represents one operation. Sending the same key with a different body returns `409 idempotency_key_reused`. Generate fresh keys for fresh operations. - **Bad:** reusing the same key across users (`create-agent`). Two different users hit the same cached response. - **Bad:** reusing the same key across attempts at slightly different operations (e.g. retried POST with the user's typo-corrected name). Macha returns 409 because the body hash differs. - **Bad:** generating a fresh key on every retry. Defeats the point, Macha can't recognize the retry, and you may create duplicates. ## Examples ### Curl ```bash curl -X POST https://dashboard.getmacha.com/api/v1/agents \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "handle": "wismo", "name": "WISMO", "instructions": "Answer Where Is My Order questions." }' ``` ### Node.js with retry ```javascript import { randomUUID } from 'crypto'; async function createAgentWithRetry(body) { // Generate the key ONCE, outside the retry loop. const idempotencyKey = randomUUID(); for (let attempt = 0; attempt setTimeout(r, 1000 * 2 ** attempt + Math.random() * 250)); } } ``` ### Python with retry ```python import os, uuid, time, requests def create_agent_with_retry(body): idempotency_key = str(uuid.uuid4()) # outside the loop headers = { 'Authorization': f'Bearer {os.environ["MACHA_API_KEY"]}', 'Content-Type': 'application/json', 'Idempotency-Key': idempotency_key, } for attempt in range(5): r = requests.post( 'https://dashboard.getmacha.com/api/v1/agents', json=body, headers=headers, ) if r.ok: return r.json() if r.status_code < 500 and r.status_code != 429: r.raise_for_status() time.sleep(min(2 ** attempt, 30)) raise RuntimeError('Retry budget exhausted') ``` ## What gets compared Macha hashes the SHA-256 of `method + path + JSON-serialized body`. Two requests are "the same" if all three match exactly. Two requests differ if any of: - HTTP method is different (e.g. POST vs PATCH) - URL path is different (e.g. `/agents` vs `/agents/abc`) - Request body bytes differ, including whitespace, key order, etc. Query strings and headers are NOT part of the hash. If you pass `?dry_run=true` vs not, that's the same operation as far as idempotency is concerned. Be deliberate about which params live in the URL vs the body. ## Race handling Two concurrent requests with the same key both miss the cache, both run, and both try to insert the cache record. Macha uses a unique index on `(org_id, key)` so exactly one insert wins; the loser catches the duplicate-key error and quietly drops its insert. Both requests still get their full response (Macha doesn't try to serialize concurrent execution). If your operation has side effects you need to be careful about, charging a payment, sending an email, ensure the operation itself is conditionally idempotent at the application level, not just at the API caching layer. ## Limits and rules - **TTL:** 24 hours from the first request. - **Key length:** 1-128 characters. - **Per-org scope:** Keys are namespaced per organization. The same string in two different orgs is two different keys. - **Per-method scope:** Sending the same key with `POST` and then `PATCH` counts as different operations and returns `409 idempotency_key_reused` on the second call. ## When NOT to use idempotency keys Reads. You'd be polluting the cache for no benefit, GET is already safe to retry. You also don't strictly need them for first-attempt write requests if you're comfortable handling duplicates yourself. But adding the header costs nothing, so the boring answer is "always set `Idempotency-Key` on writes." Defense in depth. --- # API Rate Limits Source: https://www.getmacha.com/docs/api/rate-limits > Every API key gets 1,000 requests per minute and 10,000 per hour. Headers expose what's left. Every Macha API key gets **1,000 requests per minute** and **10,000 requests per hour**. Limits are enforced per key, not per organization, if you have three keys in the same org, you get 3,000 requests per minute combined. ## The two windows | Window | Limit | Resets | | Minute | 1,000 requests | Sliding, every 60 seconds | | Hour | 10,000 requests | Sliding, every 3,600 seconds | Both windows are checked on every request. If *either* is full, the request is rejected with `429 rate_limited`. The headers (below) always reflect the **more constraining** window, whichever one you'll hit first. ## Response headers Every response (success or error) includes rate limit headers so you don't have to guess what's left: | Header | Meaning | | X-RateLimit-Limit | Requests allowed in the current window (1000 or 10000 depending on which is tighter). | | X-RateLimit-Remaining | Requests left in the current window before you hit 429. | | X-RateLimit-Reset | Unix epoch seconds when the more-constraining window resets. | | Retry-After | Only on 429 responses. Seconds to wait before retrying. | Example response headers on a normal request: ```http HTTP/1.1 200 OK X-Request-ID: req_a0b88aa084bac0f7 X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 999 X-RateLimit-Reset: 1782296880 Content-Type: application/json; charset=utf-8 ``` ## The 429 response When you exceed the limit, Macha returns `429 rate_limited` with both the standard error envelope and a `Retry-After` header: ```http HTTP/1.1 429 Too Many Requests Retry-After: 12 X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1782296892 { "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry in 12 seconds.", "request_id": "req_..." } } ``` Honor `Retry-After`. It's set to the number of seconds until the more-constraining window has space again. Ignoring it and slamming retries will just keep hitting 429. ## Building a rate-aware client The simplest pattern: every request, glance at `X-RateLimit-Remaining`. If it's low, slow down. If you get a 429, sleep `Retry-After` seconds and try again. ```javascript async function callWithBackoff(url, init) { while (true) { const res = await fetch(url, init); // Pre-emptive slowdown: if we're close to the cliff, pause. const remaining = parseInt(res.headers.get('X-RateLimit-Remaining'), 10); if (remaining setTimeout(r, Math.min(secsUntilReset * 50, 1000))); } if (res.status !== 429) return res; const retryAfter = parseFloat(res.headers.get('Retry-After')) || 1; await new Promise(r => setTimeout(r, retryAfter * 1000)); } } ``` ### Python equivalent ```python import time, requests def call_with_backoff(url, **kwargs): while True: r = requests.request(url=url, **kwargs) remaining = int(r.headers.get('X-RateLimit-Remaining', 1000)) if remaining 📘 The limit is generous on purpose 1,000/min is enough for almost any sane integration. If you're hitting it, the more common fix is to question why, usually it's a bug (e.g. polling instead of using triggers) rather than legitimate need. Macha's [triggers](/docs/api/triggers) are how you build event-driven integrations without polling. ## Failure mode: Macha can't check the limit If the rate-limit store itself is unavailable (rare but possible), Macha **fails open**, the request goes through without limit enforcement, and an error is logged on our side. We chose fail-open over fail-closed because losing rate limiting briefly is preferable to taking the entire API down. You won't see this from the client side, the request just succeeds normally. We monitor for sustained failures internally. --- # Versioning and Stability Source: https://www.getmacha.com/docs/api/versioning > The Macha API is versioned at /v1. What changes additively, what requires a new version, and how we deprecate. The Macha API is versioned at the URL path level: `/api/v1/...`. Customers can depend on v1 staying compatible with code written today. Breaking changes go to a new major version, we don't break v1 in place. ## What's in a version The v1 contract covers: - **URL structure.** Every endpoint URL under `/api/v1/` is stable. - **Authentication.** Bearer token format and scope catalog. - **Request shape.** Field names, types, required/optional, validation rules. - **Response shape.** Field names, types, the success/error envelope. - **Error codes.** The stable identifiers in `error.code`. - **Status codes.** Which HTTP code is returned for which condition. - **Pagination.** Cursor-based, opaque tokens. - **Idempotency.** The `Idempotency-Key` header semantics. - **Rate limits.** The headers always exist with this naming. What's *not* in the contract: - Exact rate limit numbers (we may raise the cap freely) - Exact error message strings (the `code` is stable; `message` may be reworded) - Internal storage formats (e.g. how cursors are encoded) - Response time, geographical routing, or HTTP/2 push behavior ## Non-breaking changes (ship into v1 freely) The following are considered additive and may ship into v1 without notice: - Adding a new endpoint - Adding a new optional request field - Adding a new response field - Adding a new error code - Adding a new query param to a list endpoint - Adding a new value to an enum that the customer doesn't pass (e.g. a new `sync_status` value) - Loosening a constraint (e.g. accepting longer names than before) 📘 Code defensively against new fields Your code shouldn't break when Macha adds a new field to a response. Don't use strict JSON schemas that reject unknown keys; use loose ones that ignore them. ## Breaking changes (require v2) The following require a new major version and we will NOT do them in v1: - Removing or renaming an endpoint - Removing or renaming a response field - Removing or renaming an error code - Changing the type of an existing field (e.g. string -> integer) - Making an optional request field required - Tightening validation (e.g. shortening the max-length cap for a field) - Adding a new enum value that the customer DOES pass (e.g. forcing them to handle a new `source` value) - Changing the response status code for an existing condition - Changing the auth scheme ## Stability tiers Within v1, every endpoint is one of: | Tier | Meaning | | stable | Shipped. Shape cannot change in a breaking way. Use freely. | | beta | Shipped. Shape may change with notice. Tagged in the OpenAPI spec and in the docs page header. | | planned | Documented but not yet implemented. Returns 404 or insufficient_scope if called today. Tracks our public roadmap. | The vast majority of v1 endpoints are **stable**. Any **beta** or **planned** endpoint is labeled prominently on its reference page. ## How you'll learn about changes - **Additions:** appear in the docs and the OpenAPI spec. Nothing else, no email blast for adding a new field. - **Beta -> stable:** announced in the change log. - **Stability downgrades:** we will never downgrade a **stable** endpoint to **beta** or **planned** without a new version. If we made a mistake and need to fix it, we ship the fix as a new endpoint, deprecate the old one (see below), and remove the old one only in v2. ## Deprecation If we need to retire an endpoint or field within v1: - The endpoint is marked **deprecated** in the docs and OpenAPI spec. - Responses include a `Deprecation` header with a date (RFC 9745 / Sunset header pattern). - A minimum of **6 months** elapse during which the endpoint still works. - At the end of the window, the endpoint *continues to work* until v2. Removal is a breaking change and only happens at version bumps. In practice, this means we may add a new better endpoint and deprecate the old one within v1, but you have at least 6 months to migrate at your leisure, the old endpoint keeps working until v2 ships (which itself is announced months ahead). ## How to know when v2 is coming v2 is not on the immediate roadmap. When we're seriously considering it, we'll: - Publish a v2 proposal as a doc page on this site (`/docs/api/v2-preview` or similar) - Make v2 available at `/api/v2/` in **beta** for a period of months while v1 stays live - Announce v1 deprecation only after v2 has been beta for at least 6 months - Keep v1 working for a minimum of **12 months** after deprecation announcement You will have at least 18 months from the v2 announcement to migrate. Macha is small enough that we can be conservative about this. ## API version vs SDK version vs Macha version Three different version numbers in the Macha world: | What | Where | Bumps when | | API version | /api/v1/ in URL | Breaking changes to the REST contract (rare). | | OpenAPI spec version | info.version in openapi.json | Any documented change to v1 (frequent). Follows semver against the spec itself. | | Macha product version | Marketing, release notes | Whenever we ship a meaningful new feature (continuous). | The API version is the only one that affects your code's compatibility. Spec and product versions can churn freely. --- # The agent object Resource: Agents Source: https://www.getmacha.com/docs/api/agents/the-agent-object > Shape of the Agent resource as returned by the Macha API. The `Agent` resource represents one AI copilot in your organization. Agents have instructions, a model, a set of tools (from connectors or custom HTTP endpoints), optional sub-agents to delegate to, and an active/inactive flag. ## Object shape ```json { "id": "agent_64f1c0ef2ec711ef6dc1dcf", "handle": "ticketTriage", "name": "Triage", "description": "Routes incoming Zendesk tickets to the right downstream agent.", "model": "gpt-5.4", "is_active": true, "color": "#000000", "avatar": "🚦", "tools_count": 2, "sub_agents_count": 4, "created_at": "2026-06-10T04:07:44.871Z", "updated_at": "2026-06-17T07:29:29.408Z" } ``` ## Attributes | Field | Type | Notes | | id | string | Prefixed identifier agent_<24 hex>. Treat as opaque. | | handle | string | camelCase alphanumeric (^[a-zA-Z][a-zA-Z0-9]*$). Used in @mentions. Unique within the org, case-insensitive. | | name | string | Display name shown in the dashboard. | | description | string | null | Short summary. Surfaced in the agent list. | | model | string | null | Model identifier, e.g. gpt-5.4, gpt-5-mini. null means org default. | | is_active | boolean | Whether the agent can be chatted with or fired by triggers. | | color | string | null | Hex color used for the agent avatar background. Default #6366f1. | | avatar | string | null | Emoji or URL. | | tools_count | integer | Number of tools assigned. Use the detail endpoint to enumerate. | | sub_agents_count | integer | Number of agents this one can hand off to. | | created_at | ISO 8601 | Always UTC. | | updated_at | ISO 8601 | Bumped on every PATCH. | ## Why `tools_count` instead of `tools[]`? List endpoints return the count, not the full array, because most agents have 5-30 tools and including them inflates list payloads by 10x without much benefit. The full `tools` array is documented but not yet returned by v1 read endpoints, you set it on create/update via the `tools` field but get back a count on read. If you need the full enumeration, request it (we'll add a `?expand=tools` parameter). ## Related - [List agents](/docs/api/agents/list-agents), pull every agent in the org - [Create an agent](/docs/api/agents/create-an-agent), full create request body - [Connectors](/docs/api/connectors), what tools can be assigned to an agent --- # List agents Resource: Agents Source: https://www.getmacha.com/docs/api/agents/list-agents Endpoint: GET /api/v1/agents > Returns a paginated list of agents in the organization. Returns a paginated list of agents in your organization, newest first. Soft-deleted agents are excluded by default; restore them from the dashboard trash if you need them back. **Scope:** agents:read ## Query parameters | Param | Type | Default | Notes | | cursor | string | | Opaque pagination token from a previous response's meta.next_cursor. Omit on the first request. | | limit | integer | 25 | Page size. Range 1-100. | ## Example request ```bash curl 'https://dashboard.getmacha.com/api/v1/agents?limit=10' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "agent_64f1c0ef2ec711ef6dc1dcf", "handle": "ticketTriage", "name": "Triage", "model": "gpt-5.4", "is_active": true, "tools_count": 2, "sub_agents_count": 4, "created_at": "2026-06-10T04:07:44.871Z", "updated_at": "2026-06-17T07:29:29.408Z" } ], "meta": { "request_id": "req_a0b88aa084bac0f7", "next_cursor": "agent_64f1c0ef2ec711ef6dc1dcd" } } ``` ## Walking the full list ```javascript async function listAllAgents() { const all = []; let cursor = null; while (true) { const params = new URLSearchParams({ limit: '100' }); if (cursor) params.set('cursor', cursor); const res = await fetch( `https://dashboard.getmacha.com/api/v1/agents?${params}`, { headers: { Authorization: `Bearer ${process.env.MACHA_API_KEY}` } }, ); const body = await res.json(); all.push(...body.data); if (!body.meta.next_cursor) break; cursor = body.meta.next_cursor; } return all; } ``` ## Errors | Status | Code | When | | 401 | unauthorized | Missing, invalid, or revoked API key. | | 403 | insufficient_scope | Key is valid but lacks agents:read. | | 422 | validation_failed | limit outside 1-100, or cursor malformed. | | 429 | rate_limited | You hit the per-minute or per-hour ceiling. Inspect Retry-After. | --- # Retrieve an agent Resource: Agents Source: https://www.getmacha.com/docs/api/agents/retrieve-an-agent Endpoint: GET /api/v1/agents/:id > Fetch a single agent by ID. Fetch a single agent by ID. Soft-deleted agents return `404 agent_not_found`, if you need to read trashed agents, restore them from the dashboard first. **Scope:** agents:read ## Path parameters | Param | Type | Notes | | :id | string | Agent identifier. Accepts the prefixed form (agent_64f1c0ef2ec711ef6dc1dcf) or a bare 24-character ObjectId. | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/agents/agent_64f1c0ef2ec711ef6dc1dcf \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "agent_64f1c0ef2ec711ef6dc1dcf", "handle": "ticketTriage", "name": "Triage", "description": "Routes incoming Zendesk tickets to the right downstream agent.", "model": "gpt-5.4", "is_active": true, "color": "#000000", "avatar": "🚦", "tools_count": 2, "sub_agents_count": 4, "created_at": "2026-06-10T04:07:44.871Z", "updated_at": "2026-06-17T07:29:29.408Z" }, "meta": { "request_id": "req_..." } } ``` ## Errors | Status | Code | When | | 401 | unauthorized | Missing, invalid, or revoked API key. | | 403 | insufficient_scope | Key lacks agents:read. | | 404 | agent_not_found | Unknown ID, soft-deleted past trash window, or belongs to another org. | | 429 | rate_limited | Per-key rate ceiling exceeded. | 📘 Bare ObjectIds work too If you have raw Mongo IDs lying around from older integrations, pass them directly, `/agents/64f1c0ef2ec711ef6dc1dcf` resolves the same as `/agents/agent_64f1c0ef2ec711ef6dc1dcf`. Responses always use the prefixed form. --- # Create an agent Resource: Agents Source: https://www.getmacha.com/docs/api/agents/create-an-agent Endpoint: POST /api/v1/agents > Create a new AI agent. Supports the Idempotency-Key header for safe retries. Create a new AI agent. Honors the `Idempotency-Key` header so retries don't create duplicates, see [Idempotency](/docs/api/idempotency). **Scope:** agents:write ## Request body | Field | Type | Required | Notes | | handle | string | yes | camelCase alphanumeric. Must be unique within the org (case-insensitive). | | name | string | yes | Display name. | | instructions | string | yes* | Plain text. Required unless instructions_html is provided. | | instructions_html | string | no | Rich text (HTML subset). Plain text is auto-derived for the system prompt. | | description | string | null | no | Short summary, surfaced in the dashboard agent list. | | model | string | no | Model ID. Defaults to org default. | | color | string | no | Hex color. Defaults to #6366f1. | | avatar | string | no | Emoji or URL. | | include_system_prompt | boolean | no | Defaults to true. | | tools | array | no | Array of { name, connector_id } tool refs. See below. | | connectors | array | no | Array of connector IDs. Derived from tools[].connector_id if omitted. | | sub_agents | array | no | Array of agent IDs to delegate to (handoff pattern). Cannot include this agent's own ID. | | data_sources | array | no | Array of { source_id, scope, documents } data source refs. | ## Sub-shapes ### Tool reference ```json { "name": "zendesk_get_ticket", "connector_id": "connector_64f1c0ef2ec711ef6dc1dcf" } ``` `name` is the base tool name (never the multi-instance suffix). `connector_id` may be `null` for built-in / knowledge tools. ### Data source reference ```json { "source_id": "source_64f1c0ef2ec711ef6dc1dcf", "scope": "selected", "documents": ["doc_abc...", "doc_def..."] } ``` `scope` is `"all"` or `"selected"`. When `"selected"`, `documents[]` is required. ## Example request ```bash curl -X POST https://dashboard.getmacha.com/api/v1/agents \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "handle": "wismo", "name": "WISMO", "instructions": "Answer Where Is My Order questions using the Shopify order tool. Never make up tracking info.", "model": "gpt-5", "tools": [ { "name": "shopify_get_order", "connector_id": "connector_abc..." }, { "name": "shopify_search_orders", "connector_id": "connector_abc..." }, { "name": "zendesk_add_public_reply", "connector_id": "connector_def..." } ] }' ``` ## Example response (201) ```json { "data": { "id": "agent_6a39a4f1c0ef2ec711ef6dc1", "handle": "wismo", "name": "WISMO", "model": "gpt-5", "is_active": true, "color": "#6366f1", "tools_count": 3, "sub_agents_count": 0, "created_at": "2026-06-24T10:42:00.000Z", "updated_at": "2026-06-24T10:42:00.000Z" }, "meta": { "request_id": "req_..." } } ``` ## Errors | Status | Code | When | | 401 | unauthorized | Bad / missing key. | | 403 | insufficient_scope | Key lacks agents:write. | | 409 | agent_handle_taken | Another agent already uses this handle. | | 409 | idempotency_key_reused | Idempotency-Key already used with a different body. | | 422 | validation_failed | Missing required field, bad handle format, unknown sub-agent, plan limit reached. | | 429 | rate_limited | Per-key ceiling exceeded. | --- # Update an agent Resource: Agents Source: https://www.getmacha.com/docs/api/agents/update-an-agent Endpoint: PATCH /api/v1/agents/:id > Partial update of an existing agent. Send only the fields you want to change. Partial update. Send only the fields you want to change, omitted fields stay unchanged. Honors `Idempotency-Key`. **Scope:** agents:write ## Path parameters | Param | Type | Notes | | :id | string | Agent ID (prefixed or bare). | ## Request body Any subset of the [create](/docs/api/agents/create-an-agent) body fields, plus: | Field | Type | Notes | | is_active | boolean | Activation guard: rejected with 422 if any assigned connector is in auth_failed state. Reconnect the connector first. | | deactivated_reason | string | null | Set/cleared by the system on cascade events; settable manually for diagnostics. | | deactivated_at | ISO 8601 | null | See above. | ## Side effects of `is_active` toggle Flipping `is_active` isn't just a flag, it cascades: - **Triggers:** deactivating the agent deactivates all of its triggers. Activating reactivates them. Zendesk webhooks are *soft-toggled* in place (status flipped on Zendesk's side) rather than torn down and recreated, so the webhook ID that the customer's own Zendesk Triggers reference is preserved. - **Chatbots:** any chatbot bound to this agent is paused/resumed. ## Example: deactivate an agent ```bash curl -X PATCH https://dashboard.getmacha.com/api/v1/agents/agent_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "is_active": false }' ``` ## Example: move an agent to a different model ```bash curl -X PATCH https://dashboard.getmacha.com/api/v1/agents/agent_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "model": "gpt-5.4" }' ``` ## Example: replace the tool list entirely ```bash curl -X PATCH https://dashboard.getmacha.com/api/v1/agents/agent_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "tools": [ { "name": "zendesk_get_ticket", "connector_id": "connector_..." }, { "name": "zendesk_update_priority", "connector_id": "connector_..." } ] }' ``` Passing `tools` replaces the whole array, there's no PATCH-style "add this tool" or "remove this tool" today. Read the agent first, then send the desired final array. ## Errors | Status | Code | When | | 404 | agent_not_found | Unknown ID or soft-deleted past trash window. | | 409 | agent_handle_taken | Renaming to a handle that already exists. | | 422 | validation_failed | Bad handle format, unhealthy-connector activation block, plan limit on custom tools, self-referencing sub-agent, etc. | ⚠ Tools are replace-not-merge Sending `"tools": [X]` drops every other tool the agent had. To add a tool while keeping the existing ones, read the agent's current tool list, append X, then PATCH the full array back. --- # Delete an agent Resource: Agents Source: https://www.getmacha.com/docs/api/agents/delete-an-agent Endpoint: DELETE /api/v1/agents/:id > Soft-delete an agent. Restorable from the dashboard trash for 30 days. **Soft delete.** The agent moves to the dashboard trash and is restorable for 30 days. After 30 days the cleanup scheduler hard-deletes. **Scope:** agents:delete ## Path parameters | Param | Type | Notes | | :id | string | Agent ID (prefixed or bare). | ## Side effects - All triggers on the agent are deactivated. External webhooks (Zendesk) are torn down so traffic stops immediately. - Chatbots bound to the agent are paused. - The agent disappears from `GET /agents` listings but is visible in the dashboard's trash view. ## Example request ```bash curl -X DELETE https://dashboard.getmacha.com/api/v1/agents/agent_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response (200) ```json { "data": { "id": "agent_64f1c0...", "deleted": true }, "meta": { "request_id": "req_..." } } ``` ## Idempotency DELETE is naturally idempotent, the second call returns `404 agent_not_found` instead of a duplicate effect. No need to pass `Idempotency-Key`. ## Restoring a deleted agent There's no API endpoint to restore yet, head to the dashboard's trash view to restore. When that's added it'll appear here. ## Errors | Status | Code | When | | 401 | unauthorized | Bad / missing key. | | 403 | insufficient_scope | Key lacks agents:delete. | | 404 | agent_not_found | Unknown ID or already deleted past trash window. | | 429 | rate_limited | Per-key ceiling exceeded. | ⛔ Triggers are torn down, not deactivated Deleting an agent calls the connector's webhook-delete API. Restoring the agent later won't auto-restore the external webhooks, you'll have to recreate triggers manually or wait for the cascade restore (planned but not yet shipped). --- # The conversation object Resource: Conversations Source: https://www.getmacha.com/docs/api/conversations/the-conversation-object > Shape of the Conversation resource, what's saved when a user (or trigger) chats with an agent. The `Conversation` resource is the persistent record of a chat between an agent and a user (or a webhook). Every message, every tool call, every sub-agent handoff lives inside a conversation. ## Object shape ```json { "id": "conv_6a392325b438d825ccaf0dc1", "title": "process ticket 549", "source": "autonomous", "agent_id": "agent_6a28e310f2ec711ef6dc1dcf", "model": "gpt-5", "autonomous": true, "is_onboarding": false, "is_simulation": false, "conversation_number": 225, "parent_conversation_id": null, "credits_used": 3, "metadata": { "ticketId": 549, "webhookReceivedAt": "2026-06-10T05:25:59.439Z" }, "message_count": 6, "last_message_at": "2026-06-10T05:26:55.455Z", "created_at": "2026-06-10T05:25:59.447Z", "updated_at": "2026-06-10T05:26:56.048Z" } ``` ## Attributes | Field | Type | Notes | | id | string | Prefixed identifier conv_<24 hex>. | | title | string | null | LLM-generated summary of what the conversation is about. | | source | enum | "dashboard" | "autonomous" | "embed" | "sub-agent". How the conversation started. | | agent_id | string | null | Which agent handled it. Null on agent-less conversations. | | model | string | null | Model that ran the conversation. May be null if it predates model tracking. | | autonomous | boolean | true if fired by a webhook/scheduled trigger, not a user. | | is_onboarding | boolean | The one-time post-onboarding welcome conversation. | | is_simulation | boolean | Test runs fired via the agent builder's "Test run" button. | | conversation_number | integer | null | Per-org sequence number. null for sub-agent runs (they don't get a number). | | parent_conversation_id | string | null | Set on sub-agent runs. Points at the parent conversation. | | credits_used | integer | Credits deducted across all assistant responses in this conversation. | | metadata | object | null | Free-form. Common keys: ticketId, ticket_id, plus connector-specific extras. Filterable via ?metadata[KEY]=VALUE. | | message_count | integer | null | Number of messages. Returns null in list responses (perf cost); the detail endpoint returns the real count. | | last_message_at | ISO 8601 | Updated on every new message. | | created_at | ISO 8601 | Always UTC. | | updated_at | ISO 8601 | Bumped on any change. | ## Two response shapes Conversation endpoints return either the **summary** shape (above) or the **detail** shape (summary + `messages[]`): - [List endpoint](/docs/api/conversations/list-conversations) returns summaries (no messages). - [Retrieve endpoint](/docs/api/conversations/retrieve-a-conversation) returns the detail (with full message thread). - [Messages endpoint](/docs/api/conversations/list-conversation-messages) paginates a single conversation's messages. ### The `messages[]` array Each message has its own shape: ```json { "id": "msg_64f1c0...", "role": "user" | "assistant" | "tool" | "system", "content": "...", "tool_calls": [ { "id": "call_abc", "name": "zendesk_get_ticket", "arguments": "{...}", "status": "completed" } ], "tool_call_id": null, "tool_name": null, "connector_type": null, "model": "gpt-5.4", "created_at": "2026-06-10T05:25:59.500Z" } ``` For `role: "tool"` messages, `content` is usually a JSON-stringified blob, consumers should attempt `JSON.parse` before treating it as text. `tool_calls` is only set on assistant messages that invoked tools. ## The `trigger_payload` field (opt-in) For autonomous conversations, the raw webhook payload that fired the run is stored alongside the conversation. It's **not** returned by default because it can contain customer PII (requester email, ticket body, custom fields). Pass `?include_trigger_payload=true` on the retrieve endpoint to opt in. 📘 message_count is null in lists by design Computing message counts at list time requires loading every conversation's full message array, a perf cliff we deliberately avoid. The detail endpoint loads the array and returns the real count. --- # List conversations Resource: Conversations Source: https://www.getmacha.com/docs/api/conversations/list-conversations Endpoint: GET /api/v1/conversations > Search and filter your org's conversation history by agent, date, ticket ID, model, or title keyword. Returns a paginated list of conversations, newest first. Rich filter surface lets you search by ticket ID, metadata, date range, model, title keyword, and source. **Scope:** conversations:read ## Default behavior By default every conversation is visible **except sub-agent runs**, which are excluded because they'd dominate the list for any org running multi-agent workflows. To see sub-agent runs, pass `source=sub-agent` explicitly. ## Query parameters ### Pagination | Param | Type | Default | Notes | | cursor | string | | Opaque token from a previous response's meta.next_cursor. | | limit | integer | 25 | Range 1-100. | ### Resource filters | Param | Type | Notes | | agent_id | string | Filter to one agent. Accepts agent_<24 hex> or a bare ObjectId. | | source | enum | dashboard | autonomous | embed | sub-agent. Sub-agent runs only appear when explicitly requested. | | model | string | Exact match against the model used (e.g. gpt-5-mini). | | parent_conversation_id | string | Filter to sub-agent runs of one parent conversation. | | conversation_number | integer | Exact match against the per-org sequence number. ?conversation_number=42 fetches conversation #42. | ### Date filters | Param | Type | Notes | | since | ISO 8601 | last_message_at >= since. Back-compat alias for last_message_after. | | created_after / created_before | ISO 8601 | Half-open range on created_at. | | last_message_after / last_message_before | ISO 8601 | Half-open range on last_message_at. | ### Metadata + search | Param | Type | Notes | | ticket_id | string or integer | Shorthand. Matches metadata.ticketId, metadata.ticket_id, OR triggerPayload.ticket.id. Both string and numeric storage forms checked. | | metadata[KEY] | string | Match against the Mixed metadata field by bracket notation: ?metadata[priority]=high&metadata[region]=apac. String and numeric forms tried; "true"/"false" also coerced to boolean. Keys with $ or . are silently dropped to prevent operator injection. | | q | string | Case-insensitive regex search against title only. Special regex characters escaped, paste search terms verbatim. | ## Examples ### Find conversations about ticket 12345 ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?ticket_id=12345' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ### Autonomous conversations from last week using gpt-5-mini ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?source=autonomous&model=gpt-5-mini&created_after=2026-06-17T00:00:00Z' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ### Sub-agent runs of one parent ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?source=sub-agent&parent_conversation_id=conv_6a28f567ba502f55d177bb50' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ### Conversations tagged with custom metadata ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations?metadata%5Bpriority%5D=high&metadata%5Bregion%5D=apac' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "conv_6a392325b438d825ccaf0dc1", "title": "process ticket 549", "source": "autonomous", "agent_id": "agent_6a28e310f2ec711ef6dc1dcf", "model": "gpt-5", "autonomous": true, "is_onboarding": false, "is_simulation": false, "conversation_number": 225, "parent_conversation_id": null, "credits_used": 3, "metadata": { "ticketId": 549 }, "message_count": null, "last_message_at": "2026-06-10T05:26:55.455Z", "created_at": "2026-06-10T05:25:59.447Z", "updated_at": "2026-06-10T05:26:56.048Z" } ], "meta": { "request_id": "req_...", "next_cursor": "conv_6a28f567ba502f55d177bb50" } } ``` ## Errors | Status | Code | When | | 401 | unauthorized | Missing / invalid / revoked key. | | 403 | insufficient_scope | Key lacks conversations:read. | | 422 | validation_failed | Bad date format, unknown source value, malformed cursor, etc. | | 429 | rate_limited | Per-key ceiling exceeded. | ⚠ Don't change filters mid-traversal The cursor is filter-scoped. Restart from scratch (no cursor) when you change the filter set. --- # Retrieve a conversation Resource: Conversations Source: https://www.getmacha.com/docs/api/conversations/retrieve-a-conversation Endpoint: GET /api/v1/conversations/:id > Fetch a conversation by ID, including the full message thread. Fetch a conversation by ID, including the full message thread. **Scope:** conversations:read ## Path parameters | Param | Type | Notes | | :id | string | Conversation ID (conv_<24 hex> or bare ObjectId). | ## Query parameters | Param | Type | Notes | | include_trigger_payload | true | 1 | When set, the raw webhook payload that fired this autonomous run is returned as trigger_payload. Off by default because trigger payloads can contain customer PII (requester email, ticket body, custom field values). | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/conversations/conv_6a392325b438d825ccaf0dc1 \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example request with trigger payload ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations/conv_6a392325...?include_trigger_payload=true' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "conv_6a392325b438d825ccaf0dc1", "title": "process ticket 549", "source": "autonomous", "agent_id": "agent_6a28e310f2ec711ef6dc1dcf", "model": "gpt-5", "autonomous": true, "is_onboarding": false, "is_simulation": false, "conversation_number": 225, "parent_conversation_id": null, "credits_used": 3, "metadata": { "ticketId": 549 }, "message_count": 6, "last_message_at": "2026-06-10T05:26:55.455Z", "created_at": "2026-06-10T05:25:59.447Z", "updated_at": "2026-06-10T05:26:56.048Z", "messages": [ { "id": "msg_...", "role": "user", "content": "process ticket 549", "created_at": "2026-06-10T05:25:59.500Z" }, { "id": "msg_...", "role": "assistant", "content": "", "tool_calls": [...], "created_at": "..." } ] }, "meta": { "request_id": "req_..." } } ``` ## For very long conversations If `message_count` is in the hundreds, loading the full thread on every request is wasteful. Use [List conversation messages](/docs/api/conversations/list-conversation-messages) instead to paginate. ## Errors | Status | Code | When | | 404 | conversation_not_found | Unknown ID, or conversation belongs to another org. | --- # List conversation messages Resource: Conversations Source: https://www.getmacha.com/docs/api/conversations/list-conversation-messages Endpoint: GET /api/v1/conversations/:id/messages > Paginate messages of one conversation. Useful when the message thread is large. Paginate the messages of a single conversation. Useful when the conversation has hundreds of messages and you don't want to load the whole thread at once. **Scope:** conversations:read ## Sort order This endpoint returns messages **oldest first**, the natural reading order of a chat thread. This is the opposite of the conversation *list* endpoint (which is newest first). ## Path parameters | Param | Type | Notes | | :id | string | Conversation ID. | ## Query parameters | Param | Type | Default | Notes | | cursor | string | | Message ID from a previous response's meta.next_cursor. Format: msg_<24 hex>. | | limit | integer | 50 | Page size. Range 1-100. | ## Example request ```bash curl 'https://dashboard.getmacha.com/api/v1/conversations/conv_6a392325.../messages?limit=20' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "msg_64f1c0...", "role": "user", "content": "process ticket 549", "tool_calls": null, "tool_call_id": null, "tool_name": null, "connector_type": null, "model": null, "created_at": "2026-06-10T05:25:59.500Z" }, { "id": "msg_64f1c1...", "role": "assistant", "content": "", "tool_calls": [ { "id": "call_abc", "name": "zendesk_get_ticket", "arguments": "{\"id\":549}", "status": "completed" } ], "tool_call_id": null, "tool_name": null, "connector_type": null, "model": "gpt-5", "created_at": "2026-06-10T05:26:01.100Z" }, { "id": "msg_64f1c2...", "role": "tool", "content": "{\"id\":549,\"subject\":\"Refund please\",\"status\":\"open\"}", "tool_call_id": "call_abc", "tool_name": "zendesk_get_ticket", "connector_type": "zendesk", "created_at": "2026-06-10T05:26:01.450Z" } ], "meta": { "request_id": "req_...", "next_cursor": "msg_64f1c2..." } } ``` ## Tool messages, parse the content For `role: "tool"` messages, `content` is a JSON-stringified blob containing the tool's response. Attempt `JSON.parse` before treating it as text: ```javascript function parseMessageContent(msg) { if (msg.role !== 'tool') return msg.content; try { return JSON.parse(msg.content); } catch { return msg.content; } // not JSON, return raw string } ``` ## Errors | Status | Code | When | | 404 | conversation_not_found | Unknown conversation ID. | | 422 | validation_failed | Bad cursor, limit out of range, etc. | --- # The connector object Resource: Connectors Source: https://www.getmacha.com/docs/api/connectors/the-connector-object > Shape of the Connector resource, a third-party integration like Zendesk, Slack, or Shopify. A `Connector` represents one configured instance of a third-party integration, one Zendesk account, one Slack workspace, one Shopify store. Connectors expose the *tools* agents can call. ## Object shape (summary) ```json { "id": "connector_64f1c0ef2ec711ef6dc1dcf", "type": "zendesk", "name": "Production Zendesk", "status": "connected", "status_reason": null, "is_active": true, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ``` ## Detail shape (with tool surface) The single-connector endpoint adds a `tools[]` array listing every tool this connector type exposes. Use this to know which tool names you can assign to agents. ```json { "id": "connector_64f1c0...", "type": "zendesk", "name": "Production Zendesk", "status": "connected", "is_active": true, "tools": [ { "name": "zendesk_get_ticket", "label": "Get Zendesk Ticket", "description": "Fetch a ticket by ID.", "type": "read", "requires_confirmation": false, "disabled": false } ] } ``` ## Attributes | Field | Type | Notes | | id | string | connector_<24 hex>. | | type | string | e.g. zendesk, slack, shopify, notion, freshdesk, stripe. See the integrations directory for the full list. | | name | string | Display name. Distinguishes multiple instances of the same type ("Production Zendesk" vs "Sandbox Zendesk"). | | status | enum | "connected" | "auth_failed" | "token_expired". Drives agent deactivation cascades. | | status_reason | string | null | Human-readable reason when status is not connected. | | is_active | boolean | Whether the connector is enabled. Inactive connectors are hidden from agent tool pickers. | | created_at | ISO 8601 | When the connector was added. | | updated_at | ISO 8601 | Bumped on status changes and reconfigurations. | ### The `tools[]` array (detail only) | Field | Type | Notes | | name | string | Base tool name. Use this when assigning to an agent. | | label | string | Human-friendly name shown in the dashboard. | | description | string | LLM-facing description. | | type | enum | "read" or "write". Write tools require approval in chat (read tools auto-execute). | | requires_confirmation | boolean | Whether agents must ask before executing. | | disabled | boolean | true if this tool has been turned off for this connector instance via the dashboard. | ## Why credentials are never returned API keys, OAuth tokens, refresh tokens, signing secrets, none of these are ever exposed via the API. They're encrypted at rest and only used server-side when agents call tools. Even the masked-credential hint shown in the dashboard catalog is computed at request time and not part of the public connector object. 📘 Connector creation is dashboard-only in v1 OAuth flows for connectors require redirect URIs and browser-driven user consent, which doesn't fit the headless REST model. Add and disconnect connectors in the dashboard; read their state via the API. --- # List connectors Resource: Connectors Source: https://www.getmacha.com/docs/api/connectors/list-connectors Endpoint: GET /api/v1/connectors > Returns every connector instance configured in your organization. Returns every connector instance configured in your organization. **Scope:** connectors:read ## Query parameters | Param | Type | Default | Notes | | cursor | string | | Opaque pagination token. | | limit | integer | 25 | Range 1-100. | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/connectors \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "connector_64f1c0ef2ec711ef6dc1dcf", "type": "zendesk", "name": "Production Zendesk", "status": "connected", "is_active": true, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" }, { "id": "connector_64f1c0ef2ec711ef6dc1dc0", "type": "slack", "name": "Customer Success Slack", "status": "connected", "is_active": true, "created_at": "2026-06-05T00:00:00.000Z", "updated_at": "2026-06-05T00:00:00.000Z" } ], "meta": { "request_id": "req_...", "next_cursor": null } } ``` ## Watch for `auth_failed` connectors If a connector returns `"status": "auth_failed"`, every agent that uses tools from it has been auto-deactivated. The fix is to reconnect the integration in the dashboard. The API does not expose a reconnect endpoint in v1. ## Errors | Status | Code | When | | 401 | unauthorized | Bad / missing key. | | 403 | insufficient_scope | Key lacks connectors:read. | --- # Retrieve a connector Resource: Connectors Source: https://www.getmacha.com/docs/api/connectors/retrieve-a-connector Endpoint: GET /api/v1/connectors/:id > Fetch a connector with its full tool surface so you can plan which tools to assign to an agent. Fetch a single connector by ID, including the full `tools[]` surface so you can plan which tools to assign to an agent. **Scope:** connectors:read ## Path parameters | Param | Type | Notes | | :id | string | connector_<24 hex> or bare ObjectId. | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/connectors/connector_64f1c0ef2ec711ef6dc1dcf \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "connector_64f1c0ef2ec711ef6dc1dcf", "type": "zendesk", "name": "Production Zendesk", "status": "connected", "status_reason": null, "is_active": true, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z", "tools": [ { "name": "zendesk_get_ticket", "label": "Get Ticket", "description": "Fetch a Zendesk ticket by ID.", "type": "read", "requires_confirmation": false, "disabled": false }, { "name": "zendesk_add_public_reply", "label": "Add Public Reply", "description": "Post a public reply to a ticket. Awaits approval before sending.", "type": "write", "requires_confirmation": true, "disabled": false } ] }, "meta": { "request_id": "req_..." } } ``` ## Using the tool list When creating or updating an agent, pass tool refs as `{ name, connector_id }`. The `name` values come from this endpoint's `tools[].name`: ```javascript // 1. Fetch the connector const conn = await fetch('https://dashboard.getmacha.com/api/v1/connectors/' + connectorId, { headers: { Authorization: `Bearer ${process.env.MACHA_API_KEY}` } }).then(r => r.json()); // 2. Filter to read-only tools, build refs const readTools = conn.data.tools .filter(t => t.type === 'read' && !t.disabled) .map(t => ({ name: t.name, connector_id: conn.data.id })); // 3. Assign to an agent await fetch('https://dashboard.getmacha.com/api/v1/agents', { method: 'POST', headers: { Authorization: `Bearer ${process.env.MACHA_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ handle: 'readOnlyZendesk', name: 'Read-only Zendesk', instructions: 'Answer questions using Zendesk data. Never modify tickets.', tools: readTools, }), }); ``` ## Errors | Status | Code | When | | 404 | not_found | Unknown connector ID or belongs to another org. | --- # The custom tool object Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/the-custom-tool-object > Shape of a Custom Tool, a user-defined HTTP endpoint that agents can call as if it were a built-in tool. A `CustomTool` is a user-defined HTTP endpoint exposed to agents as if it were a built-in tool. Define the method, URL, parameters, and auth once; assign to any agent. ## Object shape ```json { "id": "tool_64f1c0ef2ec711ef6dc1dcf", "name": "custom_list_postmark_templates", "label": "List Postmark Templates", "description": "Returns the list of email templates from Postmark.", "type": "read", "method": "GET", "url": "https://api.postmarkapp.com/templates", "headers": { "Accept": "application/json" }, "body_template": null, "parameters": [ { "name": "count", "type": "integer", "description": "How many templates to return.", "required": false, "in": "query" } ], "auth": { "type": "api_key", "header_name": "X-Postmark-Server-Token" }, "group": { "name": "Postmark", "icon": null, "color": null }, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | tool_<24 hex>. | | name | string | Auto-generated slug from label, prefixed custom_. Immutable after creation. Used in agent.tools[].name. | | label | string | Human-friendly display name. Include the connector + resource ("List Postmark Templates", not "List Templates"). | | description | string | LLM-facing description. Determines when the tool gets called. | | type | enum | "read" or "write". Write tools require approval in chat. | | method | enum | GET | POST | PUT | PATCH | DELETE. | | url | string | Endpoint URL. May contain {{param}} placeholders substituted at call time. | | headers | object | Static headers map, e.g. { "Accept": "application/json" }. | | body_template | string | null | JSON string template for POST/PUT/PATCH bodies. Supports {{param}}. | | parameters | array | See below. | | auth | object | Type + header_name only. Credentials NEVER returned. | | group | object | null | UI grouping. { name, icon, color }. | | created_at | ISO 8601 | Always UTC. | | updated_at | ISO 8601 | Bumped on every PATCH. | ### Parameter shape ```json { "name": "ticket_id", "type": "string", "description": "Ticket ID to fetch.", "required": true, "in": "query" | "header" | "body", "headerName": "X-Ticket-Id" } ``` ### Auth shape (read) Reads return type + header_name only: ```json { "type": "none" | "bearer" | "api_key" | "basic", "header_name": "X-API-Key" } ``` ### Auth shape (write input) Writes accept credentials, encrypted at rest, never returned: ```json { "type": "api_key", "credentials": { "apiKey": "secret-here", "header_name": "X-API-Key" } } ``` 🔒 Credentials are write-only Send `auth.credentials` on create/update. Read responses contain only the auth type and (for `api_key`) the header name. The secret itself is bcrypt-hashed and never returned. --- # List custom tools Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/list-custom-tools Endpoint: GET /api/v1/custom_tools > Returns every custom HTTP tool defined for your organization. Returns every custom HTTP tool defined for your organization. **Scope:** custom_tools:read ## Query parameters | Param | Type | Default | | cursor | string | | | limit | integer | 25 | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/custom_tools \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "tool_64f1c0...", "name": "custom_list_postmark_templates", "label": "List Postmark Templates", "description": "Returns the list of email templates from Postmark.", "type": "read", "method": "GET", "url": "https://api.postmarkapp.com/templates", "auth": { "type": "api_key", "header_name": "X-Postmark-Server-Token" }, "parameters": [], "group": { "name": "Postmark", "icon": null, "color": null }, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ], "meta": { "request_id": "req_...", "next_cursor": null } } ``` ## Errors | Status | Code | When | | 401 | unauthorized | Bad / missing key. | | 403 | insufficient_scope | Key lacks custom_tools:read. | --- # Retrieve a custom tool Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/retrieve-a-custom-tool Endpoint: GET /api/v1/custom_tools/:id > Fetch a single custom tool by ID. Fetch a single custom tool by ID. **Scope:** custom_tools:read ## Path parameters | Param | Type | Notes | | :id | string | tool_<24 hex> or bare ObjectId. | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/custom_tools/tool_64f1c0ef2ec711ef6dc1dcf \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Errors | Status | Code | When | | 404 | custom_tool_not_found | Unknown ID, or tool deleted. | --- # Create a custom tool Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/create-a-custom-tool Endpoint: POST /api/v1/custom_tools > Wire up any HTTP endpoint as a tool agents can call. Wire up any HTTP endpoint as a tool agents can call. The tool's `name` is auto-generated from `label` (slugified, prefixed `custom_`, deduped within the org). **Scope:** custom_tools:write ## Request body | Field | Type | Required | Notes | | label | string | yes | Human-readable name. Include connector + resource ("List Postmark Templates", not "List Templates"). | | description | string | yes | LLM-facing description. Decides when the tool gets called. | | method | enum | yes | GET | POST | PUT | PATCH | DELETE. | | url | string | yes | Endpoint URL. May contain {{param}} placeholders. | | type | enum | no | "read" or "write". Defaults to read. | | headers | object | no | Static headers map. | | body_template | string | no | JSON template for POST/PUT/PATCH bodies. Supports {{param}}. | | parameters | array | no | See below. | | response_mapping | string | no | Dot path to extract from the response, e.g. data.items. | | auth | object | no | Auth type + credentials. Omitted = no auth. | | group | object | no | UI grouping { name, icon, color }. | ## Auth shape ```json { "type": "bearer" | "api_key" | "basic" | "none", "credentials": { "token": "...", // bearer "apiKey": "...", // api_key "header_name": "...", // api_key (default "X-API-Key") "username": "...", // basic "password": "..." // basic } } ``` ## Example request ```bash curl -X POST https://dashboard.getmacha.com/api/v1/custom_tools \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "label": "List Postmark Templates", "description": "Returns email templates from Postmark.", "method": "GET", "url": "https://api.postmarkapp.com/templates", "type": "read", "parameters": [ { "name": "count", "type": "integer", "description": "How many templates to return.", "in": "query" } ], "auth": { "type": "api_key", "credentials": { "apiKey": "your-postmark-token", "header_name": "X-Postmark-Server-Token" } }, "group": { "name": "Postmark" } }' ``` ## Errors | Status | Code | When | | 409 | custom_tool_name_taken | A tool with the same generated name already exists. | | 422 | validation_failed | Missing required field, bad method, etc. | --- # Update a custom tool Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/update-a-custom-tool Endpoint: PATCH /api/v1/custom_tools/:id > Change parameters, headers, body template, or rotate auth credentials. Partial update. Send only the fields you want to change. The tool's `name` is immutable, rename means delete + recreate. **Scope:** custom_tools:write ## Path parameters | Param | Type | | :id | string | ## Request body Any subset of [create](/docs/api/custom-tools/create-a-custom-tool) body fields, plus: | Field | Type | Notes | | is_active | boolean | Disable without deleting. Disabled tools don't appear in agent pickers. | ## Rotating credentials Send a fresh `auth.credentials` object. The encrypted blob is replaced entirely. The previous credential is unrecoverable. ```bash curl -X PATCH https://dashboard.getmacha.com/api/v1/custom_tools/tool_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "auth": { "type": "api_key", "credentials": { "apiKey": "NEW-postmark-token", "header_name": "X-Postmark-Server-Token" } } }' ``` ## Errors | Status | Code | When | | 404 | custom_tool_not_found | Unknown ID. | | 422 | validation_failed | Bad enum value, malformed auth, etc. | --- # Delete a custom tool Resource: Custom tools Source: https://www.getmacha.com/docs/api/custom-tools/delete-a-custom-tool Endpoint: DELETE /api/v1/custom_tools/:id > Hard-delete a custom tool. Removed from every agent that referenced it. **Hard delete.** Custom tools have no trash UI. The tool is removed and pulled from every `agent.tools[]` array in the org in the same transaction. **Scope:** custom_tools:delete ## Path parameters | Param | Type | | :id | string | ## Example request ```bash curl -X DELETE https://dashboard.getmacha.com/api/v1/custom_tools/tool_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "tool_64f1c0...", "deleted": true }, "meta": { "request_id": "req_..." } } ``` ## Errors | Status | Code | When | | 404 | custom_tool_not_found | Unknown ID or already deleted. | ⚠ Cascade is automatic Every agent that referenced this tool has it pulled from its `tools[]` array. Affected agents keep working, just without this tool. --- # The source object Resource: Data sources Source: https://www.getmacha.com/docs/api/sources/the-source-object > Shape of a Data Source, uploaded files, scraped websites, or connector-backed knowledge bases. A `Source` is a knowledge base an agent can read from, an uploaded file collection, a scraped website, a single webpage, or a connector-backed source (Google Drive, Notion, Zendesk Help Center). ## Object shape ```json { "id": "source_64f1c0ef2ec711ef6dc1dcf", "type": "website", "name": "Macha Marketing Site", "connector_id": null, "connector_type": null, "sync_status": "ready", "last_sync_at": "2026-06-20T12:00:00.000Z", "document_count": 42, "is_active": true, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | source_<24 hex>. | | type | enum | upload | website | webpage | connector. See the four-type table below. | | name | string | Display name. | | connector_id | string | null | For type=connector, the connector this source is bound to. | | connector_type | string | null | e.g. google, notion, confluence, zendesk. | | sync_status | string | ready | fetching | syncing | error. | | last_sync_at | ISO 8601 | null | When the last sync completed. | | document_count | integer | null | How many documents are indexed. | | is_active | boolean | Whether agents can query it. | | created_at | ISO 8601 | Always UTC. | | updated_at | ISO 8601 | Bumped on changes. | ## The four source types | Type | How it's created | API-creatable? | | upload | Singleton, auto-provisioned per org. Holds files uploaded via the dashboard. | No (always exists). API POST returns 409. | | connector | Auto-created when the connector is added (Google / Notion / Confluence / Zendesk HC). | No. API POST returns 422, use the connector flow. | | website | Full-site crawl. | Yes via POST. | | webpage | Single page. | Yes via POST. | ## Sync lifecycle Indexing is asynchronous. When you POST a website source, the response returns `sync_status: "fetching"`. Agents can't query it until `sync_status: "ready"`. Poll the source by ID to check progress. 📘 No PATCH in v1 Sources are immutable after creation. To change a source, delete and recreate it. --- # List data sources Resource: Data sources Source: https://www.getmacha.com/docs/api/sources/list-sources Endpoint: GET /api/v1/sources > Returns every source configured for your organization. Returns every source configured for your organization. **Scope:** sources:read ## Query parameters | Param | Type | Default | | cursor | string | | | limit | integer | 25 | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/sources \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "source_64f1c0ef2ec711ef6dc1dcf", "type": "website", "name": "Macha Marketing Site", "sync_status": "ready", "last_sync_at": "2026-06-20T12:00:00.000Z", "document_count": 42, "is_active": true, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ], "meta": { "request_id": "req_...", "next_cursor": null } } ``` --- # Retrieve a data source Resource: Data sources Source: https://www.getmacha.com/docs/api/sources/retrieve-a-source Endpoint: GET /api/v1/sources/:id > Fetch a single source by ID. Fetch a single source by ID. Useful for polling `sync_status` on a freshly-created source. **Scope:** sources:read ## Path parameters | Param | Type | | :id | string | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/sources/source_64f1c0ef2ec711ef6dc1dcf \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Errors | Status | Code | When | | 404 | source_not_found | Unknown ID or belongs to another org. | --- # Create a data source Resource: Data sources Source: https://www.getmacha.com/docs/api/sources/create-a-source Endpoint: POST /api/v1/sources > Add a website or webpage as a knowledge source. Upload sources are dashboard-only; connector sources auto-create with the integration. Create a `website` or `webpage` knowledge source. Indexing happens asynchronously, the response returns `sync_status: "fetching"` and the agent's `search_knowledge` tool becomes useful once `sync_status: "ready"`. **Scope:** sources:write ## Request body | Field | Type | Required | Notes | | type | enum | yes | "website" or "webpage". upload returns 409 (singleton already exists); connector returns 422 (auto-created with the integration). | | name | string | yes | Display name. | | config.url | string | yes | The starting URL. | | config.indexed | boolean | no | Default false. When true, content is chunked + embedded and becomes searchable via search_knowledge. | ## Example: create a website source ```bash curl -X POST https://dashboard.getmacha.com/api/v1/sources \ -H "Authorization: Bearer $MACHA_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "type": "website", "name": "Macha Help Center", "config": { "url": "https://www.getmacha.com/docs", "indexed": true } }' ``` ## Example response (201) ```json { "data": { "id": "source_6a39a4f1c0ef2ec711ef6dc1", "type": "website", "name": "Macha Help Center", "sync_status": "fetching", "last_sync_at": null, "document_count": null, "is_active": true, "created_at": "2026-06-24T10:42:00.000Z", "updated_at": "2026-06-24T10:42:00.000Z" }, "meta": { "request_id": "req_..." } } ``` ## Polling for completion ```javascript async function waitForSync(sourceId) { while (true) { const res = await fetch(`https://dashboard.getmacha.com/api/v1/sources/${sourceId}`, { headers: { Authorization: `Bearer ${process.env.MACHA_API_KEY}` } }); const body = await res.json(); if (body.data.sync_status === 'ready') return body.data; if (body.data.sync_status === 'error') throw new Error('Sync failed'); await new Promise(r => setTimeout(r, 5000)); } } ``` ## Errors | Status | Code | When | | 409 | upload_source_exists | type=upload, the singleton is already provisioned. | | 422 | validation_failed | Missing field, bad type, type=connector, plan limit reached. | --- # Delete a data source Resource: Data sources Source: https://www.getmacha.com/docs/api/sources/delete-a-source Endpoint: DELETE /api/v1/sources/:id > Hard-delete a source. Cascades to documents and agent references. **Hard delete.** Removes every `Document` belonging to the source AND pulls the source reference from every agent's `data_sources[]` array. No trash / restore. **Scope:** sources:delete ## Path parameters | Param | Type | | :id | string | ## Example request ```bash curl -X DELETE https://dashboard.getmacha.com/api/v1/sources/source_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "source_64f1c0...", "deleted": true }, "meta": { "request_id": "req_..." } } ``` ## Errors | Status | Code | When | | 404 | source_not_found | Unknown ID or already deleted. | ⛔ Irreversible Documents are hard-deleted. If the source was indexed, all chunks and embeddings are gone too. Agents that depended on this source for knowledge searches will return empty results until the source is re-added and re-indexed. --- # The chatbot object Resource: Chatbots Source: https://www.getmacha.com/docs/api/chatbots/the-chatbot-object > Shape of an embeddable chatbot, the widget config that customers embed on their site to expose a Macha agent. A `Chatbot` is the embeddable widget configuration that customers paste onto their site to expose a Macha agent. Each chatbot binds one agent to one or more domains, with optional theme + welcome message. ## Object shape ```json { "id": "chatbot_64f1c0ef2ec711ef6dc1dcf", "public_id": "cb_abc123xyz", "name": "Marketing Site Helper", "agent_id": "agent_64f1c0...", "is_active": true, "allow_write_tools": false, "allowed_domains": ["getmacha.com", "www.getmacha.com"], "theme": { "primaryColor": "#7C3AED" }, "welcome_message": "Hi! How can I help you today?", "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | chatbot_<24 hex>. | | public_id | string | Widget identifier embedded in customer sites. Safe to expose, visible in the embed script source. | | name | string | Display name. | | agent_id | string | null | Which agent handles incoming chats. | | is_active | boolean | If false, the widget shows "unavailable" to visitors. Auto-paused when the bound agent is deactivated. | | allow_write_tools | boolean | Whether anonymous visitors can trigger write operations. Default: false. Enable only if you trust the agent's instructions to prevent abuse. | | allowed_domains | array | Domain allowlist for embed. Empty array = no restriction. | | theme | object | null | Theme overrides. Free-form, current keys: primaryColor. | | welcome_message | string | null | First message shown when a visitor opens the chat. | | created_at | ISO 8601 | | | updated_at | ISO 8601 | | 📘 Chatbot writes are planned v1 is read-only for chatbots. Create / update / delete via the dashboard. POST/PATCH/DELETE endpoints are on the roadmap. --- # List chatbots Resource: Chatbots Source: https://www.getmacha.com/docs/api/chatbots/list-chatbots Endpoint: GET /api/v1/chatbots > Returns every chatbot defined in the organization. Returns every chatbot defined in the organization. **Scope:** chatbots:read ## Query parameters | Param | Type | Default | | cursor | string | | | limit | integer | 25 | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/chatbots \ -H "Authorization: Bearer $MACHA_API_KEY" ``` --- # Retrieve a chatbot Resource: Chatbots Source: https://www.getmacha.com/docs/api/chatbots/retrieve-a-chatbot Endpoint: GET /api/v1/chatbots/:id > Fetch a single chatbot by ID. Fetch a single chatbot by ID. **Scope:** chatbots:read ## Path parameters | Param | Type | | :id | string | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/chatbots/chatbot_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Errors | Status | Code | When | | 404 | not_found | Unknown chatbot ID. | --- # The trigger object Resource: Triggers Source: https://www.getmacha.com/docs/api/triggers/the-trigger-object > Shape of a Trigger, webhook or schedule that fires an agent autonomously. A `Trigger` is what makes an agent fire **autonomously**, without a user typing. Two kinds: **webhook triggers** (a third-party event like "new Zendesk ticket") and **scheduled triggers** (cron-style, e.g. "every hour"). ## Object shape ```json { "id": "trigger_64f1c0ef2ec711ef6dc1dcf", "agent_id": "agent_64f1c0...", "connector_id": "connector_64f1c0...", "connector_type": "zendesk", "event": "ticket.created", "is_active": true, "conditions": { "tags": ["billing"] }, "settings": { "debounceMs": 0 }, "schedule": null, "created_at": "2026-06-01T00:00:00.000Z", "updated_at": "2026-06-20T12:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | trigger_<24 hex>. | | agent_id | string | null | Which agent fires when the trigger matches. | | connector_id | string | null | Null for Macha custom triggers and cron-scheduled triggers (which aren't tied to a connector). | | connector_type | string | e.g. zendesk, slack, freshdesk, macha, scheduler. | | event | string | e.g. ticket.created, app_mention, cron.scheduled, macha.custom_trigger. | | is_active | boolean | Disabled triggers don't fire. Synced with the bound agent's is_active. | | conditions | object | null | Match conditions (e.g. tag filters, status filters). Connector-specific. | | settings | object | Debounce, batching, etc. Free-form. | | schedule | object | null | Set only for cron.scheduled triggers. See below. | | created_at | ISO 8601 | | | updated_at | ISO 8601 | | ### Schedule shape (scheduled triggers only) ```json { "cron_expression": "0 * * * *", "interval_hours": null, "next_run_at": "2026-06-24T11:00:00.000Z", "last_run_at": "2026-06-24T10:00:00.000Z", "last_run_status": "succeeded" } ``` ## Why the webhook signing secret isn't exposed The `webhookSigningSecret` field on the underlying trigger document is the customer's shared HMAC secret for verifying inbound webhooks from third parties. The dashboard shows it **once** at creation time; the API treats it as write-only and never returns it. 📘 Trigger writes are planned v1 is read-only for triggers. Create / update / delete via the dashboard. The setup flow for webhook triggers requires creating webhooks in the external service (Zendesk, etc.), which has its own configuration UI. --- # List triggers Resource: Triggers Source: https://www.getmacha.com/docs/api/triggers/list-triggers Endpoint: GET /api/v1/triggers > Returns every trigger configured in the organization. Returns every trigger configured in the organization. **Scope:** triggers:read ## Query parameters | Param | Type | Default | | cursor | string | | | limit | integer | 25 | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/triggers \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Filtering inactive triggers v1 doesn't have a server-side `is_active` filter. Pull the full list and filter client-side. If you need this enough to inconvenience you, file feature feedback and we'll add it. --- # Retrieve a trigger Resource: Triggers Source: https://www.getmacha.com/docs/api/triggers/retrieve-a-trigger Endpoint: GET /api/v1/triggers/:id > Fetch a single trigger by ID. Fetch a single trigger by ID. **Scope:** triggers:read ## Path parameters | Param | Type | | :id | string | ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/triggers/trigger_64f1c0... \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Errors | Status | Code | When | | 404 | not_found | Unknown trigger ID. | --- # The member object Resource: Team Source: https://www.getmacha.com/docs/api/team/the-member-object > Shape of a team Member, a user with access to the organization. A `Member` is one user with access to the organization. Each membership has a role (owner, admin, member) that determines what the user can do in the dashboard. ## Object shape ```json { "id": "member_64f1c0ef2ec711ef6dc1dcf", "user_id": "user_64f1c0ef2ec711ef6dc1dcf", "name": "Ankeet Guha", "email": "ankeet@getmacha.com", "role": "owner", "is_active": true, "last_login_at": "2026-06-24T09:00:00.000Z", "created_at": "2026-06-01T00:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | member_<24 hex>. Specific to this org membership. | | user_id | string | user_<24 hex>. The same user across all orgs they belong to. | | name | string | null | Display name. Null if the user never set one. | | email | string | Email address. Used as the canonical identifier. | | role | enum | "owner" | "admin" | "member". | | is_active | boolean | Deactivated users can't log in. Their data is preserved. | | last_login_at | ISO 8601 | null | When the user last signed in. | | created_at | ISO 8601 | When the user was added to this org. | 📘 Team writes are planned v1 supports read only. Inviting + removing members goes through the dashboard. --- # List members Resource: Team Source: https://www.getmacha.com/docs/api/team/list-members Endpoint: GET /api/v1/team > Returns every member of the organization. Returns every member of the organization. **Scope:** team:read ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/team \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": [ { "id": "member_64f1c0...", "user_id": "user_64f1c0...", "name": "Ankeet Guha", "email": "ankeet@getmacha.com", "role": "owner", "is_active": true, "last_login_at": "2026-06-24T09:00:00.000Z", "created_at": "2026-06-01T00:00:00.000Z" } ], "meta": { "request_id": "req_..." } } ``` --- # Get agent analytics Resource: Analytics Source: https://www.getmacha.com/docs/api/analytics/get-agent-analytics Endpoint: GET /api/v1/analytics/agents/:agent_id > Per-agent usage stats, conversation counts, tool calls, and credit consumption over a time window. Returns per-agent usage statistics, conversation counts, tool calls, credits consumed, over a configurable time window. **Scope:** analytics:read ## Path parameters | Param | Type | Notes | | :agent_id | string | Agent ID (prefixed or bare). | ## Query parameters | Param | Type | Default | Notes | | since | ISO 8601 | 30 days ago | Window start. | | until | ISO 8601 | now | Window end. | | cursor | string | | For paginated row lists inside the response. | | limit | integer | 25 | Range 1-100. | ## Example request ```bash curl 'https://dashboard.getmacha.com/api/v1/analytics/agents/agent_64f1c0...?since=2026-06-01T00:00:00Z' \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Response shape The exact `data` shape is in flux as the per-agent analytics tab matures. The contract today is that `data` is a free-form analytics object, treat the keys defensively. ⚠ Beta shape This endpoint's response keys will stabilize when the analytics dashboard UI ships. Until then, expect the response shape to gain fields and treat unknown keys leniently. ## Errors | Status | Code | When | | 404 | agent_not_found | Unknown agent ID. | | 422 | validation_failed | Bad date range, malformed cursor. | --- # The organization object Resource: Organization Source: https://www.getmacha.com/docs/api/organization/the-organization-object > Shape of the Organization resource, plan, credit balance, resource limits. The `Organization` resource represents the workspace your API key is scoped to. It carries the plan, the credit balance, the resource limits, and the trial dates. ## Object shape ```json { "id": "org_64f1c0ef2ec711ef6dc1dcf", "name": "Macha AI", "slug": "macha-ai", "plan": "pro", "status": "active", "credits": { "total": 50000, "used": 12345, "remaining": 37655, "top_up": 0, "reset_at": "2026-07-01T00:00:00.000Z" }, "limits": { "agents": null, "connectors": null, "sources": null, "chatbots": 20, "scheduled_triggers": 3, "custom_tool_slots": 5 }, "trial": null, "created_at": "2026-05-01T00:00:00.000Z" } ``` ## Attributes | Field | Type | Notes | | id | string | org_<24 hex>. | | name | string | Display name. | | slug | string | URL-safe identifier. | | plan | string | trial | starter | pro | enterprise. | | status | string | Subscription status. | | credits | object | See below. | | limits | object | Per-resource caps. null means unlimited on the plan. | | trial | object | null | Trial dates (start_date, end_date) or null if not on trial. | | created_at | ISO 8601 | When the org was created. | ### Credits shape | Field | Type | Notes | | total | integer | Plan allotment per billing period. | | used | integer | Consumed this period. | | remaining | integer | What's left, including any top-up. | | top_up | integer | Additional credits purchased on top of the plan. | | reset_at | ISO 8601 | null | When credits reset (next billing cycle). | ## What's deliberately not exposed - **Chargebee customer IDs / subscription IDs**, billing internals stay server-side. - **Org-provided LLM API keys**, if you've configured BYO keys, they're encrypted at rest and never returned. - **Internal flags**, super-admin allowlists, beta feature flags, etc. --- # Retrieve the organization Resource: Organization Source: https://www.getmacha.com/docs/api/organization/retrieve-organization Endpoint: GET /api/v1/org > Fetch the org tied to the current API key. Fetch the organization tied to the current API key. Useful for showing plan / credits / limits in your own dashboard. **Scope:** org:read ## Example request ```bash curl https://dashboard.getmacha.com/api/v1/org \ -H "Authorization: Bearer $MACHA_API_KEY" ``` ## Example response ```json { "data": { "id": "org_64f1c0ef2ec711ef6dc1dcf", "name": "Macha AI", "slug": "macha-ai", "plan": "pro", "status": "active", "credits": { "total": 50000, "used": 12345, "remaining": 37655, "top_up": 0, "reset_at": "2026-07-01T00:00:00.000Z" }, "limits": { "agents": null, "connectors": null, "sources": null, "chatbots": 20, "scheduled_triggers": 3, "custom_tool_slots": 5 }, "trial": null, "created_at": "2026-05-01T00:00:00.000Z" }, "meta": { "request_id": "req_..." } } ``` ## Common use cases - **Pre-flight check before bulk operations.** Read `credits.remaining` and abort if there's not enough credit for the work you're about to do. - **Capacity planning.** Compare `limits.agents` against your current agent count to know when you'd hit the plan cap. - **Trial expiry warnings.** If `trial.end_date` is within the next 7 days, surface a banner in your own UI. ## Errors | Status | Code | When | | 401 | unauthorized | Bad / missing key. | | 403 | insufficient_scope | Key lacks org:read. | ---