Seb — Product Spec
The source of truth for what Seb does, how it behaves, and how it's configured. If this spec changes, the code changes.
What is Seb?
Seb is Coopah's AI junior partner account manager. When a new event partner is introduced via Slack, Seb handles the full onboarding flow autonomously: researching the partner, creating affiliate codes, building a Notion workspace, drafting and sending outreach, chasing replies, reporting performance, and managing ongoing campaign communications.
Seb is designed to handle all the repeatable, process-driven parts of partner management so the human AM team can focus on relationships and decisions that require real judgment.
Design Principles
- Mostly autonomous, escalates when needed — Seb works without human approval in normal flow. Escalation to Slack is triggered by ambiguity, partner pushback, anomalies, or non-standard requests. The first intro email requires a one-time approval; after that Seb sends independently.
- Configurable without code changes — all behaviour is driven by the Rules Engine config. Tone, templates, timing, escalation triggers — all editable via the UI.
- Transparent — every action is logged to Slack and to the partner's Notion hub. Nothing happens silently.
- Graceful degradation — if an integration fails (AppFlyer, Gmail, Notion), Seb escalates to Slack with all the context needed for a human to complete the step manually, then continues.
- Learns over time — Seb tracks what works across all partners (email subject lines, send timing, offer types) and incorporates that into future drafts. See Seb Learns.
Who uses it?
The Coopah Account Management team. Seb is triggered from Slack. The AM team reviews email drafts on the partner dashboard, handles escalations, and monitors weekly summaries.
Architecture
| Component | Host | Purpose |
|---|---|---|
| Seb Agent | Railway (always-on) | Orchestrates all flow steps, runs Playwright, calls Claude |
| Rules Engine | Vercel (Next.js) | Config UI — team edits behaviour without touching code |
| Slack listener | Part of Agent | Socket Mode WebSocket — receives mentions, slash commands, modal submissions |
Entry Points
@seb manage [partner name]
Mention @seb manage Royal Parks Half Marathon in any Slack channel to start the full onboarding flow. Seb researches the partner, posts findings to the intros channel, and waits for the check-in modal to be submitted before proceeding.
/coupon
Standalone tool for creating discount codes outside of the onboarding flow. See Seb Tools → /coupon.
Onboarding Flow
Triggered by @seb manage [partner name]. Eight sequential steps — click any step to expand the detail.
1
Research + Check-in
Web research → Slack post with findings → modal collects partner details
▶
Research + Check-in
Web research → Slack post with findings → modal collects partner details
Research
Seb calls Claude with the web_search_20250305 tool to find: full event name, next upcoming date (YYYY-MM-DD), approximate participant count, race type, official website. Today's date is passed so Claude searches for the next future occurrence.
Research findings are posted to config.escalation.introsChannel as a Block Kit message, tagging the AM handle with a "Fill in details" button. If research fails, Seb proceeds with confidence: low and the team corrects via modal.
Check-in Modal
Clicking "Fill in details" opens a Slack modal. Seb pre-fills what it found; the AM confirms or corrects:
| Field | Type | Required | Notes |
|---|---|---|---|
| Contact email | Text input | Yes | Partner contact email |
| Contact name | Text input | No | For personalised emails |
| Offer | Dropdown | Yes | From config.offers.items (enabled only). Default = config.offers.default |
| Coupon code | Text input | Yes | Max 15 chars. Pre-filled: name uppercased + non-alphanumeric stripped + "2". Human has final say. |
| Notes | Multiline | No | Any extra context before Seb reaches out |
On submit, the confirmed data is passed to all subsequent steps.
2
Coupon Creation
Playwright creates the discount code in the Coopah admin
▶
Coupon Creation
Playwright creates the discount code in the Coopah admin
Seb logs into admin.app.coopah.com via headless Playwright and creates the coupon using the code confirmed in the check-in modal.
| Field | Value |
|---|---|
| Title | Same as coupon code |
| Coupon code | As confirmed in Step 1 (max 15 chars) |
| Apple code | offer.appleCode |
| Google code | offer.googleCode |
| Media source | Always Event Partners for onboarding flow |
| Campaign name | CODE_OfferLabel_EventPartners_MonthYear |
On success, Seb replies in thread: ✅ Coupon created: `CODE`. On failure, Seb escalates to Slack with full error details and halts.
3
AppFlyer Link
Creates a tracking OneLink in AppFlyer for the partner's campaign
▶
AppFlyer Link
Creates a tracking OneLink in AppFlyer for the partner's campaign
Seb creates the AppFlyer OneLink tracking link via the OneLink REST API v2. This is non-blocking — if the API call fails, Seb escalates with full details for manual creation and continues the flow.
API call
POST to https://onelink.appsflyer.com/api/v2.0/shortlinks/{templateId} with the following parameters:
| Parameter | Value |
|---|---|
pid | event_partners |
c | Campaign name (CODE_OfferLabel_EventPartners_MonthYear) |
af_dp | The coupon code (used as deep link value) |
Environment variables required
| Variable | Purpose |
|---|---|
APPSFLYER_API_TOKEN | Bearer token for the OneLink REST API |
APPSFLYER_ONELINK_TEMPLATE_ID | The template ID used in the endpoint path |
4
Partner URL
Generates the partner's URL on the rules engine
▶
Partner URL
Generates the partner's URL on the rules engine
The Notion Hub approach has been replaced by a partner page hosted directly on the rules engine (Vercel) at /partners/[slug]. There is no external Notion dependency.
The partner URL (https://meetseb.co/partners/[slug]) is stored in the session and included in all subsequent emails and Slack messages.
Page contents
- Partner info (name, event, contact details)
- Coupon code
- AppFlyer OneLink
- Email drafts
- Activity log
5
Mixpanel Report Setup
Duplicates the base Mixpanel template report, scoped to this partner's coupon code
▶
Mixpanel Report Setup
Duplicates the base Mixpanel template report, scoped to this partner's coupon code
During onboarding, Seb creates a dedicated Mixpanel report for the partner so performance tracking is ready from day one — before any emails have been sent.
Process
- Find the base template report (created by Dan, referenced in
config.reporting.mixpanelTemplateId) - Duplicate the report via the Mixpanel API
- Rename it to the partner's campaign name
- Update the discount code filter to match this partner's coupon code
- Save the report URL to the partner's Notion hub (Performance section) and session
This report is used for: the partner-facing weekly performance email, the internal AM dashboard, and Seb's trial stats notifications.
6
Email Drafting
Claude drafts the intro email using the base template, customised for this partner
▶
Email Drafting
Claude drafts the intro email using the base template, customised for this partner
Claude drafts the introduction email using config.templateLibrary[0].notionUrl as the base, customised for the specific partner. The draft is stored in Vercel KV and immediately surfaced on the partner's internal dashboard page for review — the AM does not need to leave the rules engine to read or edit it.
Draft must include
- Introduction line from
config.identity.introLine - Link to the partner's public hub page
- Proposed email schedule (calculated from race date)
- Affiliate/coupon code
- AppFlyer tracking link
- Asset request (if
config.onboardingSteps.ob6enabled) - Social nudge (if
config.onboardingSteps.ob8enabled) - AI disclosure (if
config.identity.discloseAIenabled)
Tone and sign-off taken from config.identity.tone and config.identity.signOff.
7
Approval Gate (first email only)
AM reviews and edits the draft on the partner page — approve when ready
▶
Approval Gate (first email only)
AM reviews and edits the draft on the partner page — approve when ready
The intro email is the only email that requires explicit approval. After the AM approves the first email for a partner, all subsequent emails are sent autonomously — escalation handles exceptions.
Review happens on the partner's internal dashboard page in the rules engine — not via Slack. Seb posts a Slack notification with a direct link when the draft is ready.
Editor
The draft is rendered as an inline editable document on the partner page. The AM can:
- Edit directly — click into any part of the subject or body and type. For small fixes (a word, a sentence) this is the fastest path. Changes are saved automatically to Vercel KV.
- Ask Seb to rewrite a section — select any text, click "Ask Seb", type a brief note (e.g. "too formal", "mention the marathon distance"). Seb rewrites just that selection and updates the draft in place. The AM can accept or undo.
- Approve — hits the Approve button when satisfied. Seb proceeds to send immediately.
If the draft needs a full rewrite
The AM can use the "Regenerate" button with overall notes, which prompts Seb to redraft the whole email. Maximum 3 full regeneration attempts before Seb escalates to Slack as HIGH severity and halts.
On approval
Approval is timestamped and logged in the partner's comms history in Vercel KV. The final sent version of the email is also stored.
8
Send + Chase
Email sent via Gmail, inbox monitored, chase loop runs if no reply
▶
Send + Chase
Email sent via Gmail, inbox monitored, chase loop runs if no reply
Seb sends the email via Gmail OAuth and monitors the inbox for a reply.
| Event | Action |
|---|---|
| Reply received | Parse intent → move to Campaign Management |
No reply after chaseDays | Send brief chase email (Template 2), repeat up to maxChaseAttempts |
| No reply after max chases | Escalate HIGH severity, halt |
| Partner agrees to schedule | Update Notion hub to "Agreed", post success to Slack, enter campaign management loop |
| Partner asks questions | Escalate with full context + question, pause |
| Partner pushback | Escalate HIGH immediately, pause |
Timing: config.emailSchedule.chaseDays, config.emailSchedule.maxChaseAttempts.
On agreement, the onboarding flow is complete. Seb enters the ongoing Campaign Management loop for this partner.
Campaign Management
Once a partner has agreed to the email schedule, Seb manages the ongoing relationship autonomously. This covers all touchpoints from first agreed email through post-event.
Pre-send Check-in
Before each scheduled email or social post send date, Seb runs a check-in to confirm everything is in order:
- Verify the partner hub / Notion page is up to date
- Confirm the coupon code is still active in the Coopah admin
- Check if any new partner comms have been received that might affect the send
- Flag if assets haven't been received and the email requires them
If all clear, Seb proceeds automatically. If any issue is found, it escalates to Slack before sending.
Post-email Results Collection
Once a partner confirms they've sent an email or social post to their audience, Seb follows up to collect performance data.
- Seb sends a short follow-up to the partner contact asking for: open rate, click rate, and any other stats they have
- Results are stored in the partner's Notion hub (Performance section) and/or the partner URL page
- Results are included in the partner's next weekly Mixpanel report for context
Trial Stats (3-day post-email)
Three days after each send date, Seb automatically queries Mixpanel and sends a brief stats notification.
- Queries Mixpanel for trial starts attributed to the partner's coupon code in the 72 hours since the email went out
- Posts a summary to the partner: "X trials started since your email on [date]"
- Posts the same summary internally to Slack (
config.reporting.slackChannel) - Stores the data point in the Notion hub
This data informs the weekly report and Seb's content recommendations over time.
Responding to Partner Requests
Partners may reply with questions, requests, or changes outside the standard flow. Seb parses the intent and responds where confident.
| Request type | Seb's action |
|---|---|
| Standard question (in knowledge base) | Seb responds autonomously, logs in Notion comms |
| Non-standard / unusual request | Escalate to Slack with full thread context + draft response for AM approval before sending |
| Request to change schedule | Escalate with proposed new schedule for AM sign-off |
| Complaint or sensitive matter | Escalate HIGH immediately, do not respond until approved |
Weekly Performance Report (Every Monday)
Every Monday, Seb sends an automated performance summary to each active partner contact.
- Queries Mixpanel for all trials, conversions, and activity attributed to the partner's coupon code over the past 7 days
- Claude writes a brief narrative analysis: what's working, where the opportunity is, any recommended action
- Includes a comparison to the previous week if data is available
- Where email performance is declining, Seb may suggest a content change or send variation — flagged to AM for approval before acting
- Report also posted internally to
config.reporting.slackChannel
Configurable: config.reporting.cadence, config.reporting.day, config.reporting.includeOpenRate, config.reporting.includeConversionRate.
Email System
Templates
6 base templates stored as Notion pages, referenced by URL in config.templateLibrary. Claude fetches base content and customises per partner.
| # | Name | Purpose | Sent when |
|---|---|---|---|
| 1 | Introduction | First outreach email | After approval gate (one-time) |
| 2 | Chase | No-reply follow-up | After chaseDays with no reply |
| 3 | Schedule confirmed | Confirms agreed email plan | After partner agrees |
| 4 | Pre-event reminder | Reminds partner of upcoming send | Per schedule |
| 5 | Performance report | Mixpanel stats for their campaign | Weekly (Monday) |
| 6 | Post-event wrap | Thanks + next steps | After event date |
Email Schedule by Race Type
| Race type | Email 1 | Email 2 | Email 3 | Email 4 |
|---|---|---|---|---|
| Marathon | 16 weeks out | 12 weeks out | 8 weeks out | 4 weeks out |
| Half marathon | 12 weeks out | 8 weeks out | 6 weeks out | 3 weeks out |
| 10k | 10 weeks out | 6 weeks out | 4 weeks out | 2 weeks out |
| 5k / parkrun | 8 weeks out | 4 weeks out | 2 weeks out | 1 week out |
Notion Hub Structure
Every partner gets a Notion page under config.notionConfig.partnerHubsParentPageId, titled [Partner Name] — [Event Name].
| Section | Contents |
|---|---|
| Quick Reference | Coupon code, AppFlyer link, race type, race date, participant count, website, contact name + email, Mixpanel report link |
| Email Schedule | Table: email number, template, planned send date, status (Planned / Agreed / Sent / Confirmed) |
| Email Drafts | Subpages — one per template — with subject, preview text, body, send date, status |
| Partner Assets | Google Drive folder link, received status |
| Social | Social caption draft, agreed status |
| Performance | Mixpanel report link, email stats (open rate, click rate) per send, trial counts, last report date |
| Notes & Comms Log | Chronological append-only log — every Seb action, email sent, reply received, escalation raised |
Internal AM Dashboard
Built into the rules engine on Vercel. Two views — an overview of all partners, and a per-partner detail page that also serves as the email draft editor.
/partners — All partners overview
A card per active partner showing at a glance:
- Key info: partner name, event name, race date, coupon code, AppFlyer link, contact email
- Latest stats: trials last 7 days, total trials to date, last email sent date
- Status: active escalations (if any), next scheduled action
- Seb's summary: a one-paragraph AI assessment of how the partnership is going — what's working, any concerns, recommended next action
/partners/[slug] — Individual partner page
The full partner view. Also serves as the email draft editor during the approval gate:
- Draft email rendered as an editable document — AM edits inline or selects text and uses "Ask Seb" to rewrite a specific section
- Approve button sends the email immediately
- Full comms history log
- Live Mixpanel stats for this partner
- Schedule table (planned / agreed / sent per email)
- Link out to the partner-facing public page
Escalation Rules
All escalations are posted to config.escalation.channel, tagging config.escalation.amHandle. Severity determines emoji and urgency.
| Trigger | Severity | Action |
|---|---|---|
| Coupon creation fails | High | Post error + details, halt flow |
| AppFlyer automation fails | Medium | Post link params for manual creation, continue |
| Intro email not approved after 3 revisions | High | Post draft + history, halt |
| Non-standard partner request | Medium | Post request + draft response, await AM approval before sending |
| Partner asks unanswerable question | Low | Post question + full thread context, pause |
| Partner pushback | High | Post pushback text + history, pause immediately |
| No reply after max chases | High | Post contact details + full history, halt |
| Pre-send check-in finds an issue | Medium | Post issue detail, await AM go-ahead before sending |
| Mixpanel report creation fails | Medium | Post template + coupon code for manual setup, continue |
| Unhandled error | High | Post error + stack trace, halt |
Data & Reporting
Mixpanel Performance Reports
Seb maintains a dedicated Mixpanel report per partner (created at onboarding, Step 5). Reports are filtered by affiliate_code = [coupon_code].
- Partner-facing: sent every Monday via email — total trials, plan breakdown, conversion rate, week-on-week trend, Claude narrative with opportunities
- Internal Slack digest: posted to
config.reporting.slackChannelcovering all active partners — status, last action, trial count, next send date - 3-day post-email spike check: quick Mixpanel query 72h after each partner email send, posted to partner + internally
Email Performance Tracking
When a partner reports open/click rates for their own email, Seb stores these in Notion and surfaces them in reports. Seb tracks patterns across all partners to identify what subject lines, send days, or offer types generate the best engagement.
Data Storage
All partner data — session state, email drafts, comms logs, schedule, escalation history — lives in Vercel KV. Notion is used only for the 6 base email templates (human-edited). Mixpanel is the source of truth for trial and conversion data.
Seb Learns
Seb tracks outcomes across all partners and uses this to improve future work. This is not a separate system — it's built into Claude's context when drafting emails or analysing performance.
- Email effectiveness: Seb stores open rate, click rate, trial count per email send. Over time, this informs which subject line styles, send days, and offer framings perform best.
- Draft quality: If an email is rejected at the approval gate, the feedback notes are stored and factored into future drafts of the same type.
- Partner response patterns: If a partner type (e.g. large marathon) consistently responds faster to shorter emails, Seb notes this and adjusts.
- Escalation learning: Recurring escalation types that get resolved the same way become part of Seb's handling logic after review.
Seb Tools
Standalone capabilities that can be invoked directly from Slack, independent of the onboarding or campaign management flow.
/coupon — Standalone Coupon Creator
Type /coupon in any Slack channel to open the coupon creation modal. This is a utility tool for creating discount codes outside of any partner onboarding — useful for ad hoc campaigns, influencer codes, or testing.
Modal fields
| Field | Notes |
|---|---|
| Coupon code | Max 15 chars. Free text — no pre-fill. |
| Offer | Dropdown from config.offers.items (enabled only) |
| Media source | Dropdown: Event Partners, Coopah Emails, Brand Partners, Tier 1 Influencers, Tier 2 Influencers |
On submit
Seb creates the coupon in the production Coopah admin (https://admin.app.coopah.com) using the provided values. Campaign name: CODE_OfferLabel_MediaSource_MonthYear. Result is sent back to the user via DM: ✅ Coupon created: `CODE` or an error message.
ADMIN_TEST_URL environment variable.Authentication
The rules engine (www.meetseb.co) and the internal AM dashboard (/partners) must be protected. These pages can change Seb's behaviour and contain partner data — they should not be publicly accessible.
Magic link (email)
Authentication is handled via magic link — no passwords. The flow:
- User visits any protected page and is redirected to
/login - They enter their email address
- If the email is in the whitelist (
config.auth.allowedEmails), a time-limited signed link is emailed to them - Clicking the link sets a secure HTTP-only session cookie (JWT, 7-day expiry)
- They're redirected to the page they originally requested
What is protected
| Path | Protected | Notes |
|---|---|---|
/ (rules engine config) | Yes | Magic link required |
/system-prompt | Yes | Magic link required |
/partners and /partners/[slug] | Yes | Magic link required |
/api/config (GET) | No | Read-only, needed by Railway agent on startup |
/api/save (POST) | Yes | Requires valid session |
/spec.html, /plan.html | No | Public — documentation only |
/login | No | The login page itself is public |
Implementation
- Magic links are signed with
MAGIC_LINK_SECRET(env var) and expire after 15 minutes - Session tokens are JWTs signed with the same secret, stored as
HttpOnly; Secure; SameSite=Laxcookies - Auth middleware runs in
middleware.jsat the Next.js edge — redirects unauthenticated requests to/login - Magic links are sent via the same Gmail account Seb uses for partner emails (
GMAIL_REFRESH_TOKEN) - Allowed emails are stored in
AUTH_ALLOWED_EMAILSenv var as a comma-separated list
/api/config (GET) is intentionally left unprotected so the Railway agent can fetch config on startup without needing a session. It only returns config data — no partner PII. The save endpoint requires auth.Configuration Reference
All config is managed via the Rules Engine UI and stored in Vercel KV. The agent fetches it on each run via SEB_CONFIG_URL.
identity
| Key | Description |
|---|---|
identity.name | Seb's display name in emails + Slack |
identity.email | From address for outbound emails |
identity.introLine | Opening line in every intro email |
identity.tone | Voice for Claude: friendly / professional / casual |
identity.signOff | Email sign-off line |
identity.discloseAI | If true, Claude adds AI disclosure to emails |
onboardingSteps
| Toggle | Controls |
|---|---|
ob1 | Coupon creation + AppFlyer link |
ob2 | Notion hub creation |
ob3 | Email template customisation + schedule calculation |
ob4 | Intro email drafting |
ob5 | Send email + chase loop + reply processing |
ob6 | Include asset request in intro email |
ob7 | WordPress blog post creation |
ob8 | Include social nudge in intro email |
ob9 | Post-event wrap-up email |
offers
| Key | Description |
|---|---|
offers.default | Pre-selected offer in check-in modal |
offers.items[] | Each: label, appleCode, googleCode, enabled |
emailSchedule
| Key | Description |
|---|---|
emailSchedule.timing | Object keyed by race type → array of weeks-out numbers |
emailSchedule.chaseDays | Days before sending chase email |
emailSchedule.maxChaseAttempts | Max chases before escalating |
escalation
| Key | Description |
|---|---|
escalation.channel | Slack channel for escalations (e.g. #seb-escalations) |
escalation.introsChannel | Channel for check-in messages (e.g. #seb-intros) |
escalation.amHandle | Slack handle to tag (e.g. @dan) |
notionConfig
| Key | Description |
|---|---|
notionConfig.partnerHubsParentPageId | Parent Notion page ID for all partner hubs |
notionConfig.enabled | Toggle Notion integration on/off |
affiliateCode
| Key | Description |
|---|---|
affiliateCode.linkNaming | Template for AppFlyer link name, e.g. COOPAH-[PARTNER]-[YEAR] |
affiliateCode.appFlyerMethod | playwright | mcp | zapier | manual |
templateLibrary
Array of 6 template objects. Each: id, name, desc, notionUrl, requiresApproval.
reporting
| Key | Description |
|---|---|
reporting.cadence | weekly / monthly / manual |
reporting.day | Day for weekly reports (default: Monday) |
reporting.includeOpenRate | Include email open rate in partner reports |
reporting.includeConversionRate | Include Mixpanel conversion rate |
reporting.slackSummary | Post weekly digest to Slack |
reporting.slackChannel | Channel for internal Slack digest |
reporting.mixpanelTemplateId | Mixpanel report ID to duplicate for each new partner |
Integrations
| Integration | How | Used for |
|---|---|---|
| Slack | @slack/socket-mode + @slack/web-api | Triggers, modals, approvals, escalations, notifications |
| Coopah Admin | Playwright (headless Chromium) | Coupon creation |
| AppFlyer | Playwright / MCP / Zapier (TBD) | OneLink tracking link creation |
| Notion | @notionhq/client SDK | Partner hub creation, template fetching, comms log |
| Gmail | googleapis OAuth 2.0 | Send emails, poll replies |
| Mixpanel | REST API | Trial + conversion data for reports |
| Claude (Anthropic) | @anthropic-ai/sdk | Research, drafting, reply parsing, reporting narrative |
Environment Variables
Railway (Agent)
| Variable | Description |
|---|---|
ANTHROPIC_API_KEY | Claude API key |
SLACK_BOT_TOKEN | xoxb-... — bot token for posting messages |
SLACK_APP_TOKEN | xapp-... — app-level token for Socket Mode |
ADMIN_EMAIL | Login for admin.app.coopah.com (production) |
ADMIN_PASSWORD | Password for Coopah admin (production) |
ADMIN_TEST_URL | Optional — overrides admin URL for staging/testing |
ADMIN_TEST_EMAIL | Optional — login for staging admin |
ADMIN_TEST_PASSWORD | Optional — password for staging admin |
NOTION_API_KEY | Notion integration token |
GMAIL_CLIENT_ID | Google OAuth client ID |
GMAIL_CLIENT_SECRET | Google OAuth client secret |
GMAIL_REFRESH_TOKEN | Long-lived OAuth refresh token (generated once) |
MIXPANEL_SERVICE_ACCOUNT | Mixpanel service account username |
MIXPANEL_SERVICE_SECRET | Mixpanel service account secret |
MIXPANEL_PROJECT_ID | Mixpanel project ID |
SEB_CONFIG_URL | Rules engine config endpoint, e.g. https://www.meetseb.co/api/config. Falls back to local seb-config.json if unset. |
Vercel (Rules Engine)
| Variable | Description |
|---|---|
MAGIC_LINK_SECRET | Secret for signing magic links and session JWTs. Generate with openssl rand -hex 32. |
AUTH_ALLOWED_EMAILS | Comma-separated list of emails allowed to log in, e.g. dan@coopah.com,alice@coopah.com |
KV_REST_API_URL | Set automatically by Vercel Upstash integration |
KV_REST_API_TOKEN | Set automatically by Vercel Upstash integration |
KV_REST_API_READ_ONLY_TOKEN | Set automatically by Vercel Upstash integration |
Vercel (Rules Engine) — other auto-set vars
| Variable | Description |
|---|---|
KV_URL | Vercel KV connection URL |
KV_REST_API_URL | Vercel KV REST API URL |
KV_REST_API_TOKEN | Vercel KV REST API token |
KV_REST_API_READ_ONLY_TOKEN | Read-only token |
Scope & Limitations
Out of scope (v1)
- Opt-in / consent data management — this spec does not cover subscriber lists, GDPR consent capture, or any data permissions workflow. That is a separate workstream relevant to larger accounts and will be specced independently.
- Multi-contact partners — Seb currently manages one contact per partner. Multiple stakeholders at a single organisation are out of scope for now.
- Social media automation — Seb drafts social captions but does not post to social platforms directly. Publishing is done manually by the partner.
- WordPress blog posts — stub exists in config (
ob7) but automation is not yet implemented. - Inbound email triage — Seb monitors for replies to emails it sent. General inbox management is out of scope.
Known constraints
- AppFlyer integration method is not yet confirmed — Playwright, MCP, and Zapier are all being evaluated.
- Notion vs URL for partner hub is an open decision. Both paths are supported in the spec; the code will follow whichever is chosen.
- Mixpanel report duplication via API depends on Mixpanel's API supporting it — to be confirmed during Phase 3 build.