Request presigned upload URLs for a new model's images
curl --request POST \
--url https://api.samsa.ai/public/v1/models/prepare \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Acme Brand Style",
"category": "style",
"files": [
{
"filename": "logo.png",
"content_type": "image/png",
"size": 204800
}
],
"instruction": "<string>"
}
'import requests
url = "https://api.samsa.ai/public/v1/models/prepare"
payload = {
"name": "Acme Brand Style",
"category": "style",
"files": [
{
"filename": "logo.png",
"content_type": "image/png",
"size": 204800
}
],
"instruction": "<string>"
}
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: 'Acme Brand Style',
category: 'style',
files: [{filename: 'logo.png', content_type: 'image/png', size: 204800}],
instruction: '<string>'
})
};
fetch('https://api.samsa.ai/public/v1/models/prepare', 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.samsa.ai/public/v1/models/prepare",
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' => 'Acme Brand Style',
'category' => 'style',
'files' => [
[
'filename' => 'logo.png',
'content_type' => 'image/png',
'size' => 204800
]
],
'instruction' => '<string>'
]),
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.samsa.ai/public/v1/models/prepare"
payload := strings.NewReader("{\n \"name\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\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.samsa.ai/public/v1/models/prepare")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.samsa.ai/public/v1/models/prepare")
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\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"uploads": [
{
"key": "<string>",
"upload_url": "<string>",
"index": 123
}
],
"expires_in": 3600
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}Model Training
Prepare a model upload
Request presigned PUT URLs for a new model’s reference images (two-step upload).
POST
/
models
/
prepare
Request presigned upload URLs for a new model's images
curl --request POST \
--url https://api.samsa.ai/public/v1/models/prepare \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Acme Brand Style",
"category": "style",
"files": [
{
"filename": "logo.png",
"content_type": "image/png",
"size": 204800
}
],
"instruction": "<string>"
}
'import requests
url = "https://api.samsa.ai/public/v1/models/prepare"
payload = {
"name": "Acme Brand Style",
"category": "style",
"files": [
{
"filename": "logo.png",
"content_type": "image/png",
"size": 204800
}
],
"instruction": "<string>"
}
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: 'Acme Brand Style',
category: 'style',
files: [{filename: 'logo.png', content_type: 'image/png', size: 204800}],
instruction: '<string>'
})
};
fetch('https://api.samsa.ai/public/v1/models/prepare', 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.samsa.ai/public/v1/models/prepare",
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' => 'Acme Brand Style',
'category' => 'style',
'files' => [
[
'filename' => 'logo.png',
'content_type' => 'image/png',
'size' => 204800
]
],
'instruction' => '<string>'
]),
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.samsa.ai/public/v1/models/prepare"
payload := strings.NewReader("{\n \"name\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\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.samsa.ai/public/v1/models/prepare")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.samsa.ai/public/v1/models/prepare")
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\": \"Acme Brand Style\",\n \"category\": \"style\",\n \"files\": [\n {\n \"filename\": \"logo.png\",\n \"content_type\": \"image/png\",\n \"size\": 204800\n }\n ],\n \"instruction\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"uploads": [
{
"key": "<string>",
"upload_url": "<string>",
"index": 123
}
],
"expires_in": 3600
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid, expired, or revoked.",
"request_id": "8f14e45fceea167a5a36dedd4bea2543",
"param": "aspect_ratio"
}
}Step one of the presigned upload flow for large files. Send the model
name,
category, and metadata for the 1–10 files you will upload (the first file is
the cover). The response returns a model id and one presigned PUT upload_url per
file. PUT each file to its URL, then call
POST /models/{id}/complete with the
uploaded keys to start processing. Requires the models.write scope.
Use this two-step flow when images are too large to send inline. For small images
or remote URLs,
POST /models is simpler.
Each file’s content_type is one of image/jpeg, image/png, image/webp;
provide size (≤ 10 MB) when you know it.Authorizations
Organization API key as a bearer token: Authorization: Bearer samsa_sk_....
Body
application/json
POST /models/prepare body — request presigned PUT URLs for large files.
Required string length:
1 - 100Example:
"Acme Brand Style"
Model category — one of style, object, person, setting.
Available options:
style, object, person, setting Example:
"style"
Metadata for the 1-10 files you will upload (first = cover).
Required array length:
1 - 10 elementsShow child attributes
Show child attributes
Optional free-text guidance for how to use the model.
Maximum string length:
8000
