Authentication
Every request authenticates with a bearer token in the
Authorization header. One mk_live_… API key does
everything — sending, domains, webhooks, and inbound — so it's all you need for
code or for an agent.
One key, full scope
Your account has a single mk_live_… API key from the moment you sign
up. It's scoped to all your domains and authenticates every
endpoint: POST /v1/send and the whole management API
(/api/*) — create & register domains, verify DNS, set webhooks,
create routes, and read inbound. The same key works for your own code and for an
AI agent, so there's nothing extra to provision.
| Credential | Looks like | Use it for |
|---|---|---|
| API key | mk_live_… | Everything — sending and the full management API, from your server or your agent. |
| Session token | JWT (eyJ…) | The dashboard's own browser session (email/password or Google sign-in). You rarely handle this directly. |
Using your API key
Grab your key from the dashboard (it's on your first screen
and under Settings → API key) and pass it to the client — it goes out as
Authorization: Bearer mk_live_… on every request:
import { MailKite } from "mailkite";
const mk = new MailKite(process.env.MAILKITE_API_KEY);import os
from mailkite import MailKite
mk = MailKite(os.environ["MAILKITE_API_KEY"])<?php
$mk = new \MailKite\Client(getenv('MAILKITE_API_KEY'));import dev.mailkite.MailKite;
MailKite mk = new MailKite(System.getenv("MAILKITE_API_KEY"));mk := mailkite.New(os.Getenv("MAILKITE_API_KEY"))require "mailkite"
mk = Mailkite::Client.new(ENV["MAILKITE_API_KEY"])# pass -H "Authorization: Bearer $MAILKITE_API_KEY" on each request Treat it like a password — store it in a secret manager or environment variable, never in client-side code or a git repo, and use it server-side only. Need a fresh one? Rotate it in the dashboard; rotating invalidates the old key immediately. Scoped, least-privilege agent keys are on the roadmap.
Session tokens (dashboard)
The dashboard signs in with email + password (or
Sign in with Google) to get a short-lived JWT session
token. You can use it against the management API too, but for scripts and agents
prefer the mk_live_… key above. To get a token:
curl https://api.mailkite.dev/api/auth/login \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com", "password": "••••••••" }' {
"token": "eyJhbGci…",
"user": { "id": "usr_…", "email": "you@example.com", "isAdmin": false }
} Send the token on subsequent management requests:
const mk = new MailKite("eyJhbGci…");
const domains = await mk.listDomains();mk = MailKite("eyJhbGci…")
domains = mk.listDomains()$mk = new \MailKite\Client('eyJhbGci…');
$domains = $mk->listDomains();MailKite mk = new MailKite("eyJhbGci…");
Object domains = mk.listDomains();mk := mailkite.New("eyJhbGci…")
domains, err := mk.ListDomains()mk = Mailkite::Client.new("eyJhbGci…")
domains = mk.listDomainscurl https://api.mailkite.dev/api/domains \
-H "Authorization: Bearer eyJhbGci…"
To create an account programmatically, POST /api/auth/signup
with { email, password } — it returns a token too.
Errors
A missing or invalid credential returns 401 Unauthorized. A valid
credential that lacks access to a resource returns 403 Forbidden,
and an unknown or non-owned resource returns 404 Not Found. See
the API reference for the full list.
All requests must use HTTPS. Requests over plain HTTP are rejected (except
http://localhost for local webhook testing).