Skip to content

Overview

Maillune uses two authentication mechanisms:

Use caseMechanism
Server-to-server API calls (templates, rendering, sessions)Secret API key
Browser SDK (<email-builder>)Short-lived session token

Never put your secret API key in the browser

Your API key grants full access to your account. Always keep it on your server. Use session tokens for all client-side SDK usage.


API keys

Create and manage keys in the Dashboard.

Keys look like:

mms_live_6839ac7bd38675bc57ca37581b365ea...

Pass the key in the Authorization header as a Bearer token for all server-side calls:

bash
curl https://api.maillune.com/v1/templates \
  -H "Authorization: Bearer mms_live_YOUR_KEY"

Session tokens (SDK)

Before mounting <email-builder> in your frontend, your backend exchanges the secret key for a short-lived session token scoped to a single user.

POST /v1/sessions
Authorization: Bearer <your_secret_api_key>
Content-Type: application/json

{ "userId": "end-user-id-in-your-system" }

Response:

json
{
  "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 7200
}

Pass sessionToken to the browser and use it as the api-key attribute:

html
<email-builder api-key="eyJ..." user-id="..."></email-builder>

Token properties

PropertyValue
Lifetime2 hours
ScopeSingle userId, single API key
Usable forSDK validate, image uploads, template saves
RevocableYes — revoke the parent API key

Server-side example (Node.js)

js
// Your Express/Next.js route handler
app.get('/api/editor-session', requireAuth, async (req, res) => {
  const response = await fetch('https://api.maillune.com/v1/sessions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.MAILLUNE_SECRET_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ userId: req.user.id }),
  });

  const { sessionToken } = await response.json();
  res.json({ sessionToken });
});

Origin allowlisting

For an extra layer of security, restrict which domains can use a given API key's session tokens. Requests from unlisted origins are rejected with 403.

Manage allowed origins in the Dashboard → API Keys or via the API:

bash
PATCH /v1/keys/:id/origins
Authorization: Bearer <dashboard_jwt>

{ "origins": ["https://app.example.com", "https://staging.example.com"] }
  • An empty array means all origins allowed (default — backward compatible)
  • Origins are matched against the Origin request header

Key validation

Validate a key and retrieve plan details:

bash
GET /v1/keys/validate
Authorization: Bearer mms_live_YOUR_KEY

Also accepts a session token:

bash
GET /v1/keys/validate
Authorization: Bearer eyJ...sessionToken

Response:

json
{
  "plan": "pro",
  "limits": {
    "renders": 2000,
    "storageMb": 500,
    "templates": 99999
  },
  "usage": {
    "renders": 412,
    "storageMb": 84.3
  },
  "features": {
    "imageUpload": true,
    "customFonts": true,
    "exportHtml": true,
    "templateLibrary": true,
    "whiteLabel": true
  }
}

Base URL

https://api.maillune.com

All endpoints are prefixed with /v1.


Rate limits

PlanRequests / minute
Free60
Pro300
Agency1,000
EnterpriseCustom

Exceeded limits return 429 Too Many Requests.


Errors

All errors return a JSON body with an error string:

json
{ "error": "Invalid API key" }
StatusMeaning
400Bad request — missing or invalid parameters
401Unauthorized — missing or invalid key/token
402Plan limit reached — upgrade required
403Origin not in allowlist
404Resource not found
429Rate limit exceeded
500Server error