---
title: "Subscribe several accounts to a trigger"
method: POST
path: "/api/v1/connections/{connection_id}/trigger-subscriptions:batchCreate"
tags: ["Triggers"]
---

# Subscribe several accounts to a trigger

`POST /api/v1/connections/{connection_id}/trigger-subscriptions:batchCreate`

## Request

- Base URL: `https://$SCALEKIT_ENVIRONMENT_URL`
- URL: `https://$SCALEKIT_ENVIRONMENT_URL/api/v1/connections/{connection_id}/trigger-subscriptions:batchCreate`
- Auth: OAuth 2
  - Client credentials
  - Token URL: `https://$SCALEKIT_ENVIRONMENT_URL/oauth/token`
- TypeScript: <https://skmtc.dev/scalekit/apis/scalekit-api-reference/docs/api/v1/connections/:connection_id/trigger-subscriptions:batchCreate/post.ts> (a function with typed inputs; its response is checked against the schema)

Subscribes many connected accounts to one trigger with one filter, and reports what happened to each account separately. Use this instead of repeating the single-account call when onboarding a connection that already has many accounts. The call is best-effort rather than all-or-nothing: a refused account does not undo one that succeeded, because refusals here are ordinary rather than exceptional — an account may hold a revoked credential, lack a scope, or already carry this exact filter. Each result names its own outcome, and a refusal names its remedy. Retrying the whole request is safe: an account subscribed by an earlier attempt comes back as already subscribed rather than as an error. A connection-scoped trigger is subscribed on the connection itself rather than per account: send an empty connected_account_ids for it, and the one subscription comes back as a single result with an empty connected_account_id.

## Path parameters

- `connection_id` string, required

## Request body

- TriggerServiceBatchCreateTriggerSubscriptionsBody
  - `config` object: Filter values applied to every account in the batch, keyed by the trigger's config_fields keys. Each account gets its own subscription with these values, so subscribing the same accounts again with different values adds subscriptions rather than replacing these. Invalid values refuse the whole request.
  - `connected_account_ids` string[]: Connected accounts to subscribe, at most 100 — one page of the account picker — with no repeats. Which to send depends on the trigger's delivery_scope, from ListAvailableTriggers. For an ACCOUNT-scoped trigger, list at least one account; an empty list refuses the whole request with a 400. For a CONNECTION-scoped trigger, send an empty list: the trigger is subscribed once, on the connection itself, and results holds exactly one result, with an empty connected_account_id. Naming accounts for a connection-scoped trigger refuses each of them (REFUSED), since that trigger is not subscribed per account.
  - `interval_seconds` integer: Polling interval in seconds, for a polled trigger only, applied to every account in the batch. Omit it to use the trigger's default_interval_seconds. A value below the trigger's min_interval_seconds, or any value for a webhook trigger, refuses the whole request. A large batch of polled subscriptions shares the environment's polling budget, so the subscriptions can run slower than requested; effective_interval_seconds on each subscription shows the interval it runs at.
  - `trigger_name` string, required: Name of the trigger to subscribe to, as returned in the name field of ListAvailableTriggers. Up to 128 characters.

## Response `200`

One result per requested account, in request order, and the number of subscriptions this call created. Individual accounts can still be REFUSED, NOT_FOUND or FAILED

