Mint an embed session
curl --request POST \
--url https://api.craftkit.dev/v1/embed/sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tenant": {
"externalId": "org_123",
"displayName": "Acme Corp"
},
"actor": {
"externalId": "user_456",
"displayName": "Jane Doe",
"email": "jane@example.com"
},
"scope": {
"mode": "edit",
"templateExternalId": "7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f"
}
}
'import requests
url = "https://api.craftkit.dev/v1/embed/sessions"
payload = {
"tenant": {
"externalId": "org_123",
"displayName": "Acme Corp"
},
"actor": {
"externalId": "user_456",
"displayName": "Jane Doe",
"email": "jane@example.com"
},
"scope": {
"mode": "edit",
"templateExternalId": "7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
tenant: {externalId: 'org_123', displayName: 'Acme Corp'},
actor: {externalId: 'user_456', displayName: 'Jane Doe', email: 'jane@example.com'},
scope: {mode: 'edit', templateExternalId: '7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f'}
})
};
fetch('https://api.craftkit.dev/v1/embed/sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.craftkit.dev/v1/embed/sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tenant' => [
'externalId' => 'org_123',
'displayName' => 'Acme Corp'
],
'actor' => [
'externalId' => 'user_456',
'displayName' => 'Jane Doe',
'email' => 'jane@example.com'
],
'scope' => [
'mode' => 'edit',
'templateExternalId' => '7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.craftkit.dev/v1/embed/sessions"
payload := strings.NewReader("{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.craftkit.dev/v1/embed/sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.craftkit.dev/v1/embed/sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}"
response = http.request(request)
puts response.read_body{
"session_id": "1d2c3b4a-5e6f-7081-92a3-b4c5d6e7f809",
"session_token": "eyJhbGciOiJFZERTQSJ9...",
"iframe_url": "https://embed.craftkit.dev/builder?session=...",
"expires_at": "2026-06-21T11:00:00.000Z",
"renew_token": "rt_abc123"
}{
"error": "invalid_json"
}{
"error": "invalid_credentials"
}{
"error": {
"code": "catalog_not_found",
"message": "No current catalog named \"my-catalog\" found for this project."
}
}{
"error": "invalid_request",
"issues": []
}{
"error": "<string>",
"message": "<string>",
"issues": "<unknown>",
"detail": "<string>"
}Embed
Mint an embed session
Mint a short-lived embed session for the iframe builder/form, using the partner secret key. Returns the session token (JWT), the iframe URL, and a single-use renew token. Note the snake_case response keys.
POST
/
v1
/
embed
/
sessions
Mint an embed session
curl --request POST \
--url https://api.craftkit.dev/v1/embed/sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tenant": {
"externalId": "org_123",
"displayName": "Acme Corp"
},
"actor": {
"externalId": "user_456",
"displayName": "Jane Doe",
"email": "jane@example.com"
},
"scope": {
"mode": "edit",
"templateExternalId": "7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f"
}
}
'import requests
url = "https://api.craftkit.dev/v1/embed/sessions"
payload = {
"tenant": {
"externalId": "org_123",
"displayName": "Acme Corp"
},
"actor": {
"externalId": "user_456",
"displayName": "Jane Doe",
"email": "jane@example.com"
},
"scope": {
"mode": "edit",
"templateExternalId": "7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
tenant: {externalId: 'org_123', displayName: 'Acme Corp'},
actor: {externalId: 'user_456', displayName: 'Jane Doe', email: 'jane@example.com'},
scope: {mode: 'edit', templateExternalId: '7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f'}
})
};
fetch('https://api.craftkit.dev/v1/embed/sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.craftkit.dev/v1/embed/sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tenant' => [
'externalId' => 'org_123',
'displayName' => 'Acme Corp'
],
'actor' => [
'externalId' => 'user_456',
'displayName' => 'Jane Doe',
'email' => 'jane@example.com'
],
'scope' => [
'mode' => 'edit',
'templateExternalId' => '7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.craftkit.dev/v1/embed/sessions"
payload := strings.NewReader("{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.craftkit.dev/v1/embed/sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.craftkit.dev/v1/embed/sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tenant\": {\n \"externalId\": \"org_123\",\n \"displayName\": \"Acme Corp\"\n },\n \"actor\": {\n \"externalId\": \"user_456\",\n \"displayName\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n },\n \"scope\": {\n \"mode\": \"edit\",\n \"templateExternalId\": \"7c9f0b2e-2b1a-4f3d-9c8e-1a2b3c4d5e6f\"\n }\n}"
response = http.request(request)
puts response.read_body{
"session_id": "1d2c3b4a-5e6f-7081-92a3-b4c5d6e7f809",
"session_token": "eyJhbGciOiJFZERTQSJ9...",
"iframe_url": "https://embed.craftkit.dev/builder?session=...",
"expires_at": "2026-06-21T11:00:00.000Z",
"renew_token": "rt_abc123"
}{
"error": "invalid_json"
}{
"error": "invalid_credentials"
}{
"error": {
"code": "catalog_not_found",
"message": "No current catalog named \"my-catalog\" found for this project."
}
}{
"error": "invalid_request",
"issues": []
}{
"error": "<string>",
"message": "<string>",
"issues": "<unknown>",
"detail": "<string>"
}Authorizations
Project API key (ck_live_… or ck_test_…) presented as a bearer token.
For embed partner endpoints this is the partner secret key, which is the
same credential type.
Body
application/json
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Maximum string length:
60Show child attributes
Show child attributes
Show child attributes
Show child attributes
Form-fill claims; only meaningful when scope.mode === 'fill'.
Show child attributes
Show child attributes
⌘I