> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gainable.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect outbound

> Slack, SMS, calendar, DocuSign, Stripe, generic webhooks. Inbound and outbound integrations for agents

## What Connect does

Gainable Connect is the integration layer between your Gainable app and external systems. For [Gaia Autopilot](/autopilot/overview), Connect plays two roles:

* **Outbound.** The targets agents can reach when they call [tools](/autopilot/tools) like `send_slack` or `call_external`.
* **Inbound.** The sources that fire [webhook triggers](/autopilot/triggers).

If you've used [datasets](/building/data-connectors) for ingesting data, Connect is the same idea applied to action and event flow. Datasets bring data in for the [Copilot](/copilots/overview) and the [build agents](/concepts/agents) to read. Connect routes outbound work and inbound events for agents.

## Outbound channels

Every outbound integration lives behind a typed [tool](/autopilot/tools) and inherits a default [risk tier](/autopilot/risk-tiers). The org configures credentials once; the agent calls the tool.

### Slack

```yaml theme={null}
- tool: send_slack
  channel: "#sales-ops"
  text: "Pipeline summary"
  blocks: "{{ rendered }}"
```

| Capability        | Notes                                              |
| ----------------- | -------------------------------------------------- |
| Channels          | Public, private (with bot installed)               |
| DMs               | Yes, to bot-installed users                        |
| Threading         | `thread_ts` parameter                              |
| Default risk tier | High (draft-and-approve)                           |
| Common graduation | Internal channels can graduate to `auto_with_undo` |

### SMS

```yaml theme={null}
- tool: send_sms
  to: "{{ contact.phone }}"
  body: "{{ message }}"
```

| Capability        | Notes                                                                        |
| ----------------- | ---------------------------------------------------------------------------- |
| Provider          | Twilio (default), configurable                                               |
| Delivery receipts | Logged in action log                                                         |
| Default risk tier | High (draft-and-approve), no auto-with-undo path                             |
| Notes             | SMS undo isn't possible. Always draft-and-approve unless explicitly opted-in |

### Calendar

Outbound calendar operations through the configured calendar provider (Google Calendar, Microsoft 365).

```yaml theme={null}
- tool: call_external
  via: calendar
  action: create_event
  calendar_id: "{{ user.calendar_id }}"
  event:
    title: "Follow-up: {{ deal.name }}"
    start: "{{ next_business_day_at_2pm }}"
    duration_minutes: 30
    attendees:
      - "{{ contact.email }}"
```

| Capability        | Notes                             |
| ----------------- | --------------------------------- |
| Create event      | Yes, draft-and-approve by default |
| Update event      | Yes, with undo window             |
| Delete event      | Yes, draft-and-approve only       |
| Default risk tier | High (calendars are user-visible) |

### DocuSign

```yaml theme={null}
- tool: call_external
  via: docusign
  action: send_envelope
  template_id: "{{ template_id }}"
  recipients:
    - email: "{{ contact.email }}"
      name: "{{ contact.name }}"
      role: "Signer"
```

| Capability        | Notes                                    |
| ----------------- | ---------------------------------------- |
| Send envelope     | Always draft-and-approve. No exceptions. |
| Voiding           | Allowed with explicit user action        |
| Default risk tier | High (legally binding), no auto path     |

### Stripe

```yaml theme={null}
- tool: call_external
  via: stripe
  action: create_invoice
  customer: "{{ stripe_customer_id }}"
  items:
    - amount: "{{ amount_cents }}"
      currency: usd
      description: "{{ description }}"
```

| Capability        | Notes                                     |
| ----------------- | ----------------------------------------- |
| Create invoice    | Draft-and-approve                         |
| Capture payment   | Draft-and-approve only                    |
| Refund            | Draft-and-approve only                    |
| Default risk tier | High (financial operations), no auto path |

### Generic webhooks (`call_external`)

When the registry doesn't have a dedicated tool, use [`call_external`](/autopilot/tools).

```yaml theme={null}
- tool: call_external
  method: POST
  url: "https://api.example.com/notify"
  headers:
    Authorization: "Bearer {{ secrets.example_key }}"
  body:
    event: "deal_lost"
    deal_id: "{{ deal.id }}"
```

The runtime can't reason about what an arbitrary endpoint does, so the default tier is high. If the call is well-understood and idempotent, it can be graduated.

## Inbound webhooks (as triggers)

Inbound webhooks become [webhook triggers](/autopilot/triggers) on a playbook. The runtime provisions a unique URL per trigger and verifies signatures where the source supports it.

### Provisioning

When you add a webhook trigger, Connect generates a URL:

```
https://api.gainable.dev/webhooks/{app_id}/{trigger_id}
```

You configure the source system to POST to that URL.

### Signature verification

| Source   | Verification method                                     |
| -------- | ------------------------------------------------------- |
| Stripe   | `Stripe-Signature` header, HMAC-SHA256                  |
| GitHub   | `X-Hub-Signature-256` header                            |
| SendGrid | Public key signature on each event                      |
| Twilio   | `X-Twilio-Signature` header                             |
| Generic  | HMAC if shared secret is configured, else IP allow-list |

The runtime rejects unverified webhooks before the playbook runs. Rejections are logged in the [action log](/autopilot/agent-action-log) for debugging.

### Common inbound sources

| Source   | Example events                  | Common playbook                                           |
| -------- | ------------------------------- | --------------------------------------------------------- |
| Stripe   | `invoice.payment_failed`        | Draft a payment-failure recovery email                    |
| Stripe   | `customer.subscription.deleted` | Draft a churn outreach                                    |
| SendGrid | `bounce`, `spamreport`          | Mark contact as undeliverable, exclude from future drafts |
| GitHub   | `issue.opened`                  | Route to engineering Autopilot                            |
| Calendar | `event.created`                 | Draft a pre-meeting briefing                              |
| Twilio   | inbound SMS                     | Draft a reply suggestion to the assigned rep              |

## Configuring credentials

Credentials are stored at the org level, not per-app. To add a Slack workspace, a Stripe key, or a Twilio account, the org admin connects it once. All apps in the org can use the connected services through the tool registry.

```text theme={null}
Connect our Slack workspace so agents in the
sales app can post to #sales-ops.
```

```text theme={null}
Add the Stripe production key for the
billing app's invoice playbook.
```

<Note>
  Credentials never appear in the [action log](/autopilot/agent-action-log). They're referenced by name (e.g. `secrets.stripe_key`); the runtime resolves them at call time and never logs the resolved value.
</Note>

## Allow-lists for outbound recipients

For external messaging tools (`send_email`, `send_slack` to external workspaces, `send_sms`), Connect supports allow-lists at the org level:

| Allow-list                  | What it does                                        |
| --------------------------- | --------------------------------------------------- |
| Allowed email domains       | Drafts to other domains are blocked at send time    |
| Allowed phone country codes | Drafts to other countries are blocked at send time  |
| Allowed Slack workspaces    | Drafts to other workspaces are blocked at send time |
| `do_not_contact` collection | A list of recipients excluded regardless of domain  |

The allow-list is applied **after** the draft is approved but **before** the underlying tool runs. A user can approve a draft and still see it blocked if the recipient isn't allowed.

## Best practices

<AccordionGroup>
  <Accordion title="Verify signatures wherever the source supports it">
    Inbound webhooks without signature verification are an attack surface. Configure the secret on the source side and the runtime will reject anything unsigned.
  </Accordion>

  <Accordion title="Start with a small allow-list for outbound">
    A new sales agent can email `acmecorp.com` and `gainable.dev`. After a clean approval history, expand. Loud allow-lists invite mistakes.
  </Accordion>

  <Accordion title="Use generic call_external sparingly">
    Every `call_external` is a system the runtime can't reason about. Prefer a first-class tool when one exists. If you find yourself using `call_external` for the same target repeatedly, that target is a candidate for promotion.
  </Accordion>

  <Accordion title="Test webhook payloads in simulation">
    Capture a real payload from the source, then replay it through [Simulate on last 30 days](/autopilot/playbooks). It's the safest way to verify your filter and steps.
  </Accordion>
</AccordionGroup>

## Learn more

<CardGroup cols={2}>
  <Card title="Tools" icon="screwdriver-wrench" href="/autopilot/tools">
    The fixed registry, including outbound tools
  </Card>

  <Card title="Triggers" icon="bolt" href="/autopilot/triggers">
    Webhook trigger configuration
  </Card>

  <Card title="Risk tiers" icon="shield-check" href="/autopilot/risk-tiers">
    Default tiers per outbound channel
  </Card>

  <Card title="Datasets" icon="plug" href="/building/data-connectors">
    Inbound data ingestion (different from action and event flow)
  </Card>
</CardGroup>
