API keys authenticate every request and can be scoped to restrict which render targets they may produce.
Target scopes
| Targets value | Allowed render calls |
|---|---|
|
|
|
|
|
|
|
|
|
|
Creating a key via the dashboard
See API Keys (Builder) for the UI walkthrough.
Creating a key via the API
curl -X POST https://api.maildeno.com/api/v1/keys \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ADMIN_KEY>" \
-d '{"name": "HTML only", "targets": ["html"]}'
{
"id": "key_01abc...",
"name": "HTML only",
"key": "sk_live_...", // shown once — copy it now
"targets": ["html"],
"created_at": "2025-01-01T00:00:00Z"
}
Handling a 403 in the SDK
When a request hits a target outside the key’s scope, the SDK raises FORBIDDEN:
-
JavaScript
-
Python
try {
// This key only has targets: ["html"]
await client.renderMjml("template-id")
} catch (err) {
if (err instanceof MaildenoError && err.code === "FORBIDDEN") {
console.error("Key scope insufficient:", err.message)
// "Key scope insufficient: key targets ['html'], requested 'mjml'"
}
}
try:
client.render_mjml("template-id")
except MaildenoError as err:
if err.code == "FORBIDDEN":
print("Key scope insufficient:", err.message)
Recommended key naming convention
{environment}-{service}-{target}
production-api-server-html
staging-newsletter-worker-all
ci-integration-tests-html
Security best practices
-
Store keys in environment variables or a secrets manager (Vault, AWS Secrets Manager, Doppler).
-
Never commit keys to source control.
-
Use the narrowest scope sufficient for the task — principle of least privilege.
-
Rotate keys on a regular schedule or immediately if a leak is suspected.
-
Use separate keys per environment (development, staging, production).