Connecting your accounts to Laurelin
Laurelin only knows what we tell it. The faster you connect Outlook, Slack, and Telegram, the less time you spend retyping who you talked to and what about. This guide covers all four connectors (Outlook, Slack, Telegram, Notion), what each one buys you, and what's still on you to decide.
All four live on the Sync tab in Laurelin (https://laurelin.valinorinfo.com/apps/laurelin.html).
The shape of the pipeline
Every connector follows the same path:
- The adapter pulls raw messages from the source (Microsoft Graph, Slack Events webhook + web API, Telegram getUpdates, Notion API).
- The auto-router classifies each one as a known contact, a known company by domain, internal-only, blocklisted, or unknown.
- Known senders bypass review. They become interactions directly, linked to the right company and people.
- Unknown senders go to the Sync Inbox. You approve, merge, or dismiss; approval creates the company, person, and interaction in one click.
- Watermarks track progress so a worker restart never replays history.
Two things to remember:
- Laurelin reads, it never writes. None of these connectors can send mail, post to Slack, or reply on Telegram.
- The Sync Inbox is the human gate. Auto-routing handles the easy 80%; you handle the rest at your own pace.
Outlook
What it enables
- Every external email auto-logged as an interaction against the right company.
- Calendar events ingested as meetings, with attendees resolved to contacts.
- Lost-thread detection. Outbound emails that go unanswered show up as stale-thread candidates so you can chase or drop them.
How it works
OAuth into your @valinordigital.com mailbox via Microsoft Graph (Mail.Read, Calendars.Read). Every few minutes the sync worker calls /me/messages filtered to receivedDateTime ge <watermark> and walks each new message through the auto-router. Body content is summary-only (about 255 chars of bodyPreview). No full bodies, no attachments.
Automated
- Domain matching.
[email protected]matches Maple Finance because the domain is on the company'semail_domainsarray. - Contact creation when the company is known but the sender is new.
- Direction inferred from your address (outbound) vs theirs (inbound).
- Newsletter and automated-mail headers (
List-Unsubscribe,Auto-Submitted, bulk-mail signals) get dropped before they reach you. - Internal-only threads (all participants
@valinordigital.com) are skipped.
Surfaced for you
- Sync Inbox approval for anything where the sender's domain is unknown. You see the email, the suggested company match (if any), the suggested people, and pick approve, dismiss, or merge into an existing company.
- Skip rules for senders or domains you want permanently ignored (recruiters, vendor noise, vendor newsletters that slip past the header filter). Add them from the Sync tab.
- Company domain learning. When you approve an interaction from a new domain, that domain gets added to the company's
email_domainsso the next message auto-routes.
To connect
Sync tab → Connect Outlook → OAuth flow. Admin sets the Azure AD client ID / secret / tenant once; after that everyone connects in one click. Connection status, last poll time, and a Poll now button live on the same panel.
Slack
What it enables
- External Slack channels and DMs ingested as interactions on the right company.
- Live capture. Messages arrive seconds after they're sent, via the Events webhook.
- 48-hour backfill on demand so you can pull recent history into a newly mapped channel.
How it works
You install the Valinor Slack app to the workspace and OAuth your own user (channels:history, groups:history, im:history, mpim:history, users:read). The Events webhook fires on every new message; the adapter normalizes and runs the auto-router. Backfill calls conversations.history per channel for the lookback window.
Automated
- Channel-to-company mapping is sticky. Once you map
#ext-valinor-tempoto Tempo, every future message in that channel routes to Tempo without asking. - Sender resolution by
slack_user_id(stored on the people row). - Thread context preserved via
thread_tsso replies group with the parent. - Internal-only channels are auto-skipped.
Surfaced for you
- Channel mapping. New channels appear in the Sync tab with "Unmapped" until you pick the company they belong to. One-time choice per channel.
- Sync Inbox approval for DMs and shared channels where the sender isn't yet in Laurelin.
- Backfill button when you map a channel and want the last 48h of context loaded into the inbox.
To connect
Sync tab → Connect Slack → OAuth. Admin sets the Slack app credentials once. After that, mapping channels is the only recurring work, and most channels get mapped on their first message.
Telegram
What it enables
- Business-account chats logged as interactions, per chat you choose to track.
- Sender matching by
telegram_user_idandtelegram_handleon the people row. - Useful for partners who default to Telegram (most APAC and LATAM counterparties, several protocol teams).
How it works
Telegram Bot API in Business mode. The bot reads your chats via getUpdates long-poll. You pair the bot to your team-member record once, then add it to your Telegram Business account, then opt in per chat. It is read-only by design; the telegram-bot.js helper exports zero send-side methods.
Automated
- Once a chat is opted in, every new message routes through the same auto-router (known person → log, unknown → Sync Inbox).
- Chat scope persists across sessions; no re-opting per message.
- Edited messages are ignored for now (Phase 4 will reconcile them with summaries).
- Pairing codes are HMAC-signed and expire in 10 minutes so a leaked code is useless after that window.
Surfaced for you
This is the connector with the most setup friction. Three things you actively do:
- Pair once. Sync tab → My Telegram → Generate pairing code. Open Telegram, find the bot, send
/pair <code>. Binds yourtelegram_user_idto your people row. - Connect in Business mode. Telegram → Settings → Business → Chatbots → add the bot's username, enable it. Without this step the bot can't see anything.
- Pick which chats to log. Each chat starts as "Off" and appears in the chats table as messages arrive. Flip the toggle per chat. Shared chats with teammates can use a team override (force on / force off) so one person's choice covers the group.
To connect
Admin sets the bot token (from @BotFather) once. After that, the three steps above. The Refresh button on the panel surfaces new chats and pairing status.
Notion
What it enables
- The pipeline state in our Notion CRM stays in sync with Laurelin's
companiesandprojects. - Activity logged in Notion creates corresponding interactions in Laurelin.
How it works
A dedicated worker (laurelin/notion-pipeline-sync.js) reconciles records between Notion's pipeline database and Laurelin. Every 15 minutes it pulls from Notion and mirrors the pipeline fields exactly: edits and clears both propagate, deals removed from the Notion pipeline drop out of Laurelin's, and new Notion pages appear without waiting for the daily S3 roster refresh.
Pushing the other way is manual. The Push to Notion button on the Pipeline tab rewrites the linked Notion pages to match Laurelin's current state (only fields that differ are written) and creates pages for companies that exist only in Laurelin. Where Notion stores one field that Laurelin keeps on both the company and its Deal project (Process, Key questions, Goal, Size, Deal Type, End Market, Priority), the project's value wins when a Deal project is linked.
Before every pull, push, and restore, a checkpoint of the pipeline state is saved (newest 60 kept; no-op pulls don't leave one). The Checkpoints panel on the Pipeline tab lists them and can restore any snapshot into Laurelin. Restoring only changes Laurelin; push to Notion afterwards to roll Notion back too. Restores are themselves checkpointed, so they are reversible.
To connect
Notion sync is a workspace-level setup — there's no per-user OAuth. Admin configures the Notion integration token once; the worker uses it for all reads. Status and a manual "Reconcile now" button live on the Sync tab.
If something looks off (a company in Notion isn't in Laurelin or vice versa), use the reconcile button and check the pipeline/reconcile endpoint status.
Do-not-track
For correspondence with specific people you want to keep entirely out of Laurelin (a sensitive negotiation, personal threads from a work address that you don't want logged):
- Sync tab → Do-not-track.
- Add their email address.
Any future inbound or outbound to that address will be skipped at ingest. Existing interactions are unaffected — you can delete those manually if needed.
Different from skip rules: skip rules drop a domain or subject pattern globally. Do-not-track is per email address and applies regardless of company.
Day-to-day: the Sync Inbox
Once your connectors are live, your job collapses to one tab:
- Open Sync Inbox each morning. Yesterday's auto-routed interactions are already logged; the queue shows only items that need a decision.
- For each item: approve into an existing company, approve into a new company, merge with another inbox item, or dismiss.
- Skip rules (set from the same tab) cover anything you never want to see again.
Approval is the only manual step. Everything else (domain matching, contact creation, thread linking, direction inference) happens upstream of you.
When something goes wrong
- "Why isn't this email showing up?" Check the worker status banner on the Sync tab; check that the sender's domain isn't in your skip rules; check that the message isn't internal-only.
- "Slack channel not mapping." It shows up after the first message arrives. If nothing arrives, you probably aren't a member of that channel.
- "Telegram chat not appearing." The bot only sees chats that have had at least one message since you connected it in Business mode. Send a "hi" in the chat to make it appear, then toggle logging on.
- "Notion company missing in Laurelin." Hit the Reconcile button on the Notion panel. If it still doesn't appear, check that the Notion record has the required fields populated.
- Token state. Outlook tokens refresh on their own. Slack tokens don't expire for the scopes we use. Telegram pairing is one-time per team member. If a panel shows "not connected", reconnect with the same OAuth flow.
Privacy and read-only guarantees
- No connector can send on your behalf. Outlook scope is
Mail.Read+Calendars.Read, Slack scopes are all*:history+users:read, Telegram bot exports zero send methods. - Email bodies are stored as 255-char previews, not full content. Slack messages and Telegram messages store the visible text only.
- Internal-only threads (every participant
@valinordigital.com) are dropped at ingest. Personal mail to your work address still flows in if the sender domain is external; use skip rules to drop specific addresses. - Pause any connector at any time from the Sync tab. Disconnecting revokes the OAuth token and stops ingestion immediately; existing interactions stay.
Roadmap — maybe-later
These aren't built and aren't queued. They'd each give us more automation in exchange for cost or vendor surface area, so they live here as the next things to consider only after the current stack proves insufficient.
- Third-party contact enrichment. Pipe new external contacts through Apollo, Clearbit, or People Data Labs at the moment the router auto-creates them. Returns role, seniority, LinkedIn URL, phone, plus company-side metadata (industry, size, validated email domains). Cost is ~$0.05–0.20 per new contact and recurring. Privacy posture changes (sending counterparty emails to a US data broker — relevant for EU contacts). Best treated as a fallback to the existing signature parser: re-evaluate only if a meaningful share of active
peoplerows still have emptyroleafter 30 days of signature parsing. If we adopt one, default to a single provider with a fixed monthly cap and write extracted fields ontopeople/companiesonly when fields are still empty.
Four connectors, one inbox, one approval step. If you're spending more than five minutes a day on Laurelin maintenance, something is misconfigured. Flag it in #laurelin and we'll fix it.
For the deeper engineering view — how each adapter polls, how the auto-router classifies, watermark internals — see Sync internals.