Skip to Content
Browse docs

Maintained by

Receive Provider Events with Triggers

A Trigger subscription watches one end user’s connected account and sends new provider events to your project webhook as trigger.message events. When a user’s Google Sheet gets a new row, a new email reaches their Gmail, or a Stripe payment changes state, your backend receives an event.

Connector runs the subscription: it polls providers and registers and receives provider webhooks. Your backend creates subscriptions and handles the events.

How events arrive

ModeHow Connector gets eventsExamples
PollingReads the account at a fixed interval and sends rows, messages, or records that are new since the previous read.Gmail, Google Sheets, Google Calendar, Notion
PushThe provider sends events to a Connector callback URL. Connector verifies them and forwards matching events.GitHub, Stripe, Shopify, Slack

Push Triggers involve two URLs: your project webhook receives events from Connector, and the third-party callback URL (push.callbackUrl) receives events from the provider. Connector registers most callback URLs automatically; Slack, Microsoft Teams, Feishu, and Intercom need an administrator to enter it in the provider app.

Before you start

  1. Complete the Connector for SaaS guide so that your backend has a Project API key and saves each user’s connectedAccountId.
  2. Create a project webhook whose eventTypes include trigger.message and whose authTypes include the auth type of the accounts you subscribe to. Google accounts use oauth2. One webhook can receive events from every subscription in the project.
  3. Have the end user connect the account that the Trigger reads.

If the account is routed to a dedicated webhook, events go only to that webhook, so it must meet these conditions instead.

Connector checks the webhook when you create or resume a subscription. Without an active webhook that matches, the request fails with trigger_delivery_unavailable.

Step 1: Choose a Trigger

List the published Triggers and read the config schema of the one you need:

curl --silent --show-error \
  'https://connector.oomol.com/v1/saas/trigger-types/googlesheets.on_row_added' \
  -H "Authorization: Bearer $PROJECT_API_KEY"

GET /v1/saas/trigger-types lists every published Trigger; add ?service=googlesheets to filter by provider. The catalog is the same for every project.

FieldMeaning
idThe Trigger ID used when creating a subscription.
typepoll or push.
configSchemaJSON Schema for the subscription config, including defaults and required fields.
eventSchemaJSON Schema for data.payload in delivered events.
definitionVersionThe Trigger definition version recorded on new subscriptions.
defaultIntervalSeconds / minIntervalSecondsThe default and shortest polling interval. null for push Triggers.

Step 2: Create a subscription

This example watches the Orders sheet for new rows:

curl --silent --show-error \
  'https://connector.oomol.com/v1/saas/trigger-subscriptions' \
  -H "Authorization: Bearer $PROJECT_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: orders-sheet-customer-1' \
  --data @- <<JSON
{
  "userId": "customer-1",
  "connectedAccountId": "$CONNECTED_ACCOUNT_ID",
  "triggerId": "googlesheets.on_row_added",
  "config": {
    "spreadsheetId": "<spreadsheet-id>",
    "sheet": "Orders"
  },
  "intervalSeconds": 300
}
JSON
FieldUsage
userIdRequired: your product’s end-user ID that owns the connected account.
connectedAccountIdRequired: the account the subscription reads. It cannot be changed later.
triggerIdRequired: an id from the Trigger catalog.
configRequired: an object matching configSchema. It cannot be changed later; create a new subscription to watch something else.
intervalSecondsOptional, polling only: the read interval, at least minIntervalSeconds. Push subscriptions reject this field.

Send an Idempotency-Key header so that a retried request does not create a second subscription. The first request returns 201; replaying the same request with the same key returns 200 and the original subscription; reusing the key for a different request returns 409.

Save the returned id beside the user and account in your database. You can also create and manage subscriptions in Console: open the project and select Event subscriptions.

Receive events

Each event arrives at your project webhook as a signed trigger.message delivery. Verify the signature first, then read the envelope:

{
  "id": "evt_0199d2a8-4c1b-7e2f-8a3d-6b5c4d3e2f10",
  "type": "trigger.message",
  "version": 1,
  "createdAt": 1800000300000,
  "data": {
    "subscriptionId": "0199d290-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
    "triggerId": "googlesheets.on_row_added",
    "definitionVersion": 2,
    "externalUserId": "customer-1",
    "connectedAccountId": "0199d1f4-2e5f-7b61-8c72-9d0e1f2a3b4c",
    "providerConfigId": "0199d1a0-5f6e-7d8c-9b0a-1c2d3e4f5a6b",
    "service": "googlesheets",
    "payload": {
      "spreadsheetId": "<spreadsheet-id>",
      "sheetId": 0,
      "sheetTitle": "Orders",
      "rowNumber": 12,
      "row": { "Order ID": "A-1001", "Amount": 42 },
      "values": ["A-1001", 42]
    }
  }
}

data.payload follows the Trigger’s eventSchema. Use subscriptionId or externalUserId to route the event to the right user, and deduplicate by envelope id, which stays the same across retries and webhooks.

The first polling read only records the current position; existing rows, emails, or records are not sent. The subscription’s initialized field turns true after that read. Events created after it are sent on later reads.

Delivery uses the project webhook retry schedule. The same event can arrive more than once, and a delivery that runs out of retries or gets a non-retryable 4xx ends as failed; find those in Deliveries in Console or through the delivery records API. Each webhook has up to 5 requests in flight; a slow endpoint delays its own queue but not other webhooks. Events that reach a final state are kept for 7 days.

Manage subscriptions

TaskAPI
List subscriptionsGET /v1/saas/trigger-subscriptions, filtered by userId, connectedAccountId, or status, with limit (up to 100) and offset.
Read one subscriptionGET /v1/saas/trigger-subscriptions/{subscriptionId}
Pause or resumePATCH /v1/saas/trigger-subscriptions/{subscriptionId} with {"status": "paused"} or {"status": "active"}
Change the polling intervalPATCH /v1/saas/trigger-subscriptions/{subscriptionId} with {"intervalSeconds": 600}
DeleteDELETE /v1/saas/trigger-subscriptions/{subscriptionId}

A subscription shows status, pauseReason, initialized, nextPollAt, lastSuccessAt, lastError, and consecutiveFailures. Push subscriptions also show push.callbackUrl, push.setup (automatic or application), and push.ready. Deleting a subscription stops new reads; events recorded before deletion are still delivered.

When a subscription pauses

Connector pauses a subscription when it cannot continue safely. pauseReason tells you what to do:

pauseReasonCauseWhat to do
manualPaused through the API or Console.Resume when ready.
connection_unavailableThe account, credential, permission, or provider config is unavailable.Have the user reconnect the account, then resume.
config_invalidThe provider rejected the config, or the Trigger was retired.Fix the issue on the provider side and resume, or create a subscription with a new config.
delivery_unavailableNo active webhook matched the account when an event was recorded. For a routed account, only its routed webhook counts.Fix the webhook, then resume.
checkpoint_reset_requiredReading cannot continue from the saved position, for example after the sheet was replaced, rows were removed, or the provider’s sync token expired. pauseDetail has the reason.Create a new subscription. This one cannot be resumed, and changes in between are not sent.

Temporary provider errors do not pause a subscription. Connector retries with backoff from 30 seconds up to 30 minutes and records the latest error in lastError and consecutiveFailures.

If the user reconnects the same provider account, the subscription keeps working. If the user replaces it with a different provider account under the same alias, related subscriptions pause with checkpoint_reset_required.

Billing and team balance

Each event is billed once, when it is first delivered successfully to any webhook in the project. Reads, empty reads, retries, extra webhooks, and events that finally fail are not billed.

Triggers require a team balance that covers Connector usage:

  • When the balance is below zero, creating or resuming a subscription returns 402 insufficient_credit. Reads and deliveries stop. Viewing, changing the interval, pausing, and deleting still work.
  • When the balance cannot be verified, the same requests return 503 balance_unavailable with Retry-After: 30.
  • While delivery is blocked, push events are buffered up to 10,000 pending items per project. Connector still acknowledges events beyond that limit to the provider but does not store them, so the provider does not resend them. After 7 days of confirmed insufficient credit, pending events expire and new push events are dropped the same way until the balance recovers. The billing view counts both cases.
  • After the team adds credit, reads and deliveries resume automatically. Subscriptions paused for other reasons stay paused.

Subscription responses include a project billing summary with state (allowed, insufficient_credit, balance_unavailable, or unverified), the buffer size, and counts of rejected or expired events. List responses return it in meta.billing. unverified means the team balance has not been checked yet, usually because the project has no subscriptions; it does not block requests, and creating a subscription checks the balance.

Errors

HTTP status and errorCodeMeaning
404 trigger_not_foundThe Trigger ID is not published.
409 trigger_delivery_unavailableNo active webhook receives trigger.message for this account’s auth type. data.reason is no_active_webhook, event_type_not_subscribed, auth_type_not_subscribed, or routed_webhook_unavailable (the account’s routed webhook is disabled or does not match); data.webhookIds lists webhooks you can update.
409 trigger_subscription_reset_requiredThe subscription cannot be resumed. Create a new one.
409 app_not_readyThe connected account cannot be used, for example after it was disconnected. Have the user reconnect it.
402 insufficient_creditThe team balance is below zero.
503 balance_unavailableThe balance could not be verified. Retry after the Retry-After delay.

Available Triggers

The catalog from GET /v1/saas/trigger-types is the source of truth.

Polling Trigger IDWatchesDefault / minimum interval
airtable.on_record_changedNew or updated table records300 / 120 seconds
gmail.on_message_receivedNew emails120 / 120 seconds
googlecalendar.on_event_changedCalendar event changes120 / 120 seconds
googledrive.on_file_changeNew or updated files120 / 120 seconds
googlesheets.on_row_addedNew rows120 / 120 seconds
notion.on_database_page_eventNew or edited database pages120 / 120 seconds
one_drive.on_item_changedFile or folder changes120 / 120 seconds
outlook.on_message_receivedNew emails, filtered by folder and message conditions120 / 120 seconds
Push Trigger IDWatchesSetup
calendly.on_booking_eventBookings created or canceledAutomatic; uses a Personal Access Token
clickup.on_task_eventTask creation, status changes, and new commentsAutomatic; needs a Workspace ID or List ID
feishu_app_bot.on_eventEnabled app eventsApplication callback; credential needs Verification Token and Encrypt Key
github.on_repo_eventRepository eventsAutomatic; needs permission to manage repository webhooks
gitlab.on_project_eventProject pushes, issues, merge requests, pipelines, and other selected hooksAutomatic project hook; verifies with a Secret Token
intercom.on_conversation_eventCustomer conversations, customer replies, and new ticketsApplication callback; uses the connection’s OAuth client ID and Client Secret
jira.on_issue_eventIssues created, updated, or commented onAutomatic and renewed; needs Jira Cloud OAuth with webhook scopes
linear.on_issue_eventIssues created, updated, or deletedAutomatic; needs an admin API key or the OAuth admin scope
microsoft_teams_bot.on_activityBot messages and activitiesAzure Bot messaging endpoint
pandadoc.on_document_eventDocument status changesAutomatic
pipedrive.on_crm_eventPersons and deals created, or deal field changesAutomatic
resend.on_email_eventInbound email, bounces, and complaintsAutomatic
shopify.on_shop_eventShop eventsAutomatic; OAuth or app client credentials
slackbot.on_eventMentions, direct messages, and interactionsSlack app Events and Interactivity URLs; needs the app’s Signing Secret
stripe.on_eventStripe eventsAutomatic
tally.on_form_responseCompleted form responsesAutomatic
telegram.on_updateBot messages and selected update typesAutomatic setWebhook; uses the bot token
typeform.on_form_responseCompleted form responsesAutomatic
vercel.on_deployment_eventSuccessful and failed deploymentsAutomatic
woocommerce.on_store_eventOrders, products, coupons, and customer eventsAutomatic; needs a Read/Write consumer key
zendesk.on_eventSelected Zendesk eventsAutomatic

Provider notes

Polling sends the state visible at each read; edits between two reads are not sent one by one. Subscriptions on the same provider account, base, or workspace share that provider’s rate limits.

ProviderNotes
AirtabletriggerField must be a time field: Created time for new records, or a Last modified time field that tracks the fields you care about. Empty reads count toward API limits; one subscription at the default 5-minute interval makes about 8,640 reads every 30 days. Raise intervalSeconds if your plan needs it.
NotionShare the database with the connection and enable Read content. Set dataSourceId when the database has more than one data source. The first read rounds up to the minute, so earlier changes are not sent.
OneDriveparentFolderId matches only the direct parent folder.
Slack, Microsoft Teams, Feishu, IntercomAn app administrator enters push.callbackUrl in the provider app; subscriptions for the same app share it. After rotating the app’s signing key, update the connection credential. Slack and Feishu also require verifying the URL again with the new key.
Slack, FeishuSubscriptions for one app share a single receiver, and each new subscription replaces that receiver’s signing key with the one in its connection credential. If that credential’s key does not match the app, events for every subscription on the app fail verification. Keep the signing key in all of the app’s connection credentials in sync with the app, both when creating subscriptions and when rotating the key.
IntercomIn the Intercom Developer Hub, subscribe the app to the topics that cover the Trigger’s eventTypes (conversation.user.created, conversation.user.replied, ticket.created); Intercom only sends subscribed topics. Saving the callback URL sends an unsigned HEAD check, which Connector answers with 200. push.ready becomes true after a signed ping notification, and events are stored even before then.
Microsoft TeamsThe tenantId in the connection credential is the token authority. The optional tenantId in the Trigger config filters activities by tenant.
LinearAdd the admin scope to the provider config and reconnect. Connections that granted only read cannot create webhooks.
ShopifyConnector verifies events with the current client secret. Follow Shopify’s rotation steps when rotating it.

Troubleshooting

SymptomWhat to check
Creating a subscription returns trigger_delivery_unavailableFollow data.reason: create a webhook, add trigger.message to its event types, or add the account’s auth type. For routed_webhook_unavailable, update the routed webhook or remove the account’s routing.
No events after creating a polling subscriptionWait for initialized to become true, then add new data. Existing data is never sent.
A push subscription stays push.ready: falseCheck lastError. For Slack, Teams, Feishu, and Intercom, confirm that the provider app uses push.callbackUrl; for Intercom, also confirm that the app subscribes to the Trigger’s event topics.
Events stopped and pauseReason is setFollow the action in When a subscription pauses.
Events stopped and billing.state is not allowedAdd team credit or wait for the balance check to recover.

Your everyday apps, now for your AI

Let your AI find emails, read documents and look through code in the apps you already use.