Positioning
Lead with a focused promise:Send transactional email and SMS across Africa with one developer-first API.This separates Runnage from email-only products by making SMS a first-class channel and from generic SMS gateways by treating developer experience, observability, teams, webhooks, and deliverability as core product features.
Product principles
One API, two channels
Email and SMS should share authentication, idempotency, logs, webhooks,
team permissions, and API conventions, while keeping channel-specific
delivery details explicit.
Africa-first delivery
Optimize around local sender IDs, country routing, local currency billing,
carrier constraints, compliance, and regional deliverability guidance.
Debuggable by default
Every send should produce a searchable event trail with request metadata,
provider responses, normalized statuses, and webhook replay support.
Provider portable
Keep AWS SES, Arkesel, and future providers behind internal interfaces so
Runnage can route by country, cost, deliverability, and failover policy.
MVP API surface
Start with a compact REST API that developers can memorize:| Area | Endpoint shape | Purpose |
|---|---|---|
POST /v1/emails | Send one transactional email | |
| SMS | POST /v1/sms | Send one transactional SMS |
| Domains | /v1/domains | Verify sending domains and DNS records |
| Sender IDs | /v1/sender-ids | Register and manage SMS sender IDs |
| Events | /v1/events | Search normalized delivery events |
| Webhooks | /v1/webhooks | Subscribe to delivery, bounce, complaint, and inbound events |
| API keys | /v1/api-keys | Issue scoped keys for servers and CI |
Developer experience checklist
Make the first send copy-pasteable
Publish examples for cURL, Go, Node.js, Python, PHP, and Laravel. The first
successful request should require only an API key, sender, recipient, and
content.
Ship official SDKs from the API contract
Treat OpenAPI as the source of truth and generate typed SDKs. Hand-polish the
Go SDK first because the backend is Go and many African fintech and infra
teams use Go for services.
Normalize errors and events
Return stable error codes such as
invalid_sender, domain_not_verified,
insufficient_balance, rate_limited, and provider_unavailable instead
of exposing provider-specific failures.Go engineering approach
Use the current Go service boundaries as the foundation:- Keep
internal/emailandinternal/smsprovider interfaces small and stable. - Add a
message_eventsstorage model before scaling provider integrations. - Make every send operation idempotent using an
Idempotency-Keyheader. - Introduce a queue-backed worker for retries, scheduled sends, webhook delivery, and provider failover.
- Add structured logs and request IDs across HTTP handlers, provider calls, and webhooks.
- Version all public endpoints under
/v1before external SDKs are released.
Suggested build order
- Transactional email send with verified domains, event logs, and webhooks.
- Transactional SMS send with sender IDs, country routing, and delivery receipts.
- Unified logs dashboard and API request inspection.
- API key scopes, team roles, usage limits, and billing controls.
- SDKs, CLI, examples, and AI-readable documentation.
- Templates, batch sending, contacts, broadcasts, and inbound messaging.
AI-readable docs
Expose anllms.txt file and Markdown endpoint index so AI coding tools can understand Runnage quickly. Include product overview, authentication, endpoint list, SDK links, examples, rate limits, error codes, webhook events, and deliverability guides.