Create scenario
curl --request POST \
--url https://akapulu.com/api/scenarios/create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Sales Qualification",
"llm_model": "gpt-4.1-mini",
"nodes_json": {
"initial_node": "intro",
"role_instruction": "You are a friendly sales assistant. Keep responses concise because they will be converted to audio.",
"nodes": {
"intro": {
"task_instruction": "Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.",
"respond_immediately": true,
"functions": [
{
"name": "go_end",
"description": "End the conversation when the visitor is done.",
"type": "transition",
"transition_to": "end"
}
]
},
"end": {
"task_instruction": "Thank them and say goodbye.",
"end_after_bot_response": true
}
}
},
"hosted_links": [
{
"avatar_id": "66666666-7777-8888-9999-000000000000",
"label": "Acme demo",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": [
"Acme"
],
"record_conversation": false,
"redirect_url": "https://your-site.com/thanks"
}
]
}
'import requests
url = "https://akapulu.com/api/scenarios/create"
payload = {
"name": "Sales Qualification",
"llm_model": "gpt-4.1-mini",
"nodes_json": {
"initial_node": "intro",
"role_instruction": "You are a friendly sales assistant. Keep responses concise because they will be converted to audio.",
"nodes": {
"intro": {
"task_instruction": "Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.",
"respond_immediately": True,
"functions": [
{
"name": "go_end",
"description": "End the conversation when the visitor is done.",
"type": "transition",
"transition_to": "end"
}
]
},
"end": {
"task_instruction": "Thank them and say goodbye.",
"end_after_bot_response": True
}
}
},
"hosted_links": [
{
"avatar_id": "66666666-7777-8888-9999-000000000000",
"label": "Acme demo",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": ["Acme"],
"record_conversation": False,
"redirect_url": "https://your-site.com/thanks"
}
]
}
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({
name: 'Sales Qualification',
llm_model: 'gpt-4.1-mini',
nodes_json: {
initial_node: 'intro',
role_instruction: 'You are a friendly sales assistant. Keep responses concise because they will be converted to audio.',
nodes: {
intro: {
task_instruction: 'Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.',
respond_immediately: true,
functions: [
{
name: 'go_end',
description: 'End the conversation when the visitor is done.',
type: 'transition',
transition_to: 'end'
}
]
},
end: {task_instruction: 'Thank them and say goodbye.', end_after_bot_response: true}
}
},
hosted_links: [
{
avatar_id: '66666666-7777-8888-9999-000000000000',
label: 'Acme demo',
runtime_vars: {user_name: 'Alex', company_name: 'Acme Corp'},
stt_keywords: ['Acme'],
record_conversation: false,
redirect_url: 'https://your-site.com/thanks'
}
]
})
};
fetch('https://akapulu.com/api/scenarios/create', 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://akapulu.com/api/scenarios/create",
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([
'name' => 'Sales Qualification',
'llm_model' => 'gpt-4.1-mini',
'nodes_json' => [
'initial_node' => 'intro',
'role_instruction' => 'You are a friendly sales assistant. Keep responses concise because they will be converted to audio.',
'nodes' => [
'intro' => [
'task_instruction' => 'Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.',
'respond_immediately' => true,
'functions' => [
[
'name' => 'go_end',
'description' => 'End the conversation when the visitor is done.',
'type' => 'transition',
'transition_to' => 'end'
]
]
],
'end' => [
'task_instruction' => 'Thank them and say goodbye.',
'end_after_bot_response' => true
]
]
],
'hosted_links' => [
[
'avatar_id' => '66666666-7777-8888-9999-000000000000',
'label' => 'Acme demo',
'runtime_vars' => [
'user_name' => 'Alex',
'company_name' => 'Acme Corp'
],
'stt_keywords' => [
'Acme'
],
'record_conversation' => false,
'redirect_url' => 'https://your-site.com/thanks'
]
]
]),
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://akapulu.com/api/scenarios/create"
payload := strings.NewReader("{\n \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\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://akapulu.com/api/scenarios/create")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://akapulu.com/api/scenarios/create")
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 \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "created",
"id": "11111111-2222-3333-4444-555555555555",
"hosted_links": [
{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"token": "abc123token",
"url": "https://live.akapulu.com/session/abc123token",
"label": "Acme demo",
"scenario_id": "11111111-2222-3333-4444-555555555555",
"avatar_id": "66666666-7777-8888-9999-000000000000",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": [
"Acme"
],
"record_conversation": false,
"redirect_url": "https://your-site.com/thanks",
"created_at": "2026-08-16T21:47:46.000000+00:00"
}
]
}{
"error": "name is required"
}{
"error": "Invalid API key"
}Scenarios
Create Scenario
Create a scenario. Optionally mint hosted links in the same request.
POST
/
scenarios
/
create
Create scenario
curl --request POST \
--url https://akapulu.com/api/scenarios/create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Sales Qualification",
"llm_model": "gpt-4.1-mini",
"nodes_json": {
"initial_node": "intro",
"role_instruction": "You are a friendly sales assistant. Keep responses concise because they will be converted to audio.",
"nodes": {
"intro": {
"task_instruction": "Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.",
"respond_immediately": true,
"functions": [
{
"name": "go_end",
"description": "End the conversation when the visitor is done.",
"type": "transition",
"transition_to": "end"
}
]
},
"end": {
"task_instruction": "Thank them and say goodbye.",
"end_after_bot_response": true
}
}
},
"hosted_links": [
{
"avatar_id": "66666666-7777-8888-9999-000000000000",
"label": "Acme demo",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": [
"Acme"
],
"record_conversation": false,
"redirect_url": "https://your-site.com/thanks"
}
]
}
'import requests
url = "https://akapulu.com/api/scenarios/create"
payload = {
"name": "Sales Qualification",
"llm_model": "gpt-4.1-mini",
"nodes_json": {
"initial_node": "intro",
"role_instruction": "You are a friendly sales assistant. Keep responses concise because they will be converted to audio.",
"nodes": {
"intro": {
"task_instruction": "Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.",
"respond_immediately": True,
"functions": [
{
"name": "go_end",
"description": "End the conversation when the visitor is done.",
"type": "transition",
"transition_to": "end"
}
]
},
"end": {
"task_instruction": "Thank them and say goodbye.",
"end_after_bot_response": True
}
}
},
"hosted_links": [
{
"avatar_id": "66666666-7777-8888-9999-000000000000",
"label": "Acme demo",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": ["Acme"],
"record_conversation": False,
"redirect_url": "https://your-site.com/thanks"
}
]
}
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({
name: 'Sales Qualification',
llm_model: 'gpt-4.1-mini',
nodes_json: {
initial_node: 'intro',
role_instruction: 'You are a friendly sales assistant. Keep responses concise because they will be converted to audio.',
nodes: {
intro: {
task_instruction: 'Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.',
respond_immediately: true,
functions: [
{
name: 'go_end',
description: 'End the conversation when the visitor is done.',
type: 'transition',
transition_to: 'end'
}
]
},
end: {task_instruction: 'Thank them and say goodbye.', end_after_bot_response: true}
}
},
hosted_links: [
{
avatar_id: '66666666-7777-8888-9999-000000000000',
label: 'Acme demo',
runtime_vars: {user_name: 'Alex', company_name: 'Acme Corp'},
stt_keywords: ['Acme'],
record_conversation: false,
redirect_url: 'https://your-site.com/thanks'
}
]
})
};
fetch('https://akapulu.com/api/scenarios/create', 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://akapulu.com/api/scenarios/create",
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([
'name' => 'Sales Qualification',
'llm_model' => 'gpt-4.1-mini',
'nodes_json' => [
'initial_node' => 'intro',
'role_instruction' => 'You are a friendly sales assistant. Keep responses concise because they will be converted to audio.',
'nodes' => [
'intro' => [
'task_instruction' => 'Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.',
'respond_immediately' => true,
'functions' => [
[
'name' => 'go_end',
'description' => 'End the conversation when the visitor is done.',
'type' => 'transition',
'transition_to' => 'end'
]
]
],
'end' => [
'task_instruction' => 'Thank them and say goodbye.',
'end_after_bot_response' => true
]
]
],
'hosted_links' => [
[
'avatar_id' => '66666666-7777-8888-9999-000000000000',
'label' => 'Acme demo',
'runtime_vars' => [
'user_name' => 'Alex',
'company_name' => 'Acme Corp'
],
'stt_keywords' => [
'Acme'
],
'record_conversation' => false,
'redirect_url' => 'https://your-site.com/thanks'
]
]
]),
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://akapulu.com/api/scenarios/create"
payload := strings.NewReader("{\n \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\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://akapulu.com/api/scenarios/create")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://akapulu.com/api/scenarios/create")
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 \"name\": \"Sales Qualification\",\n \"llm_model\": \"gpt-4.1-mini\",\n \"nodes_json\": {\n \"initial_node\": \"intro\",\n \"role_instruction\": \"You are a friendly sales assistant. Keep responses concise because they will be converted to audio.\",\n \"nodes\": {\n \"intro\": {\n \"task_instruction\": \"Greet {{runtime.user_name}} from {{runtime.company_name}} and ask what they want to build.\",\n \"respond_immediately\": true,\n \"functions\": [\n {\n \"name\": \"go_end\",\n \"description\": \"End the conversation when the visitor is done.\",\n \"type\": \"transition\",\n \"transition_to\": \"end\"\n }\n ]\n },\n \"end\": {\n \"task_instruction\": \"Thank them and say goodbye.\",\n \"end_after_bot_response\": true\n }\n }\n },\n \"hosted_links\": [\n {\n \"avatar_id\": \"66666666-7777-8888-9999-000000000000\",\n \"label\": \"Acme demo\",\n \"runtime_vars\": {\n \"user_name\": \"Alex\",\n \"company_name\": \"Acme Corp\"\n },\n \"stt_keywords\": [\n \"Acme\"\n ],\n \"record_conversation\": false,\n \"redirect_url\": \"https://your-site.com/thanks\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": "created",
"id": "11111111-2222-3333-4444-555555555555",
"hosted_links": [
{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"token": "abc123token",
"url": "https://live.akapulu.com/session/abc123token",
"label": "Acme demo",
"scenario_id": "11111111-2222-3333-4444-555555555555",
"avatar_id": "66666666-7777-8888-9999-000000000000",
"runtime_vars": {
"user_name": "Alex",
"company_name": "Acme Corp"
},
"stt_keywords": [
"Acme"
],
"record_conversation": false,
"redirect_url": "https://your-site.com/thanks",
"created_at": "2026-08-16T21:47:46.000000+00:00"
}
]
}{
"error": "name is required"
}{
"error": "Invalid API key"
}Create a scenario from scenario JSON. You can mint hosted links in the same request.
Required headers:
Authorization: Bearer <YOUR_AKAPULU_API_KEY>Content-Type: application/json
namenodes_jsonwithinitial_nodeandnodes
llm_model(defaults togpt-4.1-mini; full-size models require a paid plan)hosted_links— each link needsavatar_idand aruntime_varskey for every{{runtime.*}}variable the scenario references (blank values are allowed)
hosted_links array includes the public url (https://live.akapulu.com/session/<token>).Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
Scenario flow JSON. See the Using JSON guide for the full contract.
Show child attributes
Show child attributes
OpenAI chat model for this scenario. Defaults to gpt-4.1-mini. Full-size models require a paid plan.
Available options:
gpt-4.1-nano, gpt-4.1-mini, gpt-4.1, gpt-5.4-nano, gpt-5.4-mini, gpt-5.4 Optional hosted links to create with the scenario.
Show child attributes
Show child attributes
⌘I

