Other languages
TypeScript gets a first-class SDK. Everything else talks to the same plain REST API — no SDK required, just HTTP and JSON over a Bearer token.
Drin's API is ordinary REST: a JSON body, a Bearer key, and conventional status codes. If your language can make an HTTPS request, it can use Drin. The TypeScript SDK is a thin wrapper over these exact endpoints — anything it does, you can do directly.
https://api.drin.run. Authenticate with Authorization: Bearer $DRIN_API_KEY. Send and read JSON. That's the entire integration surface.01 Send an email
The same request in three stacks. Each posts to /v1/emails and gets back { "id": "…" } on 202 Accepted.
curl https://api.drin.run/v1/emails \
-H "Authorization: Bearer $DRIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": { "email": "hello@acme.com" },
"to": [{ "email": "customer@example.com" }],
"subject": "Welcome aboard",
"html": "<h1>You'\''re in</h1>"
}'drin package is on PyPI — pip install drin. Or keep calling the REST API directly with the requests snippet above; it stays valid forever, since it's just HTTP.02 Naming the project
A project-scoped key already knows which project it belongs to — send with just the Authorization header. An account-wide key spans every project, so you name the sender per request with X-Drin-Product:
curl https://api.drin.run/v1/emails \
-H "Authorization: Bearer $DRIN_API_KEY" \
-H "X-Drin-Product: my-project" \
-H "Content-Type: application/json" \
-d '{ "from": {"email":"hi@acme.com"}, "to":[{"email":"a@b.com"}], "subject":"Hi", "html":"<p>…</p>" }'X-Drin-Product is the canonical header; X-Drin-Sender is an accepted alias. See Authentication for the full picture and API keys for scoping.
03 Pagination
List endpoints are cursor-paged: each response carries { data, nextCursor }. Pass cursor=$nextCursor until nextCursor comes back null. Here's the loop in shell with jq:
cursor=""
while : ; do
resp=$(curl -s "https://api.drin.run/v1/emails?limit=100&cursor=$cursor" \
-H "Authorization: Bearer $DRIN_API_KEY")
echo "$resp" | jq -c '.data[]'
cursor=$(echo "$resp" | jq -r '.nextCursor // empty')
[ -z "$cursor" ] && break
doneSee Pagination for the shared envelope and the limit bounds (1–100).
04 Errors & retries
Non-2xx responses share one JSON envelope — { "error": { "type", "message", "param?" } } — and echo a request id in X-Request-Id. On 429, honour the Retry-After header before retrying; retry 5xx idempotently by sending an Idempotency-Key. The full table lives in Errors.
05 Beyond HTTP
npx @drin00/cli — send and inspect from a terminal or CI, no code at all.MCP servernpx @drin00/mcp — give an AI agent the full API as tools.SMTPPoint any existing library at Drin's SMTP gateway instead of REST.