- TriggersBatchCreateTriggerSubscriptionsResponse
  - `created_count` integer: How many subscriptions this call created. Excludes accounts that were already subscribed.
  - `results` TriggersBatchCreateTriggerSubscriptionResult[]: One result per requested account, in the order the accounts were sent, so a client can pair them up positionally without matching on id. For a connection-scoped trigger subscribed with an empty connected_account_ids, exactly one result, with an empty connected_account_id.
    - `connected_account_id` string: The connected account ID this result is for, as sent in the request.
    - `outcome` 'CREATED' | 'ALREADY_SUBSCRIBED' | 'REFUSED' | 'NOT_FOUND' | 'FAILED': What happened to one account in a batch. - CREATED: A subscription was created for this account. - ALREADY_SUBSCRIBED: This account already had a subscription to this trigger with this exact filter, so nothing new was created. Not an error — it is what makes retrying a partly-failed batch safe. - REFUSED: This account cannot receive this trigger. reason and remedy say why and what to do. - NOT_FOUND: No such account on this connection, in this environment. - FAILED: The attempt failed for a reason unrelated to this account — nothing was created for it, and retrying it may succeed.
    - `reason` string: Why the account was not subscribed, and for a refusal what to do about it, in one sentence — the same text CreateTriggerSubscription returns for the same account. Empty for CREATED.
    - `subscription` TriggersTriggerSubscription: A subscription of one connected account, or of a whole connection, to one trigger.
      - `account_health` 'READY' | 'AWAITING_CONFIRMATION' | 'WRONG_APP' | 'DISCONNECTED' | 'NEEDS_REAUTHENTICATION': A connected account's own state, evaluated for what the trigger in question routes by: a webhook trigger needs the provider workspace captured, and an account-scoped webhook trigger the provider user too. - READY: The account can receive triggers. - AWAITING_CONFIRMATION: Connected and working, but Scalekit has not confirmed which provider workspace or user it belongs to, so inbound events cannot be routed to it. - WRONG_APP: Authorized under a different OAuth app than the connection now uses. - DISCONNECTED: The account was disconnected. - NEEDS_REAUTHENTICATION: The credential itself is unusable: it has expired, or the account has not finished connecting.
      - `config` object: The subscription's filter values, keyed by the trigger's config_fields keys. Keys are returned exactly as stored; send them back without changing their case.
      - `connected_account_id` string: ID of the subscribed connected account. Empty for a connection-scoped subscription.
      - `connected_account_identifier` string: The identifier the connected account was created with, such as your app's user ID or the user's email address, so a client can label the subscription without fetching every account separately. Empty for a connection-scoped subscription, and empty when the account has no identifier recorded — fall back to connected_account_id rather than showing a blank.
      - `connection_id` string: ID of the connection the subscription belongs to.
      - `created_at` string, date-time: When the subscription was created. Returned so a list can be ordered or explained by age without a second lookup.
      - `delivery_scope` 'ACCOUNT' | 'CONNECTION': Whether a trigger delivers once per connected account or once for the whole connection. Set by the trigger, not chosen by the subscriber. A polled trigger polls with one connected account's credential, so a polled trigger that is connection-scoped is reported as unavailable. - ACCOUNT: One event per subscribed connected account. For a webhook trigger, an event is delivered for an account only when the event's provider workspace and user match the account's; a polled trigger polls each account with that account's own credential. Subscribed on a specific connected account. - CONNECTION: One event for the whole connection, whatever accounts exist on it. Subscribed on the connection itself, naming no account.
      - `effective_interval_seconds` integer: The polling interval, in seconds, the subscription actually runs at. Larger than requested_interval_seconds when the environment's polling budget is shared across many polled subscriptions; the subscription's status is then THROTTLED. Zero for a webhook trigger.
      - `id` string: Unique identifier of the trigger subscription.
      - `poll_state` TriggersTriggerPollState: The state of a poll subscription's feed, as of its most recent run. Read from the feed's own stored state on every request rather than derived, so a feed that is failing, rate limited, or held off is visible without looking at logs. A subscription whose status is ACTIVE can still be failing every run; this is where that shows.
        - `backoff_until` string, date-time: Polling is held off until this time, because the provider asked Scalekit to slow down or a run failed in a way retrying cannot fix. Absent when no hold-off has been recorded. A time in the past means the hold-off has ended and the next scheduled run polls again.
        - `consecutive_failures` integer: How many runs in a row have failed. Zero after any successful run.
        - `last_error` string: A short, human-readable explanation of why the most recent run failed and what happens next. Empty when the most recent run succeeded or no run has happened yet. Chosen from a fixed set of messages by last_error_code and never contains the provider's response. The wording can change: match on last_error_code, not on this text.
        - `last_error_code` 'RATE_LIMITED' | 'CREDENTIAL_REVOKED' | 'INVALID_CONFIGURATION' | 'PROVIDER_ERROR' | 'DELIVERY_FAILED' | 'TIMED_OUT' | 'POLL_FAILED': Why a poll subscription's most recent run failed. - RATE_LIMITED: The provider asked Scalekit to slow down. Polling resumes after backoff_until. - CREDENTIAL_REVOKED: The connected account's authorization was revoked or has expired. Reconnect the account. - INVALID_CONFIGURATION: The subscription's configuration does not produce a valid request for this trigger. Update the subscription's configuration. - PROVIDER_ERROR: The provider returned an error. Retried on the next run. - DELIVERY_FAILED: Events could not be handed to the delivery service. Retried on the next run. - TIMED_OUT: The run timed out before it finished. Retried on the next run. - POLL_FAILED: The run failed for a reason none of the other codes describes. Retried on the next run.
        - `last_run_at` string, date-time: When Scalekit last polled the provider for this subscription, whether or not the run succeeded. Absent until the first run. A value far older than the effective interval means the feed has stopped running.
        - `watermark_updated_at` string, date-time: When the feed's position last moved forward — the last time a run found and delivered newer events. A run that finds nothing new leaves it unchanged.
      - `provider` string: The provider the trigger belongs to.
      - `requested_interval_seconds` integer: The polling interval, in seconds, the subscription asked for, or the trigger's default when it did not set one. Returned next to effective_interval_seconds so a subscription running slower than requested is visible. Zero for a webhook trigger.
      - `status` 'ACTIVE' | 'THROTTLED' | 'PAUSED' | 'PAUSED_CREDENTIAL': Why a subscription is or is not currently delivering. - ACTIVE: Delivering. For a polled trigger, at the requested interval. - THROTTLED: Running slower than requested, not stopped. Still delivering. - PAUSED: Stopped by the customer. - PAUSED_CREDENTIAL: Stopped because the account's credential no longer works. Distinct from PAUSED so the two have distinguishable explanations for missing events.
      - `trigger_name` string: Name of the subscribed trigger, as returned by ListAvailableTriggers.

## Other responses

- `400`: Invalid request, nothing created - connection_id or an entry of connected_account_ids is malformed; config is invalid for this trigger; interval_seconds is below the trigger's minimum, or is set for a webhook trigger; the trigger polls and is connection-scoped, which is not supported; or connected_account_ids is empty for a trigger that is subscribed per connected account. A well-formed ID naming an account that does not exist is not this case: it comes back as a per-account NOT_FOUND result with a 200, so one bad ID in a batch of a hundred does not discard the ninety-nine that would have succeeded
- `404`: Not found - the connection does not exist in this environment, the connection's provider publishes no trigger with this name, or Triggers is not enabled for the environment
- `500`: Internal error - the connection or the trigger's definition could not be read, so no account was processed; retry the request

## Changes

- **2026-10-30** `f47f1022d844`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/scalekit/apis/scalekit-api-reference/changes/api/v1/connections/:connection_id/trigger-subscriptions:batchCreate/post.md)

---

[API](https://skmtc.dev/scalekit/apis/scalekit-api-reference.md) - [All operations](https://skmtc.dev/scalekit/apis/scalekit-api-reference/llms.txt) - [OpenAPI document](https://skmtc.dev/scalekit/apis/scalekit-api-reference/revisions/f47f1022d844?raw)
