Skip to content

What would an engineer-first transactional send API need? #216

Closed

Description

@Silthus

Part of #210

Question

What would an engineer-first transactional send API need, and how far is the current webhook trigger from it?

  • Compare the current webhook-triggered workflow with Resend's and Postmark's send APIs: auth, idempotency, message id and status lookup, templates with variables, attachments, error shapes, rate limits.
  • What a posthog.messaging.send(...) call in the server SDKs would look like, and what it reuses (project secret API keys, message templates, preferences, the delivery pipeline).
  • Which growth loops Resend uses (hosting and app-builder integrations, a shared onboarding sender) and which fit PostHog.

Answer with the gap list and the smallest version worth a map.

Activity

  1. self-assigned this
    on Oct 3, 2026
  2. Silthus commented on Oct 3, 2026

    @Silthus
    OwnerAuthor

    Claimed by a Claude Code research worker (Opus 5.5)

  3. removed their assignment
    on Oct 3, 2026
  4. Silthus commented on Oct 3, 2026

    @Silthus
    OwnerAuthor

    Lane orphaned: the worker's temporary worktree was removed while its sub-agents ran. Unassigned; the conductor redispatches it in a persistent worktree.

  5. self-assigned this
    on Oct 3, 2026
  6. Silthus commented on Oct 3, 2026

    @Silthus
    OwnerAuthor

    Claimed by a Claude Code research worker (Opus 5.5), redispatch

  7. Silthus commented on Oct 3, 2026

    @Silthus
    OwnerAuthor

    Resolved. Findings: https://github.com/Silthus/posthog/blob/research/transactional-api/research-transactional-api.md

    Short answer. The webhook trigger (POST /public/webhooks/<workflow_id>) is a workflow trigger, not a send API. It answers 201 {"status":"queued"} with no message id. It has no idempotency, no status lookup by id, and no template by reference. It has no attachments and only one to. Its error bodies are mixed, and auth is a per-workflow shared header instead of a project key. The hard parts already exist behind EmailService.executeSendEmail: verified senders, suppression, transactional categories, pacing, the SES tenant per team, tracking and assets. Project secret API keys already give a scoped, user-less credential with write precedents.

    Gap list (gist).

    1. No project-level send endpoint; every message type needs its own workflow.
    2. No PSAK auth on sends (needs a new write scope).
    3. No message id returned (the invocation id is hidden, the SES MessageId is dropped).
    4. No status lookup by id (the data exists, keyed for the workflow UI).
    5. No Idempotency-Key (Resend: 24 h, same payload returns the same id, a different payload gets a 409).
    6. Templates are copied into steps, never resolved by key at send time; no variable validation.
    7. Send-time failures (sender, suppression, pause, quota) surface only in workflow logs after the 201.
    8. No attachments. 9. One recipient, no tags, metadata or headers. 10. No posthog.messaging.send in the server SDKs. 11. Message categories are internal-only by API. 12. Sending before DNS is verified belongs to the Where does the Workflows journey lose people today? #211 bet, but it decides early activation.

    Smallest version worth a map. POST /api/environments/:id/messaging/emails + GET .../:id. Both sit behind a PSAK scope. A send takes a template key + variables (or raw subject/html/text), a sender, a category key and an Idempotency-Key, and returns an id. Status comes from the events the pipeline already emits. It ships with messaging.send/get in posthog-node and posthog-python, plus a generated MCP tool and docs. Attachments, batch, scheduling, SMTP and the Vercel marketplace go to later maps. First decision for that map: where API sends live (a hidden per-project source or a new message record).

    Growth loops. Best fit now: app-builder recipes (Lovable, Bolt, v0, Replit) and an MCP tool, which comes almost free from OpenAPI codegen. Later: Vercel Marketplace with auto DNS, an SMTP relay, and Resend-style test recipient addresses. A shared onboarding sender is the #211 send-before-DNS bet.

    Security note, ask Michael: the auth and rate limiting of the public webhook route deserve a private look before a send API copies its shape.

    Evidence: code on master plus public Resend and Postmark docs. The SDK shape, the delivery seam and the hidden-source data model are marked as guesses in the doc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions