Craftkitdocs

Authentication

Authenticate every request with a project API key.

All requests to /v1/* carry a project API key in the Authorization header. Keys are scoped to one project and can be created or revoked from the dashboard. This page covers the format, how to create and rotate keys, scope, and the errors you'll see when something is off.

Quick Start

Three languages, the same authenticated request.

curl

curl https://api.craftkit.dev/v1/renders/0193c2c3 \
  -H "Authorization: Bearer $CRAFTKIT_API_KEY"

Node.js

const res = await fetch('https://api.craftkit.dev/v1/renders/0193c2c3', {
  headers: {
    Authorization: `Bearer ${process.env.CRAFTKIT_API_KEY}`,
  },
});

Python

import os, requests

res = requests.get(
    "https://api.craftkit.dev/v1/renders/0193c2c3",
    headers={"Authorization": f"Bearer {os.environ['CRAFTKIT_API_KEY']}"},
)

Header format

Authorization: Bearer ck_live_<random>
Prefix Environment
ck_live_ Production renders, billable, hits the live worker pool
ck_test_ Test renders, free, watermarked output

Creating a key

Dashboard → Project → API keys → enter a name → Create key. The cleartext key is returned once — copy it immediately. We only store the SHA-256 hash, so a lost key cannot be recovered.

Each project can have many keys, each independently revocable. Use one key per integration so you can rotate without coordinating an outage across services.

Revoking a key

Same screen → Revoke. Subsequent calls return 401 invalid_credentials immediately (no grace window). Issue a replacement first, deploy it, then revoke.

Scope

API keys are scoped to one project. They can:

  • POST a render against any template in that project.
  • Read renders for that project.
  • Trigger inbound webhooks for templates in that project (the inbound token authenticates instead, but the key still owns the resulting render row).

They cannot:

  • Modify templates, projects, or webhook configs (use the dashboard).
  • Read other projects' data.
  • Mint embed sessions for partner integrations (use the embed publishable + signing key pair instead).

Errors

HTTP Code When Fix
401 missing_authorization No Authorization: Bearer ... header Add the header
401 invalid_credentials Key is unknown or revoked Mint a new key
403 partner_suspended Project's embed partnership is suspended Contact support

Best practices

  • Never embed keys in client code. Browser bundles, mobile apps, and public repositories all leak. Keep keys on a server.
  • Use environment-specific keys. Separate ck_test_ for staging and ck_live_ for production. Never share a key across environments.
  • Rotate quarterly. Mint a new key, deploy it, revoke the old one once metrics confirm zero traffic on the previous key.
  • One key per workload. Background jobs, the synchronous API path, and the inbound webhook handler each get their own key. Revoking one doesn't disrupt the others.

Troubleshooting invalid_credentials

The most common cause: the key was created in a different environment.

API keys are stored as SHA-256 hashes in the database for the environment where they were created. A key you minted in your local dev environment does not exist in production, and vice versa. If you see invalid_credentials after deploying, the fix is to mint a new key inside the target environment's dashboard.

Local dev key  → only works against http://localhost:3000
Production key → only works against https://api.craftkit.dev

Second most common cause (embed sessions): embed is not enabled for the project.

POST /v1/embed/sessions and POST /v1/embed/catalogs require the API key's project to have embed enabled. An otherwise valid key returns invalid_credentials on these endpoints if the project has no embed partner record.

Fix: Dashboard → Project → Embed → OverviewEnable embed mode.

Checklist

Symptom Check
Valid key works locally, fails in production Re-mint the key in the production dashboard
Key works on /v1/renders/* but not /v1/embed/* Enable embed mode for the project
Key was working, now suddenly fails Check if it was revoked (Revoke column in API keys tab)
missing_authorization instead of invalid_credentials The Authorization: Bearer ... header is missing entirely