Skip to main content
POST
/
v1
/
themes
Create a theme
curl --request POST \
  --url https://app.loops.so/api/v1/themes \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "<string>",
  "styles": {}
}
'
import requests

url = "https://app.loops.so/api/v1/themes"

payload = {
"name": "<string>",
"styles": {}
}
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: '<string>', styles: {}})
};

fetch('https://app.loops.so/api/v1/themes', 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://app.loops.so/api/v1/themes",
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' => '<string>',
'styles' => [

]
]),
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://app.loops.so/api/v1/themes"

payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"styles\": {}\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://app.loops.so/api/v1/themes")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"styles\": {}\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://app.loops.so/api/v1/themes")

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\": \"<string>\",\n \"styles\": {}\n}"

response = http.request(request)
puts response.read_body
{
  "id": "clo1z5q7s004yl70y3z4a5b6c",
  "name": "Marketing default",
  "styles": {
    "backgroundColor": "#ffffff",
    "textBaseColor": "#111111",
    "textBaseFontSize": 16
  },
  "isDefault": false,
  "createdAt": "2026-03-28T15:00:00.000Z",
  "updatedAt": "2026-03-28T15:00:00.000Z"
}
{
  "message": "Name is required."
}
Read more about themes.

Request

Body

name
string
required
The theme name.
styles
object
Style attributes for the theme. Attributes use the same names as the LMX <Style /> tag attributes.

Response

Success

Returns 201 Created.
id
string
required
The theme ID.
name
string
required
The theme name.
styles
object
required
The theme’s style attributes.
isDefault
boolean
required
Whether this theme is the team’s default theme.
createdAt
string
required
ISO 8601 timestamp for when the theme was created.
updatedAt
string
required
ISO 8601 timestamp for when the theme was last updated.

Error

If the request body is invalid, a 400 Bad Request is returned. If the API key is invalid (or content API is not enabled for your team), a 401 Unauthorized is returned.
message
string
required
An error message describing what went wrong.
{
  "id": "clo1z5q7s004yl70y3z4a5b6c",
  "name": "Marketing default",
  "styles": {
    "backgroundColor": "#ffffff",
    "textBaseColor": "#111111",
    "textBaseFontSize": 16
  },
  "isDefault": false,
  "createdAt": "2026-03-28T15:00:00.000Z",
  "updatedAt": "2026-03-28T15:00:00.000Z"
}
{
  "message": "Name is required."
}
Last modified on July 9, 2026