- 🖥️ UI - Affects StackOne Hub, Dashboard, or Connect flows
- 🤖 MCP - Used in MCP tool declarations (
list tools) - ⚙️ Runtime - Affects API request execution
File Structure
Connectors use a modular file structure:Why use partial files?
Why use partial files?
stackone push. The $ref syntax tells the merger which partials to include. File naming must follow the pattern {provider}.{resource}.s1.partial.yaml for auto-discovery.Example from BambooHR:bamboohr.connector.s1.yaml- Auth configbamboohr.employees.s1.partial.yaml- Employee actionsbamboohr.timeoff.s1.partial.yaml- Time-off actions
Root Properties
StackOne
Impact: ⚙️ Runtime
The schema version for the connector file format.
How version affects processing
How version affects processing
1.0.0 is supported. Future versions may introduce new properties or change behavior. Always use 1.0.0 for new connectors.info Section
Metadata about the connector displayed in the UI and used for identification.
info.title
Impact: 🖥️ UI
Human-readable provider name displayed in the Hub and Dashboard.
UI display locations
UI display locations
- Integration Hub provider list
- Dashboard connector cards
- Account connection screens
- Logs and audit trails
info.key
Impact: 🖥️ UI | 🤖 MCP | ⚙️ Runtime
Unique identifier for the connector. Used in API calls, MCP tool names, and internal routing.
How key is used throughout the system
How key is used throughout the system
bamboohr_list_employeesAPI: Used in account connections:Forking connectors and inheriting updates
Forking connectors and inheriting updates
info.title). However, if you want to inherit future StackOne updates to that connector, the info.key field must match the StackOne connector key.Example:
If you fork StackOne’s BambooHR connector:- ✅ You can change
info.titleto “Custom BambooHR” - ⚠️ Keep
info.key: bamboohrto receive future updates from StackOne - ❌ Changing
info.keytocustom_bamboohrprevents automatic update inheritance
info.key identical to the original StackOne connector key if you want to inherit future improvements and bug fixes.info.version
Impact: 🖥️ UI | ⚙️ Runtime
Connector version following semver format.
Version management best practices
Version management best practices
- Major (1.x.x): Breaking changes such as authentication changes, removed/renamed actions, changed response or request shape, or behavioral changes consumers may have relied on
- Minor (x.1.x): New actions, new optional parameters, or new optional response fields
- Patch (x.x.1): Bug fixes, description updates, internal refactors
info.assets.icon
Impact: 🖥️ UI
URL to the provider’s logo image. Displayed throughout the UI.
Logo requirements and hosting
Logo requirements and hosting
https://stackone-logos.com/api/{provider}/filled/svgRequirements:- 24x24 pixels minimum
- SVG or PNG format
- Transparent background preferred
- Hosted on HTTPS
info.description
Impact: 🖥️ UI | 🤖 MCP
Brief description of the connector’s purpose.
Where description appears
Where description appears
- Keep under 200 characters
- Mention key capabilities
- Include category context (HRIS, CRM, etc.)
info.details
Impact: 🖥️ UI | 🤖 MCP
Extended, multi-line description of the connector. Use it for context that doesn’t fit in the one-line info.description — capabilities, limitations, or setup considerations.
info.changelog
Impact: 🖥️ UI
Per-version changelog entry describing what changed since the previous connector version. Surfaced in product UIs that filter on labels.
baseUrl
Impact: ⚙️ Runtime
The root URL for all API requests. Supports static URLs and dynamic interpolation.
Static URL
Dynamic URL with credentials
Dynamic URL with config
URL interpolation and runtime resolution
URL interpolation and runtime resolution
${...} string interpolation:Available contexts:${credentials.*}- Values from setupFields/configFields${config.*}- Configuration values${env.*}- Environment variables (limited)
acme-corp, the runtime resolves to:rateLimit
Impact: ⚙️ Runtime
Configure rate limiting to respect provider API limits.
Sub-pools
Apply a different limit to a subset of endpoints matched by a URL pattern.Mapped rate-limit errors
Treat specific provider error responses as rate-limit signals and honor their retry hints.Rate limiting behavior
Rate limiting behavior
- Set slightly below provider’s documented limit
- Check provider API docs for per-endpoint limits
- Some providers have different limits for different endpoints
concurrency
Impact: ⚙️ Runtime
Limit the number of in-flight requests (independently of the per-second rateLimit).
mcp
Impact: 🤖 MCP
Connector-level MCP configuration.
releaseStage
Impact: 🖥️ UI
Maturity of the connector as a whole (individual actions can override with their own releaseStage). One of preview, beta, ga, deprecated, or internal.
forkedFrom
Impact: ⚙️ Runtime
Set when this connector was forked from another. References the source connector so tooling can track lineage. See the forking guidance under info.key for how forks inherit updates.
resources
Impact: 🖥️ UI
URL to the provider’s API documentation. Displayed as a help link in the UI.
Resource link usage
Resource link usage
- Connector configuration screens
- Troubleshooting guides
- Developer documentation references
documentation
Impact: 🖥️ UI · 🤖 Agent context
Structured external references for the connector. Each entry has a required title and url, and an optional description. Rendered as a card grid on the connector’s docs page and surfaced in the /actions API response.
documentation.references fields
documentation.references fields
documentation.references for links that benefit both developers reading the docs and agents consuming the /actions API. The resources field (plain string URL) remains valid for a single legacy link; use documentation.references for structured, multi-link documentation.scopeDefinitions
Impact: 🖥️ UI · ⚙️ Runtime
Declares the requirements an action can depend on, keyed by scope name. Commonly OAuth or API scopes, but the same mechanism represents any prerequisite: a pricing tier, a platform feature, a configuration flag.
authRequirements (or the deprecated requiredScopes), and guide sections through applicableScopes. Both are validated against the keys defined here, so a reference to an undeclared scope fails validation.
Hierarchical scopes and naming
Hierarchical scopes and naming
includes should only reflect relationships the provider actually documents. A write scope typically includes its read counterpart, and a broader scope includes a narrower one, but a read-only scope must never include a write scope.authentication Section
Defines how end-users authenticate with the provider. Supports multiple authentication methods per connector.
Authentication Array Structure
Multiple authentication methods
Multiple authentication methods
- Users see all options in the Hub during connection
- Each method has independent credentials and setup flows
- Linked accounts store which method was used
- Runtime uses the appropriate authentication handler based on account config
- OAuth 2.0
- Custom Auth (API Key, Basic)
OAuth 2.0 Authentication
Impact: 🖥️ UI | ⚙️ Runtimetype
label
Impact: 🖥️ UIDisplay name for this authentication method in the Hub.support
Impact: 🖥️ UIHelp text and links shown during connection flow.Support section display
Support section display
descriptionappears as instructional textlinkcreates a “Learn more” button
authorization
Impact: ⚙️ RuntimeOAuth flow configuration.OAuth flow internals
OAuth flow internals
- User clicks “Connect” in Hub
- Runtime builds authorization URL with
authorizationParams - User redirects to provider, logs in, grants permissions
- Provider redirects back with authorization code
- Runtime exchanges code for tokens via
tokenUrl - Tokens stored in credentials for linked account
$.credentials.*- JSONPath to credential values${apiHostUri}- StackOne callback URL base'{{expression ?? default}}'- JEXL with fallback
code_verifier and code_challenge automatically.Scopes: The example '{{$.credentials.scopes ?? "default:scope"}}' lets users customize scopes in setupFields while providing sensible defaults.setupFields
Impact: 🖥️ UI | ⚙️ RuntimeFields collected when configuring the connector (your app’s credentials).url is not a valid field type. Use text for URL inputs. For a dropdown, use type: select with an options array. A computed field is never shown for input — its value (a JEXL expression) is evaluated at runtime. Field validation (pattern/format/errorMessage, format one of email/url/uuid/date/datetime/uri) runs client-side and is not allowed on computed/readOnly fields.setupFields vs configFields
setupFields vs configFields
- OAuth Client ID/Secret
- API keys for your platform
- Application-level settings
- Their API keys
- Account-specific settings (subdomain, region)
- Personal access tokens
- setupFields → Stored per connector profile
- configFields → Stored per linked account
secret: true→ Encrypted at rest, never exposed in API responsestype: password→ Masked in UI during entry
configFields
Impact: 🖥️ UI | ⚙️ RuntimeFields collected from end-users during connection (their credentials).setupFields.refreshAuthentication
Impact: ⚙️ RuntimeEmbedded action for refreshing expired OAuth tokens.Token refresh mechanics
Token refresh mechanics
- An action fails with 401 Unauthorized
- Runtime checks if refreshAuthentication is configured
- Executes the embedded refresh action
- Updates stored credentials with new tokens
- Retries the original action
- Call the provider’s token refresh endpoint
- Map the response to credential format (accessToken, refreshToken, expiresIn)
- Return data in
result.data
categories: [internal] hides this from MCP tool listings.Proactive refresh with schedule
Proactive refresh with schedule
401). Add an optional schedule to refresh tokens proactively before they expire:environments
Impact: 🖥️ UIAvailable deployment environments for this authentication method.Multi-environment support
Multi-environment support
$.environment.key.testActions
Impact: 🖥️ UI | ⚙️ RuntimeActions executed to validate a connection after OAuth completes.Connection validation flow
Connection validation flow
- Runtime executes each testAction in order
- If
required: trueand action fails → connection marked as failed - If
required: falseand action fails → warning logged but connection succeeds
- Use a simple read action (list, get)
- Test the most common use case
- Avoid actions that modify data
Authentication type values
The top-level type of each authentication method is one of:
oauth2, an optional grantType selects the flow:
authorization.type (inside authorization:) is separate from the method type above. It selects the runtime auth strategy — oauth2, bearer, basic, or none. A none authorization may still declare request signing (aws4 or hmac) for providers that sign requests instead of sending a token.certificates
Impact: ⚙️ Runtime
Client certificates for mutual-TLS providers.
configNotices / setupNotices
Impact: 🖥️ UI
Inline callouts shown above or below the config/setup fields during connection.
support and Guides
Impact: 🖥️ UI
Each authentication method can carry its own instructions as structured data, under support.guides. For StackOne authored connectors, these are published as the guide pages under Connectors. You can also fetch the same content from the API and render it in your own product, which is covered in Rendering Guides.
Which guide to write
guides.config with no configFields documents inputs nobody is asked for.
events.guides.setup, for instructions on configuring a webhook in the provider.Section and step fields
Both guides take awarning and a required array of sections. Sections and steps share the same shape, and steps nest one level inside a section.
Scope-aware guide content
Scope-aware guide content
applicableScopes filters instructions down to the configuration the user actually chose, so a read-only integration doesn’t get told to grant write permissions:scopeDefinitions, and validation fails if it doesn’t.displayScopes: true on a step renders badges for the actions those scopes unlock, which is useful on the step where a user picks scopes in the provider’s consent screen:support.link and where the Hub sends users
support.link and where the Hub sends users
support.link points at your own rendered version of these guides. The Hub sends users there instead of to StackOne’s pages.guides.config has sections, StackOne fills it in with that connector’s own generated guide page, built from the connector key and the authentication label:link when you want users in your product rather than in StackOne’s docs.actions Section
Actions define the operations available through the connector. Use $ref to include partials.
Action References
How $ref resolution works
How $ref resolution works
$ref at build time:$ref: bamboohr.employeeslooks forbamboohr.employees.s1.partial.yaml- Partial file must be in same directory as main connector
- Actions from partial are merged into main connector
- Multiple
$refstatements combine all partials
- (array items), not actions:.Action Properties
Each action defines a single operation.actionId
Impact: 🤖 MCP | ⚙️ Runtime
Unique identifier for the action. Becomes the MCP tool name with provider prefix.
bamboohr_list_employees
Action ID naming conventions
Action ID naming conventions
list_*- Get multiple records (paginated)get_*- Get single record by IDcreate_*- Create new recordupdate_*- Modify existing recorddelete_*- Remove recordsearch_*- Query with filters
list_employees- List all employeesget_employee- Get employee by IDcreate_employee- Create new employeesearch_employees_by_department- Filtered search
{provider_key}_{actionId}, so bamboohr + list_employees = bamboohr_list_employees.categories
Impact: 🖥️ UI
Categories for filtering in the UI. Does not affect MCP.
Category filtering behavior
Category filtering behavior
- Actions Explorer in Dashboard
- AI Playground action selection
- SDK
fetchTools({ categories: ['hris'] })
internal category: Actions with categories: [internal] are:- Hidden from UI listings
- Not returned in MCP
list tools - Still executable via direct API calls
- Used for token refresh and internal operations
actionType
Impact: 🤖 MCP | ⚙️ Runtime
Determines the action’s behavior pattern and response schema.
Unified vs Custom action types
Unified vs Custom action types
- Enforce consistent response schemas across providers
- Enable cross-provider compatibility
- Support automatic pagination handling
- Normalize error responses
- Returns raw provider response
- Use for provider-specific features
- No schema normalization
- Full flexibility for unique endpoints
list action always returns:custom action returns whatever the provider returns.effects
Impact: 🖥️ UI | 🤖 MCP
What the action does to provider data. StackOne derives standard MCP tool annotations from this field, so an MCP client can auto-approve reads and prompt before writes and deletes.
[read, write].
The field is optional, but set it on every action. With no effects and no annotations override, StackOne emits no annotations for that tool and the client falls back to the MCP defaults — a read then looks no safer than a delete. Authentication and event actions are excluded; events are inbound, so effects don’t apply.
How effects become MCP annotations
How effects become MCP annotations
tools/list without calling anything:write and execute produce the same two hints. The effects are finer-grained than the annotations, so pick the accurate effect even where the derived hints come out identical.Meta-tools carry fixed hints instead of derived ones: discovery and search tools are readOnlyHint: true, openWorldHint: false, and the execute_action dispatcher is openWorldHint: true with no read-only claim, since what it runs can mutate.Overriding the derived hints
Overriding the derived hints
annotations block to any action to set MCP hints directly. It’s merged last and wins per field, so you can override one hint and leave the rest derived.idempotentHint, which is never inferred, or a hint that’s wrong for a specific action — a POST that’s genuinely idempotent, for example.label
Impact: 🖥️ UI
Human-readable name displayed in the UI.
Label display locations
Label display locations
- Actions Explorer
- AI Playground action selector
- Request logs
- Error messages
- Use title case
- Start with verb (List, Get, Create, etc.)
- Keep concise (under 30 characters)
description
Impact: 🖥️ UI | 🤖 MCP
Short description of what the action does. Used in both UI and MCP tool descriptions.
Description in MCP tool declarations
Description in MCP tool declarations
list tools, the description becomes the tool’s description:- Understand the action’s purpose
- Know what data it returns
- Decide which action fits the user’s request
- Keep under 200 characters
- Mention key capabilities
- Be specific about what’s returned
details
Impact: 🤖 MCP
Extended description with full context. Used as the complete tool description in MCP.
Details vs Description in MCP
Details vs Description in MCP
descriptionas a brief summarydetailsas the full tool description
description: One-line summary (~100 chars)details: Full context for AI agents (~500 chars)
- What fields are returned
- How pagination works
- What filters are available
- Edge cases and limitations
resources
Impact: 🖥️ UI
Link to provider documentation for this specific action.
Action-level resources
Action-level resources
executionMode
Impact: ⚙️ Runtime
sync (default) runs the action in the connect engine. async short-circuits the engine and dispatches to an upstream Temporal workflow.
browser_use step must declare executionMode: async, or validation fails.authRequirements
Impact: 🖥️ UI | ⚙️ Runtime
Declares which scopes (from scopeDefinitions) each auth method must grant for this action to run. A map of auth-method key → array of required scope names.
validationRules
Impact: ⚙️ Runtime
Cross-field validation applied to inputs before the action runs. Each rule is keyed by rule.
requiredIf condition names another field and exactly one of equals, notEquals, or present. All rules accept an optional errorMessage.
tags, responses, releaseStage
Impact: 🖥️ UI | 🤖 MCP
schema / schemaType
Impact: 🤖 MCP | ⚙️ Runtime
Bind the action to a defined output schema. schemaType selects whether the schema is a provider-native shape or a StackOne unified shape.
cursor and compositeIdentifiers
Impact: ⚙️ Runtime
cursor enables engine-managed cursor pagination with a fixed page size. compositeIdentifiers builds a single logical ID from multiple provider fields (and can be versioned via version).
providerEvents
Impact: ⚙️ Runtime
For event actions, the provider event names this action handles.
examples
Impact: 🤖 MCP
Real input/output pairs demonstrating how the action is used. Each entry takes an optional exampleDescription plus arbitrary example fields (e.g. input/output).
entrypointUrl / entrypointHttpMethod
Impact: ⚙️ Runtime
Declare the action’s primary HTTP endpoint. Together they form the action’s operation key (e.g. GET /employees). When omitted, both are inferred from the action’s actionType and schema (entrypointHttpMethod defaults to get), so set them only to override the inferred value.
dataSync
Impact: 🖥️ UI | 🤖 MCP | ⚙️ Runtime
Make the action syncable by Data Sync, so its records can be stored and read with Deep Query. Sits as a sibling of result, and marks the action Syncable in the dashboard.
Getting dataKey right
Getting dataKey right
dataKey resolves against the step output, not the provider’s HTTP body. Since result.data maps to $.steps.<id>.output.data, the body sits at output.data, so the path almost always starts with data.:dataSync.pagination
Discriminated on type. iterator.in is one of query, body, or headers, and every type also takes an optional stopCondition.
dataSync.incremental
Discriminated on type. Sets what an incremental run sends to fetch only changed records.
format is one of iso8601, unix_seconds, or unix_millis.
Unified list actions need cursor pagination
Unified list actions need cursor pagination
actionType: list, one call returns a single unified page plus a next token rather than exhausting the provider. Data Sync rides on top of that, so use type: cursor with the action’s existing cursor setup. offset and page re-fetch the first page until the run hits its page cap.inputs
Impact: 🤖 MCP | ⚙️ Runtime
Define parameters the action accepts. Become MCP tool input schema.
Input Properties
Input Types
Enum Type
Enum inputs declare their allowed values throughoneOf, which takes either an inline values array of strings or a ref to a named enum defined in the codebase registry.
MCP input schema generation
MCP input schema generation
- Generate valid tool calls
- Understand parameter types
- Apply default values
- Validate inputs before calling
Array inputs
Array inputs
array: true for parameters accepting multiple values:"type": "array", "items": { "type": "string" }arrayFormat controls how array values are serialized into the request:Field validation rules
Field validation rules
rules object to enforce per-field validation at request time. Invalid inputs are rejected before the action runs.minLength, maxLength, pattern, format) are only valid on string/datetime_string; number rules (min, max) only on number. For cross-field validation (e.g. “at least one of these”), use action-level validationRules.Object type with nested properties
Object type with nested properties
type: object with a nested properties array to define the object’s structure:properties supports the same fields as top-level inputs (name, type, description, required, default, properties for deeper nesting).This generates proper JSON Schema for MCP, helping AI agents understand the expected object structure:Variant inputs
Variant inputs
variants instead of a single type. Each variant is a complete shape specification.- When
variantsis present, top-leveltype,array,properties,oneOf, andrulesmust be absent, since each variant carries its own complete schema variantsmust contain at least 2 entries- Each variant must declare a
type
steps and Step Functions
The steps array and the available step functions (request, paginated_request, map_fields, group_data, typecast, soap_request, soap_paginated_request, static_values, code_execution_lambda, upload_file, upload_binary, download_file, emit_event, browser_use, sign_jwt, and Iterator Steps) are documented on a dedicated page. See Step Functions.
result
Impact: 🤖 MCP | ⚙️ Runtime
Define the action’s output. Becomes the tool’s return value.
Result in MCP responses
Result in MCP responses
events Section
Impact: 🖥️ UI | ⚙️ Runtime
Defines inbound webhook support: how StackOne registers receivers with the provider, the event actions that normalize incoming payloads, and how raw deliveries are routed and attributed to a linked account.
events.setup
Impact: ⚙️ Runtime
Programmatic webhook lifecycle. Each phase is a list of steps.
events.actions
Event actions look like normal actions but use actionType: event and declare the providerEvents they handle. They may set requiresManualSetup: true when the webhook must be configured manually in the provider UI (pair with events.guides.setup).
events.router
Maps a raw incoming delivery to the event action that should process it.
events.externalAccountIdExtractor
A custom action (with a required result) that pulls the external account identifier out of an incoming payload so StackOne can attribute the delivery to the correct linked account.
events.guides.setup
Same schema as support.guides (sections/steps, warning, applicableScopes), but documents how to configure the webhook in the provider’s UI. Use with requiresManualSetup event actions.
Expression Formats
Three expression formats are available throughout connector YAML. For the complete reference including all built-in functions, see the Expression Language page.JSONPath ($.path)
Access data from context objects.
String Interpolation (${...})
Embed values in strings.
JEXL ('{{...}}')
Complex expressions with logic.
Expression format selection guide
Expression format selection guide
- Simple value access
- No transformation needed
- Used alone (not in string)
- Building URLs or strings
- Concatenating with static text
- Simple variable substitution
- Default values needed (
??operator) - Conditional logic required
- Complex transformations
- In
conditionfields
GraphQL Actions
For GraphQL APIs, use therequest function with POST method and query in body.
GraphQL best practices
GraphQL best practices
- Define variables for all dynamic values
- Use fragments for reusable field selections
- Keep queries focused (request only needed fields)
errors field in response:variables object, not inline in query: