Integrations

Sync card due dates with Google Calendar, show the family calendar in Apple Calendar or Outlook, forward school letters by email, sync a board with Google Sheets, send signed webhooks, link GitHub pull requests to cards, reach Zapier, Make and n8n, post to Slack, and bring in Canva designs.

Checked against the running product on 12 min readMarkdown

On this page

Nobody wants a second calendar, so these integrations are narrow on purpose. Each one moves a specific thing between The Margin and a tool you already use, and asks Google for the smallest permission that does the job.

IntegrationWhat movesWhere you set it up
Google CalendarCard due dates out, events inThe gear on the Calendar page, Google Calendar sync
Apple Calendar, Outlook, any calendar appThe family calendar out, read-only, by a private linkShare and subscribe on the Calendar page
A published calendar (a school's, a club's)Its events in, read-onlyShare and subscribe on the Calendar page
EmailA forwarded school letter becomes dates to confirmThe Calendar's settings, Forward letters by email
Google SheetsOne board's cards, either wayA board's settings, Google Sheets sync
WebhooksEvents out to a URL you chooseSettings→Webhooks and API
GitHubPull requests and issues noted on cardsSettings→Integrations
SlackEvents out to a channel, through a webhookSettings→Webhooks and API
Zapier, Make and n8nEvents out by webhook, calls in with an API keySettings→Webhooks and API
CanvaDesigns in, as pages you can work withA whiteboard's Bring in a Canva design

Connect your Google account once in Settings→Integrations. Calendar and Sheets each ask for their own permission the first time you use them.

Google Calendar#

Open the Calendar page, press the gear and choose Google Calendar sync. Pick a calendar, a direction (Push (Margin to Calendar), Pull (Calendar to Margin) or Bidirectional) and how many days ahead to cover, from 1 to 365. Turn on Enable sync. Nothing moves until you press Sync Now, and nothing runs on a timer: each sync is one press.

  • Push sends every open card with a due date inside that window to the calendar. A repeating card goes as one repeating event, so a weekly standup stays one series. Completed cards stay behind, and so does any column you have hidden from the calendar.
  • Pull brings the calendar's events into a board called Calendar, which is made for you the first time. Each event becomes a card with its date.

For a pulled card, the calendar is the source. The next pull overwrites its title, description and date with whatever the event says, so make those changes in Google.

We ask for calendar.events, which lets us create, read and update events and nothing else: not your calendar settings, not who you share calendars with. Google turned down our first verification for asking more broadly than that, and they were right to.

Google Sheets#

From a board's settings, Google Sheets sync links the board to a spreadsheet. Pick one with Google's picker or Browse, or paste the link of a sheet The Margin made for you, then choose a direction: Push (Margin to Sheets) writes the board's cards into the sheet, Pull (Sheets to Margin) reads rows back as cards (rows it has already imported are not doubled), and Bidirectional does one then the other. With no sheet chosen, Create & Sync makes a new spreadsheet named after the board. Like the calendar, Enable sync has to be on, and a sync runs when you press it.

It suits the person in the loop who lives in a spreadsheet and is not going to stop.

We ask for drive.file. That covers files you pick through Google's own picker and files the app created for you, and nothing else in your Drive, which is why a pasted link only works for a sheet The Margin made.

Webhooks#

A webhook sends a signed POST to your URL when something happens in the workspace. In Settings→Webhooks and API, press New webhook, give it a name and a payload URL, check its events, then use Send test to check the URL answers. The Active switch pauses a webhook without deleting it.

The payload URL has to be a public web address, on any port. An address on a private network, localhost or a cloud server's internal address is refused when you save it, and checked again before every delivery. Redirects are not followed: answer at the URL you gave.

The events you can subscribe to

Workspace and people

a workspace created or updated, a member added, removed or given a new role.

Boards and cards

a board created, updated or archived; a card created, updated, moved, completed or deleted.

Notes

a note made, in the app or from a share, a scan, an email or an automation.

Syncs
a Sheets sync or a Calendar sync finished.
Agent pacts

a pact created or archived, a message posted or its status changed, a section updated, a decision raised or resolved, a participant added, joined or revoked, a handshake updated.

The kitchen

a meal planned, cooked or removed, a recipe saved, a shopping run finished.

Every delivery carries X-Margin-Event with the event name, X-Margin-Event-Id with the event's own id (the same on every retry, so you can skip one you have already handled), X-Margin-Delivery with an id for that attempt, and X-Margin-Signature: an HMAC-SHA256 of the raw body, keyed with the webhook's secret. The secret is shown once, when you create the webhook, and you can regenerate it later. Check the signature before trusting a delivery:

ts
import { createHmac, timingSafeEqual } from "node:crypto"

// rawBody is the request body exactly as it arrived, before any JSON parsing.
export function isFromMargin(rawBody: string, header: string, secret: string) {
  const expected =
    "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex")
  const a = Buffer.from(expected)
  const b = Buffer.from(header)
  return a.length === b.length && timingSafeEqual(a, b)
}

A delivery that fails is tried five times in all, with the wait doubling from ten seconds. Each webhook lists its Recent deliveries, with the event, the status and the HTTP code your server sent back.

Slack#

What works today: Margin events posted into a Slack channel. In Slack, make an incoming webhook for the channel (Slack's own Incoming Webhooks app gives you a hooks.slack.com address). Paste that address as the payload URL of a new webhook in Settings→Webhooks and API and pick the events. The Margin sees it is a Slack address and sends each event as a short Slack message rather than raw JSON.

When the app is ready, an owner or admin presses Add to Slack on that card and Slack asks which channel The Margin may post to. Then /margin and a thought, a link or a to-do lands in this workspace's Inbox, Save to Margin on a message's menu keeps that message there with a link back, and the chosen channel hears about new cards, finished cards and new notes through an ordinary webhook you can change or pause. The app asks Slack only to add a command and post to one channel, so it reads no channel, and one Slack workspace connects to one Margin workspace.

GitHub#

An owner or admin connects a repository from the GitHub card in Settings→Integrations. Connect a repository gives you a Payload URL and a Secret, and the secret is shown only then. In the repository on GitHub, open Settings, Webhooks, Add webhook, paste both, set the content type to application/json and pick Pull requests and Issues.

To link a pull request or issue to a card, put the card's link (Copy link on the card) in its description or title. The card gets a comment saying which pull request or issue it is, once per link. When the pull request is merged, the card moves to its board's done column and is marked complete. The done column is the first whose name starts with Done, Shipped, Complete, Finished, Merged or Closed, and otherwise the last column. Closing an issue does not move the card, because on a public repository anyone can close one.

Only pull requests and issues opened by the repository's owner, its organization's members or its collaborators do anything; one from anyone else that names a card is ignored. Each delivery is acted on once, so redelivering it from GitHub changes nothing. Slack and GitHub write as the person who connected them, so they stop saving anything if that person leaves the workspace or the plan no longer includes integrations; connect them again from an account that is still there.

Zapier, Make and n8n#

None of the three has an app to install yet. Each one works through the two general doors here: a webhook for events going out, and an API key for calls coming in.

Zapier. Events: a Webhooks by Zapier Catch Hook trigger, its address pasted into a new webhook here. Calls: a Webhooks by Zapier POST or GET action with the header Authorization: Bearer mk_....

Make. Events: add a Custom webhook module, copy its address into a new webhook in Settings→Webhooks and API and pick the events. Calls: an HTTP "Make a request" module with the same header.

n8n. Events: a Webhook node, its production URL pasted into a new webhook here. Calls: an HTTP Request node with the same header. n8n's MCP client node can also connect to the MCP server, with the Streamable HTTP transport and an access token as the Authorization header, which gives it every tool an assistant gets. See Agents and MCP.

Make an API key on the API Keys tab of Settings→Webhooks and API with the permissions you need (Read, Write, Webhooks). It is shown once, so save it then. A key belongs to one workspace and acts as the person who made it, so it stops working if that person leaves the workspace or is held out by its two-factor rule. Its writes also stop once the plan no longer includes integrations; reads keep working. What it can call:

CallWhat it does
GET /api/webhooks/actions/boardsboards and their columns
GET /api/webhooks/actions/cards?boardId=cards on a board
POST /api/webhooks/actions/cardsa card: boardId, columnId, title, optional description, priority, dueDate
POST /api/webhooks/actions/notesa note in the Inbox: title and/or content (markdown)
GET /api/webhooks/actions/shopping-itemsthe shopping lists
POST /api/webhooks/actions/shopping-itemsan item: name ("2 liters of milk" works), optional quantity, listId. Family plan; an item already on the list is not added twice
POST /api/webhooks/subscribe and /unsubscribeREST hooks: url and events in, webhookId out
GET /api/webhooks/poll?eventType=recent events, newest first

All of them live under https://themarginapp.com. For anything wider than this, connect an MCP client instead. See Agents and MCP.

Canva#

A Canva design comes in as its pages and the words on them, kept in the workspace beside your whiteboards, where you can lay its pages on a whiteboard or share it. You keep editing it in Canva.

Bring a design in#

Press Bring in a Canva design in a whiteboard's top bar, Bring in a design under Canva designs on the Whiteboards page, or Bring in a Canva handover on a card to tie the design to that card. The dialog has up to three tabs.

  • Upload a PDF or image (the one it opens on, because it always works): download the design from Canva as a PDF or an image and drop it in, up to 50 MB. Its pages and text are read in your browser, and every page comes across. This needs no Canva account connected.
  • Paste link: paste a Canva share link. Without a connection that brings the cover and the title, and on a whiteboard nothing is placed on the canvas until the pages arrive (the dialog says so). With your Canva account connected, a link to one of your own designs brings every page.
  • Your Canva designs: shown once you connect. Search your own designs, pick one, and press Render from Canva. Canva renders every page and they arrive in a moment.

Connect your Canva account#

Connecting is optional. In Settings→Integrations, the Canva card has Connect Canva, which sends you to Canva to approve. The Margin asks Canva only to read your designs; it never changes one. Disconnect on the same card deletes the stored access and ends it at Canva too.

When a design goes#

Deleting a design removes its rendered pages from storage along with it. Deleting a workspace does the same for every design in it, and deleting your account also ends your Canva connection at Canva. PDFs were never stored, so there is nothing of them to remove.

Work with a design#

Open a design to see its pages beside what was read from them: its color palette, its fonts and its text. From there:

  • Open in Canva opens it in Canva's editor, or opens the link it came from.
  • Refresh from Canva fetches the pages again after you have changed the design in Canva.
  • PDF has Canva export the whole design as a PDF and opens it. The link Canva gives lasts about a day.
  • Embed on a board places its pages on a whiteboard you pick, and Share shares it like any other item.

Refresh and PDF appear only while your account is connected and the design is one Canva knows from that account.

The text read from a design also goes into the Mind, so asking Margin Intelligence for "the poster that says spring fair" can find it.

The Canva design hub is part of Pro, Family and Team. See Whiteboards and Canva for designs on whiteboards.

A calendar link is a private web address ending in .ics that any calendar app can subscribe to. Make one for the whole household or for one person. Apple Calendar opens it straight from Open in Apple Calendar. In Outlook, choose Add calendar, then Subscribe from web, and paste the link. Repeating events, time zones and all-day events arrive as they are in Margin. Calendar apps check for changes on their own schedule, usually every few hours.

The link is read-only, and anyone who has it can read that calendar. Revoke it from the same place and it stops working at once. Tasks are left out unless you check Include tasks when you make the link.

Going the other way, paste the address of a published calendar and give it a name and the people it is for. Its events show on the family calendar in their colors, read-only, and refresh about once an hour. Remove it, and its events go with it.

Forwarding letters by email#

Each family workspace can have a private address of the form family+…@themarginapp.com. Forward a school's email to it, attachments included, and the dates it finds wait under Letters to review on the Calendar. Nothing is added until someone in the household confirms it. Make a new address or turn it off from the Calendar's settings; the old one stops working immediately. Reading a letter uses the household's AI actions and is part of the Family plan.

Availability#

Calendar links and published calendars work on every plan.

Setting any of these up needs a connection. It is account configuration rather than your content, so it is one of the few things that does not work offline.