# 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.
## 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.
## 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.
## 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.
## 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 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.
## 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**
## 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.
## 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.
## 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.
## 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.
## 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.
## 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
### 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.
## 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.
## 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.
## 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.
## 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.
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**.
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.
## 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.
## 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.
## 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 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 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.
## 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.
## 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.
## 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.
## 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.
## 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.
## 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).
## 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.
## 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.
## 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.
## 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.
## 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**.
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