Docs
guides · other languages

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.

The whole API in three factsBase URL is 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>"
  }'
Prefer Python?A first-party 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
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:

Shell
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
done

See 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

Generate a clientPrefer a generated client in your language? The full OpenAPI spec drives this reference and can feed your generator of choice.