List Intro & Outro Templates
curl --request GET \
--url https://api.example.com/v1/intro-outro/templatesimport requests
url = "https://api.example.com/v1/intro-outro/templates"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/intro-outro/templates', 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.example.com/v1/intro-outro/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/intro-outro/templates"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/intro-outro/templates")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/intro-outro/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"templates": [
{
"templates[].id": "<string>",
"templates[].name": "<string>",
"templates[].kind": "<string>",
"templates[].template_version": 123,
"templates[].default_animation": "<string>",
"templates[].fields": [
{
"templates[].fields[].id": "<string>",
"templates[].fields[].type": "<string>",
"templates[].fields[].sent_in": "<string>",
"templates[].fields[].required": true,
"templates[].fields[].max_length": {},
"templates[].fields[].default_value": {}
}
],
"templates[].default_colors": {
"templates[].default_colors.primary": {},
"templates[].default_colors.contrast": {},
"templates[].default_colors.plate": {}
},
"templates[].preview_urls": {}
}
],
"animations": [
{
"animations[].id": "<string>",
"animations[].description": "<string>"
}
],
"INVALID_PARAMETER": {}
}Videos
List Intro & Outro Templates
Retrieve every intro and outro overlay template with its fields, default animation, default colours and preview images
GET
/
v1
/
intro-outro
/
templates
List Intro & Outro Templates
curl --request GET \
--url https://api.example.com/v1/intro-outro/templatesimport requests
url = "https://api.example.com/v1/intro-outro/templates"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/intro-outro/templates', 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.example.com/v1/intro-outro/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/intro-outro/templates"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/intro-outro/templates")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/intro-outro/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"templates": [
{
"templates[].id": "<string>",
"templates[].name": "<string>",
"templates[].kind": "<string>",
"templates[].template_version": 123,
"templates[].default_animation": "<string>",
"templates[].fields": [
{
"templates[].fields[].id": "<string>",
"templates[].fields[].type": "<string>",
"templates[].fields[].sent_in": "<string>",
"templates[].fields[].required": true,
"templates[].fields[].max_length": {},
"templates[].fields[].default_value": {}
}
],
"templates[].default_colors": {
"templates[].default_colors.primary": {},
"templates[].default_colors.contrast": {},
"templates[].default_colors.plate": {}
},
"templates[].preview_urls": {}
}
],
"animations": [
{
"animations[].id": "<string>",
"animations[].description": "<string>"
}
],
"INVALID_PARAMETER": {}
}Retrieves the intro/outro overlay catalogue: the 27 designs you can name in
elements_config.intro_outro, plus the nine animation presets that apply to them.
The catalogue is static and identical for every account, so there is nothing to page through and reading it costs no credits. Use it to build a template picker without hardcoding the catalogue: everything the visual gallery shows is served here, preview images included.
Query Parameters
string
default:"all"
Which half of the catalogue to return.Allowed values:
intro, outro, allintro: The 15 designs valid in theintroslotoutro: The 12 designs valid in theoutroslotall: Both (default)
animations is returned in full whatever you pass — the presets are the same at both ends.Response
array
required
The designs matching
kind, intros first.Show Template properties
Show Template properties
string
required
The template id,
snake_case. This is what you send as templateId on an overlay selection, and the only handle a design has.string
required
English display name, for a picker’s label. Presentation only — it is never accepted as
templateId.string
required
intro or outro. A design is valid only in its own slot.integer
required
The version to send as
templateVersion. Currently 1 for every design.string
required
The preset the design was delivered with.
animation is required on every selection and has no server-side default, so this is a recommendation rather than a fallback.array
required
The inputs the design renders, declared per template. Every intro takes
title (required) and subtitle; the eleven contact-card outros take agent_name (required), contact_line and agent_photo; custom_image takes one required image field, also called custom_image, and no text at all.Show Field properties
Show Field properties
string
required
The key to use in
values or assets. A key that is not one of these is accepted and silently ignored, so read the ids from here rather than guessing.string
required
text or image.string
required
Which half of the selection carries the value:
values for text fields, assets for image fields (as a public HTTPS URL).boolean
required
Whether the field must be sent. A required field that is missing, empty or whitespace-only is rejected with
400 VALIDATION_ERROR, whose details.field is the field’s dotted path (elements_config.intro_outro.intro.values.<id> for a text field, ...outro.assets.<id> for an image field); no task is created. title is required on every intro, agent_name on the eleven contact-card outros, and custom_image on the outro of the same name.integer | null
required
Characters the design was drawn to hold, or
null for an image field. The API accepts strings up to 500 characters; a longer value is fitted down to size rather than refused.string | null
required
Sample copy for previewing the design, published so a template picker in your own product has something to show. It is never rendered. An optional field you omit draws nothing, exactly as an empty string would, and a required field you omit is a
400 VALIDATION_ERROR. null on image fields.object
required
The colours the design ships with, in the two slots branding repaints.
Show Colour properties
Show Colour properties
string | null
required
Colour of the run the design leads with — an intro’s
title, an outro’s agent_name. This is what brandColorPrimary replaces. null on custom_image, which draws no type of its own and so has nothing to repaint.string | null
required
Colour of the line beside it —
subtitle, contact_line — and of the rules, frames, brackets and rings the design draws. This is what brandColorContrast replaces. null on custom_image, for the same reason.string | null
required
The outro card’s own background, and
null for every intro: an intro declares no surface, so what sits behind its type is your video.On the two designs that draw a gradient card (navy_neon, gradient_script) this is the first stop, which is the tone the name actually sits on.object
required
Rendered previews of the design, as
landscape and portrait image URLs. Every design has both layouts, and the one that renders follows the video’s own shape — orientation on the slideshow and living-property endpoints, format on land — never a field on the overlay itself.Intro previews are drawn on a neutral grey. An intro carries no background of its own, so over your video the type sits on whatever frame it opens on.
array
required
The nine animation presets, valid on both slots. A preset is one directional transition: an intro plays it as an exit, an outro as an entrance.
Example Request
curl https://api.vibepeak.ai/v1/intro-outro/templates?kind=outro \
-H "Authorization: Bearer vpk_live_xxxxx"
const response = await fetch(
'https://api.vibepeak.ai/v1/intro-outro/templates?kind=outro',
{ headers: { Authorization: 'Bearer vpk_live_xxxxx' } }
);
const { templates, animations } = await response.json();
import requests
response = requests.get(
'https://api.vibepeak.ai/v1/intro-outro/templates',
headers={'Authorization': 'Bearer vpk_live_xxxxx'},
params={'kind': 'outro'}
)
data = response.json()
Example Response
{
"templates": [
{
"id": "serif_business_card",
"name": "Serif Business Card",
"kind": "outro",
"template_version": 1,
"default_animation": "slide_up",
"fields": [
{
"id": "agent_name",
"type": "text",
"required": true,
"max_length": 32,
"default_value": "First Name Last Name",
"sent_in": "values"
},
{
"id": "contact_line",
"type": "text",
"required": false,
"max_length": 64,
"default_value": "[email protected] · (555) 123-4567",
"sent_in": "values"
},
{
"id": "agent_photo",
"type": "image",
"required": false,
"max_length": null,
"default_value": null,
"sent_in": "assets"
}
],
"default_colors": {
"primary": "#040404",
"contrast": "#A44A20",
"plate": "#FFFFFF"
},
"preview_urls": {
"landscape": "https://docs.vibepeak.ai/images/intro-outro/outro/serif_business_card.jpg",
"portrait": "https://docs.vibepeak.ai/images/intro-outro/outro/serif_business_card-portrait.jpg"
}
},
{
"id": "custom_image",
"name": "Custom image",
"kind": "outro",
"template_version": 1,
"default_animation": "fade",
"fields": [
{
"id": "custom_image",
"type": "image",
"required": true,
"max_length": null,
"default_value": null,
"sent_in": "assets"
}
],
"default_colors": {
"primary": null,
"contrast": null,
"plate": "#000000"
},
"preview_urls": {
"landscape": "https://docs.vibepeak.ai/images/intro-outro/outro/custom_image.jpg",
"portrait": "https://docs.vibepeak.ai/images/intro-outro/outro/custom_image-portrait.jpg"
}
}
],
"animations": [
{ "id": "fade", "description": "Opacity only. The overlay dissolves without moving." },
{
"id": "slide_up",
"description": "Travels upward: an intro leaves through the top, an outro arrives from below."
}
]
}
Using a template
Take theid, the template_version and an animation, then fill values and assets with the field ids the response gave you. Every field the response marks "required": true must be sent with a non-blank value, and every optional one you leave out simply renders nothing:
"elements_config": {
"enabled": false,
"intro_outro": {
"enabled": true,
"outro": {
"templateId": "serif_business_card",
"templateVersion": 1,
"animation": "slide_up",
"values": {
"agent_name": "Alex Rivera",
"contact_line": "[email protected] · +34 600 000 000"
},
"assets": { "agent_photo": "https://example.com/agent-photo.jpg" },
"brandColorPrimary": "#1A73E8"
}
}
}
custom_image is the one design whose fields do not follow that shape: it has no text field, so values stays empty and the whole selection is the image.
"elements_config": {
"enabled": false,
"intro_outro": {
"enabled": true,
"outro": {
"templateId": "custom_image",
"templateVersion": 1,
"animation": "fade",
"values": {},
"assets": { "custom_image": "https://example.com/listing-flyer.jpg" }
}
}
}
custom_image is an outro like the other eleven: it covers the same closing window and adds no duration. When the image’s aspect ratio differs from the video’s, the server extends its background to the video’s shape before rendering, so the image is never cropped. That happens while the create request is being accepted, so such a request takes a few seconds, and up to about 25 seconds when the ratios differ. The image must be a JPG, PNG or WEBP of at most 8 MB whose shortest edge is at least 400 px. It costs no extra credits.Errors
400
kind was something other than intro, outro or all.
