# Connections

The services your apps can use, in five pages, and how Slack notifications work.

## Five pages

**Connections** in the sidebar has a page per kind of service:

| Page | What's there |
|---|---|
| Marketing | Ad accounts (Google Ads, Meta Ads), with which app each one pays for; HubSpot for contacts and deals; Mailchimp for audiences. |
| App Functions | Services your apps call from their own code: Slack, Discord, Twilio SMS, Notion, Airtable, Google Sheets, Calendly, Google (Gmail and Calendar), Resend email, OpenAI, Supabase, any REST API. |
| Account Functions | Services that work on your Ripping account: GitHub export, your own Anthropic key; and outgoing webhooks for every app's events. |
| Finance | Your own Stripe or PayPal, for apps that sell; your Shopify store. |
| Analytics | Google Analytics: a GA4 property and tag per published app, with the last week's figures. |

A connection is made once per account and every app you build can use it. Secrets stay on the server; apps call through a proxy.

## Slack

**Connect** on App Functions installs the Ripping bot in your Slack workspace with permission to post and to list channels. Two things follow:

- **Your apps can post.** The builder knows `notify()` and `useChannels()` from `src/lib/slack.ts`; ask for "post to Slack when an order is placed" and it wires it. Only signed-in users of the app can trigger a post.
- **Ripping posts your own events.** On an app's Settings → Notifications, pick a channel and tick what you want to hear about: a visitor's inbox message, a sign-up, a sale, a refund, a chargeback. Ripping posts these itself; the app needs no code.

To post into a private channel, invite the bot to it in Slack first.

## Notion

**Connect** on App Functions authorises the Ripping integration in your Notion workspace; while connecting, Notion asks which pages and databases to share with it, and you can share more later from a database's … menu → Connections. Two things follow:

- **Your apps can read and write those databases.** The builder knows `useDatabases()`, `queryDatabase()` and `addRow()` from `src/lib/notion.ts`; ask for "save every booking to my Notion Bookings database" and it wires it.
- **Inbox messages can be logged automatically.** On an app's Settings → Notifications, pick a database under "Log inbox messages to". Each message becomes a row; properties fill in where their names match the form's fields.

## Google Analytics

**Connect** on the Analytics page signs you into Google with the Analytics permissions (a separate connection from Gmail and Calendar). Then every app you have published appears with a **Turn on** button:

1. Ripping creates a GA4 property named after the app in your Google Analytics account (you pick the account when you have more than one) and a web stream for the app's address.
2. The measurement id is kept on the app, and the GA tag goes into it at its next deploy.
3. The page shows users, sessions, page views and the top pages for the last seven days, per app.

You need a Google Analytics account first; make one at analytics.google.com if the page says there is none. The app's own code never changes.

## HubSpot

**Connect** on Marketing authorises Ripping in your HubSpot portal for contacts and deals. Then:

- **Your apps can write to the CRM.** The builder knows `upsertContact()`, `createDeal()` and `useRecentContacts()` from `src/lib/hubspot.ts`; ask for "every sign-up becomes a HubSpot contact" or "each order becomes a deal" and it wires it.
- **Inbox messages can become contacts automatically.** On an app's Settings → Notifications, switch on "Add inbox messages as HubSpot contacts". The message's email, name, phone and company fields are matched by name and the contact is created or updated, with lifecycle stage set to lead.

## Mailchimp

**Connect** on Marketing authorises Ripping in your Mailchimp account. Then:

- **Your apps can subscribe people.** The builder knows `subscribe()` and `useAudiences()` from `src/lib/mailchimp.ts`; ask for "a newsletter box that adds them to my audience" and it wires it.
- **Inbox emails can join an audience automatically.** On an app's Settings → Notifications, pick the audience under "Add inbox emails to". Every message with an email is subscribed and tagged with the app's name. That audience is also where the app's own `subscribe()` goes when it names none.

## Discord

**Connect** on App Functions adds the Ripping bot to a server you manage, with permission to see channels and post. It works like Slack: your apps can post with `notify()`, and on an app's Settings → Notifications you pick a channel and the events Ripping posts there. Give the bot a role that can see any private channel you want it to post in.

## Airtable

**Connect** on App Functions authorises Ripping in your Airtable account; Airtable asks which bases to grant. Then your apps can read and add rows in those bases (the builder knows `useBases()`, `tablesOf()`, `queryTable()` and `addRow()` from `src/lib/airtable.ts`), and on an app's Settings → Notifications you can pick a table under "Log inbox messages to". Each message becomes a row, with fields matched by name.

## Twilio SMS

Twilio has no sign-in flow, so the card takes your Account SID, auth token and a number you own. Your apps can then text people with `sendSms()` (the builder knows it), and on an app's Settings → Notifications you can enter your own number and pick the events Ripping texts you about. Every text is a Twilio message from your number, on your Twilio bill.

## Webhooks (Zapier, Make, your own server)

There is nothing to connect. On an app's Settings → Notifications, under **Webhook**, paste a URL (a Zapier or Make catch hook, or your own endpoint), tick the events, and Save. Ripping then POSTs each event as JSON:

```json
{ "event": "sale", "app": { "id": "…", "name": "Invoice Tracker" }, "at": "2026-09-20T15:04:05Z", "text": "ana@example.com paid $49.00 on Invoice Tracker — Beginner course", "data": { "payment_id": "…", "amount_cents": 4900, "currency": "usd", "customer_email": "ana@example.com", "items": "Beginner course", "reference": "A1HNMUJX" } }
```

Events and their `data`: `inbox` (`collection`, `record`), `signup` (`email`, `name`, `status`), `sale` (`payment_id`, `amount_cents`, `currency`, `customer_email`, `items`, `reference`), `refund` (`refunded_cents`, `amount_cents`, `full`, …), `dispute` (`state`, `amount_cents`, `reason`, `due_at`, …), and `test` from the **Send a test** button.

Every request carries `X-Ripping-Event` and `X-Ripping-Signature: sha256=<hex>`, the HMAC-SHA256 of the raw body with the app's signing secret (shown on the settings page; **Make a new one** rotates it). Verify it before trusting a delivery:

```js
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(rawBody).digest("hex");
if (expected !== req.headers["x-ripping-signature"]) return res.status(401).end();
```

One attempt per event, ten seconds. The settings page shows the last delivery's status.

## Google Sheets

**Connect** on App Functions signs you into Google with the Sheets permissions (a separate connection from Gmail and Calendar, and from Analytics). Your apps can then read tabs as rows and append rows (the builder knows `useSpreadsheets()`, `sheetsOf()`, `readSheet()` and `appendRow()` from `src/lib/sheets.ts`), and on an app's Settings → Notifications you can pick a spreadsheet and tab that inbox messages are appended to. The first row of a tab is its header; an empty tab gets one from the first message.

## Calendly

**Connect** on App Functions authorises Ripping with your Calendly account and, on a paid Calendly plan, subscribes to your bookings. Your apps can show your event types with their booking links and list upcoming bookings (the builder knows `useEventTypes()` and `upcoming()` from `src/lib/calendly.ts`). On an app's Settings → Notifications, switch on "Tell this app about my Calendly bookings" and each booking made or cancelled becomes a **booking** event you can route to Slack, Discord, a text or a webhook like the others.

## Shopify

On Finance, enter your store's myshopify.com address and press **Connect**; Shopify asks you to approve Ripping reading products and orders, and Ripping subscribes to new orders. Your apps can then show your products with buy links and, for admins, recent orders (the builder knows `useProducts()` and `recentOrders()` from `src/lib/shopify.ts`). On an app's Settings → Notifications, switch on "Tell this app about new Shopify orders" and every new order becomes a **sale** event routed to Slack, Discord, a text or a webhook like the others.
