feat(credentials): token-paste service accounts for 12 providers (#5682)

* feat(credentials): token-paste service accounts for 12 providers (HubSpot, Airtable, Notion, Asana, Attio, Linear, monday, Shopify, Webflow, Trello, Cal.com, Wealthbox)

* refactor(credentials): registry-dispatch service accounts + doc-verified validator hardening

- Migrate Google/Atlassian/Slack service-account branches to the same
  registry pattern as token-paste providers (builder + resolver maps,
  unified required-fields contract validation)
- Fix Shopify service-account store domain never reaching tool URL builders
- Linear: rate-limit 400s no longer mislabeled as invalid credentials;
  validation header matches runtime header rule
- Trello: server API key rejection no longer blamed on customer token
- Fleet-wide: network errors and non-JSON provider bodies map to
  provider_unavailable via shared fetchProvider/parseProviderJson
- HubSpot: drop regional-host displayName upgrade; Wealthbox: explicit 402;
  monday: provider-side GraphQL errors mapped correctly; Attio: null-body guard

* polish(credentials): ship-gate fixes, setup-guide docs, and lint pass for token service accounts

- 12 setup-guide docs pages (docs.sim.ai/integrations/<provider>-service-account)
  incl. the Trello authorize-link flow the integration depends on
- Attio: HTTP 400 on /v2/self maps to invalid_credentials (live-verified)
- monday: scan all GraphQL errors for provider-side codes; no empty audit ids
- Compile-time descriptor/validator lockstep (typed registry) and
  prototype-safe provider-id guard (Object.hasOwn)
- Shared errors.test.ts pinning fetchProvider/parseProviderJson/
  throwForProviderResponse guarantees for all validators
- Stale TSDoc updated after the registry migration; biome organizeImports pass

* docs(credentials): vendor-doc accuracy pass on service-account setup guides

34 corrections from a 12-agent audit against live official vendor docs:
current HubSpot Development-area nav, Notion connections rename, monday
Developer Center paths, Shopify legacy-vs-Dev-Dashboard token flows, and
hedged wording for claims vendors do not document (expiry, limits)

* improvement(credentials): vendor-accurate credential nouns on connect surfaces

'Add service account' only where the vendor actually has service accounts
(Google, Atlassian); token-paste providers now use their own vocabulary via a
connectNoun descriptor field — 'Add private app token' (HubSpot), 'Add API key'
(Attio/Linear/Cal.com), 'Add personal access token' (Airtable), etc. Docs page
titles updated to match; slugs and internal provider ids unchanged

* fix(credentials): classify auth-shaped Shopify GraphQL errors as invalid credentials

Shopify can reject invalid or revoked shpat_ tokens with HTTP 200 and a
GraphQL error body instead of a 401; those now map to invalid_credentials
instead of a provider-outage message

* fix(credentials): empirically-grounded HubSpot token verification

Live probing showed the documented access-token-info route returns a bare
404 for unrecognized tokens (ambiguous with a missing route), so 404/400
now falls back to the Account Information API, which answers with a JSON
401 for rejected tokens and 200/403 for live ones — verified against the
real endpoints

* fix(credentials): review-round-2 fixes for service-account edge cases

- Shopify tools prefer the credential-validated store domain over the
  block's auto-detected shopDomain (a store-bound token must hit its own store)
- Unknown non-empty service-account providerIds are rejected instead of
  silently persisting as google-service-account (empty stays the legacy
  Google fallback)
- Shopify/modal domain normalization strips URL paths ('https://x.myshopify.com/admin')
- monday: warning-class GraphQL errors no longer reject a token whose me
  data proves it authenticated

* chore(credentials): format shopify validator test

* fix(credentials): cold-review hardening pass

- Object.hasOwn guards on all provider-id registry lookups (crafted
  '__proto__'/'constructor' providerIds now 400 instead of 500) + regression test
- fetchProvider gets a 10s AbortSignal.timeout so a hung provider can't pin
  the create/reconnect request
- HubSpot: unexpected 403 on the token-info route defers to the account-info
  fallback instead of blaming the token
- Linear selector routes use the SDK apiKey option for lin_api_ keys (bare
  header parity with the tools sweep)
- Docs: UI steps aligned to the vendor-noun connect labels; HubSpot
  scope-propagation claims softened; Trello in-product-link promise corrected
This commit is contained in:
Waleed
2026-07-14 22:52:50 -07:00
committed by GitHub
parent 92549844c0
commit 00a2f26fe5
157 changed files with 5489 additions and 241 deletions
@@ -0,0 +1,108 @@
---
title: Airtable Personal Access Tokens
description: Set up an Airtable personal access token with scoped base access to use Airtable in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
Airtable personal access tokens (PATs) let your workflows authenticate to Airtable with a token that has explicit scopes and explicit base access — instead of a person's OAuth login. The token never expires on its own, and what it can touch is decided at creation time.
On Airtable Enterprise Scale plans, admins can create the same tokens from a dedicated **service account** in the Admin Panel. Those tokens are wire-identical to personal access tokens and are the better choice for organization-level use: they don't stop working when an employee leaves.
## Prerequisites
Any Airtable user can create a personal access token for the bases they have access to. Keep in mind the token is capped by its creator's own permissions — a PAT created by a read-only collaborator cannot write, no matter which scopes it has. Create the token from an account with the access level your workflows need.
For service-account tokens, you need an Enterprise Scale plan and an admin with access to the Admin Panel.
## Creating the Token
<Steps>
<Step>
Open [airtable.com/create/tokens](https://airtable.com/create/tokens) and click **Create token**
{/* TODO(screenshot): Airtable token builder page with the "Create token" button */}
</Step>
<Step>
Give the token a name (e.g. `sim-airtable-bot`)
</Step>
<Step>
Add the scopes your workflows need. The full set Sim's Airtable tools and triggers use is:
```
data.records:read
data.records:write
schema.bases:read
user.email:read
webhook:manage
```
Reading records needs `data.records:read`; creating, updating, upserting, and deleting records need `data.records:write`; listing bases and tables and reading base schemas need `schema.bases:read`; `user.email:read` lets Sim show the token owner's email as the credential name; and `webhook:manage` is only needed if you use Airtable triggers in Sim.
{/* TODO(screenshot): token builder scopes section with the five scopes added */}
</Step>
<Step>
Under **Access**, add the bases or entire workspaces the token should reach. The token can only see what you list here — a token with all five scopes but no base access can't read anything.
{/* TODO(screenshot): token builder access section with a workspace added */}
</Step>
<Step>
Click **Create token** and copy it when it's shown. Airtable only displays it once — if you close the dialog, you'll have to regenerate it.
</Step>
</Steps>
<Callout type="warn">
The token is bearer credentials for every base you granted. Treat it like a password — do not commit it to source control or share it publicly. Sim encrypts the token at rest.
</Callout>
### Enterprise Scale: Service Account Tokens
On Enterprise Scale plans, an admin can create up to 30 service accounts (raisable via Airtable support) from the Admin Panel, each with its own name and email. From a service account's **Personal access tokens** panel, the admin creates tokens with the same scopes-plus-base-access builder shown above. The resulting token works in Sim exactly like a user PAT — same format, same `pat…` prefix, same behavior — but it belongs to the organization, not a person, so it survives employee offboarding. If your plan supports it, prefer this over a user-created PAT.
<Callout type="info">
Enterprise organizations can enable "Block API access to organization-owned bases and workspaces". If your organization uses this setting, the service account must be allowlisted or every call fails despite a valid token.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Airtable Service Account" and click it, then click **Add to Sim** and choose **Add personal access token**
{/* TODO(screenshot): Integrations page with "Airtable Service Account" in the service list */}
</Step>
<Step>
Paste the **Personal access token**, and optionally set a display name and description
{/* TODO(screenshot): Add Airtable personal access token dialog with the personal access token filled in */}
</Step>
<Step>
Click **Add personal access token**. Sim verifies the token by calling Airtable's `whoami` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
<Callout type="warn">
Validation only proves the token is real — Airtable doesn't expose a PAT's scopes or base access for inspection. A token that validates fine can still fail every tool call if you skipped a scope or forgot to grant base access. If a block returns a 403 (`INVALID_PERMISSIONS`) or an unexpected 404 (`NOT_FOUND`), check the token's scopes and base access first.
</Callout>
## Using the Service Account in Workflows
Add an Airtable block to your workflow. In the credential dropdown, your Airtable service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Airtable block in a workflow with the Airtable service account selected as the credential */}
The block calls `api.airtable.com` using the token — exactly the same requests as the OAuth flow, so every Airtable tool works unchanged, limited to the scopes and bases you granted.
<FAQ items={[
{ question: "Why a personal access token instead of OAuth?", answer: "PATs don't expire and don't depend on any user staying logged in or re-consenting. You decide scopes and base access once at creation, and the token is stable until you regenerate or delete it — which is what you want for an automated workflow." },
{ question: "What's the difference between a user PAT and a service-account PAT?", answer: "Nothing on the wire — both are the same token format and behave identically in Sim. The difference is ownership: a user PAT dies with the user's base access (or when they leave the org), while a service-account PAT (Enterprise Scale, created in the Admin Panel) belongs to the organization." },
{ question: "My token validates but every block fails with 403 or 404 — why?", answer: "The token is missing a scope or, more commonly, base access. Airtable deliberately blurs the two: an unauthorized base can return 403 INVALID_PERMISSIONS or a plain 404 NOT_FOUND. Edit the token at airtable.com/create/tokens and check both the scopes list and the Access section." },
{ question: "Do tokens expire?", answer: "No. Airtable PATs remain active indefinitely until they're manually deleted, regenerated, or modified. A user PAT also stops working if its creator loses access to the granted bases or leaves the organization." },
{ question: "How do I rotate the token?", answer: "Create a new token with the same scopes and base access, update the credential in Sim with the new token, and once it's working, delete the old one. Note that regenerating an existing token invalidates the old value immediately." },
{ question: "Do I need the webhook:manage scope?", answer: "Only if you use Airtable triggers in Sim — the trigger creates and manages webhooks on your base. For workflows that only read and write records, you can omit it." },
]} />
@@ -0,0 +1,114 @@
---
title: Asana Service Accounts & Personal Access Tokens
description: Connect Asana to Sim with a service account token or a personal access token from a dedicated bot account
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Asana service accounts let your workflows authenticate as a non-human bot identity instead of a person's account. The service account has its own name and its own token, managed centrally by a super admin — no one person's OAuth consent to expire, and access can be revoked without touching anyone's personal account.
There are two ways to get a token, and both work in Sim:
- **Service account token** (recommended for teams) — available on Asana **Enterprise** and **Enterprise+** plans, created by a super admin in the Admin Console.
- **Personal access token (PAT)** — available on any plan, created from any user account. For production workflows, create it from a dedicated bot account rather than a personal one.
Both token types use the same format and paste into the same field in Sim.
## Option A: Service Account Token (Enterprise / Enterprise+)
### Prerequisites
You need an Asana **super admin** on an **Enterprise** or **Enterprise+** plan. Service accounts are an organization-level feature — regular users cannot create them.
### Create the Service Account
<Steps>
<Step>
Open the Asana **Admin Console** and go to **Apps** → **Service accounts**
{/* TODO(screenshot): Asana Admin Console with Apps → Service accounts highlighted */}
</Step>
<Step>
Click **Add service account**, give it a name (e.g. `Sim Integration`) — this is the name that will appear on tasks and comments the workflows create
</Step>
<Step>
Grant the service account **Full Permissions**. Scoped service accounts (for example, ones limited to User Provisioning / SCIM) cannot call the standard Asana API and will fail when you connect them to Sim
{/* TODO(screenshot): service account permission picker with "Full Permissions" selected */}
</Step>
<Step>
Copy the token when it's shown. Asana only displays it once — if you lose it, you'll have to regenerate it — plan to update the credential in Sim at the same time, since the old token stops working once it's replaced.
</Step>
</Steps>
<Callout type="warn">
A service account with Full Permissions has org-wide access to all data in your Asana organization, including private projects. Treat the token like an admin password.
</Callout>
## Option B: Personal Access Token
If you're not on an Enterprise plan, a personal access token works identically on the wire. For production workflows, create a dedicated bot user account (e.g. `sim-bot@yourcompany.com`) and generate the PAT from that account — a PAT is tied to the user who created it, inherits only that user's permissions, and stops working if the user is deprovisioned.
<Steps>
<Step>
Log in as the bot account and open the developer console at [app.asana.com/0/my-apps](https://app.asana.com/0/my-apps)
{/* TODO(screenshot): Asana developer console "My apps" page with "Create new token" button */}
</Step>
<Step>
Click **+ Create new token**, give it a name that describes its use (e.g. `Sim Integration`), and click **Create token**
</Step>
<Step>
Copy the token immediately — Asana only shows it once.
</Step>
<Step>
Add the bot account to the workspaces and projects your workflows need. A PAT can only see what its user can see.
</Step>
</Steps>
## Adding the Token to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Asana Service Account" and click it, then click **Add to Sim** and choose **Add access token**
{/* TODO(screenshot): Integrations page with "Asana Service Account" in the service list */}
</Step>
<Step>
Paste the token — service account token or personal access token, both work in the same field — and optionally set a display name and description
{/* TODO(screenshot): Add Asana access token dialog with the access token filled in */}
</Step>
<Step>
Click **Add access token**. Sim verifies the token by calling Asana's `/users/me` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
<Callout type="info">
If a brand-new token fails validation with an authentication error, wait a few minutes and try again — newly created service account tokens can take a short time to become active.
</Callout>
The token is encrypted before being stored.
## Using the Service Account in Workflows
Add an Asana block to your workflow. In the credential dropdown, your Asana service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Asana block in a workflow with the service account selected as the credential */}
The block calls the Asana API (`app.asana.com/api/1.0`) with the token as a standard Bearer credential. There's no impersonation step — the token acts as itself: the service account identity, or the bot user for a PAT.
<FAQ items={[
{ question: "What's the difference between a service account token and a personal access token?", answer: "A service account is an org-level bot identity with its own name and (with Full Permissions) org-wide access — it isn't tied to any person. A PAT is tied to the user who created it, inherits only their permissions, and breaks if that user is deactivated. Both use the same token format and paste into the same field in Sim; prefer the service account for team use if your plan supports it." },
{ question: "Why does my scoped service account fail to connect?", answer: "Scoped service accounts (e.g. limited to User Provisioning / SCIM) can't call the standard Asana API, so Sim's validation call fails. Ask your super admin to create the service account with Full Permissions." },
{ question: "Does the token expire?", answer: "No scheduled expiry — the token is long-lived until a super admin revokes or regenerates it (for a PAT, until the user deletes it or is deprovisioned). If a working credential suddenly starts failing with 401 errors, the token was revoked; paste a new one." },
{ question: "How do I rotate the token?", answer: "Regenerate the service account token in the Admin Console, then update the credential in Sim with the new token right away — the old token stops working once it's replaced, so expect a brief window of failed runs if workflows execute in between." },
{ question: "Do I need to enter a workspace or domain?", answer: "No. Asana has a single API host, and Sim's Asana blocks take workspace and project IDs as block parameters — the token is all the credential needs." },
{ question: "Will one shared token hit rate limits?", answer: "Asana rate-limits per token, so all workflows sharing one service account token draw from a single rate-limit bucket. If you run heavy concurrent workloads, watch for 429 responses and consider splitting workloads across tokens." },
]} />
@@ -0,0 +1,102 @@
---
title: Attio API Keys
description: Connect Attio to Sim with a workspace API key — a workspace-level, non-expiring access token with admin-chosen scopes
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Attio workspace API keys let your workflows authenticate at the workspace level instead of through a person's account. The key is created by a workspace admin, belongs to the workspace rather than any individual, and does not expire — no one person's OAuth consent to lapse, and access can be revoked at any time by deleting the key.
## Prerequisites
You need an Attio **workspace admin**. Only admins can create and manage access tokens.
## Creating the API Key
<Steps>
<Step>
Open **Workspace settings** in Attio (dropdown beside your workspace name) and go to the **Developers** tab
{/* TODO(screenshot): Attio workspace settings with the Developers tab highlighted */}
</Step>
<Step>
Click **New access token** and give it a name (e.g. `Sim Integration`)
</Step>
<Step>
Select the scopes the key needs. To match everything Sim's Attio blocks can do, grant:
```
record_permission (read-write)
object_configuration (read-write)
list_configuration (read-write)
list_entry (read-write)
note (read-write)
task (read-write)
comment (read-write)
user_management (read)
webhook (read-write)
```
Record and object tools need `record_permission` plus `object_configuration`; list tools need `list_configuration` and `list_entry`; note, task, comment, and webhook tools need their respective scopes; member lookups need `user_management:read`.
{/* TODO(screenshot): Attio access token scope picker with the scopes above selected */}
</Step>
<Step>
Copy the key and store it somewhere safe.
</Step>
</Steps>
<Callout type="info">
Scopes are editable after creation — if a workflow later fails with a permission error, an admin can add the missing scope to the existing key in the Developers settings without rotating it.
</Callout>
<Callout type="warn">
The API key is bearer credentials for your Attio workspace. Treat it like a password — do not commit it to source control or share it publicly. Sim encrypts the key at rest.
</Callout>
## Adding the API Key to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Attio Service Account" and click it, then click **Add to Sim** and choose **Add API key**
{/* TODO(screenshot): Integrations page with "Attio Service Account" in the service list */}
</Step>
<Step>
Paste the API key and optionally set a display name and description
{/* TODO(screenshot): Add Attio API key dialog with the API key filled in */}
</Step>
<Step>
Click **Add API key**. Sim verifies the key by calling Attio's `/v2/self` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The key is encrypted before being stored.
<Callout type="warn">
A key with missing scopes still validates successfully — the validation endpoint is reachable with any live key. Check the scopes granted to the key in Attio: tools whose scopes are missing will fail at run time with permission errors.
</Callout>
## Using the Service Account in Workflows
Add an Attio block to your workflow. In the credential dropdown, your Attio service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Attio block in a workflow with the service account selected as the credential */}
The block calls the Attio API (`api.attio.com/v2`) with the key as a standard Bearer credential, with whatever scopes the admin granted the key.
<FAQ items={[
{ question: "Does the API key expire?", answer: "No — Attio access tokens do not expire. They stay valid until a workspace admin deletes them, which revokes access immediately." },
{ question: "Can a regular user create an API key?", answer: "No. Only workspace admins can create and manage access tokens. Ask a workspace admin to create the key for you." },
{ question: "My key connected fine but a block fails with a permission error — why?", answer: "The key is missing a scope. Validation only checks that the key is alive, not which scopes it carries. Have an admin open the key in Workspace settings → Developers and add the missing scope — scopes are editable after creation, no rotation needed." },
{ question: "Do I need to enter a workspace domain?", answer: "No. Attio has a single API host and the key itself identifies the workspace — the key is all the credential needs." },
{ question: "How do I rotate the key?", answer: "Create a new access token with the same scopes in Attio, update the credential in Sim with the new key, and once it's working, delete the old token." },
{ question: "Is the key tied to the admin who created it?", answer: "The key belongs to the workspace, not the creating admin's user account — it keeps working regardless of who created it, until it's deleted." },
]} />
@@ -0,0 +1,82 @@
---
title: Cal.com API Keys
description: Set up a Cal.com API key to use Cal.com in Sim workflows without OAuth
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
Cal.com service account credentials let your workflows authenticate to Cal.com with a pasted API key instead of a personal OAuth connection. The key carries the full permissions of the Cal.com user who created it, and it stays valid until it expires or is revoked — no OAuth consent to renew.
## Prerequisites
You need a Cal.com account (cal.com cloud). Any user can create API keys from their own settings — no admin role required.
<Callout type="info">
Cal.com API keys are tied to the user who creates them. For production workflows, create the key from a dedicated service login (e.g. `sim-bot@yourcompany.com`) rather than a personal account — the credential then survives any individual employee leaving, and bookings and event types the workflows manage belong to the bot user.
</Callout>
## Creating the API Key
<Steps>
<Step>
Log in to Cal.com and go to **Settings** → **Developer** → **API keys** (direct link: [app.cal.com/settings/developer/api-keys](https://app.cal.com/settings/developer/api-keys))
{/* TODO(screenshot): Cal.com settings Developer section with the API keys page open */}
</Step>
<Step>
Click **+ Add**, give the key a name (e.g. `sim-workflows`), and set its expiry. Choose a non-expiring key if the option is available — otherwise pick the longest expiry offered and note the date so you can rotate before it lapses
{/* TODO(screenshot): Cal.com create API key dialog with name and expiry fields */}
</Step>
<Step>
Copy the key when it's shown. Cal.com only displays it once — if you close the dialog, you'll have to create a new key.
</Step>
</Steps>
Live-mode keys start with `cal_live_`; test-mode keys start with `cal_`. Either form is accepted.
<Callout type="warn">
The API key carries the full privileges of the user who created it — there is no scope selection. Treat it like a password: do not commit it to source control or share it publicly. Sim encrypts the key at rest.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Cal.com Service Account" and click it, then click **Add to Sim** and choose **Add API key**
{/* TODO(screenshot): Integrations page with "Cal.com Service Account" in the service list */}
</Step>
<Step>
Paste the API key, and optionally set a display name and description
{/* TODO(screenshot): Add Cal.com API key dialog with the API key filled in */}
</Step>
<Step>
Click **Add API key**. Sim verifies the key by calling Cal.com's `/v2/me` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The key is encrypted before being stored.
## Using the Service Account in Workflows
Add a Cal.com block to your workflow. In the credential dropdown, your Cal.com service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Cal.com block in a workflow with the Cal.com service account selected as the credential */}
The block calls Cal.com's API (`api.cal.com/v2`) with the key. The credential acts as the Cal.com user who created the key — bookings, event types, and schedules the workflows touch are the ones that user can see and manage.
<FAQ items={[
{ question: "Why an API key instead of OAuth?", answer: "API keys don't require any user to sit through a consent flow, and they stay valid until they expire or are revoked — which is what you want for an automated workflow. OAuth connections are tied to one person's session and consent." },
{ question: "Do Cal.com API keys have scopes?", answer: "No — a key carries the full permissions of the user who created it. There's nothing to select at creation time, and no Cal.com block in Sim can fail for missing scopes. Permission errors only arise from resource ownership, e.g. confirming a booking the key's user doesn't host." },
{ question: "What happens when the key expires?", answer: "Workflows using the credential start failing with authentication errors. Create a new key from the same Cal.com account, update the credential in Sim, and delete the expired key. If you couldn't create a non-expiring key, set a reminder before the expiry date you chose." },
{ question: "Can I use a test-mode (cal_) key?", answer: "It will validate, but test-mode keys may not behave like live keys on booking operations. Use a cal_live_ key for production workflows." },
{ question: "Does this work with self-hosted Cal.com?", answer: "No — Sim's Cal.com blocks call the cal.com cloud API (api.cal.com). Self-hosted Cal.com instances expose their own API host and are not supported by this credential." },
{ question: "How do I rotate the key?", answer: "Create a new key from Settings → Developer → API keys, update the credential in Sim with the new key, and once it's working, delete the old one in Cal.com." },
]} />
@@ -0,0 +1,141 @@
---
title: HubSpot Private App Tokens
description: Set up a HubSpot private app with a scoped access token to use HubSpot in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
HubSpot private apps let your workflows authenticate to HubSpot with a portal-level access token instead of a person's OAuth login. A super admin creates the app once, picks exactly the scopes it needs, and the token stays valid until it's rotated or revoked — no OAuth consent to expire, and permissions that are auditable from HubSpot's settings.
This is the recommended way to use HubSpot in production workflows: the token doesn't auto-expire, its scopes are explicit, and it can be rotated on a schedule without touching anyone's personal account.
## Prerequisites
You need a HubSpot **super admin** to create the private app. Private apps can only be created and managed by super admins in the portal.
<Callout type="warn">
The token is tied to the super admin who created the private app. If that user is later removed from the portal (or loses super admin), some API calls start failing with `USER_DOES_NOT_HAVE_PERMISSIONS` — association calls are commonly reported. Create the app from an account you expect to keep, and rotate the token if the creator ever leaves.
</Callout>
## Setting Up the Private App
### 1. Create the Private App
<Steps>
<Step>
In HubSpot, navigate to **Development** in the left sidebar, then **Legacy apps**
{/* TODO(screenshot): HubSpot navigation showing Development → Legacy apps */}
<Callout type="info">
HubSpot moved private apps under a new **Development** area and relabeled them "Legacy apps". The tokens themselves remain fully supported — only the navigation changed. If you don't see **Development**, look for **Private Apps** under **Settings** → **Integrations** in older portals.
</Callout>
</Step>
<Step>
Click **Create legacy app** in the top right, select **Private**, and give it a name (e.g. `sim-hubspot-bot`) and description
</Step>
<Step>
Open the **Scopes** tab and select the scopes your workflows need (see the list below)
{/* TODO(screenshot): private app Scopes tab with CRM scopes selected */}
</Step>
<Step>
Click **Create app**, confirm, and copy the access token from the app's **Auth** tab
{/* TODO(screenshot): private app Auth tab showing the access token with the Show/Copy controls */}
</Step>
</Steps>
### 2. Choose Scopes
Private apps use the same scope catalog as HubSpot OAuth apps. Grant only what your workflows use. The full set Sim's HubSpot tools can draw on is:
**CRM objects (read/write as needed):**
```
crm.objects.contacts.read
crm.objects.contacts.write
crm.objects.companies.read
crm.objects.companies.write
crm.objects.deals.read
crm.objects.deals.write
crm.objects.line_items.read
crm.objects.line_items.write
crm.objects.appointments.read
crm.objects.appointments.write
crm.objects.owners.read
crm.objects.users.read
crm.objects.marketing_events.read
crm.objects.quotes.read
crm.objects.carts.read
```
**Tickets, emails, and lists:**
```
tickets
sales-email-read
crm.lists.read
crm.lists.write
```
Ticket tools need `tickets`, email tools need `sales-email-read`, list tools need `crm.lists.*`, and each object type's tools need its `crm.objects.*` scope. Notes and association tools need the CRM object scopes of the records involved. A missing scope surfaces at run time as a `403` error with category `MISSING_SCOPES` naming the scopes required — widen the app's scopes from the same Scopes tab, commit the change in HubSpot, and re-run the workflow. If the `403` persists, rotate the token and update the credential in Sim.
<Callout type="info">
Sim's OAuth flow also requests an `oauth` scope — that one is OAuth-app-only and doesn't exist for private apps. You don't need it and can't grant it.
</Callout>
### 3. Copy the Token
The token looks like `pat-na1-…` (North America) or `pat-eu1-…` (EU data residency). Both work — Sim calls `api.hubapi.com`, which serves both regions.
<Callout type="warn">
The access token is bearer credentials for your entire portal, limited only by its scopes. Treat it like a password — do not commit it to source control or share it publicly. Sim encrypts the token at rest.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "HubSpot Service Account" and click it, then click **Add to Sim** and choose **Add private app token**
{/* TODO(screenshot): Integrations page with "HubSpot Service Account" in the service list */}
</Step>
<Step>
Paste the **Private app access token**, and optionally set a display name and description
{/* TODO(screenshot): Add HubSpot private app token dialog with the private app access token filled in */}
</Step>
<Step>
Click **Add private app token**. Sim verifies the token against HubSpot's token-info endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
## Using the Service Account in Workflows
Add a HubSpot block to your workflow. In the credential dropdown, your HubSpot service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): HubSpot block in a workflow with the HubSpot service account selected as the credential */}
The block calls `api.hubapi.com` using the private app token — exactly the same requests as the OAuth flow, so every HubSpot tool works unchanged, subject to the scopes you granted.
## Rotating the Token
Private app tokens don't auto-expire, but HubSpot recommends rotating them every six months and emails super admins once a token hasn't rotated in about 180 days. From the app's Auth tab you can:
- **Rotate and expire now** — the old token dies immediately
- **Rotate and expire later** — the old token keeps working for 7 days while you migrate
Prefer the 7-day option: rotate in HubSpot, paste the new token into the credential in Sim, confirm your workflows run, and let the old token lapse.
<FAQ items={[
{ question: "Why a private app token instead of OAuth?", answer: "Private app tokens don't expire on their own and don't depend on any user staying logged in or re-consenting. A super admin issues them with explicit scopes, and they're stable until rotated — which is what you want for an automated workflow." },
{ question: "Can a regular user create a private app?", answer: "No. Only super admins can create and manage private apps in a HubSpot portal." },
{ question: "My token validates but a block fails with a 403 — why?", answer: "The private app is missing a scope that tool needs. The error names the required scopes (category MISSING_SCOPES). Add them on the app's Scopes tab in HubSpot, commit the change, and re-run the workflow. If the 403 persists, rotate the token and update the credential in Sim." },
{ question: "Does it matter that my token starts with pat-eu1- instead of pat-na1-?", answer: "No. The prefix reflects your portal's data residency region. Sim handles both — all requests go to api.hubapi.com, which serves both regions." },
{ question: "What happens if the super admin who created the app leaves?", answer: "The token keeps validating, but calls that check user permissions can start failing with USER_DOES_NOT_HAVE_PERMISSIONS — association calls are commonly reported. Have another super admin rotate the token (or recreate the app) and update the credential in Sim." },
{ question: "How do I rotate the token?", answer: "In the private app's Auth tab, choose Rotate and expire later (7-day grace), paste the new token into the credential in Sim, verify your workflows, and let the old token expire. Use Rotate and expire now only if the token may be compromised." },
]} />
@@ -0,0 +1,86 @@
---
title: Linear API Keys
description: Connect Linear to Sim with a personal API key — ideally created from a dedicated service user for production workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Linear personal API keys let your workflows authenticate without an OAuth consent flow. A key gives full parity with the Linear API — everything Sim's Linear blocks can do over OAuth works with a key.
Keys are bound to the user who creates them: every action a workflow takes is attributed to that user, and the key stops working if the user is deactivated or leaves the workspace. For production workflows, create the key from a dedicated service user (e.g. `sim-bot@yourcompany.com`) rather than a personal account.
## Prerequisites
A Linear account that is allowed to create API keys. Workspace admins can disable API-key creation for members (**Settings** → **Administration** → **API** → **Member API keys**) — if the option is missing for you, ask an admin, or have an admin create the key (the restriction doesn't apply to admins).
## Creating the API Key
<Steps>
<Step>
Log in as the service user, open Linear **Settings**, and go to **Security & access** → **Personal API keys**
{/* TODO(screenshot): Linear settings with Security & access → API keys highlighted */}
</Step>
<Step>
Click **New API key** and give it a label (e.g. `Sim Integration`)
</Step>
<Step>
Choose the key's permissions. For full parity with Sim's Linear blocks, create it with **full access** — or, if you restrict it, grant at least **Read** and **Write** with no team restriction. A key limited to specific teams will fail on issues and projects outside those teams
{/* TODO(screenshot): Linear API key creation dialog with permission options visible */}
</Step>
<Step>
Copy the key — it starts with `lin_api_` — and store it somewhere safe.
</Step>
</Steps>
<Callout type="warn">
The API key carries the creating user's full access to your Linear workspace. Treat it like a password — do not commit it to source control or share it publicly. Sim encrypts the key at rest.
</Callout>
## Adding the API Key to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Linear Service Account" and click it, then click **Add to Sim** and choose **Add API key**
{/* TODO(screenshot): Integrations page with "Linear Service Account" in the service list */}
</Step>
<Step>
Paste the API key (`lin_api_...`) and optionally set a display name and description
{/* TODO(screenshot): Add Linear API key dialog with the API key filled in */}
</Step>
<Step>
Click **Add API key**. Sim verifies the key by querying Linear's `viewer` — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
<Callout type="warn">
A key created with permission restrictions that block reading the viewer (the key's own user) is rejected at connect time. Create the key with full access, or at minimum Read + Write, so it validates and every block works.
</Callout>
The key is encrypted before being stored.
## Using the Service Account in Workflows
Add a Linear block to your workflow. In the credential dropdown, your Linear service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Linear block in a workflow with the service account selected as the credential */}
The block calls Linear's GraphQL API (`api.linear.app/graphql`) with the key. Everything the workflow does — creating issues, adding comments, updating projects — is attributed to the user who created the key.
<FAQ items={[
{ question: "Does Linear have real service accounts?", answer: "Not for API keys — every key is tied to a user. The closest equivalent is creating a dedicated service user in your workspace and generating the key from that account, so workflows aren't attributed to (or broken by) a real person's account." },
{ question: "Does the key expire?", answer: "No — keys are long-lived and don't auto-rotate. They stay valid until deleted, or until the user who created them is deactivated or removed from the workspace." },
{ question: "What happens if the key's user leaves the company?", answer: "Keys are user-bound, so deactivating the user kills the key and every workflow using it starts failing with authentication errors. This is exactly why production keys should come from a dedicated service user." },
{ question: "My key connected fine but write blocks fail with permission errors — why?", answer: "The key was created with restricted permissions — for example, Read only, or limited to specific teams. Validation checks that the key is alive and can read its own user, but write failures surface at run time. Create a new key with Read + Write and no team restriction, then update the credential in Sim." },
{ question: "Do I need to enter a workspace domain?", answer: "No. Linear has a single API host and the key itself identifies the workspace — the key is all the credential needs." },
{ question: "How do I rotate the key?", answer: "Create a new key from the same service user in Linear, update the credential in Sim with the new key, and once it's working, delete the old one." },
]} />
@@ -7,6 +7,7 @@
"agiloft",
"ahrefs",
"airtable",
"airtable-service-account",
"airweave",
"algolia",
"amplitude",
@@ -15,10 +16,12 @@
"appconfig",
"arxiv",
"asana",
"asana-service-account",
"ashby",
"athena",
"atlassian-service-account",
"attio",
"attio-service-account",
"azure_devops",
"box",
"brandfetch",
@@ -27,6 +30,7 @@
"browser_use",
"buffer",
"calcom",
"calcom-service-account",
"calendly",
"circleback",
"clay",
@@ -104,6 +108,7 @@
"greptile",
"hex",
"hubspot",
"hubspot-service-account",
"hubspot-setup",
"huggingface",
"hunter",
@@ -128,6 +133,7 @@
"leadmagic",
"lemlist",
"linear",
"linear-service-account",
"linkedin",
"linkup",
"linq",
@@ -146,12 +152,14 @@
"millionverifier",
"mistral_parse",
"monday",
"monday-service-account",
"mongodb",
"mysql",
"neo4j",
"neverbounce",
"new_relic",
"notion",
"notion-service-account",
"obsidian",
"okta",
"onedrive",
@@ -198,6 +206,7 @@
"sftp",
"sharepoint",
"shopify",
"shopify-service-account",
"similarweb",
"sixtyfour",
"slack",
@@ -219,6 +228,7 @@
"thrive",
"tinybird",
"trello",
"trello-service-account",
"trigger_dev",
"twilio",
"twilio_sms",
@@ -229,7 +239,9 @@
"vanta",
"vercel",
"wealthbox",
"wealthbox-service-account",
"webflow",
"webflow-service-account",
"whatsapp",
"wikipedia",
"wiza",
@@ -0,0 +1,98 @@
---
title: monday.com API Tokens
description: Set up a monday.com personal API token on a dedicated integration user to use monday.com in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
monday.com authenticates API calls with a personal API token — a long-lived token tied to a monday.com user. There is no separate org-level service account feature, so the standard practice is to create a dedicated integration user (e.g. `sim-bot@yourcompany.com`), give it access to the boards your workflows need, and generate the token from that seat.
This is the recommended way to use monday.com in production workflows: monday.com doesn't document a scheduled expiry for personal tokens, no one person's OAuth consent is involved, and the credential survives when an employee leaves.
## Prerequisites
Admins and members can generate their own API token (guests and viewers cannot) — for production use, create a dedicated integration-user seat first. A token generated from a personal account stops working if that person is deactivated.
<Callout type="warn">
The token's user must be **active**, **not view-only** (Viewer), and have a **confirmed email address**. Tokens from view-only or unconfirmed users are rejected by the monday.com API with a 403 error even though the token itself is valid.
</Callout>
## Setting Up the Token
### 1. Create a Dedicated Integration User (Recommended)
<Steps>
<Step>
Have a monday.com admin invite a new member with a shared email like `sim-bot@yourcompany.com` and confirm the email address
</Step>
<Step>
Add the integration user to every board your workflows will read or write. The token mirrors the user's board access exactly — a board the user can't see is a board the token can't touch
</Step>
</Steps>
### 2. Generate the Personal API Token
<Steps>
<Step>
Log in as the integration user, click your **profile picture** (top-right), and choose **Developers**
{/* TODO(screenshot): monday.com profile-picture menu with "Developers" highlighted */}
</Step>
<Step>
In the Developer Center, open the **API token** tab and click **Show** to reveal the token
{/* TODO(screenshot): Developer Center "API token" tab with the token revealed */}
</Step>
<Step>
Copy the token exactly as shown — monday.com doesn't document a fixed token format
</Step>
</Steps>
<Callout type="warn">
monday.com issues **one API token per user**. Regenerating it immediately invalidates the old token — every integration using it breaks at once, with no overlap window. Don't regenerate the token to "get a fresh copy"; reveal and copy the existing one instead.
</Callout>
There is no scope picker: personal API tokens carry **all** API permission scopes automatically. What limits the token is the user's own access — board membership, item visibility, and account permissions.
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "monday.com Service Account" and click it, then click **Add to Sim** and choose **Add API token**
{/* TODO(screenshot): Integrations page with "monday.com Service Account" in the service list */}
</Step>
<Step>
Paste the API token and optionally set a display name and description
{/* TODO(screenshot): Add monday.com API token dialog with the API token filled in */}
</Step>
<Step>
Click **Add API token**. Sim verifies the token by querying monday.com's `me` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The token is encrypted before being stored.
## Using the Service Account in Workflows
Add a monday.com block to your workflow. In the credential dropdown, your monday.com service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): monday.com block in a workflow with the service account selected as the credential */}
The block calls monday.com's single global API endpoint (`api.monday.com/v2`) using the token — there's no per-tenant domain to configure. The token acts as the user it was created by, with that user's board access.
<FAQ items={[
{ question: "Why a personal API token instead of OAuth?", answer: "Personal tokens don't expire on a schedule and don't depend on any user's OAuth consent staying valid. Generated from a dedicated integration user, they behave like a service account credential — stable until you deliberately regenerate or deactivate them." },
{ question: "Do I need to pick scopes for the token?", answer: "No. Personal API tokens carry all permission scopes automatically. Access is limited only by what the token's user can see and do in monday.com — board membership is your permission model." },
{ question: "Why do you recommend a dedicated integration user?", answer: "The token is bound to a user, and monday.com has no org-level token. If the token comes from an employee's personal account, it dies when that person is deactivated during offboarding. A dedicated seat like sim-bot@yourcompany.com survives team changes and makes the bot's activity auditable." },
{ question: "How do I rotate the token?", answer: "Carefully. monday.com allows only one token per user, and regenerating immediately kills the old one — there's no dual-token window. Regenerate in monday.com, then update the credential in Sim right away. Expect a brief outage for any workflows that run in between." },
{ question: "Why do my workflows fail on some boards but not others?", answer: "The token mirrors its user's board access. Add the integration user to the board in monday.com (with edit rights if the workflow writes), and the failing block will start working — no token change needed." },
{ question: "Does the token expire?", answer: "monday.com doesn't expire personal tokens on a schedule — they last until regenerated or until the user is deactivated. There's no official non-expiry guarantee, so treat a sudden 401 as a signal the token was regenerated or the user was deactivated." },
]} />
@@ -0,0 +1,114 @@
---
title: Notion Internal Integrations
description: Set up a Notion internal integration with an integration secret to use Notion in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
Notion internal integrations let your workflows authenticate to Notion as a workspace-owned bot user instead of through a person's OAuth login. The integration has its own secret, its own capabilities, and its own explicit list of pages and databases it can reach — all managed from the workspace's integration settings.
This is the recommended way to use Notion in production workflows: the secret doesn't depend on any employee's account, its capabilities are explicit, and access is granted page by page rather than inheriting one person's entire sidebar.
## Prerequisites
You need a Notion **workspace owner** to create the integration. Internal integrations are a workspace-level feature — only workspace owners can access the integrations settings and create them.
## Setting Up the Integration
### 1. Create the Internal Integration
<Steps>
<Step>
Open [notion.so/profile/integrations](https://www.notion.so/profile/integrations) (in Notion: **Settings** → **Connections** → **Develop or manage connections**) and create a new integration. Notion is renaming integrations to "connections" — newer workspaces see this at app.notion.com/developers/connections with a **Create a new connection** button.
{/* TODO(screenshot): Notion integrations page with the create-integration button */}
</Step>
<Step>
Give it a name (e.g. `sim-notion-bot`), pick the workspace it belongs to, and make sure you are creating an **internal** integration (the default; newer UIs list it under **Internal connections**)
</Step>
<Step>
Under **Capabilities**, enable what your workflows need:
- **Read content** — reading pages and blocks, querying and reading databases, search
- **Insert content** — creating pages and databases, adding database rows, appending blocks
- **Update content** — updating pages and blocks, deleting blocks
- **Comment capabilities** — creating and listing comments
- **User capabilities** — listing and reading workspace users (choose with or without email)
Enable only what you use — a read-only reporting workflow needs just Read content.
{/* TODO(screenshot): integration settings Capabilities section with content capabilities enabled */}
</Step>
<Step>
Save, then copy the integration's secret from its settings page — depending on your workspace's UI it is labeled **Internal Integration Secret** or **Installation access token** (under the **Configuration** tab). Secrets issued since September 2024 start with `ntn_`; older `secret_` tokens remain valid.
{/* TODO(screenshot): integration settings page showing the Internal Integration Secret with the Show/Copy controls */}
</Step>
</Steps>
<Callout type="warn">
The secret is bearer credentials for everything the integration is connected to. Treat it like a password — do not commit it to source control or share it publicly. Sim encrypts the secret at rest.
</Callout>
### 2. Connect the Integration to Pages and Databases
This step is the one everyone misses — and without it, the integration can read **nothing**. A brand-new integration has API access but zero page access; every page or database your workflows touch must be explicitly connected.
<Steps>
<Step>
Open a page or database your workflows need in Notion
</Step>
<Step>
Click the **•••** menu in the top-right, choose **Connections** (or **Add connections**), and select your integration
{/* TODO(screenshot): Notion page ••• menu with "Add connections" and the integration selected */}
</Step>
<Step>
Repeat for each top-level page or database. Connecting a page also grants access to all of its sub-pages.
</Step>
</Steps>
<Callout type="warn">
A valid secret with no page connections validates fine in Sim but returns `404 object_not_found` on every real call. If a Notion block reports that a page or database wasn't found — and you're sure the ID is right — the page isn't connected to the integration.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Notion Service Account" and click it, then click **Add to Sim** and choose **Add integration secret**
{/* TODO(screenshot): Integrations page with "Notion Service Account" in the service list */}
</Step>
<Step>
Paste the **Internal integration secret**, and optionally set a display name and description
{/* TODO(screenshot): Add Notion integration secret dialog with the internal integration secret filled in */}
</Step>
<Step>
Click **Add integration secret**. Sim verifies the secret by calling Notion's bot-user endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
## Using the Service Account in Workflows
Add a Notion block to your workflow. In the credential dropdown, your Notion service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Notion block in a workflow with the Notion service account selected as the credential */}
The block calls `api.notion.com` using the integration secret — exactly the same requests as the OAuth flow, so every Notion tool works unchanged, limited to the capabilities you enabled and the pages you connected.
<FAQ items={[
{ question: "Why an internal integration instead of OAuth?", answer: "The integration is owned by the workspace, not a person. No user has to stay logged in or re-consent, the secret has no documented expiry, and access survives employee offboarding. Capabilities and page connections are explicit and auditable." },
{ question: "Can a regular member create an internal integration?", answer: "No. Only workspace owners can access the integrations settings and create internal integrations." },
{ question: "My secret validates but blocks return 404 object_not_found — why?", answer: "The page or database isn't connected to the integration. Validation only proves the secret is real; it says nothing about page access. Open the page in Notion, use the ••• menu → Connections, and add your integration. Connecting a page covers its sub-pages too." },
{ question: "My secret starts with secret_ instead of ntn_ — is that a problem?", answer: "No. Notion switched new secrets to the ntn_ prefix in September 2024, but existing secret_ tokens remain valid. Sim accepts both." },
{ question: "A block fails with 403 restricted_resource — what does that mean?", answer: "The secret is valid but the integration is missing a capability that tool needs — for example, calling a write tool with only Read content enabled, or listing users without a user capability. Enable the capability on the integration's settings page in Notion." },
{ question: "How do I rotate the secret?", answer: "The integration's Configuration tab has a refresh/regenerate action for the secret. Regenerate it, then update the credential in Sim with the new value. Plan for the old secret to stop working as soon as you regenerate." },
{ question: "Does the integration see everything its members can see?", answer: "No — the reverse. It sees only pages explicitly connected to it, and its capabilities can never exceed the permissions of the user interacting through it." },
]} />
@@ -0,0 +1,109 @@
---
title: Shopify Admin API Tokens
description: Set up a Shopify custom app with an Admin API access token to use Shopify in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Shopify custom apps let your workflows authenticate to a store with an Admin API access token (`shpat_...`) — a permanent, store-bound credential that belongs to the app, not to any employee's login. You choose exactly which Admin API scopes the app gets, and the token never expires.
This is the recommended way to use Shopify in production workflows: no OAuth consent to go stale, scopes are explicit and auditable, and access is revoked by uninstalling the app — without touching anyone's account.
## Prerequisites
You need store owner or staff permissions that allow managing apps on the store. You'll also need your store's permanent domain (`your-store.myshopify.com`) — Sim asks for it alongside the token.
<Callout type="info">
Shopify no longer allows creating new custom apps from the store admin — that path is legacy. New custom apps are created from the **Dev Dashboard** ([dev.shopify.com](https://dev.shopify.com/)) or the Shopify CLI. If you already have an admin-created custom app, its `shpat_` token still works and can be pasted into Sim directly.
</Callout>
## Setting Up the Custom App
### 1. Create the App and Grant Scopes
<Steps>
<Step>
Open the [Dev Dashboard](https://dev.shopify.com/), create a new app (e.g. `sim-workflows`), and connect it to your store
{/* TODO(screenshot): Shopify Dev Dashboard with a new custom app created */}
</Step>
<Step>
Configure the app's **Admin API access scopes**. The set Sim's Shopify tools use is:
```
write_products
write_orders
write_customers
write_inventory
read_locations
write_merchant_managed_fulfillment_orders
```
In Shopify, `write_X` includes `read_X`, so these six cover product, collection, order, fulfillment, customer, inventory, and location operations. Grant fewer if your workflows only read — e.g. `read_products` alone is enough for product and collection lookups
{/* TODO(screenshot): Admin API access scopes picker with the six scopes selected */}
</Step>
<Step>
Install the app on your store, then obtain the `shpat_` token as described in the next section — the flow differs by app type
</Step>
</Steps>
### 2. Get the Admin API Access Token
How you obtain the `shpat_` token depends on how the app was created:
- **Legacy admin-created custom apps** (created from the store admin before Shopify removed that path) show the **Admin API access token** — it starts with `shpat_` — once on the app's API credentials page. Reveal it, copy it immediately, and paste it into Sim. For legacy admin-created custom apps, Shopify shows the token only once, at creation — if you lose it, you have to reinstall or recreate the app to get a new one.
- **New Dev Dashboard apps** do **not** display a permanent `shpat_` token in any UI. Complete an OAuth (authorization code grant) install with the app's client ID and secret to obtain an offline `shpat_` access token programmatically. The Dev Dashboard's client-credentials tokens are different — they expire after 24 hours and cannot be stored in Sim.
{/* TODO(screenshot): legacy custom app's API credentials page with the shpat_ token revealed */}
<Callout type="warn">
Don't confuse the token types: `shpat_` is the Admin API access token Sim needs. `shpss_` is the app's client secret and `shpca_` is a custom app access token from older Partner-created custom apps — neither will work. If your Dev Dashboard app only shows a client ID and secret, that is expected: Dev Dashboard apps issue tokens via OAuth, not a UI reveal (see the setup steps above).
</Callout>
### 3. Find Your Store Domain
Use the permanent `.myshopify.com` domain — for example, `your-store.myshopify.com` — not your custom storefront domain. You can find it in your Shopify admin URL or under **Settings** → **Domains**.
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Shopify Service Account" and click it, then click **Add to Sim** and choose **Add admin API token**
{/* TODO(screenshot): Integrations page with "Shopify Service Account" in the service list */}
</Step>
<Step>
Paste the Admin API access token, enter the store domain (e.g. `your-store.myshopify.com`), and optionally set a display name and description
{/* TODO(screenshot): Add Shopify admin API token dialog with token and store domain filled in */}
</Step>
<Step>
Click **Add admin API token**. Sim verifies the token by querying your store's `shop` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The token and store domain are encrypted before being stored.
## Using the Service Account in Workflows
Add a Shopify block to your workflow. In the credential dropdown, your Shopify service account appears alongside any OAuth credentials. Select it and configure the block as you normally would — the store domain stored with the credential is used automatically.
{/* TODO(screenshot): Shopify block in a workflow with the service account selected as the credential */}
The block calls your store's Admin API (`your-store.myshopify.com/admin/api/...`) using the token, with exactly the scopes you granted the app.
<FAQ items={[
{ question: "Why an Admin API token instead of OAuth?", answer: "The custom app token is permanent, store-bound, and carries exactly the scopes you configured — no user consent to expire and no refresh cycle. That's what you want for an automated workflow." },
{ question: "Does the token expire?", answer: "No. Admin API access tokens from custom apps don't expire. They stop working only if the app is uninstalled or deleted. (Tokens from the Dev Dashboard's client-credentials flow are different — those expire in 24 hours and are not what Sim stores.)" },
{ question: "I lost the token — can I see it again?", answer: "No. Shopify reveals the token only once at creation. Reinstall the app (or recreate it) to generate a new token, then update the credential in Sim. Note the old token is invalidated when you do." },
{ question: "Can one token work for multiple stores?", answer: "No. Custom apps are single-store — the token works for exactly the store it was installed on. If you run multiple stores, create a custom app on each and add each as a separate credential in Sim." },
{ question: "What happens if the app is missing a scope a workflow needs?", answer: "The block fails at run time with an access-denied error naming the operation. Update the app's Admin API scopes and re-authorize/reinstall the app. Note that reinstalling generates new credentials, so update the token stored in Sim afterwards." },
{ question: "How do I rotate the token?", answer: "Admin-created custom apps can't rotate credentials in place — recovery is uninstall-and-reinstall or delete-and-recreate, both of which invalidate the old token immediately. Do it in a maintenance window and update the Sim credential right after." },
]} />
@@ -0,0 +1,95 @@
---
title: Trello API Tokens
description: Mint a Trello API token bound to Sim's API key to use Trello in Sim workflows without OAuth
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
Trello service account credentials let your workflows authenticate to Trello with a pasted API token instead of a personal OAuth connection. The token belongs to a Trello member — ideally a dedicated bot account — so workflows keep running even when individual teammates leave or revoke their own connections.
<Callout type="warn">
Trello tokens are bound to the API key that authorized them. A token generated with your own Trello Power-Up key will **not** work in Sim — Trello rejects it with `401 invalid token`. The token must be minted through Trello's authorize URL using the API key of the Sim deployment you're connecting to. Follow the steps below exactly.
</Callout>
## Prerequisites
You need a Trello account that has access to the boards your workflows will read and write. For production workflows, create a dedicated bot Trello account (e.g. `sim-bot@yourcompany.com`), invite it to the relevant boards, and mint the token while logged in as that account — the credential then survives any individual employee leaving.
## Generating the API Token
Trello doesn't have a token-creation settings page. Tokens are minted by visiting an authorize URL in the browser while logged in to the Trello account that should own the token:
```
https://trello.com/1/authorize?expiration=never&scope=read,write&response_type=token&name=Sim&key=<SIM_TRELLO_API_KEY>
```
<Callout type="info">
The `key` parameter must be the Trello API key of the Sim deployment:
- **Sim's hosted cloud** — contact Sim support for the ready-made authorize link with the key already filled in (a future update to the connect modal may surface it in-product). Don't substitute your own key.
- **Self-hosted Sim** — substitute the value of your deployment's `TRELLO_API_KEY` environment variable. Trello API keys are public-by-design identifiers (not secrets); yours is shown at [trello.com/power-ups/admin](https://trello.com/power-ups/admin) under your Power-Up's API key page.
</Callout>
<Steps>
<Step>
Log in to Trello as the account that should own the token (the bot account, for production)
</Step>
<Step>
Open the authorize URL above in the browser. Trello shows a consent page describing the access being granted
{/* TODO(screenshot): Trello authorize consent page showing "Sim" requesting read/write access with never expiration */}
</Step>
<Step>
Click **Allow**. Trello displays the token on-screen — copy it
{/* TODO(screenshot): Trello token display page after clicking Allow, with the token string shown */}
</Step>
</Steps>
<Callout type="warn">
Keep `expiration=never` and `scope=read,write` in the URL exactly as shown. A token minted with a shorter expiration (`1hour`, `1day`, `30days`) will validate today and silently die later. A read-only token (`scope=read`) also validates — but every Trello write tool in your workflows (create card, update card, add comment, and so on) will then fail at runtime.
</Callout>
Newer Trello tokens start with `ATTA`; older ones are 64-character hex strings. Both work — Sim doesn't enforce a format.
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Trello Service Account" and click it, then click **Add to Sim** and choose **Add API token**
{/* TODO(screenshot): Integrations page with "Trello Service Account" in the service list */}
</Step>
<Step>
Paste the API token, and optionally set a display name and description
{/* TODO(screenshot): Add Trello API token dialog with the API token filled in */}
</Step>
<Step>
Click **Add API token**. Sim verifies the token by calling Trello's `/1/members/me` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The token is encrypted before being stored.
## Using the Service Account in Workflows
Add a Trello block to your workflow. In the credential dropdown, your Trello service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Trello block in a workflow with the Trello service account selected as the credential */}
The block calls Trello's API (`api.trello.com`) with the token, paired server-side with the deployment's API key. The credential acts as the Trello member that minted the token, with access to exactly the boards that member can see.
<FAQ items={[
{ question: "Why does the token have to be minted with Sim's API key?", answer: "Trello binds every token to the API key that authorized it. At runtime, Sim pairs your token with its own API key on every request — a token minted under any other key gets rejected with 401 'invalid token'. This is a Trello platform rule, not a Sim limitation." },
{ question: "I generated a token from my own Power-Up's key and validation fails. What now?", answer: "Discard that token and mint a new one using the authorize URL with the Sim deployment's key — ask Sim support for the ready-made link on hosted cloud, or use your own TRELLO_API_KEY value if self-hosting. Tokens are free to create. (If your account is managed by a Trello Enterprise, admins can restrict token creation — ask your Enterprise admin if the authorize page won't issue a token.)" },
{ question: "Is the Trello API key a secret?", answer: "No — Trello API keys are public identifiers by design (they appear in client-side authorize URLs). The token is the secret. Treat the token like a password; the key can be shared freely." },
{ question: "Does Trello have real service accounts?", answer: "No — Trello tokens are always bound to a Trello member (a user). The closest equivalent is a dedicated bot account: create a separate Trello user for automation, invite it to the boards your workflows need, and mint the token as that user." },
{ question: "What happens if the board access changes?", answer: "The token always reflects the live permissions of the member who minted it. If the bot account is removed from a board, workflows touching that board start failing with 401/404 errors — re-invite the account to fix it, no new token needed." },
{ question: "How do I revoke or rotate the token?", answer: "Log in as the token's owner, open your Trello account settings (trello.com/u/my/account), scroll to the Applications section, and click Revoke next to 'Sim'. To rotate, mint a fresh token from the same authorize URL and update the credential in Sim before revoking the old one." },
]} />
@@ -0,0 +1,80 @@
---
title: Wealthbox API Access Tokens
description: Set up a Wealthbox API access token to use Wealthbox in Sim workflows without OAuth
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { FAQ } from '@/components/ui/faq'
Wealthbox service account credentials let your workflows authenticate to Wealthbox with a pasted API access token instead of a personal OAuth connection. Wealthbox doesn't document an expiry for these tokens — treat them as long-lived until you revoke them — so workflows keep running without anyone renewing an OAuth consent.
## Prerequisites
Wealthbox trial accounts cannot use the API (calls return `402 Trial expired`). If you don't see an **API Access** section in your Wealthbox settings, contact Wealthbox support before continuing.
<Callout type="info">
Wealthbox tokens are tied to the user who creates them and carry that user's permissions. For production workflows, create the token from a dedicated service login with adequate record visibility rather than a personal account — the credential then survives any individual employee leaving.
</Callout>
## Creating the API Access Token
<Steps>
<Step>
Log in to Wealthbox, open **Settings** (the three-dot menu), and go to **API Access** (direct link: [app.crmworkspace.com/settings/access_tokens](https://app.crmworkspace.com/settings/access_tokens))
{/* TODO(screenshot): Wealthbox settings page with the API Access section open */}
</Step>
<Step>
Click **Create Access Token**, give it a label (e.g. `sim-workflows`), and save
{/* TODO(screenshot): Wealthbox Create Access Token dialog with a label filled in */}
</Step>
<Step>
Copy the token. Wealthbox doesn't document an expiry for API access tokens; you can revoke it from this same page at any time.
</Step>
</Steps>
<Callout type="warn">
The token carries the full permissions of the user who created it — there is no scope selection. Treat it like a password: do not commit it to source control or share it publicly. Sim encrypts the token at rest.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Wealthbox Service Account" and click it, then click **Add to Sim** and choose **Add access token**
{/* TODO(screenshot): Integrations page with "Wealthbox Service Account" in the service list */}
</Step>
<Step>
Paste the API access token, and optionally set a display name and description
{/* TODO(screenshot): Add Wealthbox access token dialog with the API access token filled in */}
</Step>
<Step>
Click **Add access token**. Sim verifies the token by calling Wealthbox's `/v1/me` endpoint — if it fails, you'll see a specific error explaining what went wrong.
</Step>
</Steps>
The token is encrypted before being stored.
## Using the Service Account in Workflows
Add a Wealthbox block to your workflow. In the credential dropdown, your Wealthbox service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Wealthbox block in a workflow with the Wealthbox service account selected as the credential */}
The block calls Wealthbox's API (`api.crmworkspace.com`) with the token. The credential acts as the Wealthbox user who created the token — contacts, tasks, and notes the workflows touch are the ones that user can see under Wealthbox's permission settings.
<FAQ items={[
{ question: "Why an API access token instead of OAuth?", answer: "API access tokens are long-lived and don't require any user to sit through a consent flow — they stay valid until you revoke them, which is what you want for an automated workflow. OAuth connections are tied to one person's session." },
{ question: "Do Wealthbox tokens have scopes?", answer: "No — a token carries the full permissions of the user who created it. Authorization in Wealthbox is scoped to individual users, not organizations. If a workflow gets a 403 on a specific record, the token's user lacks visibility to that record — adjust the user's permissions in Wealthbox." },
{ question: "I don't see an API Access section in my settings. Why?", answer: "Trial accounts are blocked from the Wealthbox API, and some accounts may not show the section. Contact Wealthbox support if API Access is missing from your Settings." },
{ question: "Do tokens expire?", answer: "Wealthbox doesn't document an expiry for API access tokens — expect them to work until revoked from the API Access settings page. If a workflow suddenly fails with a 401, the most likely cause is that someone revoked the token." },
{ question: "My user belongs to multiple Wealthbox workspaces. Which one does the token use?", answer: "Wealthbox doesn't document workspace selection for API tokens. The API reports the token user's current workspace in /v1/me (current_user.account) — if your data spans multiple workspaces, test which workspace the token reads before relying on it." },
{ question: "How do I rotate the token?", answer: "There's no rotation API — create a new token from the API Access settings page, update the credential in Sim with the new token, and once it's working, revoke the old one." },
]} />
@@ -0,0 +1,89 @@
---
title: Webflow Site Tokens
description: Set up a Webflow site API token with the right scopes to use Webflow CMS in Sim workflows
---
import { Callout } from 'fumadocs-ui/components/callout'
import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
Webflow site tokens let your workflows authenticate to a single Webflow site with a token you generate from the site's settings — no OAuth consent, no user account attached. You pick the scopes at creation, and the token is bound to exactly that site.
This is the recommended way to use Webflow in production workflows: the credential belongs to the site rather than to a person, its scopes are explicit, and it can be revoked from site settings without touching anyone's account.
## Prerequisites
Only **site administrators** can generate site tokens. Each site allows a maximum of **5 tokens** — if you're at the cap, revoke an unused one before creating a token for Sim.
## Setting Up the Site Token
<Steps>
<Step>
Open your site's **Site settings** and go to **Apps & integrations** → **API access**
{/* TODO(screenshot): Webflow Site settings "Apps & integrations" page with the API access section highlighted */}
</Step>
<Step>
Click **Generate API token** and give it a recognizable name (e.g. `sim-workflows`)
</Step>
<Step>
Select the scopes the token needs. The minimum set for Sim's Webflow blocks is:
```
Sites: Read-only
CMS: Read and write
```
The picker offers **no access**, **read-only**, or **read and write** per category. `Sites: Read-only` (`sites:read`) is required for Sim to verify the token when you connect it. `CMS: Read and write` (`cms:read` + `cms:write`) covers Sim's Webflow tools — listing, getting, creating, updating, and deleting CMS items. Add other scopes only if you need them
{/* TODO(screenshot): Webflow token scope picker with Sites read and CMS read/write selected */}
</Step>
<Step>
Copy the token when it's shown. Webflow only displays it once — if you close the dialog, you'll have to generate a new token.
</Step>
</Steps>
<Callout type="warn">
Site tokens expire after **365 consecutive days of inactivity**. Any API call resets the clock, so a workflow that runs regularly keeps its token alive indefinitely — but a workflow that sits dormant for a year will start failing silently with authentication errors. If a workflow runs rarely, set a calendar reminder to run it (or any Webflow block) at least once a year, or check the credential periodically in Sim.
</Callout>
## Adding the Service Account to Sim
<Steps>
<Step>
Open your workspace **Settings** and go to the **Integrations** tab
</Step>
<Step>
Search for "Webflow Service Account" and click it, then click **Add to Sim** and choose **Add site token**
{/* TODO(screenshot): Integrations page with "Webflow Service Account" in the service list */}
</Step>
<Step>
Paste the site API token and optionally set a display name and description
{/* TODO(screenshot): Add Webflow site token dialog with the site API token filled in */}
</Step>
<Step>
Click **Add site token**. Sim verifies the token by listing the sites it can access — if it fails, you'll see a specific error explaining what went wrong. A token created without the `sites:read` scope fails this check even if its CMS scopes are correct.
</Step>
</Steps>
The token is encrypted before being stored, along with the site it grants access to.
## Using the Service Account in Workflows
Add a Webflow block to your workflow. In the credential dropdown, your Webflow service account appears alongside any OAuth credentials. Select it and configure the block as you normally would.
{/* TODO(screenshot): Webflow block in a workflow with the service account selected as the credential */}
The block calls Webflow's Data API (`api.webflow.com/v2/...`) using the token. It can only reach collections and items belonging to the token's site — pointing a block at a different site's collection fails with an access error.
<FAQ items={[
{ question: "Why a site token instead of OAuth?", answer: "Site tokens aren't tied to any user account and don't depend on OAuth consent staying valid. They're generated by a site admin, scoped explicitly, and stay valid as long as they're used — which suits automated workflows." },
{ question: "Can one token cover multiple sites?", answer: "No. A site token is bound to exactly one site. If your workflows touch several Webflow sites, generate a token on each site and add each as a separate credential in Sim. For many sites, Webflow's OAuth flow may be more practical." },
{ question: "Why did adding the token to Sim fail even though my scopes looked right?", answer: "The most common cause is a missing Sites: Read scope — Sim verifies the token by listing its accessible sites, so a CMS-only token fails validation even though the CMS tools themselves would work. Generate a new token that includes Sites: Read." },
{ question: "Does the token expire?", answer: "Only from inactivity: 365 consecutive days without any API call. Regular use resets the clock. A dormant credential dies silently, so run rarely-used workflows at least once a year or set a reminder." },
{ question: "How do I rotate the token?", answer: "Generate a new token from the site's API access settings (watch the 5-token-per-site cap), update the credential in Sim, and once it's working, revoke the old one." },
{ question: "What if a workflow needs scopes the token doesn't have?", answer: "Scopes are fixed at creation — generate a new token with the wider scope set, update the credential in Sim, and revoke the old token. Scope failures show up as 401 authorization errors on the failing block." },
]} />