# Credits Source: https://docs.shingleai.com/admin-guide/billing/credits Pre-pay for usage beyond your plan with one-time top-ups or auto top-up Credits are a USD balance on your account that ShingleAI draws from when usage exceeds your monthly plan allowance. Every consumable — LLM tokens, API calls, MCP calls, storage, email sends, SMS, and voice minutes — bills against credits at the per-tier overage rate. For the full per-tier overage table and how usage is tracked, see [Usage and metrics](/admin-guide/billing/usage). ## Prerequisites * You must be an **Owner** or **Admin** to view the credit balance, purchase credits, or change auto top-up settings * Credit purchases use the same payment method as your subscription ## View your credit balance 1. Navigate to **Settings > Account > Billing** 2. Find the **Credits** card The card shows: | Field | Meaning | | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | | **Current balance** | Available credits in USD. A **Low Balance** badge appears when the balance is at or below your low-balance threshold | | **Lifetime added** | Total credits ever purchased or auto-topped-up | | **Lifetime spent** | Total credits ever consumed by overages | | **Recent Transactions** | 5 most recent credit movements (purchase, auto top-up, consumption, refund) with amount and running balance | If you have more than 5 transactions, a **History →** button expands the list to show all movements. ## One-time credit purchase To buy credits without enabling auto top-up: 1. On the **Credits** card, click **Purchase Credits** 2. In the **Purchase Credits** dialog, enter an amount in USD 3. Click **Purchase** 4. Complete payment in the embedded Stripe checkout The amount field is free-form: the default is **$10**, the minimum is **$5**, and the maximum is **\$1,000** per purchase. Credits land in your account immediately on successful payment. Credits do not expire and roll over month to month. They are not refundable except where required by law. ## Auto top-up Auto top-up keeps your credit balance topped up automatically so usage never gets cut off mid-month. It's **off by default**. To configure auto top-up: 1. On the **Credits** card, in the **Auto Top-Up** section, click **Enable** (or **Manage** if already enabled) 2. In the **Auto Top Up** dialog, toggle **Enable auto top up** on 3. Confirm your default payment method, or add one if none is on file 4. Set **When credits are below** — the balance at which a top-up fires 5. Set **Purchase this amount** — how much to add per top-up 6. Click **Save** | Setting | Range | | ---------------------------------- | ----------------------------- | | When credits are below (threshold) | \$0 up to the purchase amount | | Purchase this amount | $5 – $100,000 | When your balance drops below the threshold, ShingleAI charges your saved payment method for the purchase amount and credits your balance. You receive a `credit_auto_recharge_triggered` notification on each successful top-up and a `credit_purchase_failed` notification if the charge fails. A failed auto top-up does not retry automatically. Update your payment method in the [Stripe Customer Portal](/admin-guide/billing/portal) and trigger a one-time purchase to restore service. ## What happens when credits run out When your monthly allowance is exhausted **and** your credit balance is depleted, behavior depends on the consumable: * **LLM tokens (agent chat).** Agent conversations are blocked. The chat shows an **Out of Credits** card with a button to purchase more * **Other consumables (API calls, MCP calls, email, SMS, voice, storage).** New requests fail until you top up credits, your billing cycle resets, or you upgrade * **Free tier.** Same behavior — Free accounts can purchase credits to keep working past the included allowance You also receive notifications as you approach exhaustion: | Notification | When | | ------------------------- | --------------------------------------------------------------------------------------------- | | `credit_balance_low` | Balance falls below your auto top-up threshold (or a default threshold if auto top-up is off) | | `credit_balance_depleted` | Balance reaches zero | ## Next steps See current usage and per-tier overage rates Update your payment method and view invoices # Billing Source: https://docs.shingleai.com/admin-guide/billing/index Manage billing, subscriptions, and usage in ShingleAI ShingleAI uses an account-based subscription model with tiered pricing. As an administrator, you manage billing at the account level, which covers all organizations and team members under your account. ## Billing Concepts ### Account-Based Billing Billing in ShingleAI is managed at the **account** level, not the organization level. A single account can contain multiple organizations, and all usage across organizations counts toward your account's limits. ``` Account (Billing Entity) ├── Subscription (Tier & Limits) ├── Organizations (Workspaces) │ └── Members (Users) └── Account Members (Billing Admins) ``` ### Subscriptions Your subscription determines: * **Resource limits** - How many organizations, seats, agents, MCP servers, and automations you can create * **Consumable allowances** - Monthly limits for LLM tokens, API calls, and MCP calls * **Feature access** - Which AI models and features are available ### Seats Seats represent unique users across all organizations in your account. A user who belongs to multiple organizations only counts as one seat. Each tier includes a certain number of seats, and you can purchase additional seats on paid tiers. ## Quick Reference | Tier | Price | Seats | Businesses | Agents | LLM Tokens/mo | | -------------- | -------- | --------- | ---------- | --------- | ------------- | | **Free** | \$0 | 1 | 1 | 3 | 100K | | **Starter** | \$25/mo | 3 | 3 | 10 | 1M | | **Pro** | \$100/mo | 10 | 10 | 50 | 10M | | **Enterprise** | Custom | Unlimited | Unlimited | Unlimited | Unlimited | See [Usage and metrics](/admin-guide/billing/usage) for the full object-and-consumable table including MCP servers, automations, storage, email sends, SMS, and voice minutes. ## Billing Topics Compare features, resource limits, and AI model access across all tiers Subscription pricing, seat add-ons, trial periods, and billing cycles Current usage, account object limits, and per-tier overage rates Balance, one-time purchases, and auto-recharge Compare tiers and switch your subscription Manage invoices, payment methods, and subscription changes Warning thresholds and downgrade behavior ## Managing your subscription From **Settings > Account > Billing** you can: * View current usage and remaining allowances ([Usage and metrics](/admin-guide/billing/usage)) * Upgrade or downgrade your subscription ([Upgrade](/admin-guide/billing/upgrade)) * Purchase credits or enable auto-recharge ([Credits](/admin-guide/billing/credits)) * Update payment methods and download invoices ([Stripe Customer Portal](/admin-guide/billing/portal)) Only account members with **Owner** or **Admin** roles can access billing settings and make changes to the subscription. # Understanding Limits Source: https://docs.shingleai.com/admin-guide/billing/limits Learn how ShingleAI enforces usage limits and what happens when you exceed them ShingleAI enforces two types of limits: resource limits (for creating objects) and consumable limits (for usage). This page explains how each type of limit works and what to expect as you approach or exceed them. ## Types of Limits ### Resource Limits Resource limits control how many of each resource type you can create: * Organizations * Seats (team members) * MCP Servers * Agents * Automations **Resource limits are hard limits.** When you reach the limit, you cannot create additional resources until you upgrade your tier or delete existing resources. ### Consumable Limits Consumable limits control your monthly usage of: * LLM Tokens * API Calls * MCP Calls **Consumable limits have flexible enforcement** with warning thresholds and a grace period for paid tiers. Free tier has a hard cutoff at 100%. ## Warning Thresholds ShingleAI monitors your consumable usage and sends notifications at key thresholds: | Threshold | Level | What Happens | | --------- | -------- | ----------------------------------------------------------- | | **90%** | Warning | Email and in-app banner alerting you to high usage | | **100%** | Critical | Email and in-app modal; overage billing begins (paid tiers) | | **110%** | Cutoff | Service paused until next billing cycle or upgrade | ### Free Tier Warnings When you approach your limits on the Free tier: * **At 90%:** "You've used 90% of your monthly allowance. Upgrade to continue." * **At 100%:** "You've reached your limit. Upgrade to Starter for more capacity." The Free tier has a **hard cutoff at 100%**. There is no grace period or overage billing. Service is paused until your next billing cycle or you upgrade. ### Paid Tier Warnings When you approach your limits on paid tiers (Starter, Pro, Enterprise): * **At 90%:** "You've used 90% of your monthly allowance. Overage billing will apply beyond 100%." * **At 100%:** "You've exceeded your allowance. Overage charges: \$X.XX. Consider upgrading." * **At 110%:** "You've reached the maximum overage limit. Service paused until next billing cycle or upgrade." Paid tiers have a **soft limit with a 10% overage allowance**. You can continue using the service up to 110% of your monthly allowance, with overage charges applying for usage between 100% and 110%. At 110%, service is paused until you purchase more credits or your billing cycle resets. ## Viewing Your Usage You can monitor your usage at any time from the usage dashboard in your account settings. The dashboard shows: * Current usage for all consumables * Remaining allowance for the billing period * Progress bars indicating usage percentage * Days until your allowances reset * Historical usage trends To access your usage dashboard: 1. Go to your account settings 2. Select **Usage** from the sidebar 3. View your current period usage and resource capacity ## What Happens When Limits Are Exceeded ### Resource Limits When you reach a resource limit: * You cannot create new resources of that type * Existing resources continue to work normally * You see an error message explaining the limit * You're prompted to upgrade or delete existing resources ### Consumable Limits (Free Tier) When you reach 100% on the Free tier: * The affected service is paused immediately * Existing data is preserved * You can still access your account and view data * AI features (agents, automations) that consume tokens are disabled * API calls return a 429 error with upgrade instructions ### Consumable Limits (Paid Tiers) When you exceed your allowance on paid tiers: 1. **100% - 110%:** Overage billing applies, service continues 2. **At 110%:** Service is paused 3. You receive email notifications at each threshold 4. Service resumes when: * You purchase additional credits * Your billing cycle resets * You upgrade to a higher tier ## Managing High Usage Check your usage dashboard regularly, especially during high-activity periods. Set up internal alerts when you approach 80% of your limits. If you anticipate high usage, purchase credits in advance. Credits can be used immediately and carry over between billing cycles. Review your agents and automations for opportunities to reduce token consumption. Shorter prompts and more efficient workflows can significantly reduce usage. If you consistently exceed your limits, upgrading to a higher tier is often more cost-effective than paying overage charges. Compare the cost of overages against the higher tier pricing. ## Limit Reset * **Monthly allowances** reset on your billing cycle anniversary date * **Resource limits** do not reset; they are permanent caps * **Credit balances** do not expire and carry over between periods Your billing cycle anniversary is the day you started your subscription. For example, if you subscribed on the 15th, your allowances reset on the 15th of each month. ## Upgrading to Increase Limits When you upgrade your subscription: * New resource limits take effect immediately * New consumable allowances are prorated for the current period * You're charged a prorated amount for the upgrade * Any existing overage usage is resolved with the new higher limits ## API Rate Limit Enforcement API rate limits work differently from consumable limits. While consumable limits track your total monthly usage, rate limits control how many requests you can make per minute. | Tier | Requests per Minute | | -------------- | ------------------- | | **Free** | 10 | | **Starter** | 30 | | **Pro** | 100 | | **Enterprise** | Custom | ### How Rate Limits Work * **Per-minute window:** Rate limits reset every minute * **429 responses:** When you exceed your rate limit, API requests return a `429 Too Many Requests` error * **No overage billing:** Unlike consumable limits, exceeding rate limits does not incur additional charges * **Automatic recovery:** Simply wait for the next minute window and your requests will succeed again If you consistently hit rate limits, consider upgrading to a higher tier for increased capacity. Enterprise tier offers custom rate limits tailored to your needs. ## Downgrade Behavior When you downgrade to a tier with lower limits, your existing resources are preserved but may become restricted. ### What Happens to Excess Resources * **Resources are not deleted:** Your existing organizations, agents, automations, and other resources remain intact * **Read-only access:** Excess resources become read-only - you can view and use them but cannot modify them * **Creation blocked:** You cannot create new resources of that type until you're under the limit * **Deletion required:** To regain full access, delete excess resources until you're within your new tier's limits ### Examples | Scenario | Result | | ---------------------------------------------------- | ------------------------------------------------- | | Pro (10 orgs) → Starter (3 orgs) with 5 orgs | 2 orgs become read-only until you delete them | | Pro (50 agents) → Starter (10 agents) with 25 agents | 15 agents become read-only | | Starter → Free with 5 seats | 2 seats must be removed before adding new members | ### Consumable Allowances on Downgrade * New consumable limits take effect at the start of your next billing cycle * Current period usage is not affected * If you've already exceeded the new tier's limit, overage billing continues until cycle reset Plan your downgrade carefully. Consider archiving or exporting data from resources you'll need to delete. Compare tier features and limits View pricing and consumable allowances # Payment methods Source: https://docs.shingleai.com/admin-guide/billing/payment-methods View, add, set as default, and remove the cards saved on your ShingleAI account New Manage the cards saved on your account directly inside ShingleAI — no hop to the Stripe-hosted portal needed for routine card changes. ## Prerequisites * You must be an **Owner** or **Admin** to view or change payment methods * An active Stripe customer record (created automatically the first time you save a card or upgrade a plan) ## Open the page 1. Navigate to **Settings > Account > Billing** 2. Click **Manage payment methods** in the page header You land at `/settings/account/billing/payment-methods`. ## What you can do | Action | What happens | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Add card** | Opens an in-app dialog with Stripe's secure card form. After your bank approves the card (including any 3-D Secure step), it appears in the list. | | **Set as default** | Marks the card as the one used for subscription renewal, credit top-ups, and consumable overage charges. The current default's row shows a **Default** badge. | | **Remove** | Detaches the card from your account immediately. Confirm in the prompt before the card is removed. You can't remove your last card — add a new one first if you want to swap. | The first card you add is automatically promoted to default. ## Empty state When no cards are saved yet, the page shows an empty state with a prominent **Add card** call-to-action. The same dialog opens whether you click the empty-state button or the **Add card** button in the page header. ## Default card behavior * Exactly one card is the default at any time. Setting a non-default card as default replaces the previous one. * If you remove the default and other cards remain, ShingleAI automatically promotes the most-recently-added remaining card on the next page load. To pick a different default, use **Set as default** on the card you prefer. * Subscription invoices, credit top-ups, and overage charges all bill the default card. * At least one card must always be on file. Removing your only card is blocked; add a replacement first. ## Related Use the hosted portal for invoices, tax info, and plan changes How credits and auto-recharge use your default card # Stripe Customer Portal Source: https://docs.shingleai.com/admin-guide/billing/portal Manage payment methods, invoices, and subscription changes in the Stripe-hosted billing portal ShingleAI uses Stripe's customer-portal for invoices, tax info, plan changes, and cancellation. The portal is hosted by Stripe and opens with single-sign-on from your ShingleAI account. Saved cards are managed in-app on the [Payment methods](/admin-guide/billing/payment-methods) page — no portal hop required. ## Prerequisites * You must be an **Owner** or **Admin** to open the portal * An active or trialing subscription with a Stripe customer record (the portal is not available before your first paid plan) ## Open the portal 1. Navigate to **Settings > Account > Billing** 2. Click **Manage billing in Stripe** A new tab opens directly into the Stripe-hosted portal. When you finish, close the tab to return to ShingleAI. Portal sessions are rate-limited to 10 per minute per account. If you've recently opened a session, wait a few seconds before opening another. ## What you can do The portal supports several focused flows. ShingleAI links you directly to the right one based on which button you click. | Flow | Triggered from | What you can do | | ----------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------- | | **Manage billing** | Default **Manage billing in Stripe** button | View invoices, update tax info, see subscription history | | **Cancel subscription** | The "Cancel subscription" link | Cancel at period end with optional feedback | | **Change plan** | "Upgrade" or "Downgrade" buttons on the [Upgrade page](/admin-guide/billing/upgrade) | Switch tier, switch monthly ↔ annual, confirm prorated charges | ### Invoices Past invoices live under **Billing history** in the portal. Each row downloads as a PDF and includes: * Subscription line items * Per-seat add-ons * Overage charges from the prior period * Credit purchases and auto-recharges ## Downgrade pre-validation Plan changes that *increase* limits go straight to the portal. Plan changes that *decrease* limits run through a pre-validation step in ShingleAI before handing off to Stripe. If your current usage exceeds the target tier's limits — for example, you have 25 agents and want to downgrade to a plan that allows 10 — ShingleAI blocks the downgrade and sends you back to **Settings > Account > Billing** with a banner that lists the specific violations: > Too many agents: 25 in use, 10 allowed on Starter To complete the downgrade: 1. Reduce the listed objects below the target tier's limits (delete agents, remove team members, archive automations, etc.) 2. Return to the [Upgrade page](/admin-guide/billing/upgrade) and select the lower tier again 3. Confirm the change in the portal Pre-validation only catches account objects (seats, businesses, agents, MCP servers, automations). Consumable usage above the new tier's allowance will simply bill as overages on the next cycle — see [Limits](/admin-guide/billing/limits) for details. ## Errors and recovery | Banner you see | What to do | | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | | `Portal is unavailable` | Your account has no Stripe customer record yet — start from the [Upgrade page](/admin-guide/billing/upgrade) instead | | `Downgrade blocked` | See the listed violations and reduce usage before retrying | | `Rate limited` | Wait a few seconds and try again | ## Next steps Compare tiers and switch plans Subscription, seat, and overage pricing # Pricing & Consumables Source: https://docs.shingleai.com/admin-guide/billing/pricing Understand ShingleAI pricing, monthly allowances, and overage billing ShingleAI uses a subscription-based pricing model with monthly consumable allowances. This page explains how pricing works, what's included in each tier, and how overage billing applies. ## Subscription Pricing | Tier | Monthly | Annual | Savings | | -------------- | ------- | ------- | ------------- | | **Free** | \$0 | - | - | | **Starter** | \$25 | \$250 | 2 months free | | **Pro** | \$100 | \$1,000 | 2 months free | | **Enterprise** | Custom | Custom | Contact sales | Annual billing saves you 2 months free. The Starter tier includes a 30-day free trial with no payment method required until the trial ends. ## Monthly Consumable Allowances Each tier includes monthly allowances for consumable resources. These reset on your billing cycle anniversary date. | Consumable | Free | Starter | Pro | Enterprise | | -------------- | ------- | --------- | ---------- | ---------- | | **LLM Tokens** | 100,000 | 1,000,000 | 10,000,000 | Custom | | **API Calls** | 1,000 | 10,000 | 100,000 | Custom | | **MCP Calls** | 500 | 5,000 | 50,000 | Custom | ### Understanding Consumables * **LLM Tokens** - Tokens used when AI agents process messages, generate responses, or run automations. Both input and output tokens count toward your limit. * **API Calls** - Requests made to the ShingleAI API, whether from your applications or third-party integrations. * **MCP Calls** - Calls made to MCP servers connected to your agents. **API rate limits** also vary by tier (Free: 10 req/min, Starter: 30 req/min, Pro: 100 req/min). See the [Subscription Tiers](/admin-guide/billing/tiers) page for full details. ## Credit System Paid tiers (Starter, Pro, Enterprise) use a credit system for usage beyond your monthly allowance. ### How Credits Work 1. Each month, you receive your tier's consumable allowances 2. Usage is first deducted from your monthly allowance 3. When you exceed your allowance, usage is automatically deducted from your credit balance in real-time 4. You can purchase credits at any time from the billing dashboard ### Overage Rates When you exceed your monthly allowance, the following rates apply: | Consumable | Rate | Unit | | -------------- | ------ | ----------------- | | **LLM Tokens** | \$0.10 | per 10,000 tokens | | **API Calls** | \$0.01 | per 100 calls | | **MCP Calls** | \$0.01 | per 100 calls | **Free tier has no overage billing.** When you reach 100% of your limit on the Free tier, service is paused until the next billing cycle or you upgrade. Paid tiers allow usage up to 110% of the limit before pausing. ### Credit Purchase Options You can purchase credits from the **Billing** section in your account dashboard. Credits are available in the following amounts: | Amount | Credits | | ------ | -------------- | | \$10 | 1,000 credits | | \$20 | 2,000 credits | | \$50 | 5,000 credits | | \$100 | 10,000 credits | **Credit conversion rate:** 1 credit = \$0.01. Credits never expire and carry over between billing cycles. ### Example: Overage Calculation A Pro tier account with a 10M token allowance and \$50 credit balance: | Usage Range | Cost | | ----------------- | -------------------------------------------- | | 0 - 10M tokens | Included in subscription | | 10M - 15M tokens | $50 from credit balance ($0.10 per 10K) | | Beyond 15M tokens | Paused until credits purchased or next cycle | ## Additional Seats If you need more seats than included in your tier, you can purchase additional seats. | Tier | Included Seats | Additional Seat Cost | | -------------- | -------------- | -------------------- | | **Free** | 3 | Not available | | **Starter** | 10 | \$5/seat/month | | **Pro** | 25 | \$8/seat/month | | **Enterprise** | Custom | Custom | Additional seats are billed monthly and prorated when added mid-cycle. ## Trial Period The Starter tier includes a **30-day free trial**: * Full access to all Starter tier features and limits * No payment method required to start * Automatic downgrade to Free tier if not converted * Convert to paid at any time during the trial Stripe manages the trial period. You'll receive email reminders before your trial ends to add a payment method and continue your subscription. The Pro tier does not include a trial period. You can start with the Starter tier trial and upgrade to Pro at any time. ## Billing Cycle * **Monthly subscriptions** are billed on the same day each month * **Annual subscriptions** are billed once per year on your subscription anniversary * **Consumable allowances** reset on your billing cycle anniversary date * **Upgrades** take effect immediately with prorated charges * **Downgrades** take effect at the end of your current billing period ## Managing Your Billing You can manage all billing settings from your account dashboard: * View current usage and remaining allowances * Purchase credits * Add or remove seats * Upgrade or downgrade your subscription * Update payment methods * Download invoices Compare tier features and limits Learn how limits are enforced # Subscription Tiers Source: https://docs.shingleai.com/admin-guide/billing/tiers Compare ShingleAI subscription tiers and choose the right tier for your organization ShingleAI offers four subscription tiers designed to scale with your business needs. Each tier provides different resource limits, consumable allowances, and feature access. ## Tier Overview | Tier | Price | Billing Options | Trial | | -------------- | ----------- | ----------------- | ---------- | | **Free** | \$0/month | Monthly only | None | | **Starter** | \$25/month | Monthly or Annual | 30 days | | **Pro** | \$100/month | Monthly or Annual | None | | **Enterprise** | Custom | Custom | Negotiated | **Annual billing discount:** Save 2 months free when you choose annual billing. Starter annual is $250/year and Pro annual is $1,000/year. ## Resource Limits Resource limits determine how many of each resource type you can create within your account. | Resource | Free | Starter | Pro | Enterprise | | -------------------- | ------------- | -------------- | -------------- | ---------- | | **Organizations** | 1 | 3 | 10 | Unlimited | | **Seats (included)** | 3 | 10 | 25 | Custom | | **Additional Seats** | Not available | \$5/seat/month | \$8/seat/month | Custom | | **MCP Servers** | 2 | 5 | 20 | Unlimited | | **Agents** | 3 | 10 | 50 | Unlimited | | **Automations** | 5 | 25 | 100 | Unlimited | Resource limits are **hard limits**. You cannot create resources beyond your tier limit. To add more resources, upgrade to a higher tier. ## AI Model Access Different tiers provide access to different AI models for agents and automations. | Model | Free | Starter | Pro | Enterprise | | ------------------------ | ---- | ------- | --- | ---------- | | **GPT-3.5 Turbo** | Yes | Yes | Yes | Yes | | **GPT-4o-mini** | - | Yes | Yes | Yes | | **GPT-4** | - | - | Yes | Yes | | **GPT-4 Turbo** | - | - | Yes | Yes | | **Claude 3 Haiku** | Yes | Yes | Yes | Yes | | **Claude 3.5 Sonnet** | - | Yes | Yes | Yes | | **Claude 3 Opus** | - | - | Yes | Yes | | **Claude 3.5 Sonnet V2** | - | - | Yes | Yes | | **Custom Models** | - | - | - | Yes | ## Feature Access Certain features are only available on higher tiers. | Feature | Free | Starter | Pro | Enterprise | | ----------------------------- | ---- | ------- | --- | ---------- | | **Email Integration** | Yes | Yes | Yes | Yes | | **API Access** | Yes | Yes | Yes | Yes | | **Automations** | Yes | Yes | Yes | Yes | | **SMS Marketing Campaigns** | - | - | Yes | Yes | | **Priority Support** | - | - | Yes | Yes | | **SSO (SAML/OAuth)** | - | - | - | Yes | | **Custom Branding** | - | - | - | Yes | | **SLA Guarantee** | - | - | - | Yes | | **Dedicated Account Manager** | - | - | - | Yes | ## API Rate Limits | Tier | Requests per Minute | | -------------- | ------------------- | | **Free** | 10 | | **Starter** | 30 | | **Pro** | 100 | | **Enterprise** | Custom | ## Choosing the Right Tier The Free tier is perfect for individuals or small teams who want to explore ShingleAI's capabilities. You get access to basic AI models and can create a limited number of agents and automations. **Best for:** Personal use, evaluation, small side projects The Starter tier is designed for small businesses or teams who need more capacity and better AI models. The 30-day trial lets you experience the full tier before committing. **Best for:** Small businesses, startups, growing teams The Pro tier provides significantly higher limits and access to the most capable AI models. SMS marketing and priority support make it ideal for businesses with demanding requirements. **Best for:** Established businesses, agencies, teams with heavy usage The Enterprise tier offers unlimited resources, custom pricing, and dedicated support. SSO, custom branding, and SLA guarantees meet the needs of large organizations. **Best for:** Large organizations, enterprises with custom requirements ## Upgrading Your Tier You can upgrade your subscription at any time from the billing settings in your dashboard. When you upgrade: * New limits take effect immediately * You're charged a prorated amount for the remainder of the billing period * All your existing data and configurations are preserved View detailed pricing and consumable limits Learn how limits are enforced # Upgrade your plan Source: https://docs.shingleai.com/admin-guide/billing/upgrade Compare tiers and switch your subscription from the upgrade page The upgrade page at **`/billing/upgrade`** is the conversion entry point for changing plans. Every paid plan transition — Free → Starter, Starter → Pro, switching billing intervals — starts here. ## Prerequisites * You must be an **Owner** or **Admin** to change the subscription * Open the page from anywhere in the app at `/billing/upgrade`, or from **Settings > Account > Billing > Upgrade plan** ## What the page shows The upgrade page is a full-screen, no-sidebar layout designed to make the choice clear: * **Trial banner** at the top if your account is currently trialing — shows trial end date and a reminder to add a payment method before it ends * **Tier cards** for Free, Starter, Pro, and Enterprise with prices, included resource limits, and key features * **Billing-interval toggle** for Monthly vs. Annual (annual saves about 17%, equivalent to two months free) * **Plan comparison** table for a side-by-side view of features and limits * **FAQ** covering proration, cancellation, and downgrade behavior The card matching your **recommended next tier** is highlighted: | Current tier | Recommended next | | ------------ | -------------------------------- | | Free | Starter | | Starter | Pro | | Pro | Enterprise | | Enterprise | None — contact sales for changes | ## Choose a plan Click the **Upgrade** (or **Switch to**) button on a tier card. Where you go next depends on your current state: | Current state | Where the button takes you | | --------------------------- | ----------------------------------------------------------------------------------------------------- | | Free | Stripe Checkout — enter payment details and confirm | | Trialing | Stripe Customer Portal (subscription confirm) — review proration and confirm | | Paid (downgrade or upgrade) | Stripe Customer Portal (subscription confirm) — review proration and confirm | | Enterprise | Redirected back to **Settings > Account > Billing** — Enterprise plans require sales-assisted changes | After payment or confirmation, Stripe sends you back to ShingleAI; the new tier takes effect immediately. ### Trials The Starter plan includes a **30-day free trial** — no payment method required up front. Pro and Enterprise plans do not include trials; you can start with the Starter trial and upgrade to Pro at any point during or after it. When your Starter trial ends: * If you've added a payment method, billing begins automatically * If you haven't, the account drops back to Free and any over-Free-tier objects become read-only (see [Limits](/admin-guide/billing/limits)) ## Frequently asked questions Yes. Stripe credits the unused portion of your current period and charges the prorated amount for the new tier on the same invoice. You see the exact line items in the portal before confirming. Yes — pick a lower tier on the upgrade page. ShingleAI runs a [pre-validation check](/admin-guide/billing/portal#downgrade-pre-validation) first; if your current usage exceeds the target tier's limits, you'll see a list of what to reduce before the downgrade can proceed. Yes. Cancel from the [Stripe Customer Portal](/admin-guide/billing/portal). Your plan stays active until the end of the current billing period, then drops back to Free. Credits roll over and don't expire. Current-period overage usage continues to bill at your prior tier's overage rate; the new tier's rate applies starting next cycle. ## Next steps Compare tier features in detail Manage cards, invoices, and confirmations # Usage and metrics Source: https://docs.shingleai.com/admin-guide/billing/usage Track resource counts, monthly consumable usage, and overage costs from the billing dashboard The usage dashboard shows your account's consumption against its plan in real time. ShingleAI tracks two kinds of usage: **account objects** (countable things you create and delete) and **consumables** (monthly allowances that reset on your billing anniversary). To open the dashboard: 1. Navigate to **Settings > Account > Billing** 2. Scroll to the **Usage** section ## Account objects Account objects have hard limits per tier. When you reach a limit you can't create more of that object until you delete one or upgrade your plan. | Object | Free | Starter | Pro | Enterprise | | ------------------------ | ---: | ------: | --: | ---------: | | **Seats** (team members) | 1 | 3 | 10 | Unlimited | | **Businesses** | 1 | 3 | 10 | Unlimited | | **Agents** | 3 | 10 | 50 | Unlimited | | **MCP Servers** | 2 | 5 | 20 | Unlimited | | **Automations** | 5 | 25 | 100 | Unlimited | Each object's card on the dashboard shows your current count, the included plan limit, and a progress bar. Additional seats can be purchased on Starter, Pro, and Enterprise plans without changing tier. See [Pricing](/admin-guide/billing/pricing) for per-seat pricing. ## Consumables Consumables are metered usage that accrues during the billing period and resets on your billing-cycle anniversary date. | Consumable | Free | Starter | Pro | Enterprise | | ----------------- | ------: | --------: | ---------: | ---------: | | **LLM tokens** | 100,000 | 1,000,000 | 10,000,000 | Unlimited | | **API calls** | 1,000 | 10,000 | 100,000 | Unlimited | | **MCP calls** | 500 | 5,000 | 50,000 | Unlimited | | **Storage** | 100 MB | 1 GB | 10 GB | Unlimited | | **Email sends** | 100 | 1,000 | 10,000 | Unlimited | | **SMS** | 50 | 500 | 5,000 | Unlimited | | **Voice minutes** | 30 | 300 | 3,000 | Unlimited | Each consumable card shows: * The included allocation * Current period usage and a progress bar * The per-tier overage rate * Live overage cost so far this period (if any) ### Allocation header colors The progress bar color tracks your usage percentage: | Usage | Color | What it means | | ------------- | ------ | ------------------------------------------ | | Below 80% | Green | Healthy — well within plan | | 80% – 99% | Yellow | Approaching the included allocation | | 100% or above | Red | Allocation exhausted — overage rates apply | You also receive `usage_warning` notifications at 90% and `usage_limit_reached` at 100%. See [Notifications](/admin-guide/notifications) to configure delivery channels. ## Overage rates Once a consumable passes 100% of its allocation, additional usage bills against your [credit balance](/admin-guide/billing/credits) at the per-tier rate below. | Consumable | Unit | Free | Starter | Pro | Enterprise | | ----------------- | ---------- | -----: | ------: | ------: | ---------: | | **LLM tokens** | per 10,000 | \$0.50 | \$0.40 | \$0.30 | Custom | | **API calls** | per 100 | \$0.03 | \$0.02 | \$0.01 | Custom | | **MCP calls** | per 100 | \$0.03 | \$0.02 | \$0.01 | Custom | | **Storage** | per 1 GB | \$0.25 | \$0.15 | \$0.10 | Custom | | **Email sends** | per 100 | \$0.15 | \$0.10 | \$0.05 | Custom | | **SMS** | per 10 | \$0.15 | \$0.10 | \$0.075 | Custom | | **Voice minutes** | per 10 | \$0.30 | \$0.20 | \$0.15 | Custom | All tiers — including Free — can purchase credits and pay overages. Enterprise overage pricing is set in your contract. Overage cost is rounded up by unit. For example, sending 110 emails when 100 are included on the Starter plan ($0.10 per 100) bills as one full overage unit = $0.10, not \$0.01. ## How usage is counted | Object or consumable | Counted at | | ------------------------------------------------ | ------------------------------------------------------------------------ | | **Seats** | Every accepted invitation; revoked when a member is removed | | **Businesses, Agents, MCP Servers, Automations** | When the object is created (counter restored on delete) | | **LLM tokens** | Every token billed by the upstream model — input plus output | | **API calls** | Every authenticated request to the public REST API | | **MCP calls** | Every authenticated tool invocation against the MCP server | | **Storage** | Sum of bytes across all uploaded files (recomputed on upload and delete) | | **Email sends** | Every outbound email; received emails are not counted | | **SMS** | Every outbound SMS segment; inbound messages are not counted | | **Voice minutes** | Live + recorded call minutes per leg, rounded up to the nearest minute | ## Next steps Top up your balance or enable auto-recharge What happens at warning thresholds and after a downgrade # Admin Guide Source: https://docs.shingleai.com/admin-guide/index Administer your ShingleAI organization, billing, security, and integrations The Admin Guide covers everything you do as an account or organization admin: shape your team, run billing, secure access, and connect external services. ## Where to start Set up your organization, invite team members, and define roles Subscriptions, credits, usage tracking, and the Stripe portal Passkeys, two-factor authentication, and API keys Connect Stripe and other external services ## Account-wide settings Configure in-app and email alerts for billing, usage, and integrations Name, avatar, timezone, language, and password ## Looking for something else? * End-user features (inbox, contacts, agents, automations) live in the [User Guide](/user-guide) * Programmatic access to ShingleAI is in the [API Reference](/api-reference/introduction) * AI agent integration is covered in the [MCP Server](/mcp-server/introduction) docs # Integrations Source: https://docs.shingleai.com/admin-guide/integrations/index Connect external services to ShingleAI Integrations let ShingleAI exchange data with the systems you already use. Each integration is configured at the right scope — payments at the Business level, mailbox connections at the email-address level, and so on. ## Available integrations Sync customers and transactions between a Business and a Stripe account Connect Gmail or Microsoft 365 mailboxes for inbound and outbound email Verify or register domains used for sending email Provision Telnyx numbers for SMS and voice Connecting a service usually requires the **Owner** or **Admin** role. Check each integration's page for specific requirements. # Stripe Connect Source: https://docs.shingleai.com/admin-guide/integrations/stripe Connect a Stripe account to a Business and sync customers and transactions into ShingleAI Stripe Connect links a Stripe account to a Business in ShingleAI so customers and transactions sync between the two systems. You configure it from your organization's settings — each Business can connect to one Stripe account. ## Prerequisites * You must be an **Owner** or **Admin** to connect, disconnect, or change sync settings * The Business you want to connect must already exist in ShingleAI (see [Business profile](/user-guide/businesses)) * You need an existing Stripe account with permission to authorize OAuth connections ## Connect Stripe To connect a Business to Stripe: 1. Navigate to **Settings > Integrations > Stripe** (at `/{orgSlug}/settings/integrations/stripe`) 2. Click **Connect Stripe** 3. You're redirected to Stripe's authorization page — sign in if needed and approve the connection 4. Stripe sends you back to the integration page with a success message When the connection completes, ShingleAI automatically: * Sets the sync mode to **One-Way** (Stripe → ShingleAI) * Triggers an initial full inbound sync of customers and transactions The connected account's name, email, and connection date appear at the top of the page once linked. The first connection's initial sync runs in the background. Larger Stripe accounts may take several minutes; the page shows the most recent full-sync timestamp when complete. ## Sync modes Stripe Connect supports three sync modes. You can switch between them at any time without disconnecting. | Mode | Direction | What syncs | When | | ----------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | **Off** | None | Nothing — connection stays linked but no data moves | N/A | | **One-Way** | Stripe → ShingleAI | Customers, charges, invoices from Stripe | Real-time via webhooks; full sync on enable from Off (if >7 days stale) or via **Sync Now** | | **Two-Way** | Both directions | Inbound from Stripe (as One-Way) plus outbound: customer name, email, and phone edits in ShingleAI push to Stripe | Inbound real-time; outbound triggered by edits in ShingleAI | To change modes: 1. On the Stripe integration page, find the **Sync mode** card 2. Select the new mode 3. Confirm in the dialog that explains what will happen Switching to **Two-Way** does not bulk-push existing ShingleAI customers to Stripe. Only future edits sync outbound. Inbound sync from Stripe remains complete in both One-Way and Two-Way. ### Manual full sync Use **Sync Now** on the integration page to re-run a full inbound sync without changing modes. This is useful after bulk changes in Stripe (e.g., importing customers there) or to recover from a long offline period. When sync mode was Off for more than 7 days and you re-enable it, ShingleAI runs a full inbound sync automatically to catch up. ## Customer mapping ShingleAI tries to link Stripe customers to existing ShingleAI customers automatically by **normalized email address** during initial sync. The matching rules: | Result | Behavior | | -------------------------------------------- | -------------------------------------------------------------- | | Exactly one ShingleAI customer matches | Auto-linked | | Multiple ShingleAI customers share the email | Marked **ambiguous** — requires manual resolution | | No ShingleAI customer matches | Left unlinked — a new customer is created on first transaction | ### Manage mappings Click **Manage Customer Mapping** on the Stripe integration page (or visit `/{orgSlug}/settings/integrations/stripe/customer-mapping`) to review and edit links. The customer-mapping table shows each Stripe customer alongside its current link status. Filter by **All**, **Unlinked**, **Ambiguous**, or **Linked** to focus on what needs attention. For each row you can: * **Link** — Open the customer picker, search ShingleAI customers by name or email, and link manually * **Unlink** — Remove the existing link without deleting either customer * **Auto-link by email** — Bulk action at the top of the page; runs the same email-matching rule against all unlinked and ambiguous customers visible on the current page and reports a summary Pages of Stripe customers are pulled directly from Stripe's API with cursor-based pagination. Run the auto-link bulk action page-by-page if you have a large backlog. ## Sync errors When inbound or outbound sync fails for a specific customer or transaction, ShingleAI records the error and surfaces it in a **Sync errors** card on the main integration page. Each error row shows: * The entity that failed * The error message * How many times it has been retried * The timestamp of the last attempt For each error you can click **Retry** to re-run the sync for that single entity. On success, the error row is removed; on failure, the attempt count increments. The **Clear all** button at the top of the card removes all error rows but **does not retry them**. Use it to acknowledge errors you've decided to ignore. ## Disconnecting To disconnect Stripe from a Business: 1. On the Stripe integration page, click **Disconnect Stripe** 2. Confirm in the dialog Disconnecting: * Stops all future inbound and outbound sync * Preserves all customers and transactions already imported into ShingleAI * Leaves the Business in a clean state — you can connect a different Stripe account afterward ### Connection revoked from Stripe If you (or another Stripe admin) revoke ShingleAI's access from the Stripe Dashboard directly, ShingleAI detects the revocation the next time the integration page loads and shows a banner explaining the connection is no longer valid. Click the **Disconnect** button in the banner to clean up the broken connection record, then reconnect when ready. ## Limitations * **One Business per Stripe account.** Each Business connects to a single Stripe account; Stripe accounts cannot be shared across multiple Businesses * **Two-Way is forward-only.** Switching to Two-Way pushes future ShingleAI edits to Stripe but does not back-fill historical edits * **Ambiguous matches require human review.** Auto-link skips any Stripe customer whose email matches multiple ShingleAI customers * **Stripe rate limits.** Initial sync respects Stripe's per-account rate limits and throttles between pages, so very large accounts take longer than a single API page would suggest ## Next steps Work with synced customers in ShingleAI Configure the Business that owns the Stripe connection # Notifications Source: https://docs.shingleai.com/admin-guide/notifications Receive in-app and email alerts for billing, usage, integrations, and system events ShingleAI sends notifications about events that need your attention — billing failures, usage thresholds, lost integration connections, credit balance changes, and more. You receive each notification in the in-app bell and (optionally) by email; preferences are configurable per type and per channel. ## In-app bell The bell icon in the app header shows your unread count. Click it to open a panel with: * The most recent notifications, newest first, each with a relative timestamp ("2 hours ago", or absolute date for older items) * A blue dot next to unread items * A **Clear all** button at the top Clicking any notification marks it read immediately. Real-time updates are pushed over a WebSocket connection to the NotificationHub Durable Object — when that connection drops, the panel falls back to polling so you don't miss anything. ## Notification settings To change which notifications you receive and where: 1. Navigate to **Settings > User > Notifications** 2. Toggle individual notification types on or off per channel 3. Use **Unsubscribe from all emails** at the top to silence non-critical email globally — critical account-related messages (payment failures, security alerts) still send Settings are per-user; each team member configures their own. ### Channels | Channel | Status | | ---------------- | ------------------------------------------------------ | | **In-app (Web)** | Live | | **Email** | Live | | **SMS** | Defined in the data model — not yet wired for delivery | | **Mobile push** | Defined in the data model — not yet wired for delivery | The notification settings page only exposes the live channels (Web and Email). SMS and mobile push settings will appear when their delivery is enabled. ## Notification types Notifications are grouped by category in the settings UI. The full set of types currently emitted: ### Domains | Type | Triggered when | | ------------------------------- | -------------------------------------------------- | | `domain_expiration_warning` | A registered domain is approaching expiration | | `domain_renewal_success` | Auto-renewal completed successfully | | `domain_renewal_failed` | A renewal attempt failed (non-payment reason) | | `domain_renewal_payment_failed` | Renewal failed because the payment method declined | | `domain_registration_succeeded` | A new domain registration completed | | `domain_registration_failed` | A new registration could not complete | ### Email accounts | Type | Triggered when | | ------------------------------- | --------------------------------------------------------------------------- | | `email_address_connection_lost` | A connected email account stopped syncing (token revoked, password changed) | | `email_address_setup_failed` | A new email account couldn't finish setup | | `gmail_connection_lost` | A Google Workspace / Gmail account specifically lost its OAuth grant | ### Email sending (Resend) | Type | Triggered when | | ----------------------------- | ------------------------------------------ | | `resend_setup_initiated` | Resend domain setup has been started | | `resend_verification_success` | A sending domain finished DNS verification | | `resend_verification_failed` | A sending domain failed DNS verification | ### Phone and voice | Type | Triggered when | | ------------------------------ | ---------------------------------------------- | | `phone_number_connection_lost` | A connected number went offline at the carrier | | `phone_number_setup_failed` | A new phone number couldn't finish setup | | `voice_call_error` | A live voice call ended with an error | ### Usage | Type | Triggered when | | ---------------------- | ----------------------------------------------------------------------- | | `usage_warning` | A consumable reaches 90% of its monthly allowance | | `usage_limit_reached` | A consumable reaches 100% of its allowance | | `usage_limit_exceeded` | A consumable goes beyond 100% (overages now apply or service is paused) | ### Billing and payments | Type | Triggered when | | --------------------------- | -------------------------------------------------------------- | | `payment_failure_immediate` | A subscription or top-up payment was declined | | `payment_failure_24h` | 24-hour follow-up if a failed payment hasn't been resolved | | `payment_failure_48h_final` | Final notice — service may be paused if not resolved | | `trial_started` | A new trial has started for your account | | `trial_will_end` | Your trial ends in the next few days | | `trial_ended` | Your trial has ended (converted to paid or downgraded to Free) | ### Credits | Type | Triggered when | | -------------------------------- | ------------------------------------------------------------------------ | | `credit_purchase_success` | A one-time credit purchase completed | | `credit_purchase_failed` | A credit purchase attempt failed | | `credit_balance_low` | Your credit balance dropped below the auto-recharge or default threshold | | `credit_balance_depleted` | Your credit balance reached zero | | `credit_auto_recharge_triggered` | An automatic credit top-up fired | ### System | Type | Triggered when | | -------------- | -------------------------------------------------------------- | | `system_error` | An internal error affected your account and warrants attention | ## Critical notifications A subset of notifications always send by email regardless of your preferences: * Payment failures (`payment_failure_*`) * Credit purchase failures (`credit_purchase_failed`) * Domain renewal payment failures (`domain_renewal_payment_failed`) * System errors (`system_error`) These exist to make sure you can recover from situations that can interrupt service or lose data. ## Next steps Configure auto-recharge to head off `credit_balance_low` alerts Track consumption that drives `usage_*` notifications # Organization Source: https://docs.shingleai.com/admin-guide/organization/index Set up your organization, invite team members, and configure roles An **organization** is the workspace your team shares — contacts, agents, automations, businesses, and integrations all live inside it. One ShingleAI account can own multiple organizations; team members and billing are tracked at the account level above. ## In this section Create an organization and configure its general and notification settings Invite, remove, and manage seats for your team Owner, Admin, and User capability matrix # Roles & Permissions Source: https://docs.shingleai.com/admin-guide/organization/permissions Understand how access control works in ShingleAI ShingleAI uses a role-based access control system to manage what team members can see and do within your organization. This guide explains the permission model and how to configure access for your team. ## Role Types Every organization member has one of three roles: | Role | Description | | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Owner** | Full access to all organization resources and settings. Can manage billing, API keys, and delete the organization. | | **Admin** | Full access to business data. Can invite members and manage integrations. Can view billing and subscription data but cannot modify the subscription or manage API keys. | | **User** | Read-only access to business data (contacts, messages, automations). Full access to their own user resources (files, preferences). Cannot access organization settings. | Each organization must have at least one Owner. Ownership can be transferred but not removed entirely. ## Permission Model ShingleAI's permission system is built on three core concepts: ### 1. Actions Every permission check evaluates one of three actions: | Action | HTTP Methods | Description | | -------- | ---------------- | -------------------------- | | `read` | GET | View resources | | `write` | POST, PUT, PATCH | Create or modify resources | | `delete` | DELETE | Remove resources | ### 2. Resources Resources are organized hierarchically using dot notation. For example: ``` contacts contacts.emails contacts.phones contacts.tags ``` ### 3. Inheritance Permissions flow from parent to child resources. If you grant `read` access to `contacts`, that permission automatically applies to `contacts.emails`, `contacts.phones`, and all other child resources—unless explicitly overridden. ## Role Permissions ### Owner Permissions Owners have unrestricted access to all resources: | Resource Category | Read | Write | Delete | | ---------------------- | ---- | ----- | ------ | | Organization settings | Yes | Yes | Yes | | Members & invites | Yes | Yes | Yes | | API keys | Yes | Yes | Yes | | Billing & subscription | Yes | Yes | Yes | | All business data | Yes | Yes | Yes | ### Admin Permissions Admins have full data access with limited administrative capabilities: | Resource Category | Read | Write | Delete | | ---------------------- | ---- | ----- | ------ | | Organization settings | Yes | No | No | | Members | Yes | No | No | | Invites | Yes | Yes | Yes | | Connections | Yes | No | No | | Workflows | Yes | Yes | Yes | | API keys | No | No | No | | Billing & subscription | Yes | No | No | | Contacts & customers | Yes | Yes | Yes | | Messages | Yes | Yes | Yes | | Automations | Yes | Yes | Yes | | Files & folders | Yes | Yes | Yes | ### User Permissions Users have read-only access to organization data with full control over their own resources: | Resource Category | Read | Write | Delete | | ---------------------------------------- | ---- | ----- | ------ | | Organization settings | No | No | No | | Members & invites | No | No | No | | API keys | No | No | No | | Contacts, customers, businesses, domains | Yes | No | No | | Messages, automations, email templates | Yes | No | No | | Tasks | Yes | No | No | | RAG resources & embeddings | Yes | No | No | | Files & folders | Yes | Yes | No | | Own user profile | Yes | Yes | Yes | | Own notifications | Yes | Yes | Yes | ## Resource Categories The permission system covers these top-level resources: ### Contact and customer data * `contacts` — Contact records (children: `emails`, `phones`, `addresses`) * `customers` — Customer relationships (children: `transactions`) * `businesses` — Business entities (children: `offerings`, `onlinePresences`, `physicalPresences`, `profiles`) * `domains` — Verified and registered domains (children: `domainContacts`, `domainRegistrations`) ### Communication * `messages` — Conversation threads (children: `attachments`, `contacts`) * `incomingMessages` — Inbound message records (children: `attachments`, `contacts`) * `outgoingMessages` — Outbound message records (children: `attachments`, `contacts`) * `emailTemplates` — Reusable email templates ### Tasks and automations * `tasks` — Tasks (children: `assignees`, `activity`) * `automations` — Plain-English automations ### Files and knowledge * `files`, `folders` — Uploaded files and the folder tree * `resources`, `embeddings` — RAG-indexed assets used by agents ### Organization administration * `organization` — Org-level settings, with children: * `members` — Team membership * `invites` — Pending invitations * `connections` — Integration connections (Stripe, etc.) * `subscriptions` — Billing and subscription * `workflows` — Internal workflow registry * `apiKeys` — Owner-only API key management ### User-level resources * `userNotifications` — Personal notification preferences and history * `userProfiles` — Personal profile (name, avatar, timezone, language) ## API Key Permissions API keys have their own independent permission system — they do **not** inherit the permissions of the user that created them. When you create a key, you grant it specific resource access and restrict it to specific actions. This means a User-role team member can still create an API key with broader permissions than they themselves have, provided their role allows key creation in the first place (currently Owner-only). See [API Key Management](/admin-guide/security/api-keys) for details. ## Best Practices ### Principle of Least Privilege Assign the minimum role needed for each team member: * Use **User** role for team members who only need to view data * Use **Admin** role for managers who need to edit data and invite members * Reserve **Owner** role for account administrators ### Regular Access Reviews Periodically review your organization's members: * Remove inactive members promptly * Verify role assignments match current responsibilities * Check for any unused API keys ### Separation of Duties For sensitive operations, consider: * Limiting Owner role to 1-2 trusted administrators * Using separate API keys for different integrations * Enabling audit logging to track changes ## Next Steps Learn how to invite and manage team members Create API keys with custom permissions # Organization Setup Source: https://docs.shingleai.com/admin-guide/organization/setup Create and configure your ShingleAI organization An organization is the primary workspace in ShingleAI where your team collaborates on business communications. All data—contacts, messages, automations—is scoped to your organization. ## Creating an Organization When you sign up for ShingleAI, you automatically create your first organization. Each organization includes: * **Name**: A display name for your organization (e.g., "Acme Corp") * **Slug**: A unique identifier used in URLs and API calls (auto-generated) * **Owner**: The user who created the organization (you) Your account tier determines how many organizations you can create. Most plans support a single organization, while enterprise tiers allow multiple organizations for managing separate business units. ## Organization Settings Access your organization settings from **Settings > Organization** in the dashboard. ### General Settings | Setting | Description | | ----------------- | ---------------------------------------------------------------------------- | | Organization Name | Display name shown throughout the app | | Slug | Unique identifier used in URLs and API references (read-only after creation) | | Time Zone | Default time zone for scheduling and reports | ### Notification Settings Configure which team members receive notifications for different event types. Notifications can be customized by role: * **Owner notifications**: Critical alerts, billing, security events * **Admin notifications**: Team changes, integration status, system alerts * **User notifications**: Assignment updates, task reminders ## Account Limits Your organization operates within your account's resource limits: | Resource | Description | | ------------- | ------------------------------------- | | Organizations | Number of organizations per account | | Seats | Maximum team members per organization | | Connections | Email provider connections | | API Keys | Active API keys | Contact support to upgrade your account limits or discuss enterprise options for multi-organization setups. ## Multi-Organization Support Enterprise accounts can create multiple organizations to: * Separate business units or brands * Isolate client data for agencies * Maintain development and production environments Each organization has its own: * Team members and roles * Email connections and integrations * Contacts, customers, and business data * API keys Users can belong to multiple organizations and switch between them from the account menu. ## Next Steps Invite team members to your organization Configure access control for your team # User Management Source: https://docs.shingleai.com/admin-guide/organization/users Invite, manage, and remove team members in your organization Manage who has access to your ShingleAI organization by inviting team members, assigning roles, and controlling seat allocation. ## Prerequisites * You must be an **Owner** or **Admin** to manage users * Available seats in your organization ## Inviting Team Members To invite a new team member: 1. Navigate to **Settings > Organization > Members** 2. Click **Invite Member** 3. Enter the invitee's email address 4. Select a role: **Admin** or **User** (Owners cannot be invited—ownership must be transferred) 5. Click **Send Invite** The invitee receives an email with a unique invitation link. They must create a ShingleAI account (or sign in to an existing one) to join your organization. Invitations expire after 7 days by default. You can resend or revoke invitations from the pending invites list. ### Invitation Statuses | Status | Description | | -------- | -------------------------------- | | Pending | Invite sent, awaiting acceptance | | Accepted | User has joined the organization | | Expired | Invite link has expired (7 days) | | Revoked | Invite was manually cancelled | ## Managing Team Members ### Viewing Members The Members page displays all organization members with: * Name and email * Role (Owner, Admin, User) * Join date * Status ### Changing Roles Only Owners can change member roles: 1. Find the member in the list 2. Click the role dropdown 3. Select the new role You cannot demote yourself. An organization must always have at least one Owner. ### Role Capabilities | Action | Owner | Admin | User | | --------------------------- | ----- | ----- | --------- | | View organization data | Yes | Yes | Yes | | Manage contacts & customers | Yes | Yes | Read-only | | Send messages | Yes | Yes | No | | Invite members | Yes | Yes | No | | Remove members | Yes | No | No | | Change member roles | Yes | No | No | | Manage API keys | Yes | No | No | | Billing & subscription | Yes | No | No | | Delete organization | Yes | No | No | See [Roles & Permissions](/admin-guide/organization/permissions) for detailed permission information. ## Removing Members Only Owners can remove members from the organization. To remove a member: 1. Navigate to **Settings > Organization > Members** 2. Find the member to remove 3. Click the **Remove** button (trash icon) 4. Confirm the removal Removing a member revokes their access immediately. Their data and activity history remain in the organization for audit purposes. ### What Happens When a Member is Removed * Immediate loss of organization access * Active sessions are terminated * Personal API keys are revoked * Email connections remain active (organization-owned) * Assigned tasks may need reassignment ## Seat Management Your organization has a maximum number of seats based on your subscription plan. ### Checking Seat Usage View your current seat allocation in **Settings > Organization > Members**: * **Used seats**: Active members * **Available seats**: Remaining capacity * **Pending invites**: Reserved but not yet accepted ### Seat Limits | Scenario | Behavior | | ------------------------ | --------------------------------------- | | At seat limit | Cannot send new invites | | Invite accepted at limit | Invite fails, user notified | | Member removed | Seat freed immediately | | Pending invite | Reserves a seat until expiry/revocation | To add more seats, upgrade your subscription plan in **Settings > Billing**. ## Transferring Ownership Organization ownership can be transferred to another Admin: 1. Navigate to **Settings > Organization > Members** 2. Find the Admin to promote 3. Click **Transfer Ownership** 4. Confirm the transfer After transfer: * The new Owner has full control * You become an Admin * This action cannot be undone without the new Owner's consent ## Next Steps Understand permission scopes for each role Create API keys for programmatic access # API Key Management Source: https://docs.shingleai.com/admin-guide/security/api-keys Create and manage API keys for programmatic access to ShingleAI API keys allow external applications and scripts to access your ShingleAI organization programmatically. This guide covers creating, configuring, and securing your API keys. This guide covers API keys for REST API access. AI agents (Claude, Cursor, Windsurf, etc.) connect through the [MCP server](/mcp-server/introduction), which uses its own authentication flow rather than API keys. ## Prerequisites * You must be an **Owner** to manage API keys * Admins and Users cannot create, view, or revoke API keys ## Creating an API Key To create a new API key: 1. Navigate to **Settings > Security > API Keys** 2. Click **Create API Key** 3. Enter a descriptive name (e.g., "Production CRM Integration") 4. Configure permissions (see below) 5. Optionally set an expiration date 6. Click **Create** The full API key is displayed only once after creation. Copy it immediately and store it securely. You cannot retrieve the full key later. ### API Key Format ShingleAI API keys follow this format: ``` sk_live_abc123... ``` * `sk_` - Indicates a secret key * `live_` - Environment (live for production) * Followed by a unique identifier ## Setting Permissions API keys support fine-grained permissions that control which resources the key can access and what actions it can perform. ### Permission Structure Each permission specifies: | Component | Description | Example | | --------- | --------------------------- | ------------------------- | | Resource | What the key can access | `contacts`, `messages` | | Action | What operations are allowed | `read`, `write`, `delete` | ### Common Permission Patterns **Read-Only Access** ```json theme={null} { "contacts": { "read": true, "write": false, "delete": false }, "customers": { "read": true, "write": false, "delete": false } } ``` **Full Contact Management** ```json theme={null} { "contacts": { "read": true, "write": true, "delete": true } } ``` **Messaging Only** ```json theme={null} { "messages": { "read": true, "write": true, "delete": false } } ``` ### Permission Inheritance Permissions cascade to child resources. Granting access to `contacts` automatically includes: * `contacts.emails` * `contacts.phones` * `contacts.addresses` * `contacts.tags` * `contacts.notes` You can override child permissions to restrict access further. ## Key Expiration Set an expiration date to automatically disable API keys after a certain period: | Use Case | Recommended Expiration | | ----------------------- | ------------------------------- | | Temporary integrations | 7-30 days | | Contractor access | Project duration | | Production integrations | 90-365 days | | Internal tools | No expiration (rotate manually) | Expired keys return a `401 Unauthorized` error. Create a new key before the old one expires to avoid service interruption. ## Monitoring Key Usage Track API key activity from the API Keys dashboard: | Metric | Description | | --------- | ------------------------------------- | | Last Used | Timestamp of the most recent API call | | Created | When the key was created | | Expires | Expiration date (if set) | | Status | Active, Expired, or Revoked | Use the "Last Used" timestamp to identify unused keys that should be revoked. ## Revoking Keys To revoke an API key: 1. Navigate to **Settings > Security > API Keys** 2. Find the key to revoke 3. Click **Revoke** 4. Confirm the action Revoked keys cannot be restored. Any application using the revoked key will immediately lose access. ### When to Revoke Revoke API keys immediately when: * A key may have been compromised * An employee with key access leaves the organization * An integration is decommissioned * A key hasn't been used in 90+ days ## Security Best Practices ### Key Storage * **Never** commit API keys to version control * Use environment variables or secret management services * Restrict file permissions on configuration files containing keys ```bash Environment Variable theme={null} export SHINGLEAI_API_KEY="sk_live_abc123..." ``` ```typescript TypeScript theme={null} const apiKey = process.env.SHINGLEAI_API_KEY; ``` ```python Python theme={null} import os api_key = os.environ.get('SHINGLEAI_API_KEY') ``` ### Key Rotation Regularly rotate API keys to limit exposure from potential leaks: 1. Create a new key with the same permissions 2. Update your application to use the new key 3. Verify the new key works in production 4. Revoke the old key Recommended rotation schedule: | Environment | Rotation Frequency | | --------------- | ------------------ | | Production | Every 90 days | | Development | Every 30 days | | After incidents | Immediately | ### Principle of Least Privilege Grant only the permissions each integration needs: * Read-only keys for reporting and analytics * Resource-specific keys for focused integrations * Separate keys for separate applications ### Audit Regularly Review your API keys monthly: * Remove unused keys (no activity in 90+ days) * Verify permissions match current requirements * Check expiration dates and rotate as needed ## Troubleshooting ### Common Errors | Error | Cause | Solution | | ----------------------- | ------------------------ | --------------------------------------- | | `401 Unauthorized` | Invalid or expired key | Check key value and expiration | | `403 Forbidden` | Insufficient permissions | Verify key has required resource/action | | `429 Too Many Requests` | Rate limit exceeded | Implement backoff and retry logic | ### Debugging Permission Issues If your API key returns `403 Forbidden`: 1. Check the error response for the required permission 2. Compare against your key's configured permissions 3. Update the key or create a new one with correct permissions ## Next Steps Learn how to use the ShingleAI API Understand API authentication methods # Security Source: https://docs.shingleai.com/admin-guide/security/index Configure security settings in ShingleAI Manage API keys and other security settings for your ShingleAI organization. ## Key Management ShingleAI uses **API Keys** for REST API access from backend services, scripts, and integrations. API key management requires the **Owner** role. Create keys for REST API integrations AI agents (Claude, Cursor, Windsurf, etc.) connect through the [MCP server](/mcp-server/introduction), which uses its own authentication flow rather than API keys. ## Security Best Practices * **Principle of least privilege**: Grant only the permissions each key needs * **Separate keys per integration**: Create dedicated keys for each service or agent * **Regular audits**: Review and revoke unused keys monthly * **Secure storage**: Never commit keys to version control; use environment variables # Passkeys Source: https://docs.shingleai.com/admin-guide/security/passkeys Sign in with biometrics or a hardware key using WebAuthn passkeys Passkeys let you sign in to ShingleAI without a password using your device's biometrics (Touch ID, Face ID, Windows Hello) or a hardware security key. Passkeys are phishing-resistant and don't require remembering or rotating a shared secret. ## Prerequisites * A device or browser that supports WebAuthn (every current major browser does) * A signed-in ShingleAI account — passkeys are added to your existing account, not used to create one ## Add a passkey 1. Navigate to **Settings > User > Security** 2. In the **Passkeys** card, click **Add passkey** 3. Your browser prompts you to choose a device — phone biometric, platform authenticator (Touch ID / Windows Hello), or a security key 4. Complete the device prompt The new passkey appears in the list with an auto-generated name (`Passkey #1`, `Passkey #2`, etc.) and the date it was added. Add as many passkeys as you have devices — each one is registered to that specific device. You can register passkeys even if your account uses email-and-password sign-in. Passkeys are an additional sign-in method, not a replacement. ## Rename or delete a passkey In the **Passkeys** card: * Click the **pencil** icon to rename a passkey (max 64 characters) — useful for distinguishing "Work laptop" from "Personal phone" * Click the **trash** icon to delete a passkey, then confirm Deleted passkeys cannot be restored — register a new one if you need access from that device again. ## Sign in with a passkey On the sign-in page: * **Conditional UI (autofill).** If your browser supports it, your saved passkey appears as a sign-in option directly in the email field's autofill menu — pick it, complete the device prompt, and you're in * **Manual button.** Click **Sign in with a passkey** to invoke the device picker without typing your email You can sign in with a passkey from any device that has one registered to your account. ## Limitations * **Last-used timestamp not yet tracked.** The passkey list shows the date a passkey was added but not when it was last used to sign in * **Per-device.** Passkeys are bound to the device that created them and don't sync across browsers unless you use a synced passkey provider (iCloud Keychain, Google Password Manager, 1Password, etc.) ## Next steps Add an extra factor with TOTP and backup codes Programmatic access for external integrations # Two-factor authentication Source: https://docs.shingleai.com/admin-guide/security/two-factor Protect your account with TOTP codes and recovery backup codes Two-factor authentication (2FA) requires a one-time code from an authenticator app each time you sign in. ShingleAI uses TOTP (time-based one-time passwords), the same standard used by Google Authenticator, 1Password, Authy, and most other authenticator apps. ## Prerequisites * A signed-in ShingleAI account with email-and-password sign-in (your password is required to enable 2FA) * An authenticator app installed on your phone or password manager ## Enable two-factor authentication 1. Navigate to **Settings > User > Security** 2. In the **Two-factor authentication** card, click **Enable two-factor authentication** 3. Enter your current password to confirm 4. Scan the displayed QR code with your authenticator app — or enter the secret manually if you can't scan 5. Enter the 6-digit code your app generates to verify the setup 6. Save the **backup codes** displayed on the next screen, then click **Done** Backup codes are shown **only once**. Save them in a password manager or other secure location before clicking Done. You'll need them if you ever lose access to your authenticator app. ### Backup codes Each backup code can be used once in place of a TOTP code. Use them when you don't have your authenticator app handy — for example, after losing or wiping a phone. To generate a fresh set: 1. In the **Two-factor authentication** card, click **Regenerate backup codes** 2. Enter your current password 3. Save the new codes — the previous set is invalidated immediately ## Sign in with two-factor authentication When 2FA is enabled, sign-in requires two steps: 1. Enter your email and password 2. Enter the 6-digit code from your authenticator app (or a one-time backup code) You're prompted on every new session — existing sessions stay valid until they expire normally. ## Disable two-factor authentication 1. Navigate to **Settings > User > Security** 2. In the **Two-factor authentication** card, click **Disable 2FA** 3. Enter your current password to confirm Disabling clears your TOTP secret and all unused backup codes. ## Limitations * **Self-serve only.** 2FA is per-user; ShingleAI does not yet support organization-wide 2FA enforcement * **Active sessions list not yet available.** You can't currently view or revoke individual signed-in sessions from the security settings page — clearing browser cookies or changing your password ends all sessions ## Recovering a locked-out account If you've lost access to both your authenticator app and your backup codes, contact support — there is no self-serve path to disable 2FA without one of those factors. ## Next steps Sign in with biometrics or a hardware key Programmatic access for integrations # User profile Source: https://docs.shingleai.com/admin-guide/user-profile Manage your name, avatar, timezone, and language preferences Your user profile is per-account, not per-organization — settings here apply everywhere you sign in. Each team member maintains their own profile. ## Where to find it Navigate to **Settings > User > Profile**. ## Editable fields | Field | Notes | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Profile picture** | Upload JPG, PNG, GIF, or WebP up to 10 MB. Drag-and-drop or pick from disk. Used in @-mentions, comments, and the team-members list | | **First name** | Optional, free-form | | **Last name** | Optional, free-form | | **Timezone** | IANA timezone (e.g., `America/Los_Angeles`). Determines display of timestamps across the app. Defaults to `America/Los_Angeles` | | **Language** | UI language. Currently supported: English (en), Spanish (es), French (fr), German (de), Italian (it), Japanese (ja), Korean (ko), Chinese (zh), Portuguese (pt), Russian (ru), Arabic (ar), Hindi (hi). Defaults to `en` | Changes save when you click **Save** at the bottom of the form. Language affects the web UI only. Email content and AI agent output use the locale they were authored in. ## Change your password Password changes live on the security settings page, not the profile page. 1. Navigate to **Settings > User > Security** 2. In the **Password** card, enter your current password 3. Enter and confirm a new password 4. Click **Update password** Password requirements: at least 8 characters with at least one uppercase letter, one lowercase letter, and one number. This option is only visible if your account uses email-and-password sign-in. Accounts that sign in only with a third-party provider (Google, Microsoft) manage credentials at the provider. ## Email verification Your email address is verified when you first sign up: 1. Click the verification link in the email ShingleAI sends after signup 2. You're automatically signed in after verification If you didn't receive the email, request a new one from the sign-in page. ## Account deletion Self-serve account deletion isn't currently available — contact support to delete your account and associated data. ## Next steps Configure how you receive alerts Add 2FA to your account # Docs MCP server Source: https://docs.shingleai.com/agent-resources/docs-mcp Mintlify-hosted MCP server for these docs. # llms.txt Source: https://docs.shingleai.com/agent-resources/llms Index of these docs in the llms.txt format. # llms-full.txt Source: https://docs.shingleai.com/agent-resources/llms-full Full body of these docs in the llms.txt format. # MCP server Source: https://docs.shingleai.com/agent-resources/mcp Connect AI agents to your ShingleAI organization. # Authentication Source: https://docs.shingleai.com/api-reference/authentication Learn how to authenticate with the ShingleAI API The ShingleAI API uses API keys to authenticate requests. You can create and manage API keys from your organization settings in the dashboard. ## Creating an API Key 1. Sign in to the [ShingleAI Dashboard](https://www.shingleai.com/home) 2. Navigate to **Settings** > **API Keys** 3. Click **Create API Key** 4. Give your key a descriptive name (e.g., "Production Server" or "Development") 5. Select the permission scopes your key needs 6. Click **Create** and copy your key immediately Your API key is only shown once when created. Store it securely - you won't be able to see it again. If you lose your key, you'll need to create a new one. ## Using Your API Key Include your API key in the `Authorization` header of every request using the Bearer token format: ``` Authorization: Bearer your-api-key ``` ```bash cURL theme={null} curl https://api.shingleai.com/v1/contacts \ -H "Authorization: Bearer sk_live_abc123..." ``` ```typescript TypeScript theme={null} const response = await fetch('https://api.shingleai.com/v1/contacts', { headers: { 'Authorization': 'Bearer sk_live_abc123...', }, }); const { data } = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( 'https://api.shingleai.com/v1/contacts', headers={ 'Authorization': 'Bearer sk_live_abc123...', } ) data = response.json()['data'] ``` ## Permission Scopes API keys are scoped to specific permissions that control what resources they can access. When creating a key, grant only the permissions your integration needs. ### Available Scopes | Resource | Actions | Description | | -------------- | ------------------- | ---------------------------------------- | | `contacts` | read, write, delete | Manage contacts and their details | | `customers` | read, write, delete | Manage customer records | | `businesses` | read, write, delete | Manage business profiles | | `messages` | read, write, delete | Access email, SMS, and voice messages | | `automations` | read, write, delete | Configure automation workflows | | `domains` | read, write, delete | Manage custom domains | | `users` | read, write, delete | Manage user profiles and settings | | `organization` | read, write, delete | Manage organization settings and members | | `api_keys` | read, write, delete | Manage API keys and their permissions | | `resources` | read, write, delete | Access shared resources and analytics | ### Permission Inheritance Permissions follow a hierarchical model. Granting access to a parent resource also grants access to its child resources: * `contacts` includes `contacts.emails`, `contacts.phones`, `contacts.addresses`, `contacts.tags`, `contacts.notes` * `customers` includes `customers.contacts` * `businesses` includes `businesses.details`, `businesses.tags`, `businesses.contacts`, `businesses.addresses` * `messages` includes `messages.email`, `messages.sms`, `messages.voice` * `automations` includes `automations.actions` * `domains` includes `domains.dns`, `domains.verification` * `users` includes `users.profile`, `users.settings` * `organization` includes `organization.settings`, `organization.billing` * `resources` includes `resources.analytics` ### HTTP Methods and Permissions | HTTP Method | Required Permission | | ----------- | ------------------- | | GET | `read` | | POST | `write` | | PUT, PATCH | `write` | | DELETE | `delete` | ## Authentication Errors If authentication fails, you'll receive a `401 Unauthorized` response: ```json theme={null} { "error": { "code": "UNAUTHORIZED", "message": "Invalid or missing API key" } } ``` Common causes: * Missing `Authorization` header * Invalid or revoked API key * Malformed Bearer token (missing "Bearer " prefix) If your key lacks permission for a specific action, you'll receive a `403 Forbidden` response: ```json theme={null} { "error": { "code": "INSUFFICIENT_PERMISSIONS", "message": "Missing write permission for contacts", "details": { "required": { "resource": "contacts", "action": "write" }, "hint": "Contact your administrator to request additional permissions" } } } ``` ## Security Best Practices Use environment variables or a secrets manager to store your API keys. Add `.env` files to your `.gitignore`. ```bash theme={null} # .env (never commit this file) SHINGLEAI_API_KEY=sk_live_abc123... ``` ```typescript theme={null} // Use environment variables const apiKey = process.env.SHINGLEAI_API_KEY; ``` Create different API keys for development, staging, and production. This limits the blast radius if a key is compromised. Follow the principle of least privilege. Only grant the specific permissions your integration needs. A read-only dashboard doesn't need write access. Periodically create new API keys and deprecate old ones. This limits the window of exposure if a key is leaked. Review your API key activity in the dashboard regularly. Revoke any keys showing suspicious activity immediately. ## Server-Side Only API keys should only be used in server-side code. Never expose your API key in client-side JavaScript, mobile apps, or any code that runs in the browser. If you need to access the ShingleAI API from a client application, implement a backend proxy that handles authentication on behalf of your users. # Get automation execution Source: https://docs.shingleai.com/api-reference/automation-executions/get-automation-execution /api-reference/openapi.json get /v1/automations/{id}/executions/{executionId} Get a specific execution for an automation # List automation executions Source: https://docs.shingleai.com/api-reference/automation-executions/list-automation-executions /api-reference/openapi.json get /v1/automations/{id}/executions List all executions for a specific automation with pagination # Create automation Source: https://docs.shingleai.com/api-reference/automations/create-automation /api-reference/openapi.json post /v1/automations Create a new automation # Delete automation Source: https://docs.shingleai.com/api-reference/automations/delete-automation /api-reference/openapi.json delete /v1/automations/{id} Delete an automation (soft delete) # Get automation Source: https://docs.shingleai.com/api-reference/automations/get-automation /api-reference/openapi.json get /v1/automations/{id} Get a specific automation by ID # List automations Source: https://docs.shingleai.com/api-reference/automations/list-automations /api-reference/openapi.json get /v1/automations List all automations with pagination support # Partially update automation Source: https://docs.shingleai.com/api-reference/automations/partially-update-automation /api-reference/openapi.json patch /v1/automations/{id} Partially update an existing automation. Only provided fields will be updated. # Update automation Source: https://docs.shingleai.com/api-reference/automations/update-automation /api-reference/openapi.json put /v1/automations/{id} Update an existing automation. Note: This endpoint accepts partial updates (same behavior as PATCH). All fields are optional. # Create business offering Source: https://docs.shingleai.com/api-reference/business-offerings/create-business-offering /api-reference/openapi.json post /v1/businesses/{id}/offerings Create a new offering for a business # Delete business offering Source: https://docs.shingleai.com/api-reference/business-offerings/delete-business-offering /api-reference/openapi.json delete /v1/businesses/{id}/offerings/{offeringId} Delete an offering from a business # Get business offering Source: https://docs.shingleai.com/api-reference/business-offerings/get-business-offering /api-reference/openapi.json get /v1/businesses/{id}/offerings/{offeringId} Get a specific offering for a business # List business offerings Source: https://docs.shingleai.com/api-reference/business-offerings/list-business-offerings /api-reference/openapi.json get /v1/businesses/{id}/offerings List all offerings for a specific business with pagination # Update business offering Source: https://docs.shingleai.com/api-reference/business-offerings/update-business-offering /api-reference/openapi.json put /v1/businesses/{id}/offerings/{offeringId} Update an existing offering for a business # Create business online presence Source: https://docs.shingleai.com/api-reference/business-online-presences/create-business-online-presence /api-reference/openapi.json post /v1/businesses/{id}/online-presences Create a new online presence for a business # Delete business online presence Source: https://docs.shingleai.com/api-reference/business-online-presences/delete-business-online-presence /api-reference/openapi.json delete /v1/businesses/{id}/online-presences/{onlinePresenceId} Delete an online presence from a business # Get business online presence Source: https://docs.shingleai.com/api-reference/business-online-presences/get-business-online-presence /api-reference/openapi.json get /v1/businesses/{id}/online-presences/{onlinePresenceId} Get a specific online presence for a business # List business online presences Source: https://docs.shingleai.com/api-reference/business-online-presences/list-business-online-presences /api-reference/openapi.json get /v1/businesses/{id}/online-presences List all online presences for a specific business with pagination # Update business online presence Source: https://docs.shingleai.com/api-reference/business-online-presences/update-business-online-presence /api-reference/openapi.json put /v1/businesses/{id}/online-presences/{onlinePresenceId} Update an existing online presence for a business # Create business physical presence Source: https://docs.shingleai.com/api-reference/business-physical-presences/create-business-physical-presence /api-reference/openapi.json post /v1/businesses/{id}/physical-presences Create a new physical presence for a business # Delete business physical presence Source: https://docs.shingleai.com/api-reference/business-physical-presences/delete-business-physical-presence /api-reference/openapi.json delete /v1/businesses/{id}/physical-presences/{physicalPresenceId} Delete a physical presence from a business # Get business physical presence Source: https://docs.shingleai.com/api-reference/business-physical-presences/get-business-physical-presence /api-reference/openapi.json get /v1/businesses/{id}/physical-presences/{physicalPresenceId} Get a specific physical presence for a business # List business physical presences Source: https://docs.shingleai.com/api-reference/business-physical-presences/list-business-physical-presences /api-reference/openapi.json get /v1/businesses/{id}/physical-presences List all physical presences for a specific business with pagination # Update business physical presence Source: https://docs.shingleai.com/api-reference/business-physical-presences/update-business-physical-presence /api-reference/openapi.json put /v1/businesses/{id}/physical-presences/{physicalPresenceId} Update an existing physical presence for a business # Get business profile Source: https://docs.shingleai.com/api-reference/business-profile/get-business-profile /api-reference/openapi.json get /v1/businesses/{id}/profile Get the profile for a specific business # Update business profile Source: https://docs.shingleai.com/api-reference/business-profile/update-business-profile /api-reference/openapi.json put /v1/businesses/{id}/profile Update the profile for a business # Get business Source: https://docs.shingleai.com/api-reference/businesses/get-business /api-reference/openapi.json get /v1/businesses/{id} Get a specific business by ID # List businesses Source: https://docs.shingleai.com/api-reference/businesses/list-businesses /api-reference/openapi.json get /v1/businesses List all businesses with pagination support # Partially update business Source: https://docs.shingleai.com/api-reference/businesses/partially-update-business /api-reference/openapi.json patch /v1/businesses/{id} Partially update an existing business. Only provided fields will be updated. # Update business Source: https://docs.shingleai.com/api-reference/businesses/update-business /api-reference/openapi.json put /v1/businesses/{id} Update an existing business. Note: This endpoint accepts partial updates (same behavior as PATCH). # Create contact address Source: https://docs.shingleai.com/api-reference/contact-addresses/create-contact-address /api-reference/openapi.json post /v1/contacts/{id}/addresses Create a new address for a contact # Delete contact address Source: https://docs.shingleai.com/api-reference/contact-addresses/delete-contact-address /api-reference/openapi.json delete /v1/contacts/{id}/addresses/{addressId} Delete an address from a contact # Get contact address Source: https://docs.shingleai.com/api-reference/contact-addresses/get-contact-address /api-reference/openapi.json get /v1/contacts/{id}/addresses/{addressId} Get a specific address for a contact # List contact addresses Source: https://docs.shingleai.com/api-reference/contact-addresses/list-contact-addresses /api-reference/openapi.json get /v1/contacts/{id}/addresses List all addresses for a specific contact with pagination # Update contact address Source: https://docs.shingleai.com/api-reference/contact-addresses/update-contact-address /api-reference/openapi.json put /v1/contacts/{id}/addresses/{addressId} Update an existing address for a contact # Create contact email Source: https://docs.shingleai.com/api-reference/contact-emails/create-contact-email /api-reference/openapi.json post /v1/contacts/{id}/emails Create a new email for a contact # Delete contact email Source: https://docs.shingleai.com/api-reference/contact-emails/delete-contact-email /api-reference/openapi.json delete /v1/contacts/{id}/emails/{emailId} Delete an email from a contact # List contact emails Source: https://docs.shingleai.com/api-reference/contact-emails/list-contact-emails /api-reference/openapi.json get /v1/contacts/{id}/emails List all emails for a specific contact with pagination # Update contact email Source: https://docs.shingleai.com/api-reference/contact-emails/update-contact-email /api-reference/openapi.json put /v1/contacts/{id}/emails/{emailId} Update an existing email for a contact # Create contact phone number Source: https://docs.shingleai.com/api-reference/contact-phone-numbers/create-contact-phone-number /api-reference/openapi.json post /v1/contacts/{id}/phone-numbers Create a new phone number for a contact # Delete contact phone number Source: https://docs.shingleai.com/api-reference/contact-phone-numbers/delete-contact-phone-number /api-reference/openapi.json delete /v1/contacts/{id}/phone-numbers/{phoneNumberId} Delete a phone number from a contact # List contact phone numbers Source: https://docs.shingleai.com/api-reference/contact-phone-numbers/list-contact-phone-numbers /api-reference/openapi.json get /v1/contacts/{id}/phone-numbers List all phone numbers for a specific contact with pagination # Update contact phone number Source: https://docs.shingleai.com/api-reference/contact-phone-numbers/update-contact-phone-number /api-reference/openapi.json put /v1/contacts/{id}/phone-numbers/{phoneNumberId} Update an existing phone number for a contact # Create contact Source: https://docs.shingleai.com/api-reference/contacts/create-contact /api-reference/openapi.json post /v1/contacts Create a new contact # Delete contact Source: https://docs.shingleai.com/api-reference/contacts/delete-contact /api-reference/openapi.json delete /v1/contacts/{id} Delete a contact (soft delete) # Get contact Source: https://docs.shingleai.com/api-reference/contacts/get-contact /api-reference/openapi.json get /v1/contacts/{id} Get a specific contact by ID with full details # List contacts Source: https://docs.shingleai.com/api-reference/contacts/list-contacts /api-reference/openapi.json get /v1/contacts List all contacts with full details and pagination support # Partially update contact Source: https://docs.shingleai.com/api-reference/contacts/partially-update-contact /api-reference/openapi.json patch /v1/contacts/{id} Partially update an existing contact. Only provided fields will be updated. # Update contact Source: https://docs.shingleai.com/api-reference/contacts/update-contact /api-reference/openapi.json put /v1/contacts/{id} Update an existing contact. Note: This endpoint accepts partial updates (same behavior as PATCH). # Create customer transaction Source: https://docs.shingleai.com/api-reference/customer-transactions/create-customer-transaction /api-reference/openapi.json post /v1/customers/{id}/transactions Create a new transaction for a customer # Delete customer transaction Source: https://docs.shingleai.com/api-reference/customer-transactions/delete-customer-transaction /api-reference/openapi.json delete /v1/customers/{id}/transactions/{transactionId} Delete a specific transaction for a customer (soft delete) # Get customer transaction Source: https://docs.shingleai.com/api-reference/customer-transactions/get-customer-transaction /api-reference/openapi.json get /v1/customers/{id}/transactions/{transactionId} Get a specific transaction for a customer # List customer transactions Source: https://docs.shingleai.com/api-reference/customer-transactions/list-customer-transactions /api-reference/openapi.json get /v1/customers/{id}/transactions List all transactions for a specific customer with pagination # Partially update customer transaction Source: https://docs.shingleai.com/api-reference/customer-transactions/partially-update-customer-transaction /api-reference/openapi.json patch /v1/customers/{id}/transactions/{transactionId} Partially update a specific transaction for a customer. Only provided fields will be updated. # Update customer transaction Source: https://docs.shingleai.com/api-reference/customer-transactions/update-customer-transaction /api-reference/openapi.json put /v1/customers/{id}/transactions/{transactionId} Update a specific transaction for a customer. Note: This endpoint accepts partial updates (same behavior as PATCH). All fields are optional. # Create customer Source: https://docs.shingleai.com/api-reference/customers/create-customer /api-reference/openapi.json post /v1/customers Create a new customer # Delete customer Source: https://docs.shingleai.com/api-reference/customers/delete-customer /api-reference/openapi.json delete /v1/customers/{id} Delete a customer (soft delete) # Get customer Source: https://docs.shingleai.com/api-reference/customers/get-customer /api-reference/openapi.json get /v1/customers/{id} Get a specific customer by ID # List customers Source: https://docs.shingleai.com/api-reference/customers/list-customers /api-reference/openapi.json get /v1/customers List all customers with pagination support # Partially update customer Source: https://docs.shingleai.com/api-reference/customers/partially-update-customer /api-reference/openapi.json patch /v1/customers/{id} Partially update an existing customer. Only provided fields will be updated. # Update customer Source: https://docs.shingleai.com/api-reference/customers/update-customer /api-reference/openapi.json put /v1/customers/{id} Update an existing customer. Note: This endpoint accepts partial updates (same behavior as PATCH). All fields are optional. # Create domain contact Source: https://docs.shingleai.com/api-reference/domain-contacts/create-domain-contact /api-reference/openapi.json post /v1/domains/{id}/contacts Create a new contact for a domain # Delete domain contact Source: https://docs.shingleai.com/api-reference/domain-contacts/delete-domain-contact /api-reference/openapi.json delete /v1/domains/{id}/contacts/{contactId} Delete a specific contact for a domain (soft delete) # Get domain contact Source: https://docs.shingleai.com/api-reference/domain-contacts/get-domain-contact /api-reference/openapi.json get /v1/domains/{id}/contacts/{contactId} Get a specific contact for a domain # List domain contacts Source: https://docs.shingleai.com/api-reference/domain-contacts/list-domain-contacts /api-reference/openapi.json get /v1/domains/{id}/contacts List all contacts for a specific domain with pagination # Partially update domain contact Source: https://docs.shingleai.com/api-reference/domain-contacts/partially-update-domain-contact /api-reference/openapi.json patch /v1/domains/{id}/contacts/{contactId} Partially update a specific contact for a domain. Only provided fields will be updated. # Update domain contact Source: https://docs.shingleai.com/api-reference/domain-contacts/update-domain-contact /api-reference/openapi.json put /v1/domains/{id}/contacts/{contactId} Update a specific contact for a domain. Note: This endpoint accepts partial updates (same behavior as PATCH). # Create domain registration Source: https://docs.shingleai.com/api-reference/domain-registrations/create-domain-registration /api-reference/openapi.json post /v1/domains/{id}/registrations Create a new registration for a domain # Delete domain registration Source: https://docs.shingleai.com/api-reference/domain-registrations/delete-domain-registration /api-reference/openapi.json delete /v1/domains/{id}/registrations/{registrationId} Delete a specific registration for a domain (soft delete) # Get domain registration Source: https://docs.shingleai.com/api-reference/domain-registrations/get-domain-registration /api-reference/openapi.json get /v1/domains/{id}/registrations/{registrationId} Get a specific registration for a domain # List domain registrations Source: https://docs.shingleai.com/api-reference/domain-registrations/list-domain-registrations /api-reference/openapi.json get /v1/domains/{id}/registrations List all registrations for a specific domain with pagination # Partially update domain registration Source: https://docs.shingleai.com/api-reference/domain-registrations/partially-update-domain-registration /api-reference/openapi.json patch /v1/domains/{id}/registrations/{registrationId} Partially update a specific registration for a domain. Only provided fields will be updated. # Update domain registration Source: https://docs.shingleai.com/api-reference/domain-registrations/update-domain-registration /api-reference/openapi.json put /v1/domains/{id}/registrations/{registrationId} Update a specific registration for a domain. Note: This endpoint accepts partial updates (same behavior as PATCH). # Create domain Source: https://docs.shingleai.com/api-reference/domains/create-domain /api-reference/openapi.json post /v1/domains Create a new domain # Delete domain Source: https://docs.shingleai.com/api-reference/domains/delete-domain /api-reference/openapi.json delete /v1/domains/{id} Delete a domain (soft delete) # Get domain Source: https://docs.shingleai.com/api-reference/domains/get-domain /api-reference/openapi.json get /v1/domains/{id} Get a specific domain by ID # List domains Source: https://docs.shingleai.com/api-reference/domains/list-domains /api-reference/openapi.json get /v1/domains List all domains with pagination support # Partially update domain Source: https://docs.shingleai.com/api-reference/domains/partially-update-domain /api-reference/openapi.json patch /v1/domains/{id} Partially update an existing domain. Only provided fields will be updated. # Update domain Source: https://docs.shingleai.com/api-reference/domains/update-domain /api-reference/openapi.json put /v1/domains/{id} Update an existing domain. Note: This endpoint accepts partial updates (same behavior as PATCH). All fields are optional. # Errors Source: https://docs.shingleai.com/api-reference/errors Understand ShingleAI API error codes and responses The ShingleAI API uses conventional HTTP status codes and returns detailed error information in JSON format to help you handle errors gracefully. ## Error Response Format All error responses follow a consistent structure: ```json theme={null} { "error": { "code": "ERROR_CODE", "message": "A human-readable description of the error", "details": { // Additional context (optional) } } } ``` | Field | Type | Description | | --------- | ------ | ------------------------------------------------------- | | `code` | string | A machine-readable error code for programmatic handling | | `message` | string | A human-readable description of what went wrong | | `details` | object | Additional context about the error (optional) | ## HTTP Status Codes | Status | Meaning | When It Occurs | | ------ | --------------------- | ------------------------------------------------------ | | `200` | OK | Request succeeded | | `201` | Created | Resource was created successfully | | `204` | No Content | Request succeeded with no response body (e.g., DELETE) | | `400` | Bad Request | Invalid request format or parameters | | `401` | Unauthorized | Missing or invalid API key | | `403` | Forbidden | Valid API key but insufficient permissions | | `404` | Not Found | Resource doesn't exist | | `429` | Too Many Requests | Rate limit exceeded | | `500` | Internal Server Error | Something went wrong on our end | | `503` | Service Unavailable | Temporary service outage | ## Error Codes Reference ### Authentication Errors | Code | Status | Description | | -------------------------- | ------ | ---------------------------------- | | `UNAUTHORIZED` | 401 | Invalid or missing API key | | `INSUFFICIENT_PERMISSIONS` | 403 | API key lacks required permissions | ```json theme={null} { "error": { "code": "UNAUTHORIZED", "message": "Invalid or missing API key" } } ``` ### Validation Errors | Code | Status | Description | | ------------------ | ------ | ----------------------------------- | | `VALIDATION_ERROR` | 400 | Request body failed validation | | `INVALID_INPUT` | 400 | Invalid query parameters or input | | `MISSING_QUERY` | 400 | Required query parameter is missing | Validation errors include details about which fields failed. `details` is a tree mirroring the request body: each node has an `errors` array (issues at that path), and object nodes additionally have a `properties` map keyed by field name. The top-level `errors` array carries issues that apply to the request as a whole. ```json theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": { "errors": [], "properties": { "email": { "errors": ["Invalid email address"] }, "name": { "errors": [ "Too small: expected string to have >=1 characters" ] } } } } } ``` ### Resource Errors | Code | Status | Description | | --------------------- | ------ | -------------------------------- | | `NOT_FOUND` | 404 | Requested resource doesn't exist | | `INVALID_MESSAGE_ID` | 400 | Invalid message ID format | | `INVALID_CONTACT_ID` | 400 | Invalid contact ID format | | `INVALID_BUSINESS_ID` | 400 | Invalid business ID format | ```json theme={null} { "error": { "code": "NOT_FOUND", "message": "Contact not found" } } ``` ### Rate Limiting Errors | Code | Status | Description | | --------------------- | ------ | ----------------- | | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | ```json theme={null} { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Please retry after 60 seconds", "details": { "retryAfter": 60 } } } ``` ### Server Errors | Code | Status | Description | | --------------------- | ------ | ------------------------------- | | `INTERNAL_ERROR` | 500 | Unexpected server error | | `SERVICE_UNAVAILABLE` | 503 | Service temporarily unavailable | ```json theme={null} { "error": { "code": "INTERNAL_ERROR", "message": "An unexpected error occurred" } } ``` ## Handling Errors ### Basic Error Handling ```typescript TypeScript theme={null} async function makeRequest() { const response = await fetch('https://api.shingleai.com/v1/contacts', { headers: { 'Authorization': `Bearer ${apiKey}`, }, }); if (!response.ok) { const { error } = await response.json(); switch (response.status) { case 401: throw new Error('Invalid API key'); case 403: throw new Error(`Permission denied: ${error.message}`); case 404: throw new Error('Resource not found'); case 429: throw new Error('Rate limited - retry later'); default: throw new Error(error.message || 'Request failed'); } } return response.json(); } ``` ```python Python theme={null} import requests def make_request(): response = requests.get( 'https://api.shingleai.com/v1/contacts', headers={'Authorization': f'Bearer {api_key}'} ) if not response.ok: error = response.json().get('error', {}) if response.status_code == 401: raise Exception('Invalid API key') elif response.status_code == 403: raise Exception(f"Permission denied: {error.get('message')}") elif response.status_code == 404: raise Exception('Resource not found') elif response.status_code == 429: raise Exception('Rate limited - retry later') else: raise Exception(error.get('message', 'Request failed')) return response.json() ``` ### Retry with Exponential Backoff For transient errors (429, 500, 503), implement retry logic with exponential backoff: ```typescript TypeScript theme={null} async function fetchWithRetry( url: string, options: RequestInit, maxRetries = 3 ): Promise { let lastError: Error; for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(url, options); // Don't retry client errors (except rate limiting) if (response.ok || (response.status >= 400 && response.status < 500 && response.status !== 429)) { return response; } // For rate limiting, use Retry-After header if available if (response.status === 429) { const retryAfter = response.headers.get('Retry-After'); const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); continue; } // For server errors, use exponential backoff if (response.status >= 500) { const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s await new Promise(resolve => setTimeout(resolve, delay)); continue; } return response; } catch (error) { lastError = error as Error; const delay = Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); } } throw lastError!; } ``` ```python Python theme={null} import time import requests def fetch_with_retry(url, headers, max_retries=3): last_error = None for attempt in range(max_retries): try: response = requests.get(url, headers=headers) # Don't retry client errors (except rate limiting) if response.ok or (400 <= response.status_code < 500 and response.status_code != 429): return response # For rate limiting, use Retry-After header if available if response.status_code == 429: retry_after = response.headers.get('Retry-After') delay = int(retry_after) if retry_after else (2 ** attempt) time.sleep(delay) continue # For server errors, use exponential backoff if response.status_code >= 500: delay = 2 ** attempt # 1s, 2s, 4s time.sleep(delay) continue return response except requests.RequestException as e: last_error = e delay = 2 ** attempt time.sleep(delay) raise last_error ``` ## Best Practices Use the `code` field for programmatic error handling, not the `message`. Error messages may change, but error codes remain stable. Include the request ID from response headers (`X-Request-ID`) when logging errors to help with debugging and support requests. Walk the `details` tree (each node's `errors` array, recursing into `properties`) to show specific field errors to your users rather than generic error messages. # Create access link Source: https://docs.shingleai.com/api-reference/file-access-links/create-access-link /api-reference/openapi.json post /v1/files/{id}/access-links Create a new access link for a file # List access links Source: https://docs.shingleai.com/api-reference/file-access-links/list-access-links /api-reference/openapi.json get /v1/files/{id}/access-links List all access links for a specific file with pagination # Delete file Source: https://docs.shingleai.com/api-reference/files/delete-file /api-reference/openapi.json delete /v1/files/{id} Delete a file from storage and database # Download file Source: https://docs.shingleai.com/api-reference/files/download-file /api-reference/openapi.json get /v1/files/{id}/download Download the file content # Download file via access link Source: https://docs.shingleai.com/api-reference/files/download-file-via-access-link /api-reference/openapi.json get /v1/files/public/{token} Download a file using a public access link token. No authentication required. # Get file Source: https://docs.shingleai.com/api-reference/files/get-file /api-reference/openapi.json get /v1/files/{id} Get a specific file by ID with full details # List files Source: https://docs.shingleai.com/api-reference/files/list-files /api-reference/openapi.json get /v1/files List all files with full details and pagination support # Search files Source: https://docs.shingleai.com/api-reference/files/search-files /api-reference/openapi.json get /v1/files/search Full-text search files by name, description, or content # Update file Source: https://docs.shingleai.com/api-reference/files/update-file /api-reference/openapi.json put /v1/files/{id} Update an existing file metadata # Upload file Source: https://docs.shingleai.com/api-reference/files/upload-file /api-reference/openapi.json post /v1/files/upload Upload a new file. Uses multipart form data with the file and optional metadata. # Create folder Source: https://docs.shingleai.com/api-reference/folders/create-folder /api-reference/openapi.json post /v1/folders Create a new folder # Delete folder Source: https://docs.shingleai.com/api-reference/folders/delete-folder /api-reference/openapi.json delete /v1/folders/{id} Delete a folder. Subfolders will be cascade deleted. Files in the folder will have their folderId set to null. # Get folder Source: https://docs.shingleai.com/api-reference/folders/get-folder /api-reference/openapi.json get /v1/folders/{id} Get a specific folder by ID with full details (including file/subfolder counts) # List folders Source: https://docs.shingleai.com/api-reference/folders/list-folders /api-reference/openapi.json get /v1/folders List all folders with full details (including file/subfolder counts) and pagination support # Update folder Source: https://docs.shingleai.com/api-reference/folders/update-folder /api-reference/openapi.json put /v1/folders/{id} Update an existing folder # Introduction Source: https://docs.shingleai.com/api-reference/introduction Learn the basics of the ShingleAI API The ShingleAI API provides programmatic access to your business communication data, including messages, contacts, customers, and businesses. Use it to build integrations, automate workflows, and extend ShingleAI's capabilities. **Quick reference for AI agents:** ```json theme={null} { "baseUrl": "https://api.shingleai.com/v1", "auth": "Authorization: Bearer ", "responseEnvelope": { "data": "T", "meta": { "pagination": { "limit": 10, "offset": 0, "hasMore": true } } }, "errorEnvelope": { "error": { "message": "string", "code": "string", "details": "object|undefined" } }, "pagination": ["limit (1-100)", "offset (>=0)", "sortOrder (asc|desc)"], "ids": "UUIDv4", "timestamps": "ISO 8601 UTC" } ``` ## Base URL All API requests should be made to: ``` https://api.shingleai.com/v1 ``` Do not include a trailing slash in the base URL. Endpoints are appended directly, e.g., `https://api.shingleai.com/v1/contacts`. The API is versioned, with `v1` being the current stable version. When breaking changes are introduced, a new version will be released. ## Request Format The API accepts JSON-encoded request bodies and returns JSON-encoded responses. ```bash cURL theme={null} curl -X POST https://api.shingleai.com/v1/messages \ -H "Authorization: Bearer sk_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"to": "user@example.com", "subject": "Hello"}' ``` ```typescript TypeScript theme={null} const response = await fetch('https://api.shingleai.com/v1/messages', { method: 'POST', headers: { 'Authorization': 'Bearer sk_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify({ to: 'user@example.com', subject: 'Hello', }), }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://api.shingleai.com/v1/messages', headers={ 'Authorization': 'Bearer sk_live_abc123...', 'Content-Type': 'application/json', }, json={ 'to': 'user@example.com', 'subject': 'Hello', } ) data = response.json() ``` ### Required Headers | Header | Value | Description | | --------------- | ------------------ | ------------------------------------------ | | `Authorization` | `Bearer ` | Your API key for authentication | | `Content-Type` | `application/json` | Required for POST, PUT, and PATCH requests | ### Response Headers Every API response includes these headers: | Header | Description | | -------------- | ------------------------------------------------------------------------------------- | | `X-Request-ID` | Unique identifier for the request. Include this when contacting support for debugging | Rate limit response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) are not yet emitted. See [Rate Limits](/api-reference/rate-limits) for the current enforcement behavior. ## Shared conventions Every endpoint in the API follows the same conventions for response shape, pagination, errors, timestamps, and IDs. Once you've learned them here, you can skim the resource-specific reference pages without rediscovering them each time. ### Response envelope All successful responses wrap the payload in a `data` field: ```json theme={null} { "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "subject": "Hello", "status": "sent", "createdAt": "2024-01-15T09:30:00Z", "updatedAt": "2024-01-15T09:30:00Z" } } ``` List endpoints add a `meta.pagination` block: ```json theme={null} { "data": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "subject": "Hello", "status": "sent" }, { "id": "550e8400-e29b-41d4-a716-446655440001", "subject": "Follow-up", "status": "draft" } ], "meta": { "pagination": { "limit": 10, "offset": 0, "total": 42, "hasMore": true } } } ``` `hasMore` is computed server-side. `total` is included when the underlying query can provide it cheaply; otherwise it is omitted and you should rely on `hasMore` to know when to stop paginating. The request identifier is returned in the `X-Request-ID` response header, not in the body. When `total` is omitted, `hasMore` is inferred from whether the page returned exactly `limit` items. This means a page that happens to fill exactly to `limit` will report `hasMore: true` even if it is the last page — your next request will simply return an empty `data` array. Always stop paginating when you receive an empty page, not just when `hasMore` becomes `false`. ### Pagination List endpoints accept three query parameters: | Parameter | Default | Accepted values | Description | | ----------- | ------- | --------------- | ---------------------------------------- | | `limit` | 10 | 1–100 | Number of items to return | | `offset` | 0 | ≥ 0 | Number of items to skip | | `sortOrder` | `desc` | `asc` \| `desc` | Sort direction, typically by `createdAt` | The API is offset-based; cursor-based pagination is not available today. ```bash theme={null} curl "https://api.shingleai.com/v1/contacts?limit=20&offset=40&sortOrder=asc" \ -H "Authorization: Bearer sk_live_abc123..." ``` ### Error responses Errors use a single consistent shape: ```json theme={null} { "error": { "message": "Validation failed", "code": "VALIDATION_ERROR", "details": { "errors": [], "properties": { "email": { "errors": ["Invalid email address"] } } } } } ``` `details` is present on validation errors and omitted otherwise. Validation errors are returned as a tree mirroring the request body: each node has an `errors` array (issues that apply at that path), and object nodes additionally have a `properties` map keyed by field name. The top-level `errors` array carries issues that apply to the request as a whole. Status codes you'll see: | Status | Meaning | | ------ | -------------------------------------------------------- | | `400` | Validation error or malformed request | | `401` | Missing or invalid API key | | `402` | Insufficient credits for the requested operation | | `403` | API key lacks the permissions required for this endpoint | | `404` | Resource does not exist (or is soft-deleted) | | `500` | Unexpected server error | | `503` | Temporarily unavailable (e.g., database outage) | See [Error Handling](/api-reference/errors) for the full list of error codes. ### Soft deletes `DELETE` endpoints perform soft deletes: the record is retained with a `deletedAt` timestamp set. Soft-deleted records are filtered out of list and get responses — there is currently no query flag to include them. If you need to recover a record, contact support. ### Timestamps and IDs * **Timestamps** are ISO 8601 UTC strings, e.g., `2024-01-15T09:30:00Z`. Every resource returns `createdAt` and `updatedAt`, plus a nullable `deletedAt`. * **Identifiers** are UUID v4 strings (for example, `550e8400-e29b-41d4-a716-446655440000`). Every resource uses `id` as its primary key, and foreign keys follow the `Id` convention (`contactId`, `businessId`, etc.). ## SDKs Official SDKs for TypeScript and Python are coming soon. In the meantime, you can use the REST API directly with any HTTP client. ## OpenAPI Specification The ShingleAI API is documented using OpenAPI 3.1. You can access the specification at: ``` https://api.shingleai.com/v1/openapi.json ``` Use this to generate client libraries, import into API tools like Postman, or explore the API programmatically. ## Next Steps Learn how to create and use API keys Understand error responses and codes # Get message attachment Source: https://docs.shingleai.com/api-reference/message-attachments/get-message-attachment /api-reference/openapi.json get /v1/messages/{id}/attachments/{attachmentId} Get a specific attachment for a message # List message attachments Source: https://docs.shingleai.com/api-reference/message-attachments/list-message-attachments /api-reference/openapi.json get /v1/messages/{id}/attachments List all attachments for a specific message # Get message contact Source: https://docs.shingleai.com/api-reference/message-contacts/get-message-contact /api-reference/openapi.json get /v1/messages/{id}/contacts/{contactId} Get a specific contact association for a message # List message contacts Source: https://docs.shingleai.com/api-reference/message-contacts/list-message-contacts /api-reference/openapi.json get /v1/messages/{id}/contacts List all contacts associated with a specific message # Delete message Source: https://docs.shingleai.com/api-reference/messages/delete-message /api-reference/openapi.json delete /v1/messages/{id} Delete a message (soft delete) # Get archived messages count Source: https://docs.shingleai.com/api-reference/messages/get-archived-messages-count /api-reference/openapi.json get /v1/messages/archived/count Get the count of archived messages # Get message Source: https://docs.shingleai.com/api-reference/messages/get-message /api-reference/openapi.json get /v1/messages/{id} Get a specific message by ID # Get messages by contact Source: https://docs.shingleai.com/api-reference/messages/get-messages-by-contact /api-reference/openapi.json get /v1/messages/contacts/{contactId}/messages Get all messages associated with a specific contact # Get messages by email address Source: https://docs.shingleai.com/api-reference/messages/get-messages-by-email-address /api-reference/openapi.json get /v1/messages/email-address/{emailAddressId}/messages Get all messages associated with a specific email address # Get messages by phone number Source: https://docs.shingleai.com/api-reference/messages/get-messages-by-phone-number /api-reference/openapi.json get /v1/messages/phone-number/{phoneNumberId}/messages Get all messages associated with a specific phone number # Get messages by thread Source: https://docs.shingleai.com/api-reference/messages/get-messages-by-thread /api-reference/openapi.json get /v1/messages/thread/{threadId} Get all messages in a specific thread # Get snoozed messages count Source: https://docs.shingleai.com/api-reference/messages/get-snoozed-messages-count /api-reference/openapi.json get /v1/messages/snoozed/count Get the count of snoozed messages # List archived messages Source: https://docs.shingleai.com/api-reference/messages/list-archived-messages /api-reference/openapi.json get /v1/messages/archived List all archived messages with pagination support # List incoming messages Source: https://docs.shingleai.com/api-reference/messages/list-incoming-messages /api-reference/openapi.json get /v1/messages/incoming List all incoming messages with pagination support # List messages Source: https://docs.shingleai.com/api-reference/messages/list-messages /api-reference/openapi.json get /v1/messages List all messages with pagination support # List outgoing messages Source: https://docs.shingleai.com/api-reference/messages/list-outgoing-messages /api-reference/openapi.json get /v1/messages/outgoing List all outgoing messages with pagination support # List snoozed messages Source: https://docs.shingleai.com/api-reference/messages/list-snoozed-messages /api-reference/openapi.json get /v1/messages/snoozed List all snoozed messages with pagination support # Update message Source: https://docs.shingleai.com/api-reference/messages/update-message /api-reference/openapi.json patch /v1/messages/{id} Update a message read status. Only readAt, archivedAt, and snoozedUntil fields are allowed. # Rate Limits Source: https://docs.shingleai.com/api-reference/rate-limits Understand API rate limits and how to handle them The ShingleAI API enforces rate limits to ensure fair usage and maintain service stability for all users. Rate limits vary by subscription tier. ## Rate Limits by Tier | Tier | Requests per Minute | Burst Limit | | ---------- | ------------------- | ----------- | | Free | 10 | 15 | | Starter | 30 | 45 | | Pro | 100 | 150 | | Enterprise | Custom | Custom | **Burst limits** allow temporary spikes above your per-minute limit. For example, a Pro tier user (100 req/min) can make up to 150 requests in a short burst. However, sustained traffic above your base rate limit will result in throttling. Burst capacity refills as your request rate drops below the limit. ## Rate Limit Headers Rate limit response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `Retry-After`) are not yet emitted. Planned for a future release — until then, track your own request rate client-side and detect throttling by the `429` status code alone. ## Handling Rate Limits When you exceed your rate limit, the API returns a `429 Too Many Requests` response: ```json theme={null} { "error": { "code": "RATE_LIMITED", "message": "Too many requests. Please try again later." } } ``` No `Retry-After` header is returned today, so use exponential backoff when retrying. ### Implementing Rate Limit Handling ```typescript TypeScript theme={null} async function fetchWithRateLimit( url: string, options: RequestInit, attempt = 0, ): Promise { const response = await fetch(url, options); if (response.status === 429) { const backoffMs = Math.min(60_000, 1_000 * 2 ** attempt); console.log(`Rate limited. Waiting ${backoffMs}ms before retry...`); await new Promise(resolve => setTimeout(resolve, backoffMs)); return fetchWithRateLimit(url, options, attempt + 1); } return response; } ``` ```python Python theme={null} import time import requests def fetch_with_rate_limit(url, headers, attempt=0): response = requests.get(url, headers=headers) if response.status_code == 429: backoff_s = min(60, 2 ** attempt) print(f'Rate limited. Waiting {backoff_s}s before retry...') time.sleep(backoff_s) return fetch_with_rate_limit(url, headers, attempt + 1) return response ``` ## Best Practices Instead of making requests as fast as possible, implement a queue that spreads requests evenly across your rate limit window. ```typescript theme={null} class RequestQueue { private queue: Array<() => Promise> = []; private processing = false; private requestsPerSecond: number; constructor(requestsPerMinute: number) { this.requestsPerSecond = requestsPerMinute / 60; } async add(fn: () => Promise): Promise { return new Promise((resolve, reject) => { this.queue.push(async () => { try { resolve(await fn()); } catch (e) { reject(e); } }); this.process(); }); } private async process() { if (this.processing) return; this.processing = true; while (this.queue.length > 0) { const fn = this.queue.shift()!; await fn(); await new Promise(r => setTimeout(r, 1000 / this.requestsPerSecond) ); } this.processing = false; } } ``` When you receive a 429 response, don't immediately retry. Implement exponential backoff starting at 1 second (e.g., 1s, 2s, 4s, 8s, capped at 60s). Reduce API calls by caching responses that don't change frequently. This is especially useful for reference data like contact lists or business details. Where available, use batch endpoints to perform multiple operations in a single request instead of making separate calls. ## Increasing Your Limits If you consistently need higher rate limits: 1. **Upgrade your plan** - Higher tiers include increased rate limits 2. **Contact sales** - Enterprise plans include custom rate limits tailored to your needs View pricing and upgrade options # List task activity Source: https://docs.shingleai.com/api-reference/task-activity/list-task-activity /api-reference/openapi.json get /v1/tasks/{id}/activity Get the activity history for a specific task showing all changes, assignments, and status updates # Assign user to task Source: https://docs.shingleai.com/api-reference/task-assignees/assign-user-to-task /api-reference/openapi.json post /v1/tasks/{id}/assignees Assign a user to a task # List task assignees Source: https://docs.shingleai.com/api-reference/task-assignees/list-task-assignees /api-reference/openapi.json get /v1/tasks/{id}/assignees List all users assigned to a specific task # Unassign user from task Source: https://docs.shingleai.com/api-reference/task-assignees/unassign-user-from-task /api-reference/openapi.json delete /v1/tasks/{id}/assignees/{userId} Remove a user assignment from a task # Create task Source: https://docs.shingleai.com/api-reference/tasks/create-task /api-reference/openapi.json post /v1/tasks Create a new task # Delete task Source: https://docs.shingleai.com/api-reference/tasks/delete-task /api-reference/openapi.json delete /v1/tasks/{id} Delete a task (soft delete) # Get task Source: https://docs.shingleai.com/api-reference/tasks/get-task /api-reference/openapi.json get /v1/tasks/{id} Get a specific task by ID with full details and assignees # List tasks Source: https://docs.shingleai.com/api-reference/tasks/list-tasks /api-reference/openapi.json get /v1/tasks List all tasks with full details, assignees, and pagination support. Supports filtering by status, category, urgency, importance, assignee, and due date. # Partially update task Source: https://docs.shingleai.com/api-reference/tasks/partially-update-task /api-reference/openapi.json patch /v1/tasks/{id} Partially update an existing task. Only provided fields will be updated. # Search tasks Source: https://docs.shingleai.com/api-reference/tasks/search-tasks /api-reference/openapi.json get /v1/tasks/search Search tasks using full-text search across title, description, and metadata # Update task Source: https://docs.shingleai.com/api-reference/tasks/update-task /api-reference/openapi.json put /v1/tasks/{id} Update an existing task. Note: This endpoint accepts partial updates (same behavior as PATCH). # Agents Source: https://docs.shingleai.com/get-started/concepts/agents What agents are, how they differ from automations, and how you control them ShingleAI has two kinds of AI worker: **agents** and **automations**. They look similar from a distance — both use LLMs, both can call tools, both can read your data and act on it — but they answer different questions, and using them interchangeably is the most common source of confusion for new users. Read this page, then read [Automations](/get-started/concepts/automations). Together they give you a clear sense of which one to reach for. ## Agents vs. Automations at a Glance | | **Agent** | **Automation** | | ------------------ | ------------------------------------------------------------- | ----------------------------------------------------------- | | **Triggered by** | A person chatting with it (or another workflow invoking it) | A platform event — new message, new contact, schedule, etc. | | **Shape** | A conversational LLM loop that calls tools to get things done | A rule that says "when X happens, do Y" | | **Has memory of?** | Yes — every turn of the conversation | No — each execution is fresh | | **Best for** | Open-ended help, research, multi-turn judgement | Routine, event-driven work that should just happen | A useful intuition: an **automation** is a tireless junior employee waiting for the inbox to ping. An **agent** is a colleague you can ask things of. The two cooperate. An automation can invoke an agent as one of its steps when the work needs more nuance than rules can capture — for example, "when a new email arrives, ask the support agent to draft a reply." ## What is an Agent? An agent is a configured persona that runs an LLM loop. When you create an agent you decide: * **Name and system prompt** — who the agent is and how it should behave. * **Model** — which LLM powers it. * **Tools it has access to** — and at what permission level. * **Step budget** — `maxSteps` caps how many tool calls a single response can make. The default is **5**. * **LLM parameters** — temperature, top-p, frequency/presence penalties, and so on, for power users. When a person (or another workflow) sends the agent a message, it runs an agentic loop: read the message, choose a tool to call, get the result, choose another tool, until it's done or it hits its step budget. Each agent runs inside its own Cloudflare **Durable Object**, which keeps the conversation state warm for the duration. ## Tool Permissions Tools are the only way an agent affects the world — read your contacts, send an email, create a task, search files. ShingleAI gives you granular control over each tool, with three levels: | Level | Behaviour | | ----------- | --------------------------------------------------------------------------------------------------- | | **`allow`** | Agent calls the tool automatically, no prompt | | **`ask`** | Agent must request approval before each call; you see what it wants to do and can approve or reject | | **`deny`** | Tool is hidden from the agent entirely | Sensible defaults are applied for you: **read-style tools default to `allow`** (an agent should be able to look things up without asking permission), **write- and delete-style tools default to `ask`** (anything that mutates state should pause for a human). You can override any of these per agent. ## Conversations Every chat with an agent is recorded as an **agent conversation** — a thread you can revisit, share, or audit later. Each conversation has: * A **status**: `active`, `completed`, `timeout`, or `error`. * A **source**: `web` (the dashboard chat UI), `api`, or `mcp` (a Model Context Protocol client like Claude Desktop or Cursor). * The full transcript, including tool calls, tool results, and any approval decisions. Conversations are how you scale review of AI work without watching every step in real time. You can browse the conversation history of any agent and see exactly what it did and why. ## How an Agent Runs ```mermaid theme={null} graph TD A[User sends message] --> B[Durable Object resumes conversation] B --> C{LLM decides:
tool call or reply?} C -->|tool| D[Permission check] D -->|allow| E[Run tool] D -->|ask| F[Pause for approval] F --> E E --> C C -->|reply| G[Stream reply to user] G --> H[Conversation persisted] ``` The loop is bounded — `maxSteps` is a hard cap on tool calls per turn — and is interruptible. If a permission prompt comes back denied, or if you pause the conversation, the agent stops cleanly. ## When to Use Which Reach for an **agent** when: * You want to ask follow-up questions in a conversation. * The work needs judgement, not just rules — "summarise this account's recent activity," "draft a polite refund refusal." * You want a human in the loop on writes. Reach for an **automation** when: * The trigger is an event you can describe — "a new email arrives," "a customer signs up." * You want it to run forever, untouched, until you tell it to stop. * The behaviour is predictable enough that you don't need to chat about it. When in doubt: if you'd ever consider hitting "send" yourself before the action happens, you probably want an agent. If the action should *always* happen the moment the trigger fires, you probably want an automation. ## Related Topics The other half of this story Build your first agent in the web app Configure allow / ask / deny for each tool Browse and audit past chats # Automations Source: https://docs.shingleai.com/get-started/concepts/automations How AI-powered automations work in ShingleAI Automations are how ShingleAI turns your inbox from a task list into a system that works for you. Instead of manually processing every message, you define rules in plain English and let AI handle the routine work. ## What Are Automations? An **automation** is a workflow that runs when something happens in ShingleAI. Every automation has three parts: 1. **Trigger** — the event that starts the automation (e.g., a new email arrives) 2. **Instructions** — what you want the AI to do, written in natural language 3. **Permissions** — what actions the automation is allowed to take What makes ShingleAI automations different from traditional "if this, then that" rules is the **AI layer**. Instead of rigid conditions and fixed responses, you describe what you want in plain English and the AI interprets each situation individually. ## Automations vs. Agents ShingleAI has two kinds of AI worker, and they're easy to confuse. **Automations** are event-triggered: a message arrives, a contact is created, a schedule fires, and the automation runs without anyone being there. **Agents** are conversational: you (or another workflow) chat with them, and they call tools to get things done across multiple turns. A useful intuition: an automation is a junior employee waiting for the inbox to ping. An agent is a colleague you can ask things of. Automations *can* invoke an agent as one of their steps when the work needs more nuance than rules can capture — for example, "when a new email arrives, ask the support agent to draft a reply." If you'd ever want to hit "send" yourself before the action happens, reach for an [agent](/get-started/concepts/agents). If the action should *always* happen the moment the trigger fires, reach for an automation. ## How Automations Work When an event occurs — say a new email arrives — ShingleAI checks if any active automations match that trigger. If so, the AI reads the incoming content, evaluates your instructions, and takes action. Here's the flow: 1. **Event occurs** — A new email, contact creation, or other trigger event happens 2. **Trigger matches** — ShingleAI identifies automations listening for this event 3. **AI processes** — The AI reads the content and interprets your instructions 4. **Action taken** — The AI performs the appropriate action (reply, create contact, etc.) 5. **Result logged** — The execution is recorded so you can review what happened The AI doesn't follow a decision tree — it understands context. An instruction like "if this looks like a support request, send an acknowledgment" works because the AI can evaluate whether an email is a support request, even if the sender doesn't use the word "support." ## The Power of Natural Language Instructions Traditional automation tools require you to define exact conditions: "if subject contains 'help' OR subject contains 'support' OR subject contains 'issue'..." This is brittle and misses edge cases. ShingleAI automations use AI instructions instead: ``` When a new email arrives: 1. If it looks like a support request, send a friendly acknowledgment 2. If it's a sales inquiry, tag the contact as "Lead" 3. If it's a newsletter or automated notification, do nothing ``` The AI handles the ambiguity. It understands that "My login isn't working" is a support request even though it doesn't contain the word "support." ## What Can Automations Do? Automations can take a range of actions depending on their permissions: * **Send replies** — Compose and send email responses * **Create and update contacts** — Add new contacts or update existing ones * **Manage messages** — Archive, label, or categorize incoming messages * **Send notifications** — Alert team members about important messages * **Create tasks** — Generate follow-up tasks from incoming requests ## Automation Lifecycle Automations have a lifecycle with different states: | Status | Meaning | | ------------- | ------------------------------------------------- | | **Active** | Running and processing events as they occur | | **Paused** | Temporarily disabled — can be resumed at any time | | **Completed** | Finished after reaching an execution limit | | **Expired** | Past its configured expiration date | You can pause an automation at any time without losing its configuration. This is useful when you want to temporarily stop processing while you refine your instructions. ## Automations and Permissions Automations run with the permissions that were set when they were created. They cannot perform actions beyond their granted permissions. This means: * An automation with read-only message access can analyze emails but not reply * An automation without contact permissions cannot create or modify contacts * Permissions are checked on every execution, not just at creation time This design ensures automations stay within the boundaries you define, even as the AI interprets instructions flexibly. ## Related Topics Step-by-step guide to building an automation Build a working AI-powered support workflow from scratch The conversational counterpart — when to reach for one instead # Businesses Source: https://docs.shingleai.com/get-started/concepts/businesses How ShingleAI models the businesses you run inside one organization In ShingleAI, your **organization** is your account — the container for users, billing, and data. Inside that account, you run one or more **businesses**. The distinction matters: most plans support multiple businesses per organization, and each business has its own profile, products, locations, and Stripe connection. If you operate a single business, the difference is mostly invisible — your one business sits inside your one organization, and you rarely think about it. If you operate several (an agency with multiple service lines, a holding company with separate brands, or a contractor who runs both a roofing and a solar business under one team), the multi-business model is the spine of how ShingleAI organizes everything else. ## What a Business Is A business represents a real-world commercial entity. It has: * A **profile** — name, industries, description, and a flexible field for whatever else you need to record. * A set of **offerings** — the products and services it sells. * **Online presences** — websites, social accounts, marketplace listings. * **Physical presences** — locations, addresses, service areas. * An optional **Stripe connection** — its own connected Stripe account for payments. A business is the customer-facing identity ShingleAI grounds itself in: when an agent drafts a reply or an automation composes an email on your behalf, the business profile, offerings, and presences tell the AI *which* business it's speaking for. Records like contacts, customers, and messages live at the organization level today; business-level scoping for agents and automations is on the roadmap. ## Business vs. Organization The two concepts are easy to conflate. The short version: | | **Organization** | **Business** | | --------------------- | ---------------------------- | ------------------------------------------------ | | **What it is** | Your ShingleAI account | A commercial entity you run inside the account | | **Holds** | Users, billing, settings | Profile, offerings, presences, Stripe | | **How many you have** | One per account | One or more | | **Used for** | Access control, subscription | Customer-facing identity, payments, AI grounding | The organization is the *container*. The business is the *thing the world sees*. ## Profile The business profile is what your AI grounds itself in when it speaks on your behalf. It includes: * **Name** — the public-facing name. * **Industries** — one or more industries (e.g. roofing, HVAC, professional services). * **Description** — a free-form pitch the AI can lean on when drafting messages. * **Custom data** — a flexible field for anything else you want recorded. When an agent writes an email or an automation drafts a reply, it reads the business profile to stay on-brand and on-topic. ## Offerings An **offering** is something the business sells. It's tagged as either a **product** (something tangible or fixed) or a **service** (something delivered). Each offering has a name and description; together they define what the business actually does. Offerings power AI features that need to know your catalogue — for example, when an inbound message asks "do you do gutter cleaning?" the agent needs to know whether the answer is yes. ## Presences Presences answer the question "where is this business in the world?" — both digitally and physically. **Online presences** capture the digital footprint: a primary website, social media profiles, marketplace listings, review pages. Each entry has a type, provider, URL, and description. **Physical presences** capture the bricks-and-mortar side: an office, a warehouse, a service area. Each entry has a name, description, and address. Together they let agents and automations answer location-aware questions — "what's your address?", "do you serve this zip code?", "what's your Yelp page?" — with truthful, current data. ## Stripe Connect Each business can connect **its own** Stripe account through Stripe Connect. The connection lives at the business level, not the organization level — meaning two businesses inside the same organization can independently link to two different Stripe accounts, with separate customers, invoices, and sync schedules. Once connected, ShingleAI keeps the business's customers and transactions in sync with its Stripe account. The connection has three sync modes: * **`off`** — Stripe is not connected, or sync is disabled. * **`one_way`** — data flows from Stripe into ShingleAI only (a read-only mirror). * **`two_way`** — data flows in both directions. You can switch modes and trigger manual syncs from the business settings page. ## Putting It Together ```mermaid theme={null} graph TD O[Organization] --> B1[Business: Acme Roofing] O --> B2[Business: Acme Solar] B1 --> P1[Profile] B1 --> O1[Offerings] B1 --> N1[Online Presences] B1 --> H1[Physical Presences] B1 --> S1[Stripe Account] B2 --> P2[Profile] B2 --> O2[Offerings] B2 --> N2[Online Presences] B2 --> H2[Physical Presences] B2 --> S2[Stripe Account] ``` One organization. Two businesses. Two Stripe accounts. Two distinct profiles, catalogues, and footprints. One team running both. ## Related Topics Edit name, industries, and description Manage your product and service catalogue Online and physical locations Link a Stripe account to a business # Contacts, Customers & Businesses Source: https://docs.shingleai.com/get-started/concepts/contacts Understand how ShingleAI organizes people and business relationships ShingleAI provides three ways to organize the people and companies you work with: **Contacts**, **Customers**, and **Businesses**. Each serves a different purpose, and understanding the distinction helps you get the most from the platform. ## Overview | Type | What It Represents | Example | | ------------ | ----------------------------------------- | ------------------------------------------------------- | | **Contact** | An individual person you communicate with | John Smith, [jane@example.com](mailto:jane@example.com) | | **Customer** | A business relationship with a person | John Smith as a buyer | | **Business** | A company or organization | Acme Corporation | ## Contacts A **contact** represents an individual person. Contacts are the core of ShingleAI's data model — they're the link between people and the messages you exchange with them. Every contact can have multiple email addresses and phone numbers, each with labels like "work" or "personal." When ShingleAI receives a message, it matches the sender's email to an existing contact, linking the message to that person's history automatically. This means you can open any contact and see every conversation you've had with them, across all channels. Contacts are also created automatically when you receive emails from new senders, so your address book grows organically as you communicate. ## Customers A **customer** represents a business relationship. While a contact is just a person in your address book, a customer indicates they have a commercial relationship with you — they've bought something, signed up for a service, or are in your sales pipeline. Customers can have **transactions** associated with them — records of purchases, payments, or other financial events. This gives you a financial history tied to a person, separate from your communication history. ### When to Use Customers * Someone makes a purchase or payment * You want to track an ongoing client relationship * You need to record transaction history * You're building a sales pipeline ## Businesses A **business** represents a company or organization. Where contacts track individuals and customers track financial relationships, businesses track company-level information: industry, offerings, online presence, and physical locations. Businesses can be connected to contacts (people who work there) and customers (commercial relationships), giving you both the company-level and individual views. ## How They Work Together These three types form a hierarchy that mirrors real business relationships: ``` Business: Acme Corporation ├── Contact: John Smith (Sales Manager) │ └── Customer: John Smith (purchased in 2024) ├── Contact: Jane Doe (CEO) └── Contact: Bob Wilson (Support) ``` In this example: * **Acme Corporation** is tracked as a business with its company information * **John**, **Jane**, and **Bob** are contacts (individuals) * **John** is also a customer because he's made purchases ## Choosing the Right Type The general rule: * **Start with contacts.** Every person you communicate with should be a contact. ShingleAI creates these automatically from email senders. * **Add customer records for buyers.** When someone makes a purchase or becomes a client, create a customer record to track the financial relationship. * **Add businesses for companies.** When you need to track company-level information — their products, locations, or team — create a business and link relevant contacts to it. ## Related Topics Add, edit, and organize your contacts How contacts link to your communications # Credits & Billing Source: https://docs.shingleai.com/get-started/concepts/credits How ShingleAI meters compute, charges for it, and protects you when you exceed your plan ShingleAI charges for two things: **what you can build** (capacity) and **what you do with it** (usage). Both are denominated in credits, and both are governed by the **tier** your account is on. This page explains the model so the line items on your bill have a story behind them. ## What is a Credit? A **credit** is the unit of measurement for usage on top of your plan. **One credit equals one cent of overage cost.** Credits accumulate against your account when you exceed the allowances bundled into your tier; you settle them up by paying for credit packs (or letting auto-recharge do it for you). Inside your tier, you don't think about credits — you have an allowance and you use it. You only feel credits when you go past it. ## Tiers There are four tiers: * **Free** — try the platform, hard caps on capacity. * **Starter** — entry-level paid plan. * **Professional** — full-featured plan for active users. * **Enterprise** — custom limits, support SLA, negotiated pricing. Each tier defines two things: how much capacity you have (the **account objects**) and how much usage is included before overages kick in (the **consumables**). ## Account Objects (Capacity) Account objects are *how much you can have* — hard caps that don't accumulate. Five of them: | Object | What it limits | | --------------- | -------------------------------------------------------- | | **Businesses** | Number of businesses you can run inside the organization | | **Seats** | Number of users with access | | **Agents** | Number of AI agents you can configure | | **MCP Servers** | Number of MCP credentials/servers | | **Automations** | Number of active automations | If you hit the cap, you can't create more without upgrading. We don't bill overages for capacity — we just stop the meter. ## Consumables (Usage) Consumables are *how much you can do* — meters that reset on each billing cycle. Seven of them: | Consumable | What it counts | | ----------------- | -------------------------------------------------------- | | **API Calls** | Calls to the public API | | **MCP Calls** | Calls to your MCP server | | **LLM Tokens** | Language model tokens consumed by agents and automations | | **Email Sends** | Outbound emails | | **SMS** | SMS messages, sent and received | | **Voice Minutes** | Voice call minutes | | **Storage** | Bytes stored in your file library | Inside your tier's allowance, these are free. Past it, every increment is billed at your tier's overage rate. ## Tier-Based Overage Rates Higher tiers get cheaper marginal usage: | Consumable | Free | Starter | Professional | | -------------------------- | ------ | ------- | ------------ | | **LLM Tokens** (per 10k) | \$0.50 | \$0.40 | \$0.30 | | **API Calls** (per 100) | \$0.03 | \$0.02 | \$0.01 | | **MCP Calls** (per 100) | \$0.03 | \$0.02 | \$0.01 | | **Email Sends** (per 100) | \$0.15 | \$0.10 | \$0.05 | | **SMS** (per 10) | \$0.15 | \$0.10 | \$0.075 | | **Voice Minutes** (per 10) | \$0.30 | \$0.20 | \$0.15 | | **Storage** (per GB) | \$0.25 | \$0.15 | \$0.10 | Enterprise rates are negotiated separately. ## How LLM Usage Becomes Credits The most common source of overage in active accounts is the **LLM Tokens** meter — every message your agents and automations send to a model counts. The relationship is direct: 1. Each LLM call records the input and output tokens consumed. 2. Tokens roll up into the `llmTokens` consumable on your account. 3. Once you cross your tier's included token allowance, additional tokens are billed at your tier's overage rate (e.g., \$0.30 per 10k on Professional). 4. The dollar charge is converted into credits — \$1 of overage = 100 credits. In other words: **credits are how the bill arrives**, not how the meter ticks. ## Recharging There are two ways to top up: * **Credit packs.** One-time purchases at $10, $20, $50, or $100. Use them when you know you have a busy month coming. * **Auto-recharge.** When your credit balance dips below a threshold, ShingleAI tops it up automatically — the default top-up is **\$20**. Turn it on once and you stop thinking about it. Both buy the same credits; only the trigger differs. ## When You Downgrade — Soft Disable ShingleAI never deletes your work because you change tiers. If you downgrade to a tier whose **account-object** caps are below your current usage, the platform doesn't throw away your extra agents, automations, or seats — it **soft-disables** them. Soft-disabled means: * Marked `isActive = false` and stamped with `disabledReason = 'tier_downgrade'`. * Newest entries are disabled first; **the organization owner is never disabled**. * The data is intact — it just can't run. * Move back up a tier (or remove other items) and you can re-activate them with one click; the platform verifies you're under the cap before allowing it. This is deliberate: downgrade decisions get reversed all the time, and losing the work each time would be punitive. ## Related Topics Detailed tier comparison See your current usage Buy credit packs and configure auto-recharge Invoices and payment methods # Files & Knowledge Source: https://docs.shingleai.com/get-started/concepts/files How ShingleAI ingests, indexes, and retrieves your files for agents ShingleAI lets you upload files — contracts, invoices, product sheets, runbooks — and makes them searchable by your agents. This page covers what happens between "I dropped a PDF in" and "my agent quoted the right paragraph back to me." ## What is a File? A **file** is any artefact you've uploaded to your organization. Each file: * Lives in **R2** (Cloudflare's object store). * Belongs to an organization, optionally inside a **folder**. * Has metadata — filename, content type, size, tags, description. * Has an **indexing status** that tracks where it is in the retrieval pipeline. Today, the indexing pipeline understands four formats end-to-end: **PDF**, **PNG**, **JPEG**, and **WebP** (via OCR), plus inline **Markdown**. Other formats can still be uploaded and shared via public links — they simply aren't indexed for retrieval. ## Folders Files can be grouped into folders. Folders are useful for two reasons: 1. **Organisation.** Same as folders anywhere — group what belongs together. 2. **Agent access control.** Each file (and each folder) carries an `agentAccessEnabled` flag. Set the flag on a folder to "off" and your agents will not see anything in it during retrieval, even if a query would otherwise match. This matters more than it sounds: it's how you separate, say, your public sales collateral from internal HR documents when both are in the same organization. ## The Indexing Pipeline When a file is uploaded, an asynchronous workflow takes it from raw bytes to retrievable knowledge: ```mermaid theme={null} graph LR A[Upload to R2] --> B[Parse] B --> C[Chunk] C --> D[Embed] D --> E[Index] E --> F[(pgvector)] ``` 1. **Upload** — the file is written to R2; a database record is created. 2. **Parse.** PDFs and images are run through Mistral OCR, which produces structured **markdown** per page. Markdown files skip OCR and are read inline. 3. **Chunk.** The structural markdown chunker splits the document along its natural seams: it walks H1 → H2 → H3 → H4 → H5 → H6 → blank-line paragraphs → sentences → words, in that order, picking the deepest split that keeps chunks within size bounds. Targets are **800 tokens** per chunk, with a **1,200-token cap** and a **\~100-token overlap** with the previous chunk so context isn't lost at boundaries. Code fences are kept intact. 4. **Embed.** Each chunk is sent to OpenAI's `text-embedding-3-small` (1536-dimensional vectors), in batches. 5. **Index.** Chunks land in PostgreSQL with `pgvector` for vector search and a tsvector column for keyword search. A file's `indexingStatus` walks through `pending → indexing → indexed`. If a file isn't indexable (unsupported format, too large, parser failure) the status ends in `skipped`, `excluded`, or `failed` — visible on the file's detail view so you know it's not searchable. ## How Agents Retrieve Files (RAG) When an agent needs information from your files, it doesn't just do a vector search. Pure embedding search is good at recall on fuzzy queries but bad at exact-term matches; pure keyword search is the opposite. ShingleAI uses **hybrid retrieval** — both, then fused. ```mermaid theme={null} graph TD Q[Agent query] --> E[EmbeddingRetriever
top 50] Q --> B[BM25Retriever
top 50] E --> F[Reciprocal Rank Fusion] B --> F F --> R[Top 10 chunks → agent] ``` Two retrievers run **in parallel**: * **EmbeddingRetriever** — embeds the query, runs an approximate-nearest-neighbour search in pgvector, returns the top 50 chunks by cosine similarity. * **BM25Retriever** — runs a `ts_rank_cd` keyword search against the chunk text, returns the top 50 chunks. Their two ranked lists are then **fused with Reciprocal Rank Fusion** (the standard k=60 formula): a chunk's final score sums `1 / (60 + rank)` across both rankings. The top 10 fused chunks go back to the agent. Two important guarantees, enforced in SQL on every retrieval: * Only chunks from the agent's own organization are returned. * Files (and folders) with `agentAccessEnabled = false`, or with `indexingStatus ≠ indexed`, or that have been soft-deleted, are silently excluded. Your agent never sees what you've told it not to see. ## What it Costs Two consumables on your account meter file usage: * **`storage`** — the total bytes you have stored in R2. * **`text-embedding-3-small`** — embedding calls made during indexing. Both count against your tier's allowance and are charged at the relevant overage rate beyond that. See the [Credits](/get-started/concepts/credits) page for how the meters and tiers fit together. ## Related Topics How to add files in the web app Re-index files, exclude folders, troubleshoot How agents use files at runtime What storage and embeddings cost # Core Concepts Source: https://docs.shingleai.com/get-started/concepts/index Understand the fundamental concepts behind ShingleAI Before diving deeper into ShingleAI, it helps to understand the key concepts that shape how the platform works. This section covers the building blocks of ShingleAI: how data is organized, how communication flows, how AI does work for you, and how it all gets paid for. ## Key Concepts Multi-tenancy, members, and access People you communicate with and people who buy from you Multiple businesses inside one organization Email, SMS, and other channels in one inbox Work tracking and the Eisenhower priority matrix File ingestion, RAG indexing, and retrieval Conversational AI workers — and how they differ from automations Event-triggered AI workflows Tiers, consumables, overage rates, and credits ## How It All Fits Together ShingleAI is built around a simple hierarchy: ```mermaid theme={null} graph TD A[Organization] --> B[Members] A --> Bus[Businesses] A --> D[Contacts] A --> E[Customers] A --> G[Automations] A --> Ag[Agents] A --> Tk[Tasks] A --> Fl[Files] Bus --> C[Email Addresses
& Phone Numbers] D --> H[Messages] E --> I[Transactions] B[Members
users with access] Bus[Businesses
commercial entities you run] C[Email & Phone
channels for sending and receiving] D[Contacts
people you communicate with] E[Customers
buyers and ongoing relationships] G[Automations
event-triggered workflows] Ag[Agents
conversational AI workers] Tk[Tasks
work to be done] Fl[Files
indexed documents agents can search] H[Messages
communications with contacts] I[Transactions
sales and purchases] ``` **Organizations** are the top-level container. Everything else belongs to an organization and is isolated from other organizations. **Members** are users with access to the organization. Each member has a role that determines their permissions. **Businesses** are the commercial entities you run *inside* the organization. Most accounts have one; agencies and holding companies often have several. Each business has its own profile, offerings, locations, and Stripe connection. **Email Addresses** and **Phone Numbers** are the connected channels ShingleAI uses to send and receive communications — Google or Microsoft accounts for email, Telnyx numbers for SMS and voice. **Contacts** represent the individuals you communicate with. **Customers** are contacts you have a commercial relationship with. **Messages** are the communications themselves, grouped into threads. **Tasks** are units of work — created by you, by automations, or by agents — and surface on your home page through the Eisenhower priority matrix. **Files** are documents you upload. Once indexed, they become a knowledge base that agents can search via hybrid retrieval (vector + keyword). **Agents** are conversational AI workers you chat with: configured persona, tool access, conversation history. **Automations** are event-triggered workflows that run on their own. Most users mix them up at first — see the [Agents](/get-started/concepts/agents) page for when to reach for which. **Credits** are how usage on top of your plan is metered and billed. They don't appear in the hierarchy because they're not data — they're the meter that runs over everything. ## Start Learning If you're new, read these in order: Start here — how access and data isolation works The people side of the platform The most important distinction in ShingleAI How tiers, consumables, and overages work # Messages & Threads Source: https://docs.shingleai.com/get-started/concepts/messages How ShingleAI organizes communications across channels ShingleAI unifies your business communications into a single inbox. This page explains how messages are organized, what channels are supported, and how threading works. ## Message Basics A **message** is any communication sent or received through ShingleAI. Each message has: | Property | Description | | ---------------- | -------------------------------------- | | **Direction** | Incoming (received) or outgoing (sent) | | **Timestamp** | When the message was sent or received | | **Sender** | Who sent the message | | **Recipient(s)** | Who received the message | | **Content** | The message body and any attachments | | **Thread ID** | Groups related messages together | ## Supported Channels ShingleAI supports multiple communication channels: | Channel | Description | Status | | ------------- | -------------------------- | ----------- | | **Email** | Gmail, Outlook, Office 365 | Available | | **SMS** | Text messages via Telnyx | Available | | **WhatsApp** | WhatsApp Business messages | Coming soon | | **Signal** | Signal messenger | Coming soon | | **Telegram** | Telegram messages | Coming soon | | **Voicemail** | Transcribed voicemails | Coming soon | Email is the primary channel. Connect your Google or Microsoft account from the **Email Addresses** page to start receiving messages. ## Email Messages Email messages include additional properties: | Property | Description | | --------------- | ---------------------------------- | | **Subject** | Email subject line | | **To/CC/BCC** | Recipients and their visibility | | **Headers** | Technical email headers | | **Labels** | Gmail labels or Outlook categories | | **Attachments** | Files attached to the email | ### Email Features * **HTML rendering** - Emails display with full formatting * **Attachment preview** - View images and documents inline * **Reply/Forward** - Respond directly from ShingleAI * **Labels sync** - Gmail labels and Outlook categories are synced ## Threads A **thread** is a group of related messages. Threading helps you follow conversations without losing context. ### How Threading Works ShingleAI groups messages into threads based on: 1. **Email headers** - The `In-Reply-To` and `References` headers 2. **Subject matching** - Messages with the same subject 3. **Participants** - Messages between the same people When you click a message in your inbox, you see the entire thread—all related messages in chronological order. ### Thread View The thread view shows: * All messages in the conversation * Newest messages at the bottom * Sender information for each message * Timestamps * Attachments You can reply from the thread view, and your response will be part of the same conversation. ## Inbox Organization Messages are organized into four views: ### Inbox Your main inbox shows messages that need attention: * Unread messages * Messages you haven't archived * Recent conversations ### Sent Messages you've sent, organized by date. ### Snoozed Messages you've temporarily hidden. Snoozed messages reappear at a time you choose: * Later today * Tomorrow * Next week * Custom date/time Snoozing is useful for messages you can't deal with right now but don't want to forget. ### Archived Messages you've filed away. Archived messages are: * Removed from your inbox * Still searchable * Still accessible in the Archived view * Not deleted ## Message Actions From any message, you can: | Action | Keyboard | Description | | ------------- | -------- | ----------------------- | | **Reply** | `R` | Send a response | | **Reply All** | `A` | Reply to all recipients | | **Forward** | `F` | Send to someone else | | **Archive** | `E` | Move to archived | | **Snooze** | `H` | Hide temporarily | | **Delete** | `#` | Move to trash | ## Searching Messages Find messages using the search bar in the header. You can search by: * **Content** - Words in the message body * **Sender** - Email address or name * **Subject** - Email subject line * **Date** - Messages from a specific time period * **Attachments** - Messages with files Example searches: * `from:john@example.com` - Messages from John * `subject:invoice` - Messages with "invoice" in the subject * `has:attachment` - Messages with attachments * `after:2024-01-01` - Messages after a specific date * `before:2024-12-31` - Messages before a specific date * `from:john has:attachment` - Combine multiple filters ## Message and Contact Linking Messages are automatically linked to contacts: 1. When a message arrives, ShingleAI checks the sender's email 2. If a contact exists with that email, the message is linked 3. Click the contact name to see their full profile This means you can: * View all messages with a contact from their profile * See contact details directly from a message * Quickly create contacts from message senders ## Related Topics Detailed email management guide How contacts work with messages # Organizations Source: https://docs.shingleai.com/get-started/concepts/organizations How multi-tenancy and team access work in ShingleAI Organizations are the foundation of ShingleAI's data model. Every piece of data — contacts, messages, automations — belongs to an organization. This page explains what organizations are, why they exist, and how they shape the way you use ShingleAI. ## What is an Organization? An organization is a container that holds all your ShingleAI data. Think of it as a workspace that can represent: * Your company * A department or team * A personal account * A client you manage Each organization is completely isolated from others. Data in one organization cannot be accessed from another, even by the same user. ## Why Organizations? Organizations exist to solve a fundamental problem: keeping different contexts separate while letting the right people collaborate within each one. | Benefit | Description | | ----------------------- | ----------------------------------------------------------- | | **Data isolation** | Keep different businesses or clients completely separate | | **Team collaboration** | Share access with colleagues while controlling permissions | | **Resource management** | Connect different email accounts to different organizations | | **Billing separation** | Each organization can have its own subscription | For example, a freelancer managing three clients can create a separate organization for each — keeping contacts, messages, and automations completely isolated. A single company would typically use one organization with multiple members. ## Members and Roles Organizations can have multiple members. Each member has a role that determines what they can do: | Role | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------- | | **Owner** | Full access to everything, including billing, API keys, and member management. Every organization has at least one owner. | | **Admin** | Can manage data and invite members, but cannot access billing or API keys. | | **User** | Read-only access to organization data. Can manage their own profile and files. | This hierarchy follows the principle of least privilege — most team members only need the User or Admin role. See [Roles & Permissions](/admin-guide/organization/permissions) for the full permission matrix. ## Organization Scope Everything in ShingleAI is scoped to an organization: * **Contacts and customers** belong to an organization * **Messages** are received and sent through the organization's connected resources * **Automations** run within the organization's context * **API keys** and **MCP server access** grant access to a single organization's data If you belong to multiple organizations, you can switch between them from the header. Each switch changes your entire view to that organization's data. ## How Organizations Relate to Accounts Your ShingleAI **account** is your personal identity — your login credentials. **Organizations** are workspaces you belong to. The relationship works like this: * One account can belong to multiple organizations * One organization can have multiple accounts (members) * Billing is managed at the account level, covering all organizations under it * Your subscription tier determines how many organizations you can create ## Related Topics Create and configure an organization Invite members, assign roles, and manage access Full permission matrix for each role # Tasks Source: https://docs.shingleai.com/get-started/concepts/tasks How tasks work in ShingleAI and the priority matrix that powers your home page A **task** is a unit of work tracked inside ShingleAI — something that needs doing, by someone, at some point. Tasks can be created by you, by an agent, or by an automation, and they all surface in the same place: the priority matrix on your home page. ## Anatomy of a Task | Property | Description | | --------------- | -------------------------------------------------------------------------------------------------- | | **Title** | Short summary of what needs doing | | **Description** | Optional longer detail | | **Status** | Where the task is in its lifecycle | | **Importance** | How significant the task is — `low`, `medium`, `high` | | **Urgency** | How time-sensitive the task is — `low`, `medium`, `high` | | **Category** | Type of work — bug fix, feature request, meeting, planning, research, review, documentation, other | | **Due date** | Optional deadline | | **Assignees** | Members of the organization responsible for the task | ### Status Lifecycle Tasks move through a small set of states: ``` backlog → todo → in_progress → in_review → done ↘ cancelled ``` You can jump between states freely — the order is suggestive, not enforced. ## The Eisenhower Priority Matrix ShingleAI uses the **Eisenhower matrix** as the model for prioritising work. The idea, popularised by Dwight Eisenhower's "what is important is seldom urgent and what is urgent is seldom important," is to plot tasks on two axes — urgency and importance — and act differently in each quadrant. | | Important | Not important | | -------------- | ----------------- | ----------------- | | **Urgent** | **Q1 — Do First** | **Q3 — Delegate** | | **Not urgent** | **Q2 — Schedule** | **Q4 — Don't Do** | ShingleAI maps each task to a quadrant using a deliberately strict rule. Only `high` counts as **urgent** or **important** — `low` and `medium` are treated equally as "not". And tasks with `null` urgency or `null` importance are routed straight to Q1, regardless of the other axis, so unclassified work can't slip past you without being triaged. * **Q1 — Do First.** Urgent and important. The fire-fighting quadrant. * **Q2 — Schedule.** Important but not urgent. Where deep work belongs — block time for it. * **Q3 — Delegate.** Urgent but not important. Hand off if you can; otherwise batch. * **Q4 — Don't Do.** Neither urgent nor important. Cut, archive, or politely ignore. ## The Home Page Widget Your organization home page leads with the priority matrix widget. It pulls together up to **50 tasks** plus up to **25 unread messages** and groups them into the four quadrants, sorted by due date and then creation time. You can flip between a 2×2 grid and a flat list, and act on items inline without leaving the page. Messages appear in the matrix because in a communications-driven business, an unread email is often a task in disguise. Treating both as items on the same grid means the AI's triage of incoming mail flows directly into your work queue. ## Where Tasks Come From Tasks are first-class entities — anything that produces work can produce a task: * **People.** You create tasks manually for things you need to track. * **Automations.** A rule like "when a customer asks for a refund, create a task for the billing team" emits a task. * **Agents.** When an agent is given the `createTask` tool and decides a follow-up is required, it can create one. Tasks created this way are flagged so you can audit them. Assignees are members of your organization. A task can have multiple assignees — useful for things one person owns but several people need to follow. ## Related Topics How to create, edit, and triage tasks in the web app Tour of the home-page priority matrix How automations create tasks for you How agents work with tasks # Welcome to ShingleAI Source: https://docs.shingleai.com/get-started/index The AI-powered platform for unified business communications ShingleAI brings all your business communications into one intelligent platform. Manage emails, contacts, customers, and automate workflows with AI—all from a single dashboard. ## What is ShingleAI? ShingleAI is a unified business communication platform that helps teams: * **Centralize communications** - Manage emails from multiple providers (Google, Microsoft) in one inbox * **Organize contacts** - Keep track of contacts, customers, and business relationships * **Automate workflows** - Create intelligent automations triggered by incoming messages * **Leverage AI** - Use AI agents to process, categorize, and respond to communications Whether you're a solo professional or part of a larger team, ShingleAI helps you stay organized and responsive. ## Key Features View and manage emails from all your connected accounts in one place. Organize with folders, labels, and smart filters. Store contact details, track customer relationships, and link communications to the right people. Create workflows that trigger automatically based on incoming messages, saving time on repetitive tasks. Deploy AI agents that can read, categorize, and help manage your communications intelligently. ## Choose Your Path **New to ShingleAI?** Start with the quickstart guide to connect your first email and explore the platform. **Managing a team?** Learn how to set up your organization, invite members, and configure integrations. **Building integrations?** Explore the API reference to programmatically access your data. ## Getting Help If you need assistance: * **Documentation** - Browse the guides in the sidebar for detailed instructions * **Support** - Email us at [support@shingleai.com](mailto:support@shingleai.com) * **Status** - Check [status.shingleai.com](https://status.shingleai.com) for system status ## Next Steps Set up your account and connect your email Build an AI-powered support workflow from scratch Learn your way around the dashboard # Platform Overview Source: https://docs.shingleai.com/get-started/overview Navigate the ShingleAI dashboard and discover key features This guide introduces you to the ShingleAI platform interface, helping you find your way around and understand where to access different features. ## Dashboard Layout The ShingleAI dashboard is organized into three main areas: 1. **Sidebar** - Navigation menu on the left for accessing different sections 2. **Main Content** - The central area where you work with messages, contacts, and other data 3. **Header** - Top bar with organization switcher, search, and account settings ## Sidebar Navigation The sidebar provides quick access to all major features. Here's what each section does: ### Home Your dashboard landing page. For new organizations this is also where the **Setup checklist** card lives — a seven-step walkthrough (business profile, email, domain, phone, contact, automation, team invite) that auto-completes as you create each entity and silently disappears once every task is done or dismissed. ### Inbox Your unified email inbox. This is where you'll spend most of your time managing communications. | View | Description | | ------------ | ----------------------------------------------------- | | **Inbox** | Unread and active messages requiring attention | | **Sent** | Messages you've sent | | **Snoozed** | Messages you've temporarily hidden to deal with later | | **Archived** | Messages you've filed away for reference | Click any message thread to open the full conversation. The thread view shows all related messages in chronological order. ### Contacts Manage your contact database. Store names, email addresses, phone numbers, and notes about the people you communicate with. * View all contacts in a searchable list * Click a contact to see their full profile and communication history * Create, edit, and delete contacts ### Email Addresses Manage the email accounts ShingleAI sends and receives on behalf of. Connect Google (Gmail) or Microsoft (Outlook / Office 365) via OAuth, or create an address on a verified custom domain. From this page you can view sync status, pause or disconnect an account, and update provider settings. ### Phone Numbers Buy and manage phone numbers via Telnyx for SMS. The page shows connected numbers, their messaging capabilities, and recording and routing settings. ### Domains Manage custom email domains for your organization. This section handles: * Domain registration and verification * DNS configuration * WHOIS contact management Domain management is typically handled by administrators. See the [Organization Setup](/admin-guide/organization/setup) guide for details. ### Automations Create and manage automated workflows that respond to incoming messages. * View all automations and their status (active, paused, completed) * Create new automations with triggers, conditions, and actions * Monitor automation execution history ### Agents AI agents that can help process and respond to communications. * View configured agents * Monitor agent activity and conversations * Configure agent behavior and permissions ### Files Upload, store, and manage files within ShingleAI. * Upload documents and attachments * Generate shareable links * Organize files into folders ## Header Bar The header bar at the top of the screen provides: ### Organization Switcher If you belong to multiple organizations, click the organization name in the header to switch between them. Each organization has its own: * Contacts and customers * Email resources * Automations and settings * Team members ### Search Use the search bar to quickly find: * Messages by content or sender * Contacts by name or email * Files by name ### Account Menu Click your profile icon to access: * Profile settings (name, email, timezone) * Organization settings * Sign out ## Working with Messages ### Thread View When you click a message in the inbox, it opens in thread view: * All messages in the conversation are shown chronologically * You can reply directly from the thread * Related contacts are linked automatically ### Message Actions From any message, you can: * **Reply** - Send a response * **Archive** - Move to archived messages * **Snooze** - Hide temporarily and resurface later * **Delete** - Remove permanently ## Mobile Access ShingleAI is a responsive web application that works on tablets and mobile devices. While there's no dedicated mobile app, you can: * Access the full platform from your mobile browser * Add ShingleAI to your home screen for app-like experience * Receive notifications if enabled in your browser For the best experience on mobile, use a modern browser like Chrome or Safari. ## Keyboard Shortcuts Speed up your workflow with keyboard shortcuts: | Shortcut | Action | | ------------ | ------------------ | | `G` then `I` | Go to Inbox | | `G` then `C` | Go to Contacts | | `G` then `S` | Go to Sent | | `/` | Focus search | | `?` | Show all shortcuts | ## Next Steps Learn about organizations, contacts, and messages Connect email and manage your inbox # Quickstart Source: https://docs.shingleai.com/get-started/quickstart Get up and running with ShingleAI in 5 minutes This guide walks you through setting up ShingleAI and connecting your first email account. By the end, you'll have a working inbox ready to manage your business communications. ## Prerequisites Before you begin, you'll need: * A Google or Microsoft email account to connect * A modern web browser (Chrome, Firefox, Safari, or Edge) ## Step 1: Create Your Account Go to [shingleai.com](https://www.shingleai.com) and click **Get Started** or **Sign In**. Create an account using your email address or sign in with Google/Microsoft. If you signed up with email, check your inbox for a verification link and click it to confirm your account. ## Step 2: Create an Organization Organizations are how ShingleAI groups users and data. Every account needs at least one organization. After signing in for the first time, you'll be prompted to create an organization. Enter a name (e.g., your company name or "Personal"). Click **Create** to finish. You'll be taken to your new organization's dashboard. You can create multiple organizations later if you need to separate work and personal communications, or manage different businesses. ## Step 3: Work Through the Setup Checklist Your new organization's home page shows a **Setup checklist** card with the seven steps that turn a blank workspace into a working AI-powered inbox: 1. Complete your business profile 2. Connect your email 3. Add a custom domain 4. Connect a phone number 5. Add your first contact 6. Set up your first automation 7. Invite your teammates Each task auto-completes when you do the thing it asks for (for example, connecting an email provider completes "Connect your email"). When every task is complete or dismissed, the card silently disappears from the home page. You don't have to complete all seven today — this quickstart walks through the two that unlock the rest of the platform: connecting email and adding a contact. Everything else can wait until you need it. ## Step 4: Connect Your Email The **Connect your email** task is the first CTA on the checklist. On the home page, click **Connect email** on the Setup checklist. This takes you to the **Email Addresses** page. Click **Connect email** and select your provider (Google or Microsoft). You'll be redirected to Google or Microsoft to authorize ShingleAI. Review the permissions and click **Allow** or **Accept**. ShingleAI begins syncing your recent emails. This takes a few minutes depending on your inbox size. ShingleAI uses OAuth — your credentials are never seen or stored. You can revoke access at any time from your provider's security settings. Once the email address is created, the **Connect your email** checklist task auto-completes. ## Step 5: Explore Your Inbox Once your email is connected, your messages appear in the inbox. Click **Inbox** in the sidebar to view your messages. Messages are organized into threads. Click any thread to view the full conversation. Use the tabs to switch between **Inbox**, **Sent**, **Snoozed**, and **Archived** messages. ## Step 6: Add Your First Contact Back on the home page, the next expanded task is **Add your first contact**. Click **Add contact** on the Setup checklist to jump to the **Contacts** page. Click **Add Contact** and fill in the details: name, email, phone number, and any notes. Click **Save**. The **Add your first contact** task auto-completes, and the home checklist moves the next incomplete task into the expanded slot. ## What's Next? You've successfully set up ShingleAI! The next step is to see what makes ShingleAI different — AI-powered automations. Build a working AI-powered support workflow from scratch — the best way to see ShingleAI in action Understand how organizations, contacts, and automations fit together Learn your way around all the features in the dashboard Add colleagues to your organization ## First Steps Checklist Use this checklist to make sure you've completed the basics: * [ ] Created your ShingleAI account * [ ] Set up your first organization * [ ] Completed the **Connect your email** setup task * [ ] Explored the inbox and viewed messages * [ ] Completed the **Add your first contact** setup task Need help? Contact us at [support@shingleai.com](mailto:support@shingleai.com) or check the rest of this documentation for detailed guides. # Tutorial: Handle Your First Support Email with AI Source: https://docs.shingleai.com/get-started/tutorial Build a working AI-powered support workflow from scratch in ShingleAI In this tutorial, you'll set up ShingleAI to automatically handle incoming support emails using AI. By the end, you'll have a working automation that acknowledges support requests, extracts key details, and saves the sender as a contact — all without you lifting a finger. This is how ShingleAI is designed to work: you connect your communications, tell the AI what to do in plain English, and let it handle the rest. ## What you'll build You'll create a complete support email workflow that: 1. Detects incoming emails that look like support requests 2. Sends an immediate, personalized acknowledgment to the sender 3. Saves the sender as a contact if they're new By the end, you'll understand how ShingleAI's core features — email, contacts, and automations — work together. ## Prerequisites * A Google or Microsoft email account you can use for testing * A modern web browser (Chrome, Firefox, Safari, or Edge) ## Step 1: Create your account and organization First, let's get you set up on ShingleAI. Go to [shingleai.com](https://www.shingleai.com) and click **Get Started**. Create an account using your email or sign in with Google/Microsoft. After signing in, you'll be prompted to create an organization. Enter a name — this can be your company name, or something like "My Business" if you're just exploring. Click **Create**. You're now on your organization's dashboard. This is your home base — everything you do in ShingleAI happens within this organization. The **Setup checklist** card lists the seven steps that get a new org ready; we'll complete two of them (connect your email, create an automation) as part of this tutorial. ## Step 2: Connect your email The **Connect your email** task is the first CTA on the Setup checklist. On the home page, click **Connect email** on the Setup checklist. This takes you to the **Email Addresses** page. Click **Connect email** and select your provider (Google or Microsoft). You'll be redirected to your provider to authorize ShingleAI. Review the permissions and click **Allow** (Google) or **Accept** (Microsoft). ShingleAI begins syncing your recent emails. This takes a few minutes depending on your inbox size. The address appears on the **Email Addresses** page with a sync indicator. ShingleAI uses OAuth — it never sees or stores your email password. You can revoke access at any time from your provider's settings. Once the email address is created, the **Connect your email** setup task auto-completes. Once sync completes, click **Inbox** in the sidebar. You should see your recent emails. Take a moment to click through a few threads — this is the unified inbox where all your connected accounts appear together. ## Step 3: Create your first automation Now for the interesting part. You'll tell ShingleAI to watch for incoming emails and respond to them using AI. Click **Automations** in the sidebar, then click **Create Automation**. Enter a descriptive name: **Support Email Auto-Acknowledgment**. Good names make it easy to find and manage your automations later. For the trigger event, enter: **New email received**. This tells ShingleAI to run the automation every time an email arrives. This is where you tell the AI what to do — in plain English. Paste the following into the instructions field: ``` When a new email arrives: 1. If the email looks like a support request or question about our services, send a friendly acknowledgment reply: - Thank them for reaching out - Confirm we received their message - Let them know we'll respond within 24 hours - Keep the tone warm and professional - Keep the reply under 100 words - Sign off with "Best regards" and "The Support Team" 2. If the email is clearly not a support request (newsletters, marketing, automated notifications), do nothing. ``` Click **Save**. The automation is enabled by default and starts working immediately. Saving also auto-completes the **Set up your first automation** task on the home checklist. ## Step 4: Test it Let's see your automation in action. From a different email account (or ask a friend), send an email to the address you connected. Write something that looks like a support request, for example: > Subject: Help with my account > > Hi, I'm having trouble logging in to my dashboard. I keep getting an "invalid credentials" error even though I'm sure my password is correct. Can you help? Wait a minute or two, then check the **Inbox** in ShingleAI. You should see: * The incoming support email in your inbox * An outgoing reply that the AI generated and sent automatically Click the thread to see the full conversation. The AI's reply should be a friendly acknowledgment that follows your instructions — thanking the sender, confirming receipt, and setting expectations. If the automation didn't trigger, check a few things: Is the automation enabled? (Look for the toggle on the Automations page.) Did the email finish syncing? Give it another minute and check the automation's execution history for any errors. ## Step 5: Check the results Let's verify everything worked end-to-end. Go to **Automations**, click your automation, and look at the execution history. You should see a successful execution with details about what the AI did. Click **Contacts** in the sidebar. If the sender was new, ShingleAI may have automatically created a contact record for them. Click the contact to see their profile and the linked message history. ## What you've accomplished You've built a working AI-powered support workflow. Here's what's happening behind the scenes every time an email arrives: 1. ShingleAI receives the email through your connected account 2. The automation detects a new message and triggers 3. The AI reads the email and evaluates your instructions 4. If it's a support request, the AI composes and sends a reply 5. The sender and message are linked in your contact database This is the core loop of ShingleAI: **connect → automate → let AI handle it**. Every feature builds on this pattern. ## Next steps Now that you've seen ShingleAI in action, here are some ways to go further: Learn how to fine-tune triggers, add conditions, and write better AI instructions Learn how organizations, contacts, messages, and automations fit together Organize your contacts with labels, notes, and detailed profiles Give AI assistants like Claude direct access to your ShingleAI data # Authentication Source: https://docs.shingleai.com/mcp-server/authentication How AI agents authenticate to the ShingleAI MCP server The ShingleAI MCP server is a protected resource. Clients authenticate using **OAuth 2.1 with PKCE and Dynamic Client Registration (RFC 7591)**, following the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). Modern MCP clients — Claude Desktop, Claude Code, Cursor, Windsurf, and the MCP Inspector — run the entire flow automatically. As an end user you only need to: 1. Point the client at `https://mcp.shingleai.com`. 2. Sign in to ShingleAI when the consent screen opens in your browser. 3. Approve the consent screen, choosing which tool categories the client may use. The rest of this page describes the flow in detail for client developers and for anyone debugging a connection. ## How the flow works ``` Client → /mcp (or /sse) (no token) Server → 401 + WWW-Authenticate Client → /.well-known/oauth-protected-resource/mcp (route-scoped; host-level also available) Client → /.well-known/oauth-authorization-server Client → POST /oauth/register (Dynamic Client Registration) Client → /oauth/authorize (browser, with PKCE code_challenge) User → consent screen Server → redirect with auth code Client → POST /oauth/token (code + code_verifier) Server → access_token (+ refresh_token if offline_access) Client → /mcp or /sse (Authorization: Bearer ) ``` The handshake is plain OAuth 2.1; no ShingleAI-specific extensions are involved. ## Discovery The server publishes two host-derived metadata documents. A client discovers everything else from these. | Endpoint | Purpose | | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `/.well-known/oauth-protected-resource` | RFC 9728 protected-resource metadata. Lists the authorization server. | | `/.well-known/oauth-authorization-server` | RFC 8414 authorization-server metadata. Lists `/oauth/register`, `/oauth/authorize`, `/oauth/token`, supported scopes, and PKCE methods. | You can fetch them directly: ```bash theme={null} curl -s https://mcp.shingleai.com/.well-known/oauth-protected-resource | jq curl -s https://mcp.shingleai.com/.well-known/oauth-authorization-server | jq ``` ## 401 response shape A request to `/mcp` or `/sse` without a valid Bearer token returns HTTP `401` with a `WWW-Authenticate` header pointing back to a route-scoped protected-resource metadata URL on the same host: ```http theme={null} HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="OAuth", resource_metadata="https://mcp.shingleai.com/.well-known/oauth-protected-resource/mcp", error="invalid_token", error_description="Missing or invalid access token" Content-Type: application/json {"error":"invalid_token","error_description":"Missing or invalid access token"} ``` The 401 — not a JSON-RPC error envelope — is the canonical signal that the client should run discovery and the OAuth flow. The `resource_metadata` URL is route-scoped (`/mcp` and `/sse` advertise their own metadata documents); a host-level document is also available at `/.well-known/oauth-protected-resource` for clients that prefer it. ## Dynamic Client Registration Clients register themselves at `POST /oauth/register` per RFC 7591. Registration is open (no admin approval required) but rate-limited to **10 requests per 60 seconds per IP**, so clients should cache the returned `client_id` (and any `client_secret`) and reuse it across launches rather than re-registering every time. Prefer the OS credential store (Keychain on macOS, Credential Manager on Windows, libsecret on Linux) over a plaintext file on disk, especially for `client_secret` values. ## PKCE The server requires PKCE on every authorization request and only accepts the `S256` code-challenge method. Plain PKCE is rejected — clients that send `code_challenge_method=plain` will fail the authorize step. ## Scopes Two scopes are advertised: | Scope | Required | Purpose | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mcp` | Yes | Access to the MCP transport endpoints. | | `offline_access` | No | Issues a refresh token alongside the access token. Request only for persistent or background clients; omit for interactive one-shot use, since the 90-day refresh token is a longer-lived credential. | During consent the user also chooses which tool categories the client may call. The set of tools advertised over `tools/list` is filtered against that selection on every request. ## Token lifetime | Token | TTL | Notes | | ------------- | ------- | -------------------------------------------------------------- | | Access token | 60 min | Bearer token presented on `/mcp` and `/sse`. | | Refresh token | 90 days | Issued only when `offline_access` was granted; rotated on use. | Access tokens are refreshed via `POST /oauth/token` with `grant_type=refresh_token`. Refresh tokens rotate on every use per OAuth 2.1. ## Rate limits on the transport Once authenticated, `/mcp` and `/sse` are rate-limited to **100 requests per 60 seconds per (user, client)**. A throttled response is HTTP `429` with a JSON-RPC error body (`code: -32004`, `message: "Rate limit exceeded"`) and a `Retry-After` header. The server does not emit `X-RateLimit-*` headers. ## Reference * [MCP authorization spec (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) * [RFC 9728 — OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) * [RFC 8414 — OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) * [RFC 7591 — Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) # Connection Guide Source: https://docs.shingleai.com/mcp-server/connection Connect AI agents to the ShingleAI MCP server This guide covers how to connect AI agents to the ShingleAI MCP server, including the available transports and troubleshooting common issues. ## Connection URL The MCP server is available at: ``` https://mcp.shingleai.com ``` ## Authentication Modern MCP clients (Claude Desktop, Claude Code, Cursor, Windsurf) handle OAuth 2.1 + PKCE automatically — point them at the connection URL above and they walk you through sign-in and consent. See [Authentication](/mcp-server/authentication) for the full flow. ## Transports The MCP server supports two transports: * **Streamable HTTP** — `https://mcp.shingleai.com/mcp`. The current MCP transport; recommended for new clients. * **Server-Sent Events (SSE)** — `https://mcp.shingleai.com/sse`. Kept for compatibility with clients that implement the earlier SSE transport. Pick whichever your client supports; you do not need to configure both. ## Health Check Verify the MCP server is available before connecting: ```bash theme={null} curl https://mcp.shingleai.com/health ``` Response: ```json theme={null} {"status": "ok"} ``` The health check endpoint doesn't require authentication. Use it to verify connectivity before attempting to establish an authenticated connection. ## Troubleshooting **Possible causes:** * Network connectivity issues * Firewall blocking outbound HTTPS * Incorrect URL **Solutions:** 1. Verify network connectivity: `curl https://mcp.shingleai.com/health` 2. Check firewall rules allow outbound HTTPS (port 443) 3. Ensure you're using `https://` not `http://` A 401 is the canonical signal that your client needs to run (or re-run) the OAuth flow. The `WWW-Authenticate` header on the response points to a route-scoped protected-resource metadata URL (e.g. `/.well-known/oauth-protected-resource/mcp`), which a spec-compliant client uses to start discovery. **Solutions:** 1. Confirm your client supports OAuth 2.1 + PKCE + Dynamic Client Registration. Most current MCP clients do. 2. Make sure you completed the consent screen in your browser. If you cancelled it, retry the connection from your client. 3. If the client looks stuck after a successful consent, remove and re-add the ShingleAI server in the client so it re-registers via DCR. 4. See [Authentication](/mcp-server/authentication) for the full handshake. **Possible causes:** * Insufficient permissions for the requested tool * Monthly call limit exceeded * Account suspended **Solutions:** 1. Check the error message for details 2. Check your usage in the dashboard 3. Upgrade your plan if you've hit the monthly limit **Possible causes:** * Too many requests in a short period * Exceeding 100 requests per 60 seconds per (user, client) **Solutions:** 1. Implement request queuing or throttling 2. Use exponential backoff when retrying 3. Wait for the duration in the `Retry-After` response header before retrying **Possible causes:** * Network instability * Idle timeout * Server maintenance **Solutions:** 1. Implement automatic reconnection logic 2. Send periodic ping messages to keep the connection alive 3. Check [status.shingleai.com](https://status.shingleai.com) for service issues ## Session Management MCP connections are stateful. Each connection receives a unique session ID that persists for the duration of the connection. * **Session IDs** are generated automatically on connection * **Sessions expire** after extended idle periods * **Reconnections** create new sessions - previous session state is not preserved Design your agent to be stateless where possible. Don't rely on server-side session state persisting between tool calls. ## Next Steps Explore the complete list of MCP tools See examples of MCP integrations # Claude Desktop Source: https://docs.shingleai.com/mcp-server/integrations/claude Connect ShingleAI to Claude Desktop using MCP This guide walks you through connecting the ShingleAI MCP server to Claude Desktop, allowing Claude to access your contacts, messages, and other business data directly. ## Prerequisites Before you begin, ensure you have: * [Claude Desktop](https://claude.ai/download) installed * A ShingleAI account ## Connect Claude Desktop ships with native support for streamable-HTTP MCP servers and runs the OAuth 2.1 + PKCE handshake for you. The custom-connector UI used below requires a recent Claude Desktop build — if you don't see **Connectors** under **Settings**, install the latest version from [claude.ai/download](https://claude.ai/download). 1. Open Claude Desktop and go to **Settings → Connectors → Add custom connector**. 2. Paste the ShingleAI MCP URL as the server URL: ``` https://mcp.shingleai.com ``` 3. Click **Connect**. Claude Desktop opens a browser tab on `https://mcp.shingleai.com/oauth/authorize`. 4. Sign in to ShingleAI (if you aren't already), then review the consent screen — choose which tool categories Claude Desktop may use, and decide whether to grant `offline_access` for a long-lived refresh token. 5. Approve. The browser hands control back to Claude Desktop and the connector goes green. See [Authentication](/mcp-server/authentication) if you want to understand the OAuth handshake in detail. ## Verification Once the connection is working: 1. Open a new conversation in Claude Desktop 2. Ask Claude: "What ShingleAI tools do you have access to?" 3. Claude should list the available tools based on your permissions ## Example Prompts Once connected, you can ask Claude to interact with your ShingleAI data: | Task | Example Prompt | | ----------------- | -------------------------------------------------------------------------------------- | | Find a contact | "Find the contact information for John Smith" | | Search messages | "Show me recent messages about the project proposal" | | View conversation | "What's the full email thread with [support@example.com](mailto:support@example.com)?" | | Create a contact | "Add a new contact for Jane Doe at [jane@example.com](mailto:jane@example.com)" | ## Troubleshooting **Possible causes:** * The connector wasn't approved in the consent screen * Tool categories were unchecked during consent * The connector is showing red in **Settings → Connectors** **Solutions:** 1. Open **Settings → Connectors** and confirm the ShingleAI connector is green. 2. If it's red, click **Reconnect** and re-approve the consent screen. 3. If it's green but Claude can't see specific tools, remove and re-add the connector — during consent, make sure the relevant tool categories are checked. If the consent screen fails to load, check that you can reach `https://mcp.shingleai.com/.well-known/oauth-protected-resource` from your machine and that you're signed in to ShingleAI in the same browser Claude Desktop opened. If the connector goes red after a successful approval, remove and re-add it — Claude Desktop will register a fresh OAuth client via Dynamic Client Registration. ## Next Steps Explore all available MCP tools Learn about MCP server authentication # Cursor IDE Source: https://docs.shingleai.com/mcp-server/integrations/cursor Connect ShingleAI to Cursor using MCP This guide walks you through connecting the ShingleAI MCP server to Cursor IDE, allowing Cursor's AI to access your contacts, messages, and other business data while coding. ## Prerequisites Before you begin, ensure you have: * [Cursor IDE](https://cursor.com/) installed * A ShingleAI account ## Connect Cursor supports streamable-HTTP MCP servers and runs the OAuth 2.1 + PKCE handshake for you. 1. Add ShingleAI to your Cursor MCP config. Use `.cursor/mcp.json` in a project directory, or `~/.cursor/mcp.json` for every project: ```json theme={null} { "mcpServers": { "shingleai": { "url": "https://mcp.shingleai.com/mcp" } } } ``` You can also add the server through **File → Preferences → Cursor Settings → MCP**, which writes the same JSON. 2. Restart Cursor. 3. The first time Cursor calls a ShingleAI tool — or when you click **Connect** in the MCP settings — Cursor opens a browser tab for OAuth. 4. Sign in to ShingleAI and approve the consent screen. Cursor stores the access token and the tools become available in chat. See [Authentication](/mcp-server/authentication) for details on the OAuth handshake. ## Verification To verify the connection is working: 1. Open Cursor's AI chat (Cmd+L or Ctrl+L) 2. Ask: "What ShingleAI tools do you have access to?" 3. Cursor should list the available tools ## Example Usage Once connected, you can use ShingleAI tools in your development workflow: | Task | Example Prompt | | --------------------- | ---------------------------------------------------- | | Find contact info | "Look up the contact details for our main client" | | Search communications | "Find all messages about the API integration" | | Review history | "Show the conversation history with the design team" | ## Troubleshooting **Possible causes:** * Configuration file in wrong location * Invalid JSON syntax * Cursor not restarted **Solutions:** 1. Verify the configuration file path 2. Validate your JSON syntax 3. Completely restart Cursor (not just reload window) If the OAuth browser tab fails to load, check that you can reach `https://mcp.shingleai.com/.well-known/oauth-protected-resource` from your machine. If Cursor shows a stale token error, remove the `shingleai` entry from your `mcp.json`, restart Cursor, and re-add it — that forces a fresh Dynamic Client Registration. See [Authentication](/mcp-server/authentication) for the underlying flow. Cursor currently supports MCP tools but not MCP resources. This means you can call ShingleAI tools (like `createContact`, `listMessages`) but cannot access read-only MCP resources that some servers provide. ## Next Steps Explore all available MCP tools Learn about MCP server authentication # Integrations Overview Source: https://docs.shingleai.com/mcp-server/integrations/index Connect the ShingleAI MCP Server to AI coding tools The ShingleAI MCP server integrates with popular AI-powered development tools, allowing you to access your business data directly from your preferred coding environment. ## Supported Tools | Tool | Platform | Configuration | | ------------------------------------------------- | --------------------- | --------------------- | | [Claude Desktop](/mcp-server/integrations/claude) | macOS, Windows | Settings → Connectors | | [Cursor](/mcp-server/integrations/cursor) | macOS, Windows, Linux | `.cursor/mcp.json` | | [Windsurf](/mcp-server/integrations/windsurf) | macOS, Windows, Linux | `mcp_config.json` | ## Authentication Each of the clients listed above runs the OAuth 2.1 + PKCE handshake automatically. Point the client at `https://mcp.shingleai.com`, sign in to ShingleAI in the browser tab that opens, and approve the consent screen. See [Authentication](/mcp-server/authentication) for the full flow. ## Integration Guides Connect to Anthropic's Claude Desktop app Integrate with Cursor IDE Set up Windsurf with Cascade ## Next Steps See what tools are available Learn about MCP server authentication # Windsurf Source: https://docs.shingleai.com/mcp-server/integrations/windsurf Connect ShingleAI to Windsurf using MCP This guide walks you through connecting the ShingleAI MCP server to Windsurf, allowing Cascade (Windsurf's AI) to access your contacts, messages, and other business data. ## Prerequisites Before you begin, ensure you have: * [Windsurf](https://windsurf.com/) installed * A ShingleAI account ## Connect Windsurf supports streamable-HTTP MCP servers and runs the OAuth 2.1 + PKCE handshake for you. 1. Add ShingleAI to `~/.codeium/windsurf/mcp_config.json`: ```json theme={null} { "mcpServers": { "shingleai": { "serverUrl": "https://mcp.shingleai.com/mcp" } } } ``` Or, from Windsurf, open the Command Palette with `Cmd+Shift+P` (Mac) / `Ctrl+Shift+P` (Windows/Linux), run **Open Windsurf Settings**, navigate to **Cascade → Plugins**, and add ShingleAI as a custom MCP plugin pointing at `https://mcp.shingleai.com/mcp` — Windsurf writes the same JSON. 2. Restart Windsurf. 3. The first time Cascade uses a ShingleAI tool — or when you click **Connect** in the plugin entry — Windsurf opens a browser tab for OAuth. 4. Sign in to ShingleAI and approve the consent screen. Cascade then has access to the tools you granted. See [Authentication](/mcp-server/authentication) for details on the OAuth handshake. ## Verification To verify the connection is working: 1. Open Cascade (Windsurf's AI assistant) 2. Ask: "What ShingleAI tools do you have access to?" 3. Cascade should list the available tools ## Example Usage Once connected, you can use ShingleAI tools in Cascade: | Task | Example Prompt | | --------------------- | ------------------------------------------------ | | Find contact info | "Look up contact information for our vendor" | | Search communications | "Find messages mentioning the deployment issue" | | View thread | "Show the full conversation thread with support" | ## Troubleshooting **Possible causes:** * Configuration file in wrong location * Invalid JSON syntax * Windsurf not restarted **Solutions:** 1. Verify the file is at `~/.codeium/windsurf/mcp_config.json` 2. Validate your JSON syntax 3. Completely restart Windsurf If the OAuth browser tab fails to load, check that you can reach `https://mcp.shingleai.com/.well-known/oauth-protected-resource` from your machine. If Cascade shows a stale token error, remove the `shingleai` entry from `~/.codeium/windsurf/mcp_config.json`, restart Windsurf, and re-add it — that forces a fresh Dynamic Client Registration. See [Authentication](/mcp-server/authentication) for the underlying flow. Cascade has a limit of 100 total tools. If you have many MCP servers configured, you may need to disable some tools. **Solution:** 1. Open **Windsurf Settings**, navigate to **Cascade → Plugins** 2. Navigate to the Tools tab 3. Toggle off tools you don't need ## Next Steps Explore all available MCP tools Learn about MCP server authentication # Introduction Source: https://docs.shingleai.com/mcp-server/introduction Connect AI agents to ShingleAI using the Model Context Protocol The ShingleAI MCP Server provides AI agents with direct access to your business communication platform. Using the Model Context Protocol (MCP), agents can manage contacts, customers, messages, automations, and more through a standardized interface. ## What is MCP? The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard that enables AI assistants to interact with external systems through a unified interface. Instead of building custom integrations for each AI platform, MCP provides a single connection point that works with Claude, GPT-based agents, and other MCP-compatible AI systems. MCP uses a client-server architecture where AI agents connect as clients to the ShingleAI MCP server. The server exposes tools that agents can discover and invoke to perform actions on your behalf. ## Why Use ShingleAI's MCP Server? * **Direct AI Access** - Give your AI agents the ability to read and manage your business data without building custom APIs * **Permission Control** - Fine-grained permissions let you control exactly what each agent can access * **Real-Time Operations** - Agents can create contacts, send messages, manage customers, and automate workflows in real-time * **Standardized Protocol** - Works with any MCP-compatible AI assistant or automation platform ## Available Tools The MCP server provides **106 tools** across 12 resource categories: | Category | Tools | Description | | ------------------- | ----- | ------------------------------------------------------------ | | **Automations** | 7 | Create, update, and inspect automations and their executions | | **Businesses** | 20 | Business profile, offerings, and online/physical presences | | **Contacts** | 20 | Contacts and their emails, phones, and addresses | | **Customers** | 10 | Customer records and customer transactions | | **Domains** | 15 | Domains, domain contacts, and domain registrations | | **Email Addresses** | 2 | List and read connected email addresses | | **Email Templates** | 7 | Manage templates, render previews, and send templated email | | **Files** | 5 | Upload, download, list, search, and delete files | | **Folders** | 2 | Create and list folders | | **Messages** | 6 | Read messages, threads, and attachments; update status | | **Phone Numbers** | 2 | List and read connected phone numbers | | **Tasks** | 10 | Task CRUD, search, and assignee management | ## Use Cases ### AI Assistants Connect Claude Desktop or other AI assistants to ShingleAI. Your assistant can then: * Look up contact information during conversations * Create follow-up tasks after meetings * Search through message history * Draft and queue messages for review ### Workflow Automation Build automated workflows that leverage AI decision-making: * Process incoming leads and create customer records * Categorize and route messages to appropriate team members * Generate reports from business data * Trigger automations based on AI analysis ### Custom Integrations Develop custom AI-powered applications that interact with ShingleAI: * Build chatbots that can access customer information * Create AI agents that manage your inbox * Integrate with other business tools through AI orchestration ## Transports The MCP server supports two transports. Pick the one your client expects: * **Streamable HTTP** at `/mcp` — the current MCP transport; recommended for new clients. * **Server-Sent Events (SSE)** at `/sse` — kept for compatibility with clients that implement the earlier SSE transport. See the [Connection Guide](/mcp-server/connection) for full URLs and setup details. ## Next Steps Learn how MCP clients authenticate to the server Connect your AI agents to the MCP server # Automation Tools Source: https://docs.shingleai.com/mcp-server/tools/automations Create, manage, and inspect organization automations and their executions The ShingleAI MCP server provides 7 tools for managing automations and inspecting their execution history. These tools are organized into two categories: automations and executions. ## Automations Core tools for creating, reading, updating, and deleting automations. ### createAutomation Create a new automation with trigger event, conditions, and instructions. **Permission:** `automations:write` **Parameters:** | Name | Type | Required | Description | | -------------- | ----------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Yes | The name of the automation | | `description` | string | No | A description of what the automation does | | `triggerEvent` | string \| null | No | The event type that triggers this automation (e.g., "message", "contact", "customer") | | `condition` | `Record` | No | A key-value map of conditions that must be met for the automation to execute. Values must be strings or booleans (no nesting) | | `instructions` | string | Yes | Natural language instructions describing what the automation should do | | `createdBy` | string (UUID) | No | The user ID who created the automation | | `enabled` | boolean | No | Whether the automation is enabled (defaults to true) | After creation, the automation is generated and evaluated asynchronously. System-managed fields like generated code, evaluation results, group metadata, and execution counters are populated by the platform — do not pass them in here, as they are overwritten or ignored. **Returns:** The created automation object. *** ### getAutomation Get details of a specific automation by ID. **Permission:** `automations:read` **Parameters:** | Name | Type | Required | Description | | -------------- | ------------- | -------- | ------------------------------------ | | `automationId` | string (UUID) | Yes | The ID of the automation to retrieve | **Returns:** The automation object, or `null` if not found. *** ### listAutomations List automations with pagination. **Permission:** `automations:read` **Parameters:** | Name | Type | Required | Default | Description | | -------- | ------ | -------- | ------- | -------------------------------------------- | | `limit` | number | No | 20 | Number of automations to return (1-100) | | `offset` | number | No | 0 | Number of automations to skip for pagination | **Returns:** ```json theme={null} { "automations": [...], "count": 42, "limit": 20, "offset": 0 } ``` *** ### updateAutomation Update an existing automation - all fields are optional except `automationId`. **Permission:** `automations:write` **Parameters:** | Name | Type | Required | Description | | -------------- | ----------------------------------- | -------- | ---------------------------------------------------------------------- | | `automationId` | string (UUID) | Yes | The ID of the automation to update | | `name` | string | No | Update the automation name | | `description` | string | No | Update the description | | `triggerEvent` | string | No | Update the trigger event | | `condition` | `Record` | No | Update the conditions. Values must be strings or booleans (no nesting) | | `instructions` | string | No | Update the instructions | | `createdBy` | string (UUID) | No | Update the creator | | `enabled` | boolean | No | Enable or disable the automation | **Returns:** The updated automation object. *** ### deleteAutomation Delete an automation (soft delete). **Permission:** `automations:delete` **Parameters:** | Name | Type | Required | Description | | -------------- | ------------- | -------- | ---------------------------------- | | `automationId` | string (UUID) | Yes | The ID of the automation to delete | **Returns:** The deleted automation object. *** ## Executions Tools for inspecting individual automation executions and their history. ### getAutomationExecution Get details of a specific automation execution by ID. **Permission:** `automations.executions:read` **Parameters:** | Name | Type | Required | Description | | ------------- | ------------- | -------- | ---------------------------------------------- | | `executionId` | string (UUID) | Yes | The ID of the automation execution to retrieve | **Returns:** The automation execution object, or `null` if not found. *** ### listAutomationExecutions List automation executions with pagination, optionally filtered by automation ID. **Permission:** `automations.executions:read` **Parameters:** | Name | Type | Required | Default | Description | | -------------- | ------------- | -------- | ------- | ------------------------------------------- | | `automationId` | string (UUID) | No | - | Filter executions by automation ID | | `limit` | number | No | 20 | Number of executions to return (1-100) | | `offset` | number | No | 0 | Number of executions to skip for pagination | **Returns:** ```json theme={null} { "executions": [...], "count": 17, "limit": 20, "offset": 0 } ``` *** ## Next Steps Manage contacts and their associated data Learn how MCP clients authenticate to the server # Business Tools Source: https://docs.shingleai.com/mcp-server/tools/businesses Manage businesses, profiles, offerings, and online and physical presences The ShingleAI MCP server provides 20 tools for managing businesses, their profile, offerings, and online and physical presences. These tools are organized into five categories: businesses, business profile, offerings, online presences, and physical presences. ## Businesses Core tools for reading and updating businesses. Businesses are provisioned with the organization, so there are no `create` or `delete` tools. ### getBusiness Get details for a specific business by ID. **Permission:** `businesses:read` **Parameters:** | Name | Type | Required | Description | | ------------ | ------------- | -------- | ------------------------------ | | `businessId` | string (UUID) | Yes | ID of the business to retrieve | **Returns:** Business object, or `null` if not found. *** ### listBusinesses List all businesses in the organization. **Permission:** `businesses:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Maximum number of items to return (max: 100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "businesses": [...], "count": 3, "limit": 10, "offset": 0 } ``` *** ### updateBusiness Update an existing business by ID. **Permission:** `businesses:write` **Parameters:** | Name | Type | Required | Description | | ------ | ------------- | -------- | ---------------------------- | | `id` | string (UUID) | Yes | ID of the business to update | | `name` | string | No | The name of the business | Stripe Connect-related fields on the business record are managed by the Stripe integration — do not pass them in here, as they are overwritten or ignored. **Returns:** The updated business object. *** ## Business Profile Tools for reading and updating the descriptive profile of a business. The profile is created alongside the business, so there is no `create`, `list`, or `delete` tool — there is exactly one profile per business. ### getBusinessProfile Get the detailed profile of a business by ID. **Permission:** `businesses.profiles:read` **Parameters:** | Name | Type | Required | Description | | ------------ | ------------- | -------- | ----------------------------------------------------------------------------- | | `businessId` | string (UUID) | Yes | ID of the business whose profile to retrieve (profile shares the business ID) | **Returns:** Business profile object, or `null` if not found. *** ### updateBusinessProfile Update the profile information of a business. **Permission:** `businesses.profiles:write` **Parameters:** | Name | Type | Required | Description | | ------------- | -------------------------------- | -------- | ------------------------------------------------------ | | `id` | string (UUID) | Yes | The ID of the business profile to update | | `description` | string \| null | No | A new detailed description of the business (optional) | | `industries` | string\[] \| null | No | New industries the business operates in (optional) | | `data` | Record\ \| null | No | Additional business data as key-value pairs (optional) | **Returns:** The updated business profile object. *** ## Offerings Tools for managing the products and services a business offers. ### createBusinessOffering Create a new product or service offering for a business. **Permission:** `businesses.offerings:write` **Parameters:** | Name | Type | Required | Description | | ------------- | --------------- | -------- | -------------------------------------------------------------- | | `businessId` | string (UUID) | Yes | The ID of the business this offering belongs to | | `name` | string | Yes | The name of the offering | | `description` | string \| null | No | A description of the offering (optional) | | `isService` | boolean \| null | No | Whether this is a service (true) or product (false) - optional | **Returns:** The created business offering object. *** ### getBusinessOffering Get details of a specific business offering by ID. **Permission:** `businesses.offerings:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the business offering to retrieve | **Returns:** Business offering object, or `null` if not found. *** ### listBusinessOfferings List all products and services offered by a business. **Permission:** `businesses.offerings:read` **Parameters:** | Name | Type | Required | Default | Description | | ------------ | ------------- | -------- | ------- | -------------------------------------------- | | `businessId` | string (UUID) | Yes | - | The ID of the business to list offerings for | | `limit` | number | No | 100 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | **Returns:** ```json theme={null} { "offerings": [...], "count": 12, "limit": 100, "offset": 0 } ``` *** ### updateBusinessOffering Update details of an existing business offering. **Permission:** `businesses.offerings:write` **Parameters:** | Name | Type | Required | Description | | ------------- | --------------- | -------- | -------------------------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the business offering to update | | `name` | string | No | The new name for the offering (optional) | | `description` | string \| null | No | A new description for the offering (optional) | | `isService` | boolean \| null | No | Whether this is a service (true) or product (false) - optional | **Returns:** The updated business offering object. *** ### deleteBusinessOffering Delete a business offering (soft delete). **Permission:** `businesses.offerings:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ----------------------------------------- | | `id` | string (UUID) | Yes | The ID of the business offering to delete | **Returns:** The deleted business offering object. *** ## Online Presences Tools for managing a business's online presence — websites, social media profiles, marketplace listings, and similar. ### createBusinessOnlinePresence Create a new online presence for a business (website, social media, marketplace, etc.). **Permission:** `businesses.online-presences:write` **Parameters:** | Name | Type | Required | Description | | ------------- | -------------- | -------- | ---------------------------------------------------------------------------------------- | | `businessId` | string (UUID) | Yes | The ID of the business this online presence belongs to | | `name` | string | Yes | The name of the online presence (e.g., "Company Website", "Facebook Page") | | `url` | string \| null | No | The URL of the online presence (optional) | | `description` | string \| null | No | A description of the online presence (optional) | | `type` | string \| null | No | The type of online presence (e.g., "website", "social\_media", "marketplace") (optional) | | `provider` | string \| null | No | The provider or platform (e.g., "facebook", "linkedin", "amazon") (optional) | **Returns:** The created business online presence object. *** ### getBusinessOnlinePresence Get details of a specific business online presence by ID. **Permission:** `businesses.online-presences:read` **Parameters:** | Name | Type | Required | Description | | ------------------ | ------------- | -------- | -------------------------------------------------- | | `onlinePresenceId` | string (UUID) | Yes | The ID of the business online presence to retrieve | **Returns:** Business online presence object, or `null` if not found. *** ### listBusinessOnlinePresences List all online presences for a specific business. **Permission:** `businesses.online-presences:read` **Parameters:** | Name | Type | Required | Default | Description | | ------------ | ------------- | -------- | ------- | --------------------------------------------------- | | `businessId` | string (UUID) | Yes | - | The ID of the business to list online presences for | | `limit` | number | No | 100 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | **Returns:** ```json theme={null} { "onlinePresences": [...], "count": 4, "limit": 100, "offset": 0 } ``` *** ### updateBusinessOnlinePresence Update an existing business online presence - all fields are optional except onlinePresenceId. **Permission:** `businesses.online-presences:write` **Parameters:** | Name | Type | Required | Description | | ------------------ | -------------- | -------- | ------------------------------------------------ | | `onlinePresenceId` | string (UUID) | Yes | The ID of the business online presence to update | | `name` | string | No | Update the online presence name | | `url` | string \| null | No | Update the URL | | `description` | string \| null | No | Update the description | | `type` | string \| null | No | Update the type of online presence | | `provider` | string \| null | No | Update the provider or platform | **Returns:** The updated business online presence object. *** ### deleteBusinessOnlinePresence Delete a business online presence (soft delete). **Permission:** `businesses.online-presences:delete` **Parameters:** | Name | Type | Required | Description | | ------------------ | ------------- | -------- | ------------------------------------------------ | | `onlinePresenceId` | string (UUID) | Yes | The ID of the business online presence to delete | **Returns:** The deleted business online presence object. *** ## Physical Presences Tools for managing a business's physical locations — offices, stores, warehouses, and similar. ### createBusinessPhysicalPresence Create a new physical location (office, store, warehouse, etc.) for a business. **Permission:** `businesses.physical-presences:write` **Parameters:** | Name | Type | Required | Description | | ------------- | -------------- | -------- | ------------------------------------------------------------------------- | | `businessId` | string (UUID) | Yes | The ID of the business this physical location belongs to | | `name` | string | Yes | The name of the physical location (e.g., "Main Office", "Downtown Store") | | `description` | string \| null | No | A description of the physical location (optional) | | `address` | string \| null | No | The full address of the physical location (optional) | **Returns:** The created business physical presence object. *** ### getBusinessPhysicalPresence Get details of a specific business physical location by ID. **Permission:** `businesses.physical-presences:read` **Parameters:** | Name | Type | Required | Description | | -------------------- | ------------- | -------- | ---------------------------------------------------- | | `physicalPresenceId` | string (UUID) | Yes | The ID of the business physical presence to retrieve | **Returns:** Business physical presence object, or `null` if not found. *** ### listBusinessPhysicalPresences List all physical locations (offices, stores, etc.) for a business. **Permission:** `businesses.physical-presences:read` **Parameters:** | Name | Type | Required | Default | Description | | ------------ | ------------- | -------- | ------- | ----------------------------------------------------- | | `businessId` | string (UUID) | Yes | - | The ID of the business to list physical locations for | | `limit` | number | No | 100 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | **Returns:** ```json theme={null} { "physicalPresences": [...], "count": 2, "limit": 100, "offset": 0 } ``` *** ### updateBusinessPhysicalPresence Update an existing business physical location - all fields are optional except physicalPresenceId. **Permission:** `businesses.physical-presences:write` **Parameters:** | Name | Type | Required | Description | | -------------------- | -------------- | -------- | -------------------------------------------------- | | `physicalPresenceId` | string (UUID) | Yes | The ID of the business physical presence to update | | `name` | string | No | Update the physical location name | | `description` | string \| null | No | Update the description | | `address` | string \| null | No | Update the address | **Returns:** The updated business physical presence object. *** ### deleteBusinessPhysicalPresence Delete a business physical location (soft delete). **Permission:** `businesses.physical-presences:delete` **Parameters:** | Name | Type | Required | Description | | -------------------- | ------------- | -------- | -------------------------------------------------- | | `physicalPresenceId` | string (UUID) | Yes | The ID of the business physical presence to delete | **Returns:** The deleted business physical presence object. *** ## Next Steps Manage customers and their relationships with your business Learn how MCP clients authenticate to the server # Contact Tools Source: https://docs.shingleai.com/mcp-server/tools/contacts Manage contacts, emails, addresses, and phone numbers The ShingleAI MCP server provides 21 tools for managing contacts and their associated data. These tools are organized into four categories: contact management, emails, addresses, and phone numbers. ## Contact Management Core tools for creating, reading, updating, and deleting contacts. ### createContact Create a new contact with name, email, phone, and company information. **Permission:** `contacts:write` **Parameters:** | Name | Type | Required | Description | | -------------- | --------- | -------- | ------------------------------------ | | `firstName` | string | No | The contact's first name | | `lastName` | string | No | The contact's last name | | `name` | string | No | Full display name | | `company` | string | No | Company or organization affiliation | | `jobTitle` | string | No | Job title or role | | `title` | string | No | Honorific or prefix (e.g., Mr, Dr) | | `picture` | string | No | URL to the contact's profile picture | | `notes` | string | No | Internal notes and comments | | `emails` | string\[] | No | Array of email addresses | | `phoneNumbers` | string\[] | No | Array of phone numbers | | `addresses` | object\[] | No | Array of address objects | **Address object:** | Name | Type | Required | Description | | ------------ | ------ | -------- | --------------------- | | `country` | string | Yes | Country | | `city` | string | Yes | City | | `label` | string | No | Label for the address | | `address1` | string | No | Address line 1 | | `address2` | string | No | Address line 2 | | `state` | string | No | State | | `postalCode` | string | No | Postal code | **Returns:** The created contact object with all associated data. *** ### getContact Get details of a specific contact by ID. **Permission:** `contacts:read` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | --------------------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact to retrieve | **Returns:** Contact object with all associated addresses, emails, and phone numbers. *** ### listContacts List contacts in the organization with pagination. **Permission:** `contacts:read` **Parameters:** | Name | Type | Required | Default | Description | | -------- | ------ | -------- | ------- | ----------------------------------------- | | `limit` | number | No | 50 | Number of contacts to return (1-100) | | `offset` | number | No | 0 | Number of contacts to skip for pagination | **Returns:** ```json theme={null} { "contacts": [...], "count": 150, "limit": 50, "offset": 0 } ``` *** ### updateContact Update an existing contact. **Permission:** `contacts:write` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | ------------------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact to update | | `firstName` | string | No | Update the contact's first name | | `lastName` | string | No | Update the contact's last name | | `name` | string | No | Update the full display name | | `company` | string | No | Update the company | | `jobTitle` | string | No | Update the job title | | `title` | string | No | Update the honorific | | `picture` | string | No | Update the profile picture URL | | `notes` | string | No | Update internal notes | **Returns:** The updated contact object. *** ### deleteContact Delete a contact (soft delete). **Permission:** `contacts:delete` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | ------------------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact to delete | **Returns:** The deleted contact object. *** ## Contact Emails Tools for managing email addresses associated with contacts. ### createContactEmail Create a new email address for a contact. **Permission:** `contacts.emails:write` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | -------------------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact | | `email` | string | Yes | The email address | | `label` | string | No | Label (e.g., "work", "personal") | **Returns:** The created contact email object. *** ### getContactEmail Get details of a specific contact email. **Permission:** `contacts.emails:read` **Parameters:** | Name | Type | Required | Description | | --------- | ------------- | -------- | ------------------------------- | | `emailId` | string (UUID) | Yes | The ID of the email to retrieve | **Returns:** Contact email object with all details. *** ### listContactEmails List all email addresses for a specific contact. **Permission:** `contacts.emails:read` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | --------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact | **Returns:** ```json theme={null} { "emails": [...], "count": 3 } ``` *** ### updateContactEmail Update an existing contact email address. **Permission:** `contacts.emails:write` **Parameters:** | Name | Type | Required | Description | | --------- | ------------- | -------- | ----------------------------- | | `emailId` | string (UUID) | Yes | The ID of the email to update | | `email` | string | No | Update the email address | | `label` | string | No | Update the label | **Returns:** The updated contact email object. *** ### deleteContactEmail Delete a contact email address. **Permission:** `contacts.emails:delete` **Parameters:** | Name | Type | Required | Description | | --------- | ------------- | -------- | ----------------------------- | | `emailId` | string (UUID) | Yes | The ID of the email to delete | **Returns:** The deleted contact email object. *** ## Contact Addresses Tools for managing physical addresses associated with contacts. ### createContactAddress Create a new address for a contact. **Permission:** `contacts.addresses:write` **Parameters:** | Name | Type | Required | Description | | ------------ | ------------- | -------- | --------------------- | | `contactId` | string (UUID) | Yes | The ID of the contact | | `country` | string | Yes | Country | | `city` | string | Yes | City | | `label` | string | Yes | Label for the address | | `address1` | string | No | Address line 1 | | `address2` | string | No | Address line 2 | | `state` | string | No | State | | `postalCode` | string | No | Postal code | **Returns:** The created contact address object. *** ### getContactAddress Get details of a specific contact address. **Permission:** `contacts.addresses:read` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | --------------------------------- | | `addressId` | string (UUID) | Yes | The ID of the address to retrieve | **Returns:** Contact address object with all details. *** ### listContactAddresses List all addresses for a specific contact. **Permission:** `contacts.addresses:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | ---------------------------- | | `contactId` | string (UUID) | Yes | - | The ID of the contact | | `limit` | number | No | 10 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "asc" | Sort order ("asc" or "desc") | **Returns:** Array of contact address objects. *** ### updateContactAddress Update an existing contact address. **Permission:** `contacts.addresses:write` **Parameters:** | Name | Type | Required | Description | | ------------ | ------------- | -------- | ------------------------------- | | `addressId` | string (UUID) | Yes | The ID of the address to update | | `country` | string | No | Update the country | | `city` | string | No | Update the city | | `label` | string | No | Update the label | | `address1` | string | No | Update address line 1 | | `address2` | string | No | Update address line 2 | | `state` | string | No | Update the state | | `postalCode` | string | No | Update the postal code | **Returns:** The updated contact address object. *** ### deleteContactAddress Delete a contact address. **Permission:** `contacts.addresses:delete` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | ------------------------------- | | `addressId` | string (UUID) | Yes | The ID of the address to delete | **Returns:** The deleted contact address object. *** ## Contact Phone Numbers Tools for managing phone numbers associated with contacts. ### createContactPhoneNumber Create a new phone number for a contact. **Permission:** `contacts.phoneNumbers:write` **Parameters:** | Name | Type | Required | Description | | ---------------- | ------------- | -------- | ------------------------------ | | `contactId` | string (UUID) | Yes | The ID of the contact | | `phoneNumber` | string | Yes | The phone number | | `countryCode` | string | Yes | Country code | | `nationalNumber` | string | Yes | National number | | `label` | string | Yes | Label (e.g., "mobile", "work") | **Returns:** The created contact phone number object. *** ### getContactPhoneNumber Get details of a specific contact phone number. **Permission:** `contacts.phoneNumbers:read` **Parameters:** | Name | Type | Required | Description | | --------------- | ------------- | -------- | -------------------------------------- | | `phoneNumberId` | string (UUID) | Yes | The ID of the phone number to retrieve | **Returns:** Contact phone number object with all details. *** ### listContactPhoneNumbers List all phone numbers for a specific contact. **Permission:** `contacts.phoneNumbers:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | ---------------------------- | | `contactId` | string (UUID) | Yes | - | The ID of the contact | | `limit` | number | No | 10 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "asc" | Sort order ("asc" or "desc") | **Returns:** Array of contact phone number objects. *** ### updateContactPhoneNumber Update an existing contact phone number. **Permission:** `contacts.phoneNumbers:write` **Parameters:** | Name | Type | Required | Description | | ---------------- | ------------- | -------- | ------------------------------------ | | `phoneNumberId` | string (UUID) | Yes | The ID of the phone number to update | | `phoneNumber` | string | No | Update the phone number | | `countryCode` | string | No | Update the country code | | `nationalNumber` | string | No | Update the national number | | `label` | string | No | Update the label | **Returns:** The updated contact phone number object. *** ### deleteContactPhoneNumber Delete a contact phone number. **Permission:** `contacts.phoneNumbers:delete` **Parameters:** | Name | Type | Required | Description | | --------------- | ------------- | -------- | ------------------------------------ | | `phoneNumberId` | string (UUID) | Yes | The ID of the phone number to delete | **Returns:** The deleted contact phone number object. *** ## Next Steps Manage messages and threads Learn how MCP clients authenticate to the server # Customer Tools Source: https://docs.shingleai.com/mcp-server/tools/customers Manage customers and their financial transactions The ShingleAI MCP server provides 10 tools for managing customers and their transactions. These tools are organized into two categories: customers and customer transactions. ## Customers Core tools for creating, reading, updating, and deleting customer records. ### createCustomer Create a new customer record with business association and contact information. **Permission:** `customers:write` **Parameters:** | Name | Type | Required | Description | | --------------- | --------------------- | -------- | ------------------------------------------------------ | | `businessId` | string (UUID) | Yes | The ID of the business this customer belongs to | | `type` | string | Yes | Customer type (e.g., individual, business, enterprise) | | `contactId` | string (UUID) \| null | No | Optional reference to an existing contact record | | `name` | string \| null | No | Customer display name | | `email` | string \| null | No | Primary email address | | `phone` | string \| null | No | Primary phone number | | `notes` | string \| null | No | Internal notes and comments about the customer | | `status` | string \| null | No | Customer status (e.g., active, inactive, pending) | | `customerSince` | string \| null | No | Date when the customer relationship began (ISO 8601) | **Returns:** The created customer object. *** ### getCustomer Get a specific customer by ID. **Permission:** `customers:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ---------------------------------- | | `id` | string (UUID) | Yes | The ID of the customer to retrieve | **Returns:** Customer object, or `null` if not found. *** ### listCustomers List all customers for the organization with pagination. **Permission:** `customers:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Number of customers to return (1-100) | | `offset` | number | No | 0 | Number of customers to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "customers": [...], "count": 10, "limit": 10, "offset": 0 } ``` *** ### updateCustomer Update an existing customer record. **Permission:** `customers:write` **Parameters:** | Name | Type | Required | Description | | --------------- | --------------------- | -------- | ------------------------------------------------------ | | `id` | string (UUID) | Yes | The ID of the customer to update | | `businessId` | string (UUID) | No | The ID of the business this customer belongs to | | `contactId` | string (UUID) \| null | No | Reference to an existing contact record | | `type` | string | No | Customer type (e.g., individual, business, enterprise) | | `name` | string \| null | No | Customer display name | | `email` | string \| null | No | Primary email address | | `phone` | string \| null | No | Primary phone number | | `notes` | string \| null | No | Internal notes and comments about the customer | | `status` | string \| null | No | Customer status (e.g., active, inactive, pending) | | `customerSince` | string \| null | No | Date when the customer relationship began (ISO 8601) | **Returns:** The updated customer object. *** ### deleteCustomer Delete a customer (soft delete). **Permission:** `customers:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | -------------------------------- | | `id` | string (UUID) | Yes | The ID of the customer to delete | **Returns:** The deleted customer object. *** ## Customer Transactions Tools for recording and managing financial transactions associated with customers. ### createCustomerTransaction Create a new customer transaction to record a financial activity. **Permission:** `customers.transactions:write` **Parameters:** | Name | Type | Required | Description | | ----------------- | -------------- | -------- | ------------------------------------------------------------- | | `customerId` | string (UUID) | Yes | UUID of the customer this transaction belongs to | | `businessId` | string (UUID) | Yes | UUID of the business associated with the transaction | | `amount` | string | Yes | Transaction amount as a string (to handle decimal precision) | | `currency` | string | Yes | Currency code (e.g., USD, EUR) | | `status` | string | Yes | Transaction status (e.g., pending, completed, failed) | | `type` | string | Yes | Transaction type (e.g., purchase, refund, subscription) | | `description` | string \| null | No | Optional description of the transaction | | `transactionDate` | string \| null | No | Optional date when the transaction occurred (ISO 8601 format) | **Returns:** The created customer transaction object. *** ### getCustomerTransaction Get a specific customer transaction by its ID. **Permission:** `customers.transactions:read` **Parameters:** | Name | Type | Required | Description | | --------------- | ------------- | -------- | -------------------------------------------- | | `transactionId` | string (UUID) | Yes | UUID of the customer transaction to retrieve | **Returns:** Customer transaction object, or `null` if not found. *** ### listCustomerTransactions List all transactions for a specific customer with pagination support. **Permission:** `customers.transactions:read` **Parameters:** | Name | Type | Required | Default | Description | | ------------ | ------------- | -------- | ------- | --------------------------------------------------- | | `customerId` | string (UUID) | Yes | - | UUID of the customer whose transactions to retrieve | | `limit` | number | No | 10 | Maximum number of items to return (1-100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "transactions": [...], "count": 25, "limit": 10, "offset": 0 } ``` *** ### updateCustomerTransaction Update an existing customer transaction - all fields are optional except `transactionId`. **Permission:** `customers.transactions:write` **Parameters:** | Name | Type | Required | Description | | ----------------- | -------------- | -------- | ----------------------------------------------------------------------- | | `transactionId` | string (UUID) | Yes | UUID of the customer transaction to update | | `businessId` | string (UUID) | No | Update the business associated with the transaction | | `amount` | string | No | Update the transaction amount as a string (to handle decimal precision) | | `currency` | string | No | Update the currency code (e.g., USD, EUR) | | `status` | string | No | Update the transaction status (e.g., pending, completed, failed) | | `type` | string | No | Update the transaction type (e.g., purchase, refund, subscription) | | `description` | string \| null | No | Update the description of the transaction | | `transactionDate` | string \| null | No | Update the date when the transaction occurred (ISO 8601 format) | **Returns:** The updated customer transaction object. *** ### deleteCustomerTransaction Delete a customer transaction (soft delete). **Permission:** `customers.transactions:delete` **Parameters:** | Name | Type | Required | Description | | --------------- | ------------- | -------- | ------------------------------------------ | | `transactionId` | string (UUID) | Yes | UUID of the customer transaction to delete | **Returns:** The deleted customer transaction object. *** ## Next Steps Manage contacts that may be linked to customers Learn how MCP clients authenticate to the server # Domain Tools Source: https://docs.shingleai.com/mcp-server/tools/domains Manage domains, WHOIS contacts, and domain registrations The ShingleAI MCP server provides 15 tools for managing domains and their associated registration data. These tools are organized into three categories: domains, domain contacts, and domain registrations. Domain Contacts on this page are the registrant, admin, and tech contacts attached to a domain registration (WHOIS data). They are distinct from CRM Contacts (people in your address book) — see [Contact Tools](/mcp-server/tools/contacts) for those. ## Domains Tools for managing domain records used for DNS and email. ### createDomain Create a new domain record for DNS and email management. **Permission:** `domains:write` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | --------------------- | -------- | --------- | ----------------------------------------------- | | `domain` | string | Yes | - | The domain name (e.g., example.com) | | `status` | string | No | "pending" | Domain status (e.g., active, pending, inactive) | | `zoneId` | string \| null | No | - | Optional DNS zone ID for the domain | | `createdBy` | string (UUID) \| null | No | - | Optional user ID who created the domain | Verification, registrar, and Resend-related fields are managed by the platform — do not pass them in here, as they are overwritten or ignored. **Returns:** The created domain object. *** ### getDomain Get a specific domain by ID. **Permission:** `domains:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | -------------------------------- | | `id` | string (UUID) | Yes | The ID of the domain to retrieve | **Returns:** Domain object, or `null` if not found. *** ### listDomains List all domains for the organization with pagination. **Permission:** `domains:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Maximum number of items to return (max: 100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "domains": [...], "count": 12, "limit": 10, "offset": 0 } ``` *** ### updateDomain Update an existing domain record. **Permission:** `domains:write` **Parameters:** | Name | Type | Required | Description | | ----------- | --------------------- | -------- | ----------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the domain to update | | `domain` | string | No | The domain name (e.g., example.com) | | `status` | string | No | Domain status (e.g., active, pending, inactive) | | `zoneId` | string \| null | No | DNS zone ID for the domain | | `createdBy` | string (UUID) \| null | No | User ID who created the domain | **Returns:** The updated domain object. *** ### deleteDomain Delete a domain (soft delete). **Permission:** `domains:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ------------------------------ | | `id` | string (UUID) | Yes | The ID of the domain to delete | **Returns:** The deleted domain object. *** ## Domain Contacts Tools for managing the registrant, admin, and tech contacts attached to a domain registration. These are WHOIS-style contacts at the domain registrar — not CRM contacts. ### createDomainContact Create a new domain contact for domain registration and administrative purposes. **Permission:** `domain-contacts:write` **Parameters:** | Name | Type | Required | Description | | ------------------ | --------------------- | -------- | -------------------------------------------------------- | | `externalId` | string | Yes | External ID from the domain registrar | | `accountId` | string | Yes | Account ID at the domain registrar | | `label` | string \| null | No | Optional label for the contact (e.g., "Primary Contact") | | `firstName` | string | Yes | First name of the contact | | `lastName` | string | Yes | Last name of the contact | | `organizationName` | string \| null | No | Optional organization/company name | | `jobTitle` | string \| null | No | Optional job title of the contact | | `address1` | string \| null | No | Primary address line | | `address2` | string \| null | No | Secondary address line | | `city` | string \| null | No | City | | `stateProvince` | string \| null | No | State or province | | `postalCode` | string \| null | No | Postal/ZIP code | | `country` | string \| null | No | Country code (e.g., US, CA) | | `email` | string | Yes | Contact email address | | `phone` | string | Yes | Contact phone number | | `createdBy` | string (UUID) \| null | No | Optional user ID who created the contact | **Returns:** The created domain contact object. *** ### getDomainContact Get a specific domain contact by ID. **Permission:** `domain-contacts:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ---------------------------------------- | | `id` | string (UUID) | Yes | The ID of the domain contact to retrieve | **Returns:** Domain contact object, or `null` if not found. *** ### listDomainContacts List all domain contacts for the organization with pagination. **Permission:** `domain-contacts:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Maximum number of items to return (max: 100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "domainContacts": [...], "count": 8, "limit": 10, "offset": 0 } ``` *** ### updateDomainContact Update an existing domain contact record. **Permission:** `domain-contacts:write` **Parameters:** | Name | Type | Required | Description | | ------------------ | --------------------- | -------- | ----------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the domain contact to update | | `externalId` | string | No | External ID from the domain registrar | | `accountId` | string | No | Account ID at the domain registrar | | `label` | string \| null | No | Label for the contact (e.g., "Primary Contact") | | `firstName` | string | No | First name of the contact | | `lastName` | string | No | Last name of the contact | | `organizationName` | string \| null | No | Organization/company name | | `jobTitle` | string \| null | No | Job title of the contact | | `address1` | string \| null | No | Primary address line | | `address2` | string \| null | No | Secondary address line | | `city` | string \| null | No | City | | `stateProvince` | string \| null | No | State or province | | `postalCode` | string \| null | No | Postal/ZIP code | | `country` | string \| null | No | Country code (e.g., US, CA) | | `email` | string | No | Contact email address | | `phone` | string | No | Contact phone number | | `createdBy` | string (UUID) \| null | No | User ID who created the contact | **Returns:** The updated domain contact object. *** ### deleteDomainContact Delete a domain contact (soft delete). **Permission:** `domain-contacts:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | -------------------------------------- | | `id` | string (UUID) | Yes | The ID of the domain contact to delete | **Returns:** The deleted domain contact object. *** ## Domain Registrations Tools for managing domain registration records that track ownership, renewal, and registrar metadata. ### createDomainRegistration Create a new domain registration record to track domain ownership and renewal. **Permission:** `domain-registrations:write` **Parameters:** | Name | Type | Required | Description | | ------------------ | --------------------- | -------- | ------------------------------------------------------- | | `state` | string | Yes | Registration state (e.g., registered, pending, expired) | | `externalDomainId` | string | Yes | External domain ID from the registrar | | `externalId` | string | Yes | External registration ID from the registrar | | `autoRenew` | boolean | Yes | Whether auto-renewal is enabled | | `whoisPrivacy` | boolean | Yes | Whether WHOIS privacy is enabled | | `transferLock` | boolean | Yes | Whether domain transfer lock is enabled | | `period` | number | Yes | Registration period in years | | `domainId` | string (UUID) \| null | No | Optional reference to the related domain record | | `createdBy` | string (UUID) \| null | No | Optional user ID who created the registration | **Returns:** The created domain registration object. *** ### getDomainRegistration Get a specific domain registration by ID. **Permission:** `domain-registrations:read` **Parameters:** | Name | Type | Required | Description | | ---------------- | ------------- | -------- | --------------------------------------------- | | `registrationId` | string (UUID) | Yes | The ID of the domain registration to retrieve | **Returns:** Domain registration object, or `null` if not found. *** ### listDomainRegistrations List all domain registrations for the organization with pagination. **Permission:** `domain-registrations:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Maximum number of items to return (max: 100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "domainRegistrations": [...], "count": 5, "limit": 10, "offset": 0 } ``` *** ### updateDomainRegistration Update an existing domain registration record - all fields are optional except registrationId. **Permission:** `domain-registrations:write` **Parameters:** | Name | Type | Required | Description | | ------------------ | --------------------- | -------- | ------------------------------------------------------------------ | | `registrationId` | string (UUID) | Yes | The ID of the domain registration to update | | `state` | string | No | Update the registration state (e.g., registered, pending, expired) | | `externalDomainId` | string | No | Update the external domain ID from the registrar | | `externalId` | string | No | Update the external registration ID from the registrar | | `autoRenew` | boolean | No | Update whether auto-renewal is enabled | | `whoisPrivacy` | boolean | No | Update whether WHOIS privacy is enabled | | `transferLock` | boolean | No | Update whether domain transfer lock is enabled | | `period` | number | No | Update the registration period in years | | `createdBy` | string (UUID) \| null | No | Update the user ID who created the registration | **Returns:** The updated domain registration object. *** ### deleteDomainRegistration Delete a domain registration (soft delete). **Permission:** `domain-registrations:delete` **Parameters:** | Name | Type | Required | Description | | ---------------- | ------------- | -------- | ------------------------------------------- | | `registrationId` | string (UUID) | Yes | The ID of the domain registration to delete | **Returns:** The deleted domain registration object. *** ## Next Steps Manage CRM contacts, distinct from the WHOIS-style domain contacts above Learn how MCP clients authenticate to the server # Email Address Tools Source: https://docs.shingleai.com/mcp-server/tools/email-addresses Inspect organization email addresses available for sending and receiving The ShingleAI MCP server provides 2 tools for inspecting the email addresses connected to your organization. Use these tools to discover which addresses are available for sending templated emails or to look up a specific address by ID. ## getEmailAddress Get details of a specific email address by ID. **Permission:** `email-addresses:read` **Parameters:** | Name | Type | Required | Description | | ---------------- | ------------- | -------- | --------------------------------------- | | `emailAddressId` | string (UUID) | Yes | The ID of the email address to retrieve | **Returns:** The email address object, or `null` if not found. *** ## listEmailAddresses List email addresses for the organization with optional filtering. **Permission:** `email-addresses:read` **Parameters:** | Name | Type | Required | Default | Description | | ---------- | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------- | | `limit` | number | No | 100 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | | `provider` | string | No | - | Filter by email provider. Valid values: `google`, `microsoft`, `shingleai`, `apple` | | `status` | string | No | - | Filter by email address status. Valid values: `pending`, `active`, `disabled`, `errored`, `deleted` | **Returns:** ```json theme={null} { "emailAddresses": [...], "count": 12, "limit": 100, "offset": 0 } ``` *** ## Next Steps Create, render, and send templated emails Learn how MCP clients authenticate to the server # Email Template Tools Source: https://docs.shingleai.com/mcp-server/tools/email-templates Create, render, and send Mustache-based email templates The ShingleAI MCP server provides 7 tools for managing email templates and using them to send templated emails. These tools are organized into two categories: templates and render & send. ## Templates CRUD tools for managing reusable email templates. Templates support Mustache syntax for dynamic content in both subject lines and bodies. ### createEmailTemplate Create a new email template with name (max 200 chars), subject (max 1000 chars), body (max 50000 chars), and optional variables. Templates support Mustache syntax for dynamic content. **Permission:** `emailTemplates:write` **Parameters:** | Name | Type | Required | Description | | ------------- | --------- | -------- | ----------------------------------------------------------------------------------------- | | `name` | string | Yes | The name of the email template (1-200 characters) | | `subject` | string | Yes | The subject line of the email template (1-1000 characters). Supports Mustache variables. | | `body` | string | Yes | The body content of the email template (1-50000 characters). Supports Mustache variables. | | `description` | string | No | Optional description of the email template (max 2000 characters) | | `variables` | string\[] | No | Optional list of variable names used in the template for documentation | **Returns:** The created email template object. *** ### getEmailTemplate Get a specific email template by ID, including all template details. **Permission:** `emailTemplates:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ---------------------------------------- | | `id` | string (UUID) | Yes | The ID of the email template to retrieve | **Returns:** The email template object, or `null` if not found. *** ### listEmailTemplates List email templates for the organization with pagination. Supports filtering by status and name. **Permission:** `emailTemplates:read` **Parameters:** | Name | Type | Required | Default | Description | | -------- | ------ | -------- | ------- | ------------------------------------------------------------------- | | `limit` | number | No | 10 | Number of email templates to return (1-100) | | `offset` | number | No | 0 | Number of email templates to skip for pagination | | `status` | string | No | - | Filter by template status (`active` or `archived`) | | `name` | string | No | - | Filter by name (case-insensitive partial match, max 200 characters) | **Returns:** ```json theme={null} { "emailTemplates": [...], "count": 8, "limit": 10, "offset": 0 } ``` *** ### updateEmailTemplate Update an existing email template with new values for any template fields. Name max 200 chars, subject max 1000 chars, body max 50000 chars. **Permission:** `emailTemplates:write` **Parameters:** | Name | Type | Required | Description | | ------------- | ----------------- | -------- | ------------------------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the email template to update | | `name` | string | No | The name of the email template (1-200 characters) | | `description` | string \| null | No | Description of the email template (max 2000 characters) | | `subject` | string | No | The subject line of the email template (1-1000 characters) | | `body` | string | No | The body content of the email template (1-50000 characters) | | `variables` | string\[] \| null | No | List of variable names used in the template for documentation | | `status` | string | No | Template status (`active` or `archived`) | **Returns:** The updated email template object. *** ### deleteEmailTemplate Delete an email template (soft delete). **Permission:** `emailTemplates:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | -------------------------------------- | | `id` | string (UUID) | Yes | The ID of the email template to delete | **Returns:** The deleted email template object. *** ## Render & Send Tools for rendering templates with variable data and dispatching templated emails through the organization's email pipeline. ### renderEmailTemplate Render an email template by ID with provided data variables using Mustache templating. Returns the rendered subject and body. **Permission:** `emailTemplates:read` **Parameters:** | Name | Type | Required | Description | | ------------ | ------------------------ | -------- | ------------------------------------------------------------ | | `templateId` | string (UUID) | Yes | The ID of the email template to render | | `data` | Record\ | Yes | Key-value pairs of variable data to render into the template | **Returns:** Object with `subject` and `body` strings containing the rendered content. *** ### sendTemplatedEmail Render an email template with data and send it. Fetches the template, renders subject and body with the provided data, and sends the email from the specified email address. **Permission:** `emailTemplates:write` **Parameters:** | Name | Type | Required | Description | | -------------------- | ------------------------ | -------- | ------------------------------------------------- | | `templateId` | string (UUID) | Yes | The ID of the email template to use | | `data` | Record\ | Yes | Template variable data for rendering | | `to` | string\[] | Yes | Array of recipient email addresses (at least one) | | `fromEmailAddressId` | string (UUID) | Yes | The ID of the email address to send from | | `cc` | string\[] | No | Array of CC email addresses | | `bcc` | string\[] | No | Array of BCC email addresses | | `replyTo` | string | No | Reply-to email address | **Returns:** Object with `subject`, `to`, `from`, `rendered`, and `sent` fields summarizing the send result. *** ## Next Steps Discover which email addresses are available to send from Learn how MCP clients authenticate to the server # File Tools Source: https://docs.shingleai.com/mcp-server/tools/files Upload, download, search, and organize files in organization storage The ShingleAI MCP server provides 7 tools for managing files and folders in organization storage. These tools are organized into two categories: files and folders. ## Files Tools for uploading, downloading, listing, searching, and deleting files. File content is exchanged as base64-encoded strings to support the MCP protocol. ### uploadFile Upload a file to organization storage with base64-encoded content. **Permission:** `files:write` **Parameters:** | Name | Type | Required | Description | | ------------- | --------------------- | -------- | ------------------------------------------------------------ | | `filename` | string | Yes | Name of the file (1-255 characters) | | `content` | string | Yes | Base64-encoded file content (max 10MB file size) | | `contentType` | string | Yes | MIME type of the file (e.g., `application/pdf`, `image/png`) | | `folderId` | string (UUID) \| null | No | Optional folder ID to place the file in | | `description` | string | No | Optional description of the file (max 5000 characters) | | `tags` | string\[] | No | Optional tags for the file (max 10) | **Returns:** Object with `success` boolean and a `file` object containing `id`, `filename`, `size`, `contentType`, and `folderId`. *** ### downloadFile Download a file from organization storage as base64-encoded content. **Permission:** `files:read` **Parameters:** | Name | Type | Required | Description | | -------- | ------------- | -------- | ------------------------------ | | `fileId` | string (UUID) | Yes | The ID of the file to download | **Returns:** Object with a `file` metadata object (`id`, `filename`, `contentType`, `size`) and a `content` string containing base64-encoded file bytes. Downloads are gated by each file's `agentAccessEnabled` flag. Files with agent access disabled return an error. *** ### listFiles List files in organization storage with optional folder filtering and pagination. **Permission:** `files:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | --------------------- | -------- | ------- | --------------------------------------------------------------- | | `folderId` | string (UUID) \| null | No | - | Filter by folder ID (`null` for root level, omit for all files) | | `limit` | number | No | 10 | Number of files to return (1-100) | | `offset` | number | No | 0 | Pagination offset | | `sortOrder` | string | No | "desc" | Sort order by creation date (`asc` or `desc`) | **Returns:** ```json theme={null} { "files": [...], "count": 23, "limit": 10, "offset": 0 } ``` *** ### searchFiles Search files by filename, description, or tags using full-text search. **Permission:** `files:read` **Parameters:** | Name | Type | Required | Default | Description | | -------- | ------ | -------- | ------- | -------------------------------------------------------------------------------- | | `query` | string | Yes | - | Search query to match against filename, description, and tags (1-255 characters) | | `limit` | number | No | 10 | Number of results to return (1-100) | | `offset` | number | No | 0 | Pagination offset | **Returns:** ```json theme={null} { "files": [...], "count": 5, "query": "invoice", "limit": 10, "offset": 0 } ``` *** ### deleteFile Delete a file from organization storage (soft delete). **Permission:** `files:delete` **Parameters:** | Name | Type | Required | Description | | -------- | ------------- | -------- | ---------------------------- | | `fileId` | string (UUID) | Yes | The ID of the file to delete | **Returns:** Object with `success` boolean, the deleted `file` object, and a `message` string. *** ## Folders Tools for organizing files into a folder hierarchy. Folders can be nested up to 5 levels deep. ### createFolder Create a new folder in organization storage with optional parent folder (max 5 levels deep). **Permission:** `folders:write` **Parameters:** | Name | Type | Required | Description | | ---------------- | --------------------- | -------- | ------------------------------------------------- | | `name` | string | Yes | Name of the folder (1-255 characters) | | `parentFolderId` | string (UUID) \| null | No | Optional parent folder ID (`null` for root level) | **Returns:** The created folder object. *** ### listFolders List folders in organization storage with optional parent folder filtering and pagination. **Permission:** `folders:read` **Parameters:** | Name | Type | Required | Default | Description | | ---------------- | --------------------- | -------- | ------- | ------------------------------------------------------------------------ | | `parentFolderId` | string (UUID) \| null | No | - | Filter by parent folder ID (`null` for root level, omit for all folders) | | `limit` | number | No | 10 | Number of folders to return (1-100) | | `offset` | number | No | 0 | Pagination offset | | `sortOrder` | string | No | "desc" | Sort order by creation date (`asc` or `desc`) | **Returns:** ```json theme={null} { "folders": [...], "count": 6, "limit": 10, "offset": 0 } ``` *** ## Next Steps Manage contacts and their associated data Learn how MCP clients authenticate to the server # Tools Overview Source: https://docs.shingleai.com/mcp-server/tools/index Available tools in the ShingleAI MCP Server The ShingleAI MCP server provides tools for managing your business communications and contacts. Tools are organized by resource type and require appropriate [permissions](/mcp-server/authentication) to access. ## Available Tool Categories The MCP server exposes 106 tools across 11 resource categories. Each category has a dedicated reference page listing every tool, its parameters, permission, and return shape. | Category | Tools | Description | | ---------------------------------------------------- | ----- | ------------------------------------------------------------ | | [Automations](/mcp-server/tools/automations) | 7 | Create, update, and inspect automations and their executions | | [Businesses](/mcp-server/tools/businesses) | 20 | Business profile, offerings, and online/physical presences | | [Contacts](/mcp-server/tools/contacts) | 20 | Contacts and their emails, phones, and addresses | | [Customers](/mcp-server/tools/customers) | 10 | Customer records and customer transactions | | [Domains](/mcp-server/tools/domains) | 15 | Domains, domain contacts, and domain registrations | | [Email Addresses](/mcp-server/tools/email-addresses) | 2 | List and read connected email addresses | | [Email Templates](/mcp-server/tools/email-templates) | 7 | Manage templates, render previews, and send templated email | | [Files](/mcp-server/tools/files) | 7 | Upload, download, search, and delete files; manage folders | | [Messages](/mcp-server/tools/messages) | 6 | Read messages, threads, and attachments; update status | | [Phone Numbers](/mcp-server/tools/phone-numbers) | 2 | List and read connected phone numbers | | [Tasks](/mcp-server/tools/tasks) | 10 | Task CRUD, search, and assignee management | ## Permission Model Each tool requires specific permissions to execute. Permissions follow the pattern `resource:action` (e.g., `contacts:read`) or `resource.subresource:action` for nested resources (e.g., `contacts.emails:write`). **Permission levels:** | Action | Description | | -------- | --------------------------- | | `read` | View and list resources | | `write` | Create and update resources | | `delete` | Remove resources | **Examples:** * `contacts:read` - List and view contacts * `contacts:write` - Create and update contacts * `contacts.emails:write` - Add or update contact email addresses * `messages:read` - View and search messages You grant these permissions on the MCP server's consent screen during the OAuth handshake. The set of tools advertised over `tools/list` is filtered against the categories you approve. See [Authentication](/mcp-server/authentication) for the full flow. ## Common Starting Points 20 tools for managing contacts, emails, addresses, and phone numbers 6 tools for accessing messages, threads, and attachments 10 tools for managing tasks and assignees 7 tools for uploading, downloading, and organizing files ## Next Steps Learn how MCP clients authenticate to the server Connect to AI tools like Claude, Cursor, and Windsurf # Message Tools Source: https://docs.shingleai.com/mcp-server/tools/messages Access and manage messages, threads, and attachments The ShingleAI MCP server provides 7 tools for accessing and managing messages. These tools allow you to retrieve messages, search content, manage message status, and view conversation threads. ## getMessage Get detailed information about a specific message by its ID, including all message type-specific fields (email headers, SMS encoding, WhatsApp media, etc.). **Permission:** `messages:read` **Parameters:** | Name | Type | Required | Description | | ----------- | ------------- | -------- | ----------------------------- | | `messageId` | string (UUID) | Yes | ID of the message to retrieve | **Returns:** Message object with all type-specific fields. *** ## listMessages List messages in the organization with optional filtering. **Permission:** `messages:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | ------------------------------------------------------ | | `limit` | number | No | 10 | Maximum number of messages to return (1-100) | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | | `direction` | string | No | - | Filter by message direction ("incoming" or "outgoing") | **Returns:** Array of message objects. *** ## updateMessageStatus Update the status of a message - mark as read/unread, archive/unarchive, or snooze/unsnooze. **Permission:** `messages:write` **Parameters:** | Name | Type | Required | Description | | -------------- | -------------- | -------- | --------------------------------------------------------- | | `messageId` | string (UUID) | Yes | ID of the message to update | | `readAt` | string \| null | No | ISO datetime to mark as read, or `null` to mark as unread | | `archivedAt` | string \| null | No | ISO datetime to archive, or `null` to unarchive | | `snoozedUntil` | string \| null | No | ISO datetime to snooze until, or `null` to unsnooze | **Returns:** The updated message object. This tool only allows updating status fields for security reasons. To modify message content, use the appropriate channel-specific tools. *** ## getMessagesByContact Get all messages sent to or received from a specific contact. Useful for viewing the complete communication history with a contact. **Permission:** `messages:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | ------------------------------------------------------------------------ | | `contactId` | string (UUID) | Yes | - | Contact ID to retrieve messages for | | `limit` | number | No | 20 | Maximum number of messages to return (1-100) | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | | `direction` | string | No | - | Filter by direction ("incoming" = from contact, "outgoing" = to contact) | **Returns:** Array of message objects from/to the specified contact. *** ## getMessageThread Get all messages that belong to the same conversation thread. Useful for viewing the complete conversation history. **Permission:** `messages:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | ------------------------------------------------------------------------------ | | `threadId` | string | Yes | - | Thread ID to retrieve messages for | | `limit` | number | No | 50 | Maximum number of messages to return (1-100) | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "asc" | Sort order ("asc" = oldest first for conversation flow, "desc" = newest first) | | `direction` | string | No | - | Filter by message direction ("incoming" or "outgoing") | **Returns:** Array of message objects in the thread. *** ## listMessageAttachments List all file attachments associated with a specific message, including details like filename, size, content type, and URL. **Permission:** `messages:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | --------------------------------------------- | | `messageId` | string (UUID) | Yes | - | ID of the message | | `limit` | number | No | 20 | Maximum number of attachments to return | | `offset` | number | No | 0 | Offset for pagination | | `sortOrder` | string | No | "asc" | Sort order by creation date ("asc" or "desc") | **Returns:** Array of attachment objects with metadata (filename, size, content type, URL). *** ## Next Steps Manage contacts and their data Learn how MCP clients authenticate to the server # Phone Number Tools Source: https://docs.shingleai.com/mcp-server/tools/phone-numbers Inspect organization phone numbers used for SMS and voice channels The ShingleAI MCP server provides 2 tools for inspecting the phone numbers connected to your organization. Use these tools to discover which numbers are available or to look up a specific number by ID. ## getPhoneNumber Get details of a specific phone number by ID. **Permission:** `phone-numbers:read` **Parameters:** | Name | Type | Required | Description | | --------------- | ------------- | -------- | -------------------------------------- | | `phoneNumberId` | string (UUID) | Yes | The ID of the phone number to retrieve | **Returns:** The phone number object, or `null` if not found. *** ## listPhoneNumbers List phone numbers for the organization with optional filtering. **Permission:** `phone-numbers:read` **Parameters:** | Name | Type | Required | Default | Description | | ---------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------- | | `limit` | number | No | 100 | Maximum number of results | | `offset` | number | No | 0 | Offset for pagination | | `provider` | string | No | - | Filter by phone provider. Valid values: `telnyx`, `twilio` | | `status` | string | No | - | Filter by phone number status. Valid values: `pending`, `active`, `disabled`, `errored`, `deleted` | **Returns:** ```json theme={null} { "phoneNumbers": [...], "count": 4, "limit": 100, "offset": 0 } ``` *** ## Next Steps Inspect email addresses available for sending Learn how MCP clients authenticate to the server # Task Tools Source: https://docs.shingleai.com/mcp-server/tools/tasks Manage tasks, search them, and assign them to users The ShingleAI MCP server provides 10 tools for managing tasks and their assignees. These tools are organized into two categories: tasks and assignees. ## Tasks Core tools for creating, reading, updating, deleting, and searching tasks. ### createTask Create a new task with title (max 500 chars), description (max 10,000 chars), priority settings, and optional metadata. Tasks can be categorized and assigned due dates. **Permission:** `tasks:write` **Parameters:** | Name | Type | Required | Default | Description | | ------------- | ---------------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | | `title` | string | Yes | - | The title of the task (1-500 characters) | | `description` | string | Yes | - | Detailed description of the task and what needs to be done | | `status` | string | No | "todo" | Current status of the task. Valid values: `backlog`, `todo`, `in_progress`, `in_review`, `done`, `cancelled` | | `category` | string \| null | No | - | Task category. Valid values: `bug_fix`, `feature_request`, `documentation`, `meeting`, `planning`, `research`, `review`, `other` | | `importance` | string \| null | No | - | How important this task is. Valid values: `low`, `medium`, `high` | | `urgency` | string \| null | No | - | How urgent this task is. Valid values: `low`, `medium`, `high` | | `dueDate` | string \| null | No | - | Due date for the task (ISO 8601 datetime with offset) | | `messageId` | string (UUID) \| null | No | - | Optional reference to a related message | | `contactId` | string (UUID) \| null | No | - | Optional reference to a related contact | | `metadata` | Record\ \| null | No | - | Additional structured metadata for the task | **Returns:** The created task object. *** ### getTask Get a specific task by ID, including all task details and assignees. **Permission:** `tasks:read` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ------------------------------ | | `id` | string (UUID) | Yes | The ID of the task to retrieve | **Returns:** Full task object with assignees, or `null` if not found. *** ### listTasks List all tasks for the organization with pagination, including assignee details. **Permission:** `tasks:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | --------------------------------------------- | | `limit` | number | No | 10 | Number of tasks to return (1-100) | | `offset` | number | No | 0 | Number of tasks to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "tasks": [...], "count": 42, "limit": 10, "offset": 0 } ``` *** ### updateTask Update an existing task with new values for any task fields. Title max 500 chars, description max 10,000 chars. **Permission:** `tasks:write` **Parameters:** | Name | Type | Required | Description | | ------------- | ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `id` | string (UUID) | Yes | The ID of the task to update | | `title` | string | No | The title of the task (1-500 characters) | | `description` | string | No | Detailed description of the task and what needs to be done | | `category` | string \| null | No | Task category. Valid values: `bug_fix`, `feature_request`, `documentation`, `meeting`, `planning`, `research`, `review`, `other` | | `importance` | string \| null | No | How important this task is. Valid values: `low`, `medium`, `high` | | `urgency` | string \| null | No | How urgent this task is. Valid values: `low`, `medium`, `high` | | `status` | string | No | Current status of the task. Valid values: `backlog`, `todo`, `in_progress`, `in_review`, `done`, `cancelled` | | `dueDate` | string \| null | No | Due date for the task (ISO 8601 datetime with offset) | | `messageId` | string (UUID) \| null | No | Reference to a related message | | `contactId` | string (UUID) \| null | No | Reference to a related contact | | `metadata` | Record\ \| null | No | Additional structured metadata for the task | **Returns:** The updated task object. *** ### deleteTask Delete a task (soft delete). **Permission:** `tasks:delete` **Parameters:** | Name | Type | Required | Description | | ---- | ------------- | -------- | ---------------------------- | | `id` | string (UUID) | Yes | The ID of the task to delete | **Returns:** The deleted task object. *** ### searchTasks Search for tasks using PostgreSQL full-text search across title, description, and metadata. Supports automatic word stemming, phrase matching, and relevance ranking. Results are sorted by relevance (most relevant first). **Permission:** `tasks:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | string | Yes | - | Search query to find tasks using full-text search. Searches across title, description, and metadata. Supports automatic word stemming (e.g., "running" matches "run") and phrase matching (max 255 characters) | | `limit` | number | No | 10 | Maximum number of results to return (1-50) | | `offset` | number | No | 0 | Number of tasks to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by relevance rank ("desc" = most relevant first, "asc" = least relevant first) | **Returns:** Array of full task objects ordered by relevance. *** ## Assignees Tools for assigning users to tasks and listing assignment relationships. ### assignTask Assign a user to a task. **Permission:** `tasks:write` **Parameters:** | Name | Type | Required | Description | | -------- | ------------- | -------- | ---------------------------------------- | | `taskId` | string (UUID) | Yes | The ID of the task to assign | | `userId` | string (UUID) | Yes | The ID of the user to assign to the task | **Returns:** The created task assignee object. *** ### unassignTask Remove a user assignment from a task. **Permission:** `tasks:write` **Parameters:** | Name | Type | Required | Description | | -------- | ------------- | -------- | -------------------------------------------- | | `taskId` | string (UUID) | Yes | The ID of the task to unassign from | | `userId` | string (UUID) | Yes | The ID of the user to unassign from the task | **Returns:** The removed task assignee object. *** ### listTaskAssignees Get all users assigned to a specific task. **Permission:** `tasks:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | --------------------------------------------- | | `taskId` | string (UUID) | Yes | - | The ID of the task to get assignees for | | `limit` | number | No | 10 | Maximum number of items to return (1-100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "assignees": [...], "count": 3, "limit": 10, "offset": 0 } ``` *** ### listUserTasks Get all tasks assigned to a specific user. **Permission:** `tasks:read` **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ------------- | -------- | ------- | ---------------------------------------------- | | `userId` | string (UUID) | Yes | - | The ID of the user to get task assignments for | | `limit` | number | No | 10 | Maximum number of items to return (1-100) | | `offset` | number | No | 0 | Number of items to skip for pagination | | `sortOrder` | string | No | "desc" | Sort order by creation date ("asc" or "desc") | **Returns:** ```json theme={null} { "assignments": [...], "count": 8, "limit": 10, "offset": 0 } ``` *** ## Next Steps Build automations that create or update tasks in response to events Learn how MCP clients authenticate to the server # Agent Conversations Source: https://docs.shingleai.com/user-guide/agent-conversations/index Browse past agent chats, filter by status, and resume any conversation Beta Every chat with an agent is saved. The **Agent Conversations** page lists every conversation across every agent in your organization — with filters for status and pagination for large histories. Agent conversations list ## The list view Columns typically include: * **Title** — auto-generated from the first message; editable on the detail page * **Agent** — which agent handled the conversation * **Status** — current state * **Last updated** — when the most recent message landed ### Status values | Status | Meaning | | ----------- | ------------------------------------------------- | | `active` | Open — you can still send messages | | `completed` | Ended cleanly | | `timeout` | The agent hit a tool-approval or max-step timeout | | `error` | An error stopped the conversation | ### Filters * **Status** — pick one of the four statuses to narrow the list. * **Pagination** — page size defaults to 20 (max 100). ## Opening a conversation Click any row to open its [transcript](/user-guide/agent-conversations/transcripts), where you can see every message, every tool call, and every approval decision. ## Next steps Detailed conversation view Configure the agents that drive these conversations # Conversation Transcripts Source: https://docs.shingleai.com/user-guide/agent-conversations/transcripts Review the full message and tool-call history of a ShingleAI agent conversation The conversation detail page shows every turn, every tool call, and every approval decision in the chat — in order. Conversation transcript view ## What you see ### Messages Each user and agent message renders as a bubble with the content and a timestamp. ### Tool invocations When the agent called a tool, you see an inline card with: * **Tool name** and **category** * **Inputs** — the arguments the agent passed (collapsed by default; click to expand) * **Outputs** — what the tool returned * **Duration** — how long the call took ### Tool approval audit For any tool set to **Ask**, the card also records: * Who approved or denied * The timestamp of the decision * If the approval timed out This gives you a complete trail of what the agent wanted to do and how you responded. ## Actions on the detail page | Action | How | Effect | | ---------- | ---------------------- | ----------------------------------------------------------------------------------- | | **Rename** | Edit the title | Updates the title via `PATCH` — useful when the auto-generated title isn't helpful | | **Delete** | Delete button | Soft-deletes the conversation — the transcript is hidden but recoverable by support | | **Resume** | Type into the composer | Sends a new message; if status was `active`, the conversation continues | ## When can I resume? * **Active:** always — just type and send. * **Completed / timeout / error:** sending a message reopens the conversation and changes its status back to active. Tool state may be stale (for example, if the conversation referenced a contact that has since been deleted). ## Exporting No UI export today. If you need a transcript out of ShingleAI, contact support. ## Next steps Adjust what gets auto-approved Start a new conversation # Chatting with an Agent Source: https://docs.shingleai.com/user-guide/agents/chat The full-page ShingleAI agent chat interface Each agent has a chat interface at `/{org}/agents/{id}` — a full-page, message-by-message view with inline tool calls and approval cards. Agent chat page with tool approval card ## Starting a conversation 1. Open an agent from the **Agents** list. 2. Type a message in the composer at the bottom of the chat. 3. Send. The agent thinks, optionally calls tools (subject to your [permissions](/user-guide/agents/tool-permissions)), and replies. ## Tool calls inline When the agent calls a tool, you see an inline card showing the tool name, inputs (collapsed by default — expand to see), and outputs once the call returns. If the tool is set to **Ask**, the card pauses with: * The tool's risk badge * The inputs the agent wants to use * A countdown timer * **Approve** / **Deny** buttons If the timer runs out with no decision, the tool is treated as denied and the agent continues without it. ## Resuming past conversations Past conversations appear in [Agent Conversations](/user-guide/agent-conversations/index). Open any conversation's detail page to see the full history; send a new message to continue from where it left off. ## Under the hood * The chat uses a WebSocket connection for low-latency streaming. * The UI is lazy-loaded, so the first open of an agent chat may take a moment. * Messages persist even if you close the tab — reload and you'll see what was already there. ## Troubleshooting | Problem | Likely cause | Fix | | -------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------ | | Agent just says "Max steps reached" | The agent hit its `maxSteps` budget mid-turn | Raise `maxSteps` on the agent, or simplify the request | | Tool keeps asking for approval | Permission set to **Ask** | Change to **Allow** in the Tools tab if you trust it | | Agent refuses a task it should be able to do | System prompt too restrictive, or tool set to **Deny** | Review the prompt and Tools tab | ## Next steps Review or resume past chats Fine-tune what the agent can do # Creating an Agent Source: https://docs.shingleai.com/user-guide/agents/creating Configure a new ShingleAI agent with a system prompt, model, and LLM parameters 1. Go to **Agents** in the sidebar. 2. Click **New Agent**. 3. Fill in the form. Create agent form ## Required fields | Field | Notes | | ---------- | ----------------------------------------------------------------------- | | **Name** | Short label — shown in chat and conversation history | | **Type** | `Assistant` (general-purpose) or `Specialist` (narrower, task-focused) | | **Status** | `Active` to enable chat; `Disabled` to park it | | **Model** | See [Models](/user-guide/agents/models). Defaults to Claude Sonnet 4.6. | The type influences the default system prompt applied if you leave the prompt empty. ## System prompt Open the **System Prompt** section to customize behavior. Write in plain English — describe the agent's role, tone, any rules, and what kind of output you want. If left blank, a sensible default per type is used. The system prompt is the single biggest lever on agent behavior. Be specific about scope ("only answer support questions about our product X") and boundaries ("do not send email without explicit user confirmation"). ## LLM settings Advanced settings in the accordion — safe to leave at defaults for most cases: | Setting | Typical range | What it does | | --------------------- | ------------------- | ---------------------------------------------------- | | **Temperature** | 0 – 2 | Randomness. Lower = more deterministic | | **Max tokens** | Varies by model | Cap on output length per turn | | **Top P** | 0 – 1 | Nucleus sampling cutoff | | **Top K** | Integer | Candidate token cap | | **Frequency penalty** | -2 – 2 | Discourages repetition | | **Presence penalty** | -2 – 2 | Encourages new topics | | **Max steps** | Integer (default 5) | How many tool-call cycles the agent can run per turn | | **Max retries** | Integer | Retries on provider errors | ## Saving Click **Save**. The agent is created immediately. Tool permissions default to the regular-user baseline — open the new agent's detail page and visit the **Tools** tab to adjust. See [Tool Permissions](/user-guide/agents/tool-permissions). ## Default agent Each organization can have one **default agent**, marked with a badge in the list. The default agent is what ShingleAI suggests when you haven't picked another one explicitly. To mark an agent as default, toggle the flag on its detail page. ## Next steps Available OpenRouter models Decide what the agent can do # Agents Source: https://docs.shingleai.com/user-guide/agents/index Create interactive AI assistants with custom system prompts, tool permissions, and model selection Beta Agents are interactive AI assistants you can chat with inside ShingleAI. Each agent has its own system prompt, model, and per-tool permissions, so you can make an agent that answers support email one way and a research agent that behaves entirely differently. Agents list ## Agents vs. Automations **Agents** are interactive — you open a chat window and talk to them, and they can ask for your approval before running tools. **[Automations](/user-guide/automations/index)** are event-triggered — they fire automatically on events like "new email received" without a human in the loop. The two complement each other: automations handle recurring, well-defined work; agents handle ad-hoc, exploratory work. ## What you can do Name, type, system prompt, model, LLM settings Claude, GPT, Gemini — via OpenRouter Allow / ask / deny each tool Full-page chat with tool approval Conversations with an agent are saved and visible in [Agent Conversations](/user-guide/agent-conversations/index), including the full tool-call history. # Agent Models Source: https://docs.shingleai.com/user-guide/agents/models LLM models available for ShingleAI agents via OpenRouter ShingleAI agents run through [OpenRouter](https://openrouter.ai), which exposes a unified API over Anthropic, OpenAI, and Google models. ## Available models | Model | Typical use | | --------------------------------- | -------------------------------------------------------------- | | **Claude Sonnet 4.6** *(default)* | Balanced reasoning + cost for most agent tasks | | **Claude Haiku 4.5** | Fast, cheap — great for simple classification or short replies | | **Claude Opus 4** | Hardest reasoning, highest cost | | **GPT-4o** | Strong general model with broad tool use | | **GPT-4o Mini** | Smaller GPT-4o for cost-sensitive work | | **Gemini Flash** | Low-latency Google model | | **Gemini Pro** | Higher-capability Google model | No tier gating today — every organization can select any of these models. Usage is billed by the token, converted into ShingleAI credits. See [Admin Guide → Billing](/admin-guide/billing/index) for how credits work. ## Picking a model Rough guidance: * **Default to Claude Sonnet 4.6.** It hits the best balance of quality and cost for most agent workloads. * **Move to Haiku or Flash** if latency and per-call cost matter more than reasoning depth (for example, a classifier agent that only picks a label). * **Move to Opus** only when a task consistently fails at Sonnet — the cost delta is substantial. ## Changing the model Open the agent's detail page and edit the **Model** field. The change applies to all new conversations; conversations already in progress continue on whichever model they started. ## Next steps Control what the agent can do The chat UI # Tool Permissions Source: https://docs.shingleai.com/user-guide/agents/tool-permissions Allow, ask, or deny each tool an agent can call Agents can use ShingleAI tools — things like "read contact," "send email," "create task." You control what each agent is allowed to do on a per-tool basis. Tool permissions tab ## The three permission levels Each tool on each agent is set to one of three values: | Level | Icon | Behavior | | --------- | ------------- | ------------------------------------------------------ | | **Allow** | Green check | Agent calls the tool silently — no interruption | | **Ask** | Blue question | Agent pauses and requests your approval before calling | | **Deny** | Red X | Tool is hidden from the agent entirely | The "Ask" approval appears inline in the chat with a countdown timer and a risk-level badge. You can expand the card to see the exact tool input before approving. ## Finding the permissions UI 1. Open the agent's detail page. 2. Go to the **Tools** tab. 3. Tools are grouped by category (for example, Contacts, Messages, Tasks). Expand a category to see its tools, each with a three-way button. ## How defaults work When you create an agent, it inherits the **regular-user** baseline permissions for the organization. Tools considered sensitive default to **Ask**; lower-risk tools default to **Allow**. Your overrides are stored sparsely — only the tools where you deviate from the default are persisted. If the default shifts later (for example, we promote a new tool from risky to routine), agents inherit the new default unless you had explicitly overridden that tool. ## Risk levels Tool approval cards display a risk badge (low / medium / high) to help you decide quickly. Use your judgment: a low-risk tool misused is rarely damaging, a high-risk tool might send email from your domain or spend money. Changing permissions takes effect on the **next** tool call by the agent. A tool call already mid-flight when you change the setting will complete under the old rules. ## Next steps See approvals in action Review past approvals and denials # Creating Your First Automation Source: https://docs.shingleai.com/user-guide/automations/first-automation Build an AI-powered automation workflow in ShingleAI This guide walks you through creating your first automation in ShingleAI. By the end, you'll have a working automation that responds to events with AI-powered actions. For background on how automations work and what they can do, see [Automations Concepts](/get-started/concepts/automations). ## Prerequisites * A ShingleAI account with an active organization * At least one connected email account * User permissions to create automations ## Step 1: Navigate to Automations 1. Click **Automations** in the sidebar navigation 2. View your existing automations (if any) 3. Click **Create Automation** or **New Automation** Create automation form ## Step 2: Name Your Automation Give your automation a clear, descriptive name: * **Good**: "Support Email Auto-Acknowledgment" * **Good**: "New Lead Welcome Message" * **Avoid**: "Automation 1" or "Test" The name helps you identify the automation later and understand its purpose at a glance. Automation names must be unique within your organization and under 100 characters. ## Step 3: Define the Trigger Event Specify what event should trigger this automation: ### Common Trigger Events | Event | When It Fires | | ------------------ | ------------------------------------------- | | New email received | An incoming email arrives in your inbox | | Contact created | A new contact is added to your organization | | Message sent | An outgoing email is sent | Enter a description of your trigger event. Be specific about when you want the automation to run. **Example triggers:** * "When a new email arrives from a domain ending in .edu" * "When a contact is created without a company name" * "When an email subject contains 'urgent' or 'help'" ## Step 4: Write Your Instructions This is where you tell the AI what to do when the trigger fires. Write in natural language as if you were instructing a colleague. Be specific about the action, tone, and any conditions. Here's an example for a support auto-reply: ``` When a support email arrives: 1. Send an acknowledgment reply 2. Thank them for contacting support 3. Mention we typically respond within 24 hours 4. If they mention "urgent", add that we'll prioritize their request 5. Keep the tone friendly and professional 6. Keep the reply under 100 words ``` Instructions have a 5,000 character limit. If you need more complex logic, consider splitting into multiple automations. ## Step 5: Save and Enable Once you've configured your automation: 1. Review your settings 2. Click **Save** or **Create** to save the automation 3. The automation is enabled by default and starts running immediately ## Testing Your Automation After creating your automation: 1. **Trigger a test event** - Send yourself an email or perform the trigger action 2. **Check the results** - Verify the automation performed as expected 3. **Adjust if needed** - Edit the instructions to refine the behavior ## Managing Automations ### Viewing Automations All your automations are listed on the Automations page, showing: * Automation name * Trigger event * Status (enabled/disabled) * Last run time ### Enabling/Disabling Toggle an automation on or off: 1. Navigate to **Automations** 2. Find the automation 3. Click the enable/disable toggle Disabled automations don't run but retain their configuration. ### Editing Automations To modify an existing automation: 1. Click on the automation name 2. Update the fields as needed 3. Save your changes Changes take effect immediately for enabled automations. ### Deleting Automations To remove an automation: 1. Open the automation 2. Click **Delete** 3. Confirm the deletion Deleted automations cannot be recovered. Consider disabling instead if you might need it later. ## Example: Complete Automation Walkthrough Let's create a complete automation for acknowledging support emails: ### Configuration | Field | Value | | ----------------- | ----------------------------------------------------------------------- | | **Name** | Support Email Auto-Acknowledgment | | **Trigger Event** | New email received to [support@company.com](mailto:support@company.com) | | **Instructions** | See below | ### Instructions ``` When a new email arrives at the support address: 1. Send an immediate acknowledgment reply 2. Include these elements: - Thank them for contacting our support team - Confirm we received their message - Set expectations: we respond within 24 hours (Mon-Fri) - For urgent issues, mention they can call our hotline 3. Tone guidelines: - Professional but warm - Empathetic if they describe a problem - Concise - keep under 100 words 4. Sign off with: - "Best regards" - "The ShingleAI Support Team" ``` ### Expected Result When someone emails [support@company.com](mailto:support@company.com), they'll receive a reply like: > Thank you for contacting ShingleAI Support! We've received your message and a member of our team will respond within 24 business hours. > > If your issue is urgent, you can reach our priority support line at 1-800-XXX-XXXX. > > Best regards, > The ShingleAI Support Team ## Troubleshooting ### Automation Not Triggering | Issue | Cause | Solution | | ----------------- | ------------------------ | --------------------------------------- | | No action taken | Automation disabled | Check and enable the automation | | Wrong events | Trigger too specific | Broaden the trigger event description | | Permission denied | Insufficient permissions | Contact your admin to check permissions | ### Unexpected Results | Issue | Cause | Solution | | ------------------- | -------------------- | ---------------------------- | | Wrong tone | Instructions unclear | Add explicit tone guidelines | | Missing information | Context not provided | Add context to instructions | | Too verbose | No length guidance | Add word or sentence limits | ## Next Steps Connect more email accounts Organize contacts for automations # Automations Source: https://docs.shingleai.com/user-guide/automations/index Set up automated workflows in ShingleAI Automations let you create AI-powered workflows that respond to events automatically. For background on how automations work, see [Automations Concepts](/get-started/concepts/automations). ## Getting Started Step-by-step guide to building an automation Build a complete AI-powered support workflow from scratch ## Common Use Cases | Scenario | Trigger | Action | | ------------------- | -------------------------- | ------------------------- | | Auto-acknowledgment | New email received | Send confirmation reply | | Lead qualification | Contact form submission | Categorize and route lead | | Support triage | Support email | Tag by urgency and type | | Meeting scheduling | Email with meeting request | Propose available times | # AI Suggestions Source: https://docs.shingleai.com/user-guide/businesses/ai-suggestions Let ShingleAI draft your business profile, offerings, and presences Every section of the Business page has a **Suggest** button that uses an LLM to draft content based on what you've already filled in. It's the fastest way to go from an empty profile to a useful one. AI suggestions review modal ## How suggestions work 1. Click **Suggest** on any block (Name, Description, Industries, Offerings, Online Presences, Physical Presences). 2. ShingleAI sends the existing business context to the LLM and asks for **1–5 suggestions** for that section. 3. A modal shows the suggestions. Select the ones you want. 4. Click **Add** — the selected items are created in a single batch operation. The LLM is instructed to avoid duplicating items you already have, so repeat clicks generally produce new ideas rather than the same ones again. ## What gets sent to the LLM * Your business name * Business description * Industries you've selected * Other entities already on the page (for context and to avoid duplicates) Nothing is sent except what you've already typed into the Business page. ## Per-type behavior | Block | Typical suggestions | | ---------------------- | -------------------------------------------------------- | | **Name** | Cleaner or more formal versions of what you typed | | **Description** | A drafted paragraph based on name + industries | | **Industries** | Categories that might apply given name + description | | **Offerings** | 3–5 likely products/services based on industries | | **Online presences** | Guessed URLs for website and common social platforms | | **Physical presences** | Rarely useful — the LLM doesn't know your real addresses | ## Rate limiting Suggestions are rate-limited to **10 requests per minute per user**. If you hit the limit, wait a minute and try again. ## When to trust suggestions * **Always review.** Especially URLs and addresses — AI guesses can look right and be wrong. * **Prefer editing to accepting verbatim.** The suggestion is a draft; shape it to match your actual business. * **Combine with manual input.** Use suggestions to start a section, then edit. ## Next steps Review the core fields Iterate on what you sell # Business Source: https://docs.shingleai.com/user-guide/businesses/index Describe your business to ShingleAI so agents and automations have accurate context The **Business** page is a single source of truth for what your organization does, where it operates, and how it sells. Agents, automations, and AI suggestions all reference this information, so filling it in meaningfully pays dividends across the product. Business profile page ## What lives on this page Name, description, industries Products and services you sell Online and physical locations LLM-generated drafts for every section Link your Stripe account for customer sync ## Why this matters When an agent drafts an email, when an automation classifies a message, when the platform shows you a Customers list — they all use Business information to ground their behavior in your actual context. A generic "we're a business" profile produces generic outputs; a detailed profile with offerings, presences, and industries produces outputs that actually sound like you. ## Where this data is used * **Agents** read the business profile as part of their context when composing replies. * **Automations** use offerings and industries to classify and route inbound messages. * **Customers** sync from Stripe is scoped to the primary business (via Stripe Connect). ## Next steps Start with the essentials Let ShingleAI draft your profile # Offerings Source: https://docs.shingleai.com/user-guide/businesses/offerings Describe the products and services your business sells Offerings are the products and services you provide. ShingleAI uses them when classifying inbound messages, drafting outbound replies, and surfacing relevant context to agents. Offerings list ## Per-offering fields | Field | Notes | | --------------- | ------------------------------------------------------ | | **Name** | Short label — "Basic Tune-Up", "Enterprise Onboarding" | | **Description** | Prose description of what the offering includes | | **Is service** | Toggle — `true` for services, `false` for products | The service vs. product toggle affects how agents phrase things (for example, "the service lasts 2 hours" vs. "the product ships in 2 days"). ## Adding offerings 1. Scroll to the **Offerings** block on the Business page. 2. Click **Add Offering**. 3. Fill in name, description, and the service toggle. 4. Save. ### Bulk add with AI suggestions Instead of typing each offering, click **Suggest** on the Offerings block. ShingleAI returns 1–5 offerings based on your business profile; select the ones to add and commit them all at once. ## Editing Click any offering row to edit in place. Changes save on the next **Save** click. ## Removing Use the row menu → **Delete** to remove an offering. Deletion is immediate. ## Tips * Stay concrete. "Consulting" is weaker than "Monthly retainer: weekly 30-min calls + Slack support". * Keep descriptions short enough that an agent's context window can include several of them at once. ## Next steps Online and physical locations Draft offerings with the LLM # Online and Physical Presences Source: https://docs.shingleai.com/user-guide/businesses/presences Link websites, social accounts, listings, and physical addresses to your ShingleAI business Presences tell ShingleAI where your business shows up in the world — online and offline. Agents and automations use them for context and to build accurate replies (e.g., embedding your website URL in a signature). ## Online presences Each online presence has: | Field | Notes | | --------------- | -------------------------------------------------------------------------------- | | **URL** | Full URL, including `https://` | | **Type** | `Website`, `Social`, or `Listing` | | **Provider** | Brand label when applicable (Facebook, Instagram, Google Business Profile, etc.) | | **Description** | Optional prose context | Typical examples: * **Website:** `https://yourbusiness.com` * **Social:** your Instagram / LinkedIn / Facebook pages * **Listing:** Google Business Profile, Yelp, industry directories ### Adding Click **Add Online Presence** on the Business page. Pick a type and provider; paste the URL; save. ### AI suggestions The **Suggest** button on the Online Presences block proposes likely URLs based on your business name. These are best-guesses and may or may not actually belong to you. AI-generated URLs can be wrong or impersonate other businesses. Always review suggestions before accepting — the UI displays a disclaimer for this reason. ## Physical presences Each physical presence has: | Field | Notes | | --------------- | ----------------------------------------------------------------------- | | **Address** | Street / city / state / ZIP (or local equivalent) | | **Description** | Optional context — "main office", "east bay service area", "storefront" | Use physical presences for any location that matters to your business — offices, shops, service areas, warehouses. ### Adding **Add Physical Presence** → fill in address → save. ### AI suggestions Physical suggestions are weaker than online ones because the LLM has less reliable signal. Review carefully. ## Next steps How suggestions work across the page Link Stripe for customer sync # Business Profile Source: https://docs.shingleai.com/user-guide/businesses/profile Name, description, and industries for your ShingleAI business The profile block is the core "who are you" section. Agents and automations read these fields directly when they need context about your organization. ## Fields ### Name Your business's public name. Agents use this in greetings and signatures. ### Description A longer prose description — what you do, who you serve, and how. This is a rich-text editor, so you can use headings, lists, and emphasis. Keep the description specific. "A company that sells things" gives agents nothing to work with; "a small roofing company in Northern California that handles residential replacements and inspections" gives them plenty. ### Industries A multi-select tag input. Pick every industry that fits — you can (and should) select multiple if your business straddles categories. Industries are stored on the business profile and feed into: * Automation classification (e.g., "is this a sales or support inquiry?") * AI suggestions across other sections * Customer segmentation ## Saving Edits save via the **Save** button under each block. Validation is light — only the name has a length cap. ## Using AI suggestions Every field supports AI suggestions — see [AI Suggestions](/user-guide/businesses/ai-suggestions). For the profile, suggestions draft a description and propose industries based on whatever you've already filled in. ## Next steps Add what you sell Add where you sell # Stripe Connect Source: https://docs.shingleai.com/user-guide/businesses/stripe-connect Link your Stripe account to ShingleAI to sync customers and payments Stripe Connect is the OAuth handshake that lets ShingleAI read customer data from your Stripe account. Once linked, your Stripe customers appear in the [Customers](/user-guide/customers/index) section. Stripe Connect card on the Business page ## Prerequisites * An existing Stripe account. If you don't have one, create it at [stripe.com](https://stripe.com). * Owner or Admin role in ShingleAI — the Stripe Connect card is visible to everyone, but connecting runs under Owner/Admin authority. ## Connecting 1. Scroll to the **Stripe Connect** card on the Business page. 2. Click **Connect Stripe**. A Stripe-hosted page opens in a new tab. 3. Log in to Stripe and confirm the connection. 4. Stripe redirects you back to ShingleAI. The card now shows your Stripe account as linked. Behind the scenes, ShingleAI stores a `stripeAccountId` on the business record. That ID scopes every customer sync and billing action. ## What Connect enables * **Customer sync.** Stripe customers flow into ShingleAI [Customers](/user-guide/customers/index). * **Account metadata.** Stripe's payout currency, country, and other profile fields become visible. ## What Connect does *not* do * **ShingleAI's billing.** Your ShingleAI subscription is unaffected by the Connect link. You still pay ShingleAI separately — see [Admin Guide → Billing](/admin-guide/billing/index). * **Write to Stripe.** Today, sync is read-only from Stripe → ShingleAI. There is no "create customer in Stripe from ShingleAI" flow. ## Disconnecting Revoke the connection from your Stripe dashboard (Settings → Connected Accounts). When you revoke, ShingleAI loses read access; existing synced customer records remain in your Customers list but no longer update. ## Troubleshooting | Problem | Likely cause | Fix | | -------------------------------- | ------------------------------------ | ---------------------------------------------- | | OAuth popup blocked | Browser blocker | Allow popups from ShingleAI and retry | | "Connection failed" after Stripe | Stripe account requires verification | Complete Stripe onboarding, then retry | | Customers don't appear | Sync in progress | Wait a few minutes; initial sync can take time | ## Next steps See your synced customers How sync actually works # Contacts Source: https://docs.shingleai.com/user-guide/contacts/index Manage your contacts in ShingleAI ShingleAI's contact management helps you organize and maintain information about the people you communicate with. Store contact details, track conversation history, and build relationships with your business contacts. ## Features | Feature | Description | | ---------------- | ------------------------------------------ | | Contact Profiles | Store names, companies, and job titles | | Multiple Emails | Track multiple email addresses per contact | | Phone Numbers | Store phone numbers with country codes | | Addresses | Save physical addresses for contacts | | Message History | View all messages with each contact | | Profile Images | Add photos to contact profiles | ## Getting Started Add, edit, and organize your contacts ## Contact Data Each contact in ShingleAI can include: * **Name** - First name, last name, and display name * **Company** - Organization or business affiliation * **Job Title** - Professional role or position * **Email Addresses** - Multiple emails with labels (work, personal, etc.) * **Phone Numbers** - Multiple numbers with country codes * **Addresses** - Physical addresses with full details * **Notes** - Internal notes about the contact * **Profile Picture** - Visual identifier for the contact ## Automatic Contact Creation ShingleAI automatically creates contact records when: * You receive an email from a new sender * You send an email to a new recipient These auto-created contacts can be enriched with additional details as needed. Contact data is scoped to your organization. Team members with appropriate permissions can view and edit shared contacts. # Managing Contacts Source: https://docs.shingleai.com/user-guide/contacts/managing Add, edit, and organize contacts in ShingleAI This guide covers how to create, edit, and manage contacts in ShingleAI. Keep your contact information organized to improve communication and enable powerful automations. ShingleAI contacts list ## Viewing Contacts Access your contacts from the main navigation: 1. Click **Contacts** in the sidebar 2. Browse the contact list or use search to find specific contacts 3. Click a contact to view their full profile The contact list displays: * Contact name and profile picture * Company and job title * Primary email address * Quick action buttons ## Adding a New Contact To create a new contact: 1. Navigate to **Contacts** 2. Click the **Add Contact** button 3. Fill in the contact details: * First name and last name * Company and job title * Email addresses * Phone numbers * Addresses 4. Click **Save** to create the contact ### Required Fields At minimum, a contact needs one of the following: * First name or last name * Email address All other fields are optional and can be added later. ## Editing Contact Details Contact detail view ### Basic Information To edit a contact's basic information: 1. Open the contact profile 2. Click **Edit** or click directly on the field you want to change 3. Update the information: * **First Name** / **Last Name** - The contact's name * **Company** - Their organization or employer * **Job Title** - Their role or position * **Title** - Honorific prefix (Mr., Ms., Dr., etc.) * **Notes** - Internal notes about this contact 4. Changes save automatically ### Profile Picture Add or change a contact's profile picture: 1. Open the contact profile 2. Click the profile picture area or the **Upload Image** button 3. Select an image file from your computer 4. The image uploads and displays on the profile Supported formats: JPG, PNG, GIF (max 5MB) ## Managing Email Addresses Contacts can have multiple email addresses with labels. ### Adding an Email 1. Open the contact profile 2. Navigate to the **Emails** section 3. Click **Add Email** 4. Enter the email address 5. Optionally add a label (e.g., "Work", "Personal") 6. Click **Save** ### Editing an Email 1. Find the email in the contact's profile 2. Click the **Edit** button next to the email 3. Update the address or label 4. Click **Save** ### Deleting an Email 1. Find the email in the contact's profile 2. Click the **Delete** button 3. Confirm the deletion Deleting an email address also removes its association with message history. The messages remain but won't be linked to this contact via the deleted email. ## Managing Phone Numbers Store multiple phone numbers with international support. ### Adding a Phone Number 1. Open the contact profile 2. Navigate to the **Phone Numbers** section 3. Click **Add Phone Number** 4. Enter the phone number 5. Select the country code 6. Click **Save** ### Phone Number Format Phone numbers are stored with: | Field | Description | Example | | --------------- | -------------------- | ----------------- | | Phone Number | Full number | +1 555 123 4567 | | Country Code | International prefix | +1 (US), +44 (UK) | | National Number | Local format | 555 123 4567 | ## Managing Addresses Store physical addresses for contacts. ### Adding an Address 1. Open the contact profile 2. Navigate to the **Addresses** section 3. Click **Add Address** 4. Fill in the address fields: * Address Line 1 (street address) * Address Line 2 (apartment, suite, etc.) * City * State/Province * Postal Code * Country 5. Click **Save** ### Address Fields | Field | Description | Required | | -------------- | ------------------ | -------- | | Address Line 1 | Street address | No | | Address Line 2 | Additional info | No | | City | City name | Yes | | State | State or province | No | | Postal Code | ZIP or postal code | No | | Country | Country name | Yes | ## Viewing Message History See all communications with a contact: 1. Open the contact profile 2. Navigate to the **Messages** section 3. Browse messages sent to/from this contact 4. Click a message to open it in the inbox Messages are displayed chronologically with: * Date and time * Subject line * Message preview * Direction (incoming/outgoing) ## Deleting Contacts To remove a contact from your organization: 1. Open the contact profile 2. Click **Delete Contact** (usually in a menu or at the bottom) 3. Confirm the deletion Deleting a contact is a soft delete. The contact is removed from views but data is preserved for compliance. Contact support if you need permanent deletion. ## Troubleshooting ### Contact Not Saving | Issue | Cause | Solution | | ------------------------- | ----------------------- | ------------------------------------------ | | Save button disabled | Required fields missing | Ensure name or email is provided | | Error on save | Invalid data format | Check email format and phone number format | | Duplicate contact warning | Contact already exists | Search for existing contact and merge | ### Missing Contacts | Issue | Cause | Solution | | --------------------- | -------------------- | ----------------------------------- | | Contact not appearing | Search filter active | Clear search and filters | | Contact deleted | User removed contact | Contact cannot be recovered by user | ## Next Steps View messages from your contacts Create automated workflows for contacts # Customers Source: https://docs.shingleai.com/user-guide/customers/index Browse customers synced from your Stripe account into ShingleAI The **Customers** section shows the customers on your primary business's Stripe account. Think of it as a CRM-style view over Stripe data — unified with the rest of ShingleAI so agents and automations can reference customer context. Customers list with Stripe-synced badges ## The list Each row shows: | Column | Notes | | ------------------ | -------------------------------------------- | | **Name** | From Stripe | | **Email** | From Stripe | | **Customer since** | Stripe creation date | | **Stripe badge** | Green badge if the row is synced from Stripe | ### Filters * **Search** — matches name and email. * **Sync filter** — `All` / `Synced from Stripe` / `Not synced`. ## Customer detail Click a row to open the customer's detail page. You'll see: * Contact information (name, email) * Stripe-sourced metadata (customer since, Stripe customer ID if synced) * Related context from ShingleAI when applicable ## Prerequisites For the Customers section to be populated, you need: 1. A linked Stripe account — see [Stripe Connect](/user-guide/businesses/stripe-connect). 2. Customers in that Stripe account. If Stripe isn't linked yet, the list will be empty and you'll see guidance pointing you to connect. ## Limitations today * **Read-only from Stripe.** The current UI displays Stripe customers — it doesn't create them. New customers show up only after they exist in Stripe. * **No manual "sync now".** Sync happens automatically; there's no button to force an immediate refresh. * **No customer ↔ contact mapping.** Customers and [Contacts](/user-guide/contacts/index) are separate entities today; linking them explicitly is not yet supported in the UI. ## Next steps Understand the data flow Link Stripe to populate this list # How Customer Sync Works Source: https://docs.shingleai.com/user-guide/customers/sync The data flow between Stripe and ShingleAI Customers Customer sync is **Stripe → ShingleAI**, scoped to your primary business's connected Stripe account. ## What triggers a sync * **Initial sync** runs when you first connect Stripe — existing customers are imported in a batch. * **Ongoing sync** runs on Stripe webhooks. New customers and updates to existing customers propagate to ShingleAI automatically. There is no manual "sync now" button today. Webhook propagation is usually within seconds. ## Sync scope * Only the Stripe account you linked via [Stripe Connect](/user-guide/businesses/stripe-connect) is synced. * The linked account is scoped to your **primary** business. In a multi-business setup, the other businesses' customers don't appear here. ## What gets synced * **Name** * **Email** * **Customer ID** (`stripeCustomerId`, used to detect that a row is synced) * **Customer creation date** (displayed as "Customer since") Stripe-specific metadata that ShingleAI doesn't surface today (tax IDs, shipping addresses, metadata keys) remains in Stripe. Contact support if you need a specific field pulled through. ## Detecting sync status * **Synced** customers have a green **Stripe** badge in the list and a populated `stripeCustomerId`. * **Not synced** customers are rows added in ShingleAI directly — today this path is rare because the UI doesn't expose customer creation, but some API/MCP callers do. The **Sync filter** in the list lets you narrow to synced or not-synced. ## What does NOT sync * **ShingleAI → Stripe.** Edits in the Customers list do not push back to Stripe. Customer data in Stripe is authoritative. * **Deletion.** Deleting a customer in Stripe does not delete the ShingleAI record automatically — it stays visible until support removes it (or a future sync pass handles soft-deletes). ## When sync breaks | Symptom | Likely cause | Fix | | ----------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------- | | New Stripe customer not showing | Webhook delivery delay or failure | Wait a few minutes; if still missing, check Stripe's event log | | Stripe disconnected | OAuth revoked | Reconnect from [Stripe Connect](/user-guide/businesses/stripe-connect) | | Initial import didn't populate everything | Rate limits on large Stripe accounts | Contact support | ## Next steps Back to the list view Link or relink Stripe # Domain Events Source: https://docs.shingleai.com/user-guide/domains/events Audit trail of status transitions and actions on a ShingleAI domain Each domain has an events timeline on its detail page. The timeline is your audit trail for verifications, registration milestones, and status changes. Domain events timeline ## What shows up Events are logged for the transitions that matter: | Event | Fires when | | ---------------------- | ---------------------------------------------------------- | | Domain created | You added the domain (via verify or register) | | Verification check | The verification workflow ran against DNS | | Verification succeeded | TXT record observed, status moved to active | | Registration purchased | Stripe checkout completed | | Registration activated | DNSimple confirmed the registration | | Status changed | Any transition — pending → active, active → expiring, etc. | | Email address added | An address was created on the domain | The exact set depends on the source (registered vs. verified) and how old the domain is. ## Reading the timeline * Most recent event appears at the top. * Each event shows a timestamp and a short description. * For verification-related events, the full DNS resolution context is typically included. ## When this is useful * **Debugging verification.** If a domain stays stuck in pending, the timeline shows what the verification workflow actually saw in DNS. * **Audit.** If a domain unexpectedly lost active status, the timeline tells you when and, often, why. * **Compliance.** If someone asks "when did we add this domain," the answer is here. ## Next steps Back to verification Buy one through ShingleAI # Domains Source: https://docs.shingleai.com/user-guide/domains/index Verify or register a domain to send email from ShingleAI A domain is the piece before the `@` in an email address. ShingleAI needs your domain to be verified — and optionally registered through us — before you can send from addresses on it. Domains list ## Two ways to get a domain Add a TXT record at your DNS provider — free Buy through ShingleAI via DNSimple — Stripe checkout ## Status states Each domain has a status — visible as a badge in the list: | Status | Meaning | | ---------- | ------------------------------------------------------------------------------------------------ | | `pending` | Awaiting verification (TXT record hasn't been seen yet) | | `active` | Verified and healthy — ready for [email addresses](/user-guide/email-addresses/shingleai-hosted) | | `expiring` | Registration renewal due within 7–30 days | | `expired` | Registration has lapsed — domain is non-functional | ## Source The list also shows each domain's source: * **Registered** — bought through ShingleAI via DNSimple + Stripe * **Verified** — owned elsewhere; verified via TXT record ## Events Each domain has an events timeline (on its detail page). See [Domain Events](/user-guide/domains/events) for what you can learn from it. ## Filters and search * **Search** — matches domain names. * **Status filter** — narrow to active / pending / expiring / expired. * **Source filter** — all / registered / verified. * **Pagination** — 25 items per page. ## Next steps Add a TXT record at your DNS host Buy one through ShingleAI # Registering a Domain Source: https://docs.shingleai.com/user-guide/domains/register Buy a new domain through ShingleAI via DNSimple and Stripe checkout If you don't already own a domain, ShingleAI can register one for you through [DNSimple](https://dnsimple.com). Payment runs through Stripe and the domain is auto-configured for email once the purchase completes. ## When to register vs. verify * **Register** if you're buying a fresh domain specifically for your ShingleAI business. * **Verify** if you already own the domain somewhere else. See [Verify a domain](/user-guide/domains/verify). ## The registration flow 1. Go to **Domains** and click **Add Domain** → **Register a new domain** (or visit `/{org}/domains/create` directly). 2. **Search** for a domain. ShingleAI queries DNSimple for availability. 3. **Pick a TLD** — the pricing list shows available extensions (`.com`, `.co`, `.io`, etc.) with their annual prices. 4. **Continue to checkout** — you're redirected to Stripe. 5. **Pay** — once payment succeeds, you're sent back to ShingleAI and the domain registration kicks off at DNSimple. Domain registration search and TLD picker ## After purchase * The domain appears in your Domains list with source **Registered**. * Initial DNS is configured automatically — you don't need to add TXT records; ShingleAI already controls the zone. * The domain transitions to **active** once DNS propagation completes (usually within a few minutes). ## Renewals * Registered domains renew annually by default via Stripe. * The list highlights domains entering **expiring** status 7–30 days before renewal. * If payment fails and the domain reaches **expired**, you'll need to contact support to recover it. ## Troubleshooting | Problem | Likely cause | Fix | | ---------------------------------------------- | ---------------------------- | ---------------------------------------------------------------- | | "Domain not available" | Already registered elsewhere | Try a different name or TLD | | Checkout fails | Payment method issue | Update in [Billing](/admin-guide/billing/index) | | Purchase completed but domain stuck in pending | DNS propagation lag | Wait 10–30 minutes; contact support if still stuck after an hour | ## Next steps Use the new domain Verify one you already own # Verifying a Domain Source: https://docs.shingleai.com/user-guide/domains/verify Prove ownership of a domain you already have by adding a DNS TXT record Verification proves you control a domain — without this, ShingleAI can't let you send from addresses on it. ## Prerequisites * Access to DNS at your domain registrar (or wherever DNS for the domain is hosted). * Permission in ShingleAI to add domains (typically Owner or Admin). ## The verification flow 1. Go to **Domains** and click **Verify Domain**. 2. Enter the domain name (for example `example.com`). 3. Save. ShingleAI generates a **verification token** for you. Verify domain dialog showing TXT record to add 4. Copy the TXT record ShingleAI displays — the record name (often `@`) and the value (the verification token). 5. Add the TXT record at your DNS provider. Exact steps vary by host; most providers have a "TXT" record type in their dashboard. 6. Back in ShingleAI, click **Check Verification**. The app polls DNS and updates the status once it sees the record. ## Expiry You have **7 days** to complete verification. If the TXT record isn't found by then, the pending domain is cleaned up and you can start over. ## Statuses you'll see | Status | What it means for you | | --------- | --------------------------------------------------------------------------------------------------- | | `pending` | TXT record not yet observed — still waiting | | `active` | Verified — you can now create [email addresses](/user-guide/email-addresses/shingleai-hosted) on it | ## Troubleshooting | Problem | Likely cause | Fix | | ----------------------------------- | -------------------------------------- | ------------------------------------------------------------- | | Check keeps saying "not found" | TXT record hasn't propagated | Wait 5–30 minutes; some hosts are slow | | Check finds a different value | Old TXT record cached | Verify at the DNS host that the value matches exactly | | Record is in place but not detected | Record is on a subdomain or wrong host | The record must be on the apex of the domain you're verifying | ## Next steps Use your newly verified domain Buy a new one through ShingleAI instead # Email Addresses Source: https://docs.shingleai.com/user-guide/email-addresses/index Create ShingleAI-hosted email addresses or connect your existing Google / Microsoft account There are two ways to get email flowing in and out of ShingleAI: Create `name@yourdomain.com` on a domain you've verified. Sending is handled by ShingleAI's infrastructure. Authorize Google Workspace / Gmail or Microsoft 365 via OAuth. Sending stays in your provider's outbox. ## When to pick which | Situation | Recommended | | ---------------------------------------------------------------------------------- | ---------------- | | You own a domain and want a clean `support@`, `hello@`, `info@` address | ShingleAI-hosted | | You already use Gmail / Google Workspace for personal email | Connect external | | You already use Microsoft 365 / Outlook | Connect external | | You want automations to send from a generic mailbox your team doesn't have to open | ShingleAI-hosted | Both paths feed the same [unified inbox](/user-guide/email/inbox). You can mix: connect a personal Gmail for one sender and host `support@` through ShingleAI for another. ## Prerequisites * **ShingleAI-hosted:** you need a domain in **active** verified state. See [Domains → Verify](/user-guide/domains/verify) to add one. * **External:** your Google Workspace admin or Microsoft 365 admin may need to approve the app. No prep is required for personal Gmail. ## Next steps Create an address on a verified domain OAuth flow for Google and Microsoft # ShingleAI-Hosted Email Addresses Source: https://docs.shingleai.com/user-guide/email-addresses/shingleai-hosted Create an email address on a domain you have verified with ShingleAI Once a domain reaches **active** status, you can create email addresses on it. ShingleAI handles sending and receiving for those addresses — you don't need to run a mail server. ## Prerequisites * At least one domain with **Active** status. See [Domains → Verify](/user-guide/domains/verify). ## Creating an address 1. Go to **Email Addresses** in the sidebar. 2. Click **Add Email Address** (or visit `/{org}/email-addresses/new` for the full-page form). 3. Select **ShingleAI** as the provider. The domain dropdown lists only domains in active state. 4. Fill in the form: | Field | Notes | | --------------------- | ----------------------------------------------------------------- | | **Name** | Display name — what recipients see as the "From" | | **Email** | The local part — what comes before the `@` | | **Domain** | Select from your verified domains | | **System email** | Check this if the address is for automated sends and not a person | | **Daily send limit** | Soft cap on sends per day | | **Hourly rate limit** | Soft cap on sends per hour | 5. Click **Save**. Create email address form The new address appears in the list and is ready to use. Messages sent to it land in the [inbox](/user-guide/email/inbox); messages sent from it route through ShingleAI's infrastructure (Resend). ## Limits The daily and hourly limits exist to keep deliverability healthy. If you regularly hit them, raise them — just be mindful of the reputation impact of large sudden increases on a new domain. ## Removing an address Open the address's detail page and delete it. The underlying domain is unaffected — other addresses on the same domain keep working. ## Next steps Verify or register the domain first Where incoming mail shows up # Creating an Email Template Source: https://docs.shingleai.com/user-guide/email-templates/creating Write a template with variables and validate it against ShingleAI templating rules 1. Go to **Email Templates** in the sidebar. 2. Click **Add Email Template**. 3. Fill in the form. Create email template dialog ## Fields | Field | Limit | Required | | --------------- | --------------------- | -------- | | **Name** | 1 – 200 characters | Yes | | **Subject** | 1 – 1,000 characters | Yes | | **Body** | 1 – 50,000 characters | Yes | | **Description** | 0 – 2,000 characters | No | ## Template variables Use `{{mustache}}` syntax anywhere in the subject or body: ``` Subject: Welcome to {{business_name}}, {{first_name}}! Body: Hi {{first_name}}, Thanks for signing up — we're excited to have you. If you need help, just reply to this email. Cheers, {{sender_name}} ``` ShingleAI extracts every `{{variable}}` automatically. There's no separate step to declare them — just use them where you want them filled in. ### What the preview shows The template detail page has a **Preview** tab that lists every extracted variable. You can fill sample values and see the rendered subject and body update live. ## Validation ShingleAI validates the subject and body for Mustache syntax errors on save — for example, an unclosed `{{` or a dangling `}}`. You cannot save a template whose syntax is invalid. Variables that aren't provided at send time render as empty strings — Mustache silently skips them. If a variable is truly required, enforce that in the automation or agent that calls the template, not in the template itself. ## Active vs. archived Every template has an **active** or **archived** state. Archived templates don't appear in the automation/agent picker but remain in the list for reference and reactivation. This is a soft state — archiving does not delete history. ## Next steps Preview, versions, sends Reference a template from an automation # Email Templates Source: https://docs.shingleai.com/user-guide/email-templates/index Reusable email templates with variables, previews, and version history Email templates are reusable, variable-aware message bodies. Write them once and let automations or agents fill them in with specific contact data at send time. Email templates list ## When to use templates * **Repeatable sends.** Welcome emails, follow-ups, appointment confirmations. * **Automations.** An automation references a template by ID — the template evolves independently of the automation logic. * **Agent sends.** Agents can use templates via LLM tools, so the message stays on-brand even when an agent writes it. ## What a template is * A **name** (internal label) * An optional **description** * A **subject** line * A **body** (plain text or markdown) * Optional **variables** in `{{mustache}}` syntax that get filled at send time Variables are not declared explicitly — ShingleAI extracts them from whatever you put in the subject and body. ## Next steps Form fields, variables, validation Preview, version history, send via automation # Using Email Templates Source: https://docs.shingleai.com/user-guide/email-templates/using Preview, version history, and referencing templates from automations and agents The template detail page is where you iterate on an existing template. It has tabs for editing, previewing, and reviewing version history. Email template detail tabs ## Tabs | Tab | Contents | | ------------ | ------------------------------------------------------------------ | | **Settings** | Edit name, description, subject, body. Validation runs on save. | | **Preview** | Fill sample variable values and see the rendered email update live | | **History** | Version snapshots — view or restore any previous version | ## Previewing Open the **Preview** tab: 1. The list on the left shows every variable ShingleAI extracted from the subject and body. 2. Type sample values for each. 3. The rendered subject and body update as you type. Use this to verify that your variable names match what your automations actually pass. ## Version history Every meaningful change to the subject or body creates a new version. The **History** tab shows: * When the version was saved * Who saved it * A **View** button to inspect that version * A **Restore** button to promote that version back to current Restoring a version becomes the new current version — older versions remain in history. ## Sending from an automation In an automation's instructions, reference the template by name or by ID. Under the hood, the automation calls `renderEmailTemplateContent` with the variable data it has available and the rendered result goes out via the configured sender. Because Mustache silently ignores missing variables, make sure the automation actually has the data it needs before the send step. ## Sending from an agent Agents can call a `send_email` tool that accepts a template reference and a map of variable values. Tool permissions apply — see [Tool permissions](/user-guide/agents/tool-permissions) — and a human can be required to approve each send. ## Deleting Use the dropdown on the list or detail page to **Delete** a template. Deletion is soft — the row is hidden but version history and references are preserved. ## Next steps Trigger a template send from an event Ask an agent to send using a template # Connecting Email Providers Source: https://docs.shingleai.com/user-guide/email/connect Link your Google or Microsoft email accounts to ShingleAI Connect your email accounts to ShingleAI to bring all your business communications into a single, unified inbox. ShingleAI uses secure OAuth authentication to access your email—we never store your email password. ## Prerequisites * A ShingleAI account with an active organization * Access to a Google Workspace/Gmail or Microsoft 365/Outlook account * Permission to authorize third-party applications (may require admin approval in some organizations) ## Connecting Google Workspace / Gmail To connect your Google account: 1. Navigate to **Settings > Connected Accounts** 2. Click **Connect Google** 3. Sign in to your Google account if prompted 4. Review the permissions ShingleAI is requesting 5. Click **Allow** to authorize the connection Google OAuth authorization screen ### Google Permissions When connecting Google, ShingleAI requests the following permissions: | Permission | Purpose | | ------------------------- | -------------------------------------- | | View your email messages | Read incoming and sent emails | | Send email on your behalf | Allow ShingleAI to send replies | | View your contacts | Access contact information for context | | View your profile | Display your name and email in the app | ShingleAI only accesses the permissions you grant. You can revoke access at any time from your Google Account settings or from ShingleAI. ## Connecting Microsoft 365 / Outlook To connect your Microsoft account: 1. Navigate to **Settings > Connected Accounts** 2. Click **Connect Microsoft** 3. Sign in to your Microsoft account if prompted 4. Review the permissions ShingleAI is requesting 5. Click **Accept** to authorize the connection Microsoft OAuth authorization screen ### Microsoft Permissions When connecting Microsoft, ShingleAI requests the following permissions: | Permission | Purpose | | ----------------- | -------------------------------------- | | Read your mail | Access incoming and sent emails | | Send mail as you | Allow ShingleAI to send replies | | Read your profile | Display your name and email in the app | For Microsoft 365 business accounts, your organization's admin may need to approve ShingleAI as a trusted application before you can connect. ## Managing Connected Accounts Once connected, you can manage your email accounts from **Settings > Connected Accounts**: * **View permissions** - See which permissions are granted to each connection * **Manage** - Access connection-specific settings * **Disconnect** - Remove the connection and revoke ShingleAI's access ## Multiple Accounts You can connect multiple email accounts to ShingleAI. Each account will: * Appear in your unified inbox * Be identified by its email address in message lists * Maintain separate authentication and permissions ## Troubleshooting ### Connection Failed | Issue | Cause | Solution | | --------------------- | --------------------------------------------- | -------------------------------------------------- | | "Access Denied" error | Organization policy blocking third-party apps | Contact your IT administrator to approve ShingleAI | | Connection times out | Network or browser issue | Try a different browser or clear cookies | | "Invalid Grant" error | Authorization expired | Disconnect and reconnect the account | ### Sync Issues | Issue | Cause | Solution | | ----------------------- | ----------------------------- | ------------------------------------------------- | | Emails not appearing | Initial sync in progress | Wait a few minutes for the first sync to complete | | Old emails missing | Only recent emails are synced | ShingleAI syncs emails from the last 30 days | | Sent emails not showing | Permission issue | Verify the "send email" permission was granted | ### Organization Restrictions If you're using a corporate Google Workspace or Microsoft 365 account: 1. Check if your organization allows third-party applications 2. Contact your IT administrator if you see "admin approval required" 3. Request that ShingleAI be added to the approved applications list ## Security ShingleAI takes your email security seriously: * **OAuth 2.0** - We use industry-standard OAuth 2.0 for authentication * **No password storage** - We never see or store your email password * **Encrypted connections** - All data is transmitted over HTTPS * **Minimal permissions** - We only request permissions necessary for the features you use ## Next Steps Learn how to navigate your unified inbox Set up automated email workflows # Inbox Overview Source: https://docs.shingleai.com/user-guide/email/inbox Navigate and manage your unified inbox in ShingleAI The ShingleAI inbox brings every connected email account and SMS-enabled phone number into a single, organized view. This guide covers how to navigate, read, and manage your messages. ShingleAI inbox interface ## Inbox modes ShingleAI organizes messages into four modes, switched from the sidebar: | Mode | Contents | | ------------ | ------------------------------------------ | | **Inbox** | Incoming messages that need your attention | | **Snoozed** | Messages you've snoozed to review later | | **Archived** | Messages you've archived for reference | | **Sent** | Outgoing messages you've sent | Use the URL to link directly to a mode — `/{org}/inbox/snoozed`, `/{org}/inbox/archived`, etc. ## Reading messages ### The message list Each row shows: * **Sender** — who the message is from * **Subject** — the subject line (for email) or the SMS preview (for phone) * **Preview** — first line of the body * **Time** — when the message arrived * **Attachment icon** — present if the message has attachments Click a row (or focus it and press Enter/Space) to open the message in the reading pane. ### Thread view Email replies and forwards group into conversation threads: * All messages in the thread appear together, oldest at the top. * Thread participants are shown in the header. * Expand or collapse individual messages within the thread. ### Attachments Messages with attachments show an attachment icon in the list and the full file list inside the message view. Click an attachment to preview supported formats or download the original. ## Message actions Actions are available per message from the toolbar at the top of the reading pane. ### Archive Remove a message from your Inbox while keeping it accessible: 1. Open the message. 2. Click the **Archive** button. 3. The message moves to **Archived**. ### Snooze Hide a message and have it return later: 1. Open the message. 2. Click the **Snooze** button. 3. Pick how long from the dropdown: | Option | Returns to Inbox in | | ----------- | ------------------- | | For 1 hour | 1 hour | | For 3 hours | 3 hours | | For 1 day | 24 hours | | For 3 days | 72 hours | The message moves to **Snoozed** and comes back to **Inbox** when the time elapses. Custom times and "until next week"-style options are not currently exposed. ### Delete Permanently remove a message: 1. Open the message. 2. Click the **Delete** button. Delete is permanent. Use **Archive** if you might want the message back. ### Mark as read / unread Opening a message marks it read. To toggle state without opening, use the context menu on the message row. ## Selection and bulk actions The current UI supports **one selected message at a time**. Multi-select and bulk actions (select all, bulk archive, bulk delete) are not yet available — open an issue or contact support if you need them. ## Search Search is accessed via the search bar at the top of the inbox. It queries across every connected account and mode. ## Keyboard interactions The inbox relies on standard browser focus behavior plus a few specific actions: | Interaction | What it does | | ---------------------------------- | ----------------------------------------------- | | `Tab` / `Shift+Tab` | Move focus between message rows and UI controls | | `Enter` / `Space` on a focused row | Open that message | | Click | Open a message or activate a toolbar action | Per-action keyboard shortcuts (archive, snooze, delete) are not implemented today. ## Connected accounts and numbers When multiple mailboxes or phone numbers are in play: * Each message shows which account it arrived at. * Replies default to sending from the same address that received the original. * Sent messages are grouped under the outbound channel for easy auditing. ## Troubleshooting ### Messages not loading | Issue | Cause | Fix | | ---------------------------- | ------------------------ | ------------------------------------------------------------------- | | Empty inbox on first load | Initial sync in progress | Wait for sync to complete (usually a minute or two) | | Missing recent emails | Sync delay | Refresh the page | | "Connection error" indicator | Account was disconnected | Reconnect from [Email Addresses](/user-guide/email-addresses/index) | ### Performance | Issue | Cause | Fix | | ------------------- | ---------------- | ------------------------------- | | Slow list scroll | Very large inbox | Use search instead of scrolling | | Thread won't expand | Browser cache | Hard refresh (Cmd/Ctrl+Shift+R) | ## Next steps Add more sending addresses Auto-respond to incoming mail # Email Source: https://docs.shingleai.com/user-guide/email/index Manage your email communications with ShingleAI ShingleAI integrates with your existing email providers to bring all your business communications into a single, AI-powered inbox. Connect your Google or Microsoft accounts to start managing emails more efficiently. ## Features | Feature | Description | | --------------- | ---------------------------------------------------- | | Unified Inbox | View all emails from connected accounts in one place | | Thread View | See complete conversation threads with context | | Message Actions | Archive, snooze, and manage messages efficiently | | Search | Find messages quickly across all connected accounts | | AI Processing | Let ShingleAI help process and respond to messages | ## Getting Started Link your Google or Microsoft email accounts Learn how to navigate and manage your inbox ## Supported Providers ShingleAI currently supports the following email providers: * **Google Workspace / Gmail** - Full integration with Gmail, including labels and search * **Microsoft 365 / Outlook** - Complete support for Outlook and Exchange Online Additional email providers may be added in future updates. Contact support if you need integration with a specific provider. # Deleting Files and Folders Source: https://docs.shingleai.com/user-guide/files/deletion How ShingleAI handles file and folder deletion Deletion in ShingleAI Files is **soft** — deleted items are hidden from the UI but retained behind the scenes. Contact support if you need to restore something recently deleted. ## Deleting a file 1. Open the file (either in a row menu or from the detail page). 2. Click **Delete**. 3. Confirm. The file disappears from the list immediately (optimistic UI). If the delete request fails, the item reappears with an error message. ## Deleting a folder Folders can be deleted from their row menu. The folder and all its contents are soft-deleted together. Large folders may take a moment to finish processing after you click Delete. The folder disappears immediately from the UI, but downstream indexes (like agent retrieval) catch up asynchronously. ## What happens to agent indexes When a file with **agent access** is deleted, its chunks are removed from the retrieval index. Agents won't be able to retrieve content from deleted files in new queries. Existing agent conversations that previously cited the file still show the original content in their transcripts. ## Restoring There is no self-serve restore UI today. Contact support with the file name and approximate deletion time to recover deleted content. ## Next steps Back to Files Account-level storage and retention # Organizing Files with Folders Source: https://docs.shingleai.com/user-guide/files/folders Create nested folders and navigate them in ShingleAI Files Folders keep your Files section organized. You can nest folders to any depth, and the breadcrumb at the top of the page shows where you are in the hierarchy. Folder breadcrumbs in Files ## Creating a folder 1. Navigate to the folder you want the new folder to live inside (or stay at the root). 2. Click **New Folder**. 3. Enter a name. 4. Save. The folder appears in the current view. Click into it to drill down. ## Navigating * **Click a folder** to drill in. * **Click a breadcrumb segment** to jump back to that level. * **Click the root** (leftmost breadcrumb) to return to the top of the hierarchy. ## Pagination Each folder page lists up to **50 items** (files + sub-folders) per page. Use the pagination controls to walk through larger folders. ## Deleting a folder Open the folder's menu and choose **Delete**. The folder and its contents are soft-deleted — see [Deletion](/user-guide/files/deletion). ## Next steps Add files into your folders Make folder contents agent-readable # Files Source: https://docs.shingleai.com/user-guide/files/index Upload, organize, and share files in ShingleAI — with optional agent access for RAG-powered retrieval The Files section holds documents attached to your organization — contracts, manuals, reference docs, whatever agents or teammates need to read. Files can optionally be made accessible to [agents](/user-guide/agents/index), which indexes them for retrieval. Files list with folders and breadcrumbs ## What you can do Drag-drop or the upload dialog Nested folders with breadcrumb navigation Make files searchable by agents Soft-delete semantics ## Limits Storage is counted against your organization's allocation. See [Admin Guide → Billing](/admin-guide/billing/index) for current limits and overage behavior. # Agent Access & RAG Indexing Source: https://docs.shingleai.com/user-guide/files/rag-indexing Let ShingleAI agents search and retrieve content from your uploaded files Files can optionally be made **agent-accessible**. When a file is agent-accessible, ShingleAI indexes its contents for retrieval — so an [agent](/user-guide/agents/index) can pull relevant passages into its context when answering questions. ## The agent-access flag Every file has a boolean **agent access** flag: | State | What it means | | ------------------------------------------ | --------------------------------------------------- | | **Agent Access** (default off for privacy) | The file's contents can be retrieved by agents | | **No Agent Access** | The file exists in Files but is invisible to agents | The flag is set at upload time and shown as a badge on the file detail page. Agent access badge on file detail page ## How indexing works When you enable agent access: 1. ShingleAI splits the file into semantic chunks using a **structural markdown chunker** — sections, paragraphs, and other structural boundaries rather than fixed-size windows. 2. Each chunk is embedded and stored in the retrieval index. 3. When an agent needs information, it queries the index and receives the most relevant chunks back as context. This approach (RAG — retrieval-augmented generation) keeps the agent grounded in your actual documents rather than relying on its generic training. There is no UI indicator for index status today. Once you enable agent access, give the system a minute to finish indexing before relying on the file's content in an agent chat. ## Turning agent access on or off Edit the file (via its detail page) and toggle **Agent access**. Turning it off removes the file from the index; turning it back on re-indexes. ## What content agents see Agents see the file's **text** — extracted from the document. Binary content (images, raw PDFs without OCR) isn't indexed meaningfully; the indexer works best with markdown, plain text, and documents with recoverable text layers. ## Privacy Agent-accessible files are scoped to your organization. Agents in other organizations never see them. Within your org, any agent that has the "read files" tool permission can retrieve content. ## Next steps Enable agent access at upload time Configure which agent reads which files # Uploading Files Source: https://docs.shingleai.com/user-guide/files/uploading Upload files to ShingleAI via drag-drop or the upload dialog Files upload directly to ShingleAI storage (Cloudflare R2) and appear in the list as soon as they finish. ## Two ways to upload ### Drag and drop Drop one or more files anywhere on the Files page. The upload starts immediately. ### Upload dialog Click **Upload Files** to open the upload dialog. Select one or more files from your file picker and confirm. File upload dialog ## What you can attach per file On upload you can optionally set: | Field | Purpose | | ---------------- | -------------------------------------------------------------------------------------- | | **Description** | Short note about what the file is | | **Tags** | Free-form labels | | **Agent access** | Whether agents can read this file — see [RAG indexing](/user-guide/files/rag-indexing) | ## Where uploads land New files appear in the **current folder** — whichever folder you're viewing when you start the upload. To upload into a specific folder, navigate into it first. ## Storage limits Before any upload, ShingleAI checks your organization's remaining storage allocation. If you're out of space, the upload fails with an error and no partial file is stored. Raise your allocation in [Admin Guide → Billing](/admin-guide/billing/index). ## Troubleshooting | Problem | Likely cause | Fix | | --------------------------------- | --------------------------- | ------------------------------ | | Upload fails with "storage limit" | Hit your allocation | Free up space or upgrade | | Very large file times out | Network interruption | Retry from a stable connection | | File doesn't appear in list | Browser cached the old list | Refresh the page | ## Next steps Group files into folders Let agents search file contents # User Guide Source: https://docs.shingleai.com/user-guide/index Learn how to use ShingleAI to manage your business communications, contacts, tasks, and AI agents The User Guide covers the everyday features of ShingleAI — the things you'll use to run your business. For account-level configuration (billing, team members, API keys, security), see the [Admin Guide](/admin-guide/organization/setup). New to ShingleAI? Start with the [Setup Checklist](/user-guide/setup-checklist/index). It walks through the seven things worth doing first so the rest of the product works end-to-end. ## Get your inbox working Connect a mailbox or create an address on a verified domain Send and receive from addresses you control Buy phone numbers via Telnyx for voice and SMS Read, snooze, archive, and search unified messages ## Organize who and what People and companies you communicate with Customers synced from your Stripe account Track work with an urgency × importance matrix Upload documents for agents to reference ## Automate with AI Event-triggered workflows described in plain English Interactive AI assistants with tool permissions Review past agent transcripts and approvals Reusable templates with variables for sends ## Set up your business Profile, offerings, presences, Stripe Connect Verify or register domains for email History of phone numbers and other purchases Seven onboarding tasks to finish early # Buying a Phone Number Source: https://docs.shingleai.com/user-guide/phone-numbers/buying Search available numbers from Telnyx and purchase through ShingleAI ShingleAI sells phone numbers through Telnyx. Checkout runs through Stripe — the line item appears on your ShingleAI invoice, not a separate Telnyx one. ## Two entry points ### From the inbox setup wizard If you're still setting up, the **Inbox Setup Wizard** at `/{org}/inbox/setup` lets you choose "Phone" and walks through search → select → checkout → add to organization. ### From the purchases page Once you're past initial setup: 1. Go to **Purchases** in the sidebar. 2. Click **Purchase Phone Numbers**. 3. You land on the phone number search page. ## The purchase flow 1. **Choose a location** — select country and (optionally) area code or region. 2. **Pick available numbers** — ShingleAI queries Telnyx and lists available numbers with features (SMS, voice, MMS) and any per-number monthly cost. 3. **Review** — confirm your selection and the calculated total. 4. **Checkout** — you're redirected to Stripe to pay. 5. **Success** — you land back on ShingleAI's success page, and the number attaches to your organization automatically. The `phone_number_provision` metric is emitted for billing. You can select multiple numbers in a single checkout. The total reflects Telnyx pricing for each number. ## Adding a number you already own If you already have a Telnyx number and want to attach it directly: 1. Go to **Phone Numbers**. 2. Click **Add Phone Number** to open the inline form (or visit `/{org}/phone-numbers/new` for the full-page version). 3. Fill in: * **Name** — a label you'll recognize * **Phone number** — in E.164 format (for example `+14155550123`) * **Country code** and **Region** * **Provider** — Telnyx 4. Save. The number is now available for configuration. ## Troubleshooting | Problem | Likely cause | Fix | | ---------------------------------------- | -------------------------------- | ----------------------------------------------- | | No available numbers in search | Area code out of stock at Telnyx | Try a nearby area code or a broader region | | Stripe checkout fails | Payment method issue | Update in [Billing](/admin-guide/billing/index) | | Purchase succeeded but number not listed | Webhook lag | Wait 30–60 seconds and refresh | ## Next steps Turn on SMS, voice, voicemail, recording See your purchase history # Configuring a Phone Number Source: https://docs.shingleai.com/user-guide/phone-numbers/configuring Set SMS, voice, voicemail, and recording options on a ShingleAI phone number Open any phone number from the Phone Numbers list to reach its detail page. Settings save when you submit the form. Phone number settings ## Channels Each number has three independent toggles: | Toggle | What it enables | | ------------- | ------------------------------------------------------------------------------------------------- | | **SMS** | Inbound and outbound text messaging. Incoming SMS lands in your [inbox](/user-guide/email/inbox). | | **Voice** | Inbound and outbound voice calls, governed by the voice mode below. | | **Voicemail** | Unanswered calls fall through to voicemail. | Leave channels off that you don't intend to use. ## Voice modes When **Voice** is on, choose how calls are handled: | Mode | Behavior | | ---------- | ------------------------------------------------------------------ | | **WebRTC** | Calls ring into the ShingleAI web app for you to answer in-browser | | **IVR** | An automated menu routes callers before (or instead of) a human | Additional modes may appear in the UI depending on what's rolled out for your account. ## Recording If recording is enabled on the number, both inbound and outbound calls are recorded. Recordings are retained per your account's retention settings — see [Admin Guide → Billing](/admin-guide/billing/index) for storage implications. Call recording laws vary by jurisdiction. In some regions you must notify or obtain consent from both parties. Check local requirements before enabling recording. ## Name and display The **Name** field is how the number appears in the ShingleAI UI — it's internal only. Outbound caller ID is set by Telnyx at the provider level. ## Removing a phone number Phone number removal releases the number back to Telnyx (or disconnects it if it's a BYO number). Contact support if you need to remove a number — the current UI does not expose self-serve deletion. ## Next steps Where inbound SMS and voice events land See what you've bought # Phone Numbers Source: https://docs.shingleai.com/user-guide/phone-numbers/index Buy and configure phone numbers in ShingleAI for voice and SMS ShingleAI provisions phone numbers through [Telnyx](https://telnyx.com). Once a number is attached to your organization, you can route calls, record voice, and send and receive SMS through the [inbox](/user-guide/email/inbox). Phone numbers list ## What you can do | Action | Where | | --------------------------------- | ---------------------------------------------------------------------------- | | Search for and buy a number | Inbox Setup Wizard → phone option, or Purchases → **Purchase Phone Numbers** | | Add a number you already own | **Phone Numbers** → **Add Phone Number** | | Configure SMS / voice / voicemail | Phone number detail page | | See purchase history | [Purchases](/user-guide/purchases/index) | ## Next steps Search Telnyx and check out via Stripe Voice mode, SMS, voicemail, recording # Purchases Source: https://docs.shingleai.com/user-guide/purchases/index History of phone-number purchases and other account-level buys in ShingleAI The **Purchases** page is your record of what you've bought through ShingleAI — phone numbers today, with additional product lines rolling out. Purchases dashboard ## What's tracked here | Product | Available today | Where to buy | | -------------------------- | --------------- | ----------------------------------------------------------------- | | Phone numbers | ✅ | Purchases → **Purchase Phone Numbers**, or the inbox setup wizard | | Brand registration (10DLC) | Coming soon | — | | Campaign setup (10DLC) | Coming soon | — | **Domain registrations are not in Purchases.** Domains have their own flow on the [Domains](/user-guide/domains/register) page. This is intentional — Domains are account resources that persist and renew, while Purchases captures one-off buys of consumable or single-use items. ## The purchase history list Each row shows: | Column | Notes | | ----------- | ---------------------------------------------- | | **Type** | Phone numbers, brand, campaign | | **Date** | When you checked out | | **Items** | Phone numbers (or names) purchased | | **Amount** | Total charged in USD | | **Status** | `completed`, `processing`, `failed`, `pending` | | **Actions** | View details | ### Filters * **Search** — matches against item names / phone numbers * **Type** — filter to a specific product line ## Status banner The index shows a status banner when you land after a checkout: | URL param | Banner | | ------------- | ------------------------------------ | | `?success=1` | Success confirmation | | `?canceled=1` | You canceled checkout | | `?error=...` | Something went wrong during checkout | ## Making a purchase Click **Purchase Phone Numbers** to start the phone-number buy flow. See [Phone Numbers → Buying](/user-guide/phone-numbers/buying) for the full walkthrough. Brand and Campaign flows are stubbed in the UI and not yet functional. The tiles will activate once 10DLC support ships. ## Next steps Current purchase flow Payment methods and invoices # Setup Checklist Source: https://docs.shingleai.com/user-guide/setup-checklist/index Seven onboarding tasks that unlock the rest of ShingleAI The Setup Checklist is a home-page widget that tracks the seven things worth doing when you first join an organization. It auto-completes as you work — most tasks finish when you create the matching entity somewhere else in the product. Setup checklist widget on the home page ## The seven tasks | # | Task | What it asks you to do | Auto-completes when | | - | --------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | 1 | **Business profile** | Fill in your business name, description, and industries | You save the [Business profile](/user-guide/businesses/profile) | | 2 | **Connect email** | Connect a Google or Microsoft account, or create an address on a verified domain | You add any [email address](/user-guide/email-addresses/index) | | 3 | **Add domain** | Verify ownership of a domain, or register one through ShingleAI | You add a [domain](/user-guide/domains/index) | | 4 | **Connect phone** | Buy a phone number through Telnyx | You add a [phone number](/user-guide/phone-numbers/index) | | 5 | **Add contact** | Create your first contact record | You add a [contact](/user-guide/contacts/index) | | 6 | **Create automation** | Write a natural-language automation | You create an [automation](/user-guide/automations/index) | | 7 | **Invite team** | Send an invitation to a team member | You invite an [organization member](/admin-guide/organization/users) | ## How the widget behaves ### The first pending task is expanded The top pending task is shown with its full description and a large **Open** button that takes you to the right page. Remaining pending tasks appear as collapsed rows underneath. ### Completed tasks vanish silently There is no "Setup complete!" message. When you finish a task — by creating the matching entity — it disappears from the list. When all seven are done, the widget disappears from the home page entirely. ### Manual actions (Owner and Admin only) If you have the **Owner** or **Admin** role, each pending task also shows: * **Mark done** — complete the task without creating the entity, useful when you finished it through another path (for example, you imported a contact via API before opening the web app). * **Dismiss** — hide the task. Dismissed tasks move into a **View dismissed** section at the bottom of the widget, where you can **Restore** them later. Users without the manage-setup-tasks permission see the same list but without these buttons — the tasks still auto-complete based on entity creation. Auto-completion runs regardless of your role. Even a regular user can finish the entire checklist just by using the product; the manual buttons only exist for Owner/Admin edge cases. ## When the widget appears * **At least one task pending:** the widget renders on the home page. * **All tasks completed:** the widget is hidden. The home page shows other dashboards (Eisenhower matrix, recent activity, etc.) in its place. * **Brand-new org with no tasks yet:** the widget renders with all seven tasks pending. ## Next steps Start with task 1 Work on task 2 # Eisenhower Widget Source: https://docs.shingleai.com/user-guide/tasks/eisenhower-widget The urgency × importance priority matrix on your ShingleAI home page The Eisenhower widget is a 2×2 grid on your home page that groups active tasks by **urgency** and **importance**. It's the fastest way to see what to work on next. Home-page Eisenhower matrix ## The four quadrants | | High importance | Low importance | | ---------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- | | **High urgency** | **Do** — top-left, crisis and deadlines | **Delegate** — top-right, interruptions and batchable work | | **Low urgency** | **Schedule** — bottom-left, strategic work worth planning time for | **Eliminate** — bottom-right, candidates to drop | A task's quadrant is purely a function of the importance and urgency fields you set on it. Change either field and the task moves accordingly. ## What the widget shows * Up to **50 tasks** across the four active statuses: `backlog`, `todo`, `in_progress`, `in_review`. * Each quadrant lists the tasks that fall into it, with title, status badge, and due date if one is set. * Clicking a task takes you to its detail page. ## When the widget is visible * **At least one qualifying task:** the widget renders on the home page. * **No qualifying tasks:** the widget is hidden. Create your first task from the [Tasks page](/user-guide/tasks/managing) and it will appear. ## Tips for the quadrants * Treat **Do** as a "today" list — if it stays crowded, importance or urgency probably needs re-evaluating. * Put recurring strategic work in **Schedule** and actually block calendar time for it. * **Delegate** is where to hand work off when that's an option. * If **Eliminate** keeps filling up, consider whether those tasks belong anywhere at all. ## Next steps Create and edit tasks Auto-create tasks from incoming email # Tasks Source: https://docs.shingleai.com/user-guide/tasks/index Track work in ShingleAI with a priority matrix based on urgency and importance Tasks in ShingleAI are lightweight to-do items that integrate with the rest of your workspace — they can be created manually, surfaced from emails by automations, or produced by agents while they work. Each task is scored on two axes — **urgency** and **importance** — which place it in one of four quadrants on the home-page Eisenhower matrix. Tasks list page ## The priority matrix The urgency × importance matrix sorts work by whether it needs your attention *now* and whether it moves the needle. | | High importance | Low importance | | ---------------- | ---------------------------------- | --------------------------------- | | **High urgency** | **Do** — do these first | **Delegate** — hand off or batch | | **Low urgency** | **Schedule** — plan time for these | **Eliminate** — consider dropping | Set urgency and importance when you create a task. Change them anytime as priorities shift. ## Task fields | Field | Required | Notes | | --------------- | -------- | ------------------------------------------------------------------------------------------- | | **Title** | Yes | Short summary — this is what shows in lists | | **Description** | No | Longer context | | **Status** | Yes | Defaults to `todo` — see [statuses](#statuses) | | **Importance** | Yes | Low, Medium, or High | | **Urgency** | Yes | Low, Medium, or High | | **Due date** | No | ISO date — no default | | **Category** | No | One of: Bug Fix, Documentation, Feature Request, Meeting, Other, Planning, Research, Review | ## Statuses Tasks move through six statuses: | Status | Meaning | | ------------- | --------------------------------- | | `backlog` | Captured but not worked yet | | `todo` | Ready to pick up | | `in_progress` | Actively being worked on | | `in_review` | Waiting on review or confirmation | | `done` | Completed | | `cancelled` | Won't be done | The home-page matrix widget shows tasks in the four active statuses (`backlog`, `todo`, `in_progress`, `in_review`). ## Next steps Create, edit, filter, and search tasks The home-page priority matrix # Managing Tasks Source: https://docs.shingleai.com/user-guide/tasks/managing Create, edit, filter, and search tasks in ShingleAI This guide covers the task list, the create form, and the detail page. ## Creating a task 1. Go to **Tasks** in the sidebar. 2. Click **Create Task**. 3. Fill in the form: * **Title** (required) * **Description** (optional) * **Category** (optional) — Bug Fix, Documentation, Feature Request, Meeting, Other, Planning, Research, or Review * **Importance** — Low, Medium, or High * **Urgency** — Low, Medium, or High * **Due date** (optional) * **Status** — defaults to `todo` 4. Click **Save**. Create task modal The task appears in the list and — if its status is active — in the home-page [Eisenhower widget](/user-guide/tasks/eisenhower-widget). ## The task list The tasks index page is a data table with a filter sidebar. ### Filters | Filter | Behavior | | -------------- | -------------------------------------------------------------------------------- | | **Search** | Matches against both task title and description | | **Category** | Select one or more categories | | **Status** | Any subset of `backlog`, `todo`, `in_progress`, `in_review`, `done`, `cancelled` | | **Importance** | Any subset of Low, Medium, High | | **Urgency** | Any subset of Low, Medium, High | ### Sorting Sort by: * **Title** * **Due date** * **Created at** Each sort supports ascending or descending order. ## The task detail page Click any task to open its detail page. The page has three tabs: | Tab | Contents | | ------------ | ----------------------------------------------------------------------- | | **Overview** | Title, description, status, priority, due date, category — all editable | | **Activity** | Timeline of status changes, edits, and system events | | **Settings** | Delete the task | Changes saved on the Overview tab take effect immediately and are recorded in Activity. ## Deleting a task 1. Open the task. 2. Go to the **Settings** tab. 3. Click **Delete**. 4. Confirm. Deleted tasks are soft-deleted — they're hidden from the UI but the history remains. Contact support if you need to restore one. ## Next steps See tasks grouped by urgency × importance Have an automation create tasks from emails