Documentación de la API de StoryMint
Todo lo que necesitas para generar libros infantiles con IA de forma programática. Marca personalizada, varios formatos y ejemplos de código en todos los lenguajes principales.
Inicio rápido
Crea tu primer libro con unas pocas llamadas a la API.
Configuración
- Crea tu cuenta en storymint.ca/signup
- Suscríbete al plan Developer, Max o Escuelas y organizaciones (se requiere acceso a la API)
- Crea una clave API en tu panel de API
- Haz tu primera solicitud — mira los ejemplos más abajo
- Consulta el estado hasta que sea
status: "done"y luego descarga
5 formatos de libro
Libros para colorear, libros ilustrados, cómics, cómics por capítulos y novelas Beta.
Marca personalizada
Define el nombre del autor, la serie y el estilo de ilustración, y elige entre más de 8 estilos visuales para tu marca.
Libros más largos en planes superiores
Los límites de páginas y capítulos por libro dependen de tu plan. Consulta los límites de uso.
Descargas en PDF
Descarga el libro terminado en PDF en los planes elegibles; obtén el texto y las URL de las imágenes de cada página en JSON.
Generación de audiolibros
Genera un audiolibro narrado con IA a partir de un libro terminado (Max y Escuelas y organizaciones).
Edición por chat con IA
Envía instrucciones de edición en lenguaje natural y la IA reescribe las páginas en tiempo real.
Ruta de integración con menos código
- Verifica primero la autenticación con
GET /api/pingpara confirmar que la clave y el plan son válidos. - Genera con
POST /api/generate. - Consulta
GET /api/status/{job_id}hasta que veasdone. - Obtén o descarga con
GET /api/book/{job_id}para el JSON oGET /api/download/{job_id}para el PDF.
Autenticación
Toda solicitud debe incluir uno de estos dos métodos de autenticación:
Opción 1 — Clave API (recomendada)
Envía tu clave en el encabezado X-API-Key. Las claves API heredan el plan y el límite de uso de tu cuenta. Funcionan en los endpoints de libros (crear, seguir, leer, descargar, editar y narrar libros); los endpoints de la cuenta, como el perfil, las claves API, los equipos, los créditos y la facturación, necesitan el token de sesión de la Opción 2.
X-API-Key: sm_your_key_here
Opción 2 — Token Bearer de Firebase
Si estás construyendo un frontend, envía el token de ID de Firebase:
Authorization: Bearer <firebase_id_token>
Seguridad: las claves API se cifran con hash SHA-256 antes de almacenarse — nunca guardamos tu clave en texto plano. Trata tu clave como si fuera una contraseña.
URL base de la API de StoryMint
https://api.storymint.ca
Este es el endpoint actual de la API de StoryMint. Todas las rutas que siguen son relativas a él. Ejemplo: POST https://api.storymint.ca/api/generate
Límites de solicitudes
Los límites de solicitudes se aplican por cuenta según tu plan:
| Plan | Libros / mes | Máx. páginas ilustradas | Máx. páginas para colorear | Máx. páginas de cómic | Máx. capítulos de novela | API |
|---|---|---|---|---|---|---|
| Free | 1 de prueba (vista previa) | vista previa | vista previa | — | — | — |
| Plus | 15 | 50 | 40 | 100 | 20 | — |
| Max | 50 | 50 | 40 | 100 | 30 | Incluida |
| Developer | 100 | 50 | 40 | — | — | 150 llamadas de prueba |
| Escuelas y org. | 9,999 | 100 | 40 | 100 | 40 | Incluida |
Cuando superas tu límite de uso, la API devuelve 402 con error_code: "quota" y un mensaje error fácil de leer. Los límites se reinician el día 1 de cada mes. Los límites de páginas son por libro, no por mes.
Generar un libro
Inicia un trabajo asíncrono de generación de libro. Devuelve un job_id que usarás para consultar el estado y obtener el resultado.
Cuerpo de la solicitud (JSON)
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
prompt |
string | obligatorio | Descripción de la historia, hasta 600 caracteres. Por ejemplo: "Un pequeño mapache valiente que aprende a compartir con sus amigos del bosque" |
book_format |
string | opcional | Uno de: coloring, picture, comic, chapter_comic, novel Beta. El valor predeterminado es picture. Consulta los formatos. |
author |
string | opcional | Nombre del autor impreso en la portada y en la página de título. Ideal para marca personalizada. |
series |
string | opcional | Nombre de la serie si este libro pertenece a una colección con marca. Se muestra en la portada. |
art_style |
string | opcional | Estilo visual de las ilustraciones. Consulta Estilos de ilustración. Predeterminado: cartoon. Los libros para colorear usan lineart_simple (formas grandes para manos pequeñas), lineart_bold (predeterminado) o lineart_fine. |
story_model |
string | opcional | Ajuste de calidad para el texto de la historia. Por ahora el único ajuste es standard, que también es el predeterminado, así que puedes omitirlo. Consulta los ajustes de calidad. |
image_model |
string | opcional | Ajuste de calidad para las ilustraciones. Por ahora el único ajuste es standard (el predeterminado). |
coloring_variant |
string | opcional | Solo libros para colorear: pure (solo dibujos, predeterminado) o story (una frase corta debajo de cada dibujo). |
num_pages |
integer | opcional | Número de páginas (libro ilustrado/cómic) o de capítulos (novela). Se ajusta a los límites de tu plan — los cómics de pago llegan a 100 páginas, los libros ilustrados alcanzan 100 páginas en Escuelas y organizaciones, y las novelas están en beta con topes de capítulos según el plan. |
save_mode |
string | opcional | Se ignora para la duración del almacenamiento en los planes que incluyen la biblioteca en la nube: esos libros siempre se guardan en cloud_library y nunca expiran. Los planes que no la incluyen usan siempre temporary_cloud (se conservan 7 días). Envía local_until_export para omitir por completo el guardado en la nube. |
attachments |
array<string> | opcional | Ids de archivos adjuntos devueltos por POST /api/attachments. Las imágenes de referencia se describen con visión por IA y pueden guiar el renderizado imagen a imagen de SD Forge. |
Archivos adjuntos de referencia
Sube los archivos antes de llamar a /api/generate. StoryMint acepta hasta 5 archivos de 10 MB cada uno: PNG, JPEG, WebP, GIF, PDF, TXT o Markdown.
curl -X POST https://es.storymint.ca/api/attachments \ -H "Authorization: Bearer $TOKEN" \ -F "files=@character-reference.png"
La respuesta es { "ids": ["abc123ef"] }. Envía esos ids en el campo attachments cuando inicies la generación.
Respuesta
{
"job_id": "a1b2c3d4",
"status": "running"
}
Cómo se ve — vista previa del prompt
Así se ve una solicitud a la API aplicada a la pantalla Crear de StoryMint. Tu llamada a la API define todos estos campos de forma programática:
Cada etiqueta de arriba corresponde a un campo JSON del cuerpo de la solicitud. El prompt es el área de texto y las opciones se convierten en pares clave-valor.
Ejemplo completo — crear un libro ilustrado con tu marca
import requests
API_KEY = "sm_your_key_here"
BASE = "https://api.storymint.ca"
resp = requests.post(
f"{BASE}/api/generate",
headers={"X-API-Key": API_KEY},
json={
"prompt": "A brave little raccoon who learns to share",
"book_format": "picture",
"author": "My Brand Publishing",
"series": "Forest Friends",
"art_style": "watercolor",
"num_pages": 12,
},
)
data = resp.json()
print(f"Job started: {data['job_id']}")
const API_KEY = "sm_your_key_here";
const BASE = "https://api.storymint.ca";
const resp = await fetch(`${BASE}/api/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
prompt: "A brave little raccoon who learns to share",
book_format: "picture",
author: "My Brand Publishing",
series: "Forest Friends",
art_style: "watercolor",
num_pages: 12,
}),
});
const data = await resp.json();
console.log("Job started:", data.job_id);
import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String body = """
{
"prompt": "A brave little raccoon who learns to share",
"book_format": "picture",
"author": "My Brand Publishing",
"series": "Forest Friends",
"art_style": "watercolor",
"num_pages": 12
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.storymint.ca/api/generate"))
.header("Content-Type", "application/json")
.header("X-API-Key", "sm_your_key_here")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
curl -X POST https://api.storymint.ca/api/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: sm_your_key_here" \
-d '{
"prompt": "A brave little raccoon who learns to share",
"book_format": "picture",
"author": "My Brand Publishing",
"series": "Forest Friends",
"art_style": "watercolor",
"num_pages": 12
}'
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "sm_your_key_here");
var payload = new {
prompt = "A brave little raccoon who learns to share",
book_format = "picture",
author = "My Brand Publishing",
series = "Forest Friends",
art_style = "watercolor",
num_pages = 12,
};
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8, "application/json");
var resp = await client.PostAsync(
"https://api.storymint.ca/api/generate",
content);
var json = await resp.Content.ReadAsStringAsync();
Console.WriteLine(json);
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"io"
)
func main() {
body, _ := json.Marshal(map[string]interface{}{
"prompt": "A brave little raccoon who learns to share",
"book_format": "picture",
"author": "My Brand Publishing",
"series": "Forest Friends",
"art_style": "watercolor",
"num_pages": 12,
})
req, _ := http.NewRequest("POST",
"https://api.storymint.ca/api/generate",
bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", "sm_your_key_here")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}
Consultar estado
Consulta este endpoint cada pocos segundos para seguir el progreso hasta que status sea done o failed. El tiempo que tarda un libro depende de su formato y su extensión.
Respuesta
{
"status": "running",
"step": "Generating illustrations",
"msg": "Drawing page 4 of 12...",
"pct": 45,
"title": "Rusty's Big Day",
"format": "picture",
"can_download": false
}
Valores de estado: running → done o error.
Ejemplo de sondeo (Python)
import time, requests
API_KEY = "sm_your_key_here"
BASE = "https://api.storymint.ca"
job_id = "a1b2c3d4" # devuelto por /api/generate
while True:
r = requests.get(f"{BASE}/api/status/{job_id}",
headers={"X-API-Key": API_KEY})
info = r.json()
print(f"[{info.get('pct', 0)}%] {info.get('msg', '')}")
if info["status"] == "done":
print(f"Book ready! Title: {info.get('title')}")
break
elif info["status"] == "error":
print(f"Error: {info.get('msg')}")
break
time.sleep(3) # consulta cada 3 segundos
Progreso por SSE
Flujo de Server-Sent Events en tiempo real. Más eficiente que el sondeo — recibes las actualizaciones a medida que ocurren.
Formato de los eventos
data: {"step":"generating","msg":"Writing page 3...","pct":25}
data: {"step":"illustrating","msg":"Drawing page 3...","pct":40}
data: {"step":"done","msg":"Book complete!","pct":100}
Ejemplo en JavaScript
const BASE = "https://api.storymint.ca";
const jobId = "a1b2c3d4";
const evtSrc = new EventSource(`${BASE}/api/stream/${jobId}`);
evtSrc.onmessage = (e) => {
const data = JSON.parse(e.data);
console.log(`[${data.pct}%] ${data.msg}`);
if (data.step === "done" || data.step === "error") {
evtSrc.close();
}
};
Obtener datos del libro
Obtén la vista previa completa del libro: páginas, portada, texto, metadatos y URLs de las imágenes. Solo está disponible cuando el estado del trabajo es done.
Respuesta (libro ilustrado)
{
"title": "Rusty's Big Day",
"author": "My Brand Publishing",
"series": "Forest Friends",
"format": "picture",
"pages": [
{
"page_num": 1,
"text": "Once upon a time, in a hollow oak tree...",
"image_url": "/api/book/a1b2c3d4/image/page_01.png"
}
],
"cover_url": "/api/book/a1b2c3d4/image/cover.jpg",
"can_download": true,
"metadata": {
"total_pages": 12,
"art_style": "watercolor"
}
}
Edición por chat
Envía instrucciones en lenguaje natural para modificar un libro terminado. La IA reescribe las páginas afectadas.
Cuerpo de la solicitud
{
"message": "Make the ending happier and add a rainbow"
}
Respuesta
{
"assistant_message": "I've updated pages 10-12 with a happier ending featuring a rainbow celebration!",
"pages": [ ... ]
}
Ejemplo en Python
resp = requests.post(
f"{BASE}/api/book/{job_id}/chat",
headers={"X-API-Key": API_KEY},
json={"message": "Change the main character's name to Luna"},
)
edit = resp.json()
print(edit["assistant_message"])
Descargar el PDF
Descarga el libro terminado en PDF (application/pdf). Requiere un plan de pago elegible (Plus, Max, Developer o Escuelas y organizaciones) o un crédito de libro para ese libro.
Ejemplo de descarga en Python
resp = requests.get(
f"{BASE}/api/download/{job_id}",
headers={"X-API-Key": API_KEY},
)
if resp.status_code == 200:
with open("my_book.pdf", "wb") as f:
f.write(resp.content)
print("Downloaded!")
else:
print("Error:", resp.json())
Planificador de historias (Plan Mode)
Genera preguntas aclaratorias y respuestas sugeridas para un borrador de prompt de libro. Disponible en los planes Max y Escuelas y organizaciones.
{ "prompt": "A city gardener finds a tiny door under a tomato plant" }
Combina el prompt original con las respuestas del Modo Plan y devuelve un prompt mejorado para /api/generate.
{
"prompt": "A city gardener finds a tiny door under a tomato plant",
"answers": [
{ "question": "Who opens the door?", "answer": "Maya, a curious gardener" }
]
}
Audiolibro
Genera un audiolibro narrado con IA a partir de un libro terminado. Disponible en los planes Max y Escuelas y organizaciones. Si la narración no está disponible en este momento, la API devuelve un error con error_code en lugar de un archivo incompleto.
Respuesta
Devuelve el archivo MP3 directamente como audio/mpeg. Guárdalo en disco:
resp = requests.post(
f"{BASE}/api/audiobook/{job_id}",
headers={"X-API-Key": API_KEY},
)
with open("audiobook.mp3", "wb") as f:
f.write(resp.content)
Listar ajustes de calidad
Lista los ajustes de calidad disponibles en tu plan. Pasa el id de un ajuste en story_model o image_model al generar, u omite ambos para usar standard.
Respuesta
{
"presets": [
{ "id": "standard", "label": "Estándar" }
]
}
StoryMint elige y actualiza los servicios de IA que usa por dentro, así que los ajustes se mantienen estables aunque esos servicios cambien.
Verificar autenticación
Ejecuta una verificación de autenticación de bajo costo antes de generar. Confirma el acceso a la API, te indica qué plan está asociado a la clave e incrementa el contador de pings independiente que usa el plan Developer.
Respuesta
{
"status": "ok",
"tier": "developer",
"plan_display_name": "Developer",
"api_test_calls_this_month": 12,
"api_test_calls_limit": 150,
"timestamp": "2026-03-27T18:41:22.115000+00:00"
}
Developer incluye 150 llamadas de ping al mes. Max y Escuelas y organizaciones incluyen acceso a la API y por ahora no tienen un tope de pings independiente.
Plan y uso
Obtén tu plan actual, los contadores de uso, los límites y la cuota restante.
Respuesta
{
"tier": "developer",
"plan_display_name": "Developer",
"books_this_month": 12,
"books_limit": 100,
"next_reset": "2026-04-01",
"api_access": true,
"api_test_calls_this_month": 12,
"api_test_calls_limit": 150,
"full_download": true,
"max_pages": 50,
"novel_max_chapters": 0,
"org_type": ""
}
Marca personalizada
StoryMint está diseñado para la generación de libros de marca blanca. Usa estos campos para poner tu identidad en cada libro:
| Campo | Dónde aparece | Ejemplo |
|---|---|---|
author |
Portada, página de título, metadatos del PDF | "Maple Leaf Publishing" |
series |
Subtítulo de la portada, lomo (si aplica) | "Tiny Explorers Vol. 3" |
art_style |
Todas las ilustraciones del libro | "watercolor" |
book_format |
Diseño y estructura de todo el libro | "novel" |
Flujo de trabajo de marca
# Crea una serie de libros con tu marca
for topic in ["Space", "Ocean", "Jungle"]:
resp = requests.post(f"{BASE}/api/generate",
headers={"X-API-Key": API_KEY},
json={
"prompt": f"A child explores the {topic.lower()}",
"author": "Your Publishing Company",
"series": f"Little Explorers: {topic}",
"art_style": "watercolor",
"book_format": "picture",
})
print(f"Started {topic}: {resp.json()['job_id']}")
Personalización del perfil
Consulta o actualiza tu perfil de editor (nombre visible, biografía, sitio web). Esta información aparece en las publicaciones del mercado.
requests.put(f"{BASE}/api/profile",
headers={"Authorization": f"Bearer {ID_TOKEN}"},
json={
"display_name": "Maple Leaf Publishing",
"bio": "We create magical stories for curious kids.",
"website": "https://mapleleaf.example.com",
})
Estilos de ilustración
Elige un estilo visual para todas las ilustraciones de tu libro. Envía el valor de art_style en tu solicitud de generación.
cartoon
Estilo de caricatura brillante y llamativo. Ideal para los más pequeños (de 3 a 7 años). Predeterminado.
watercolor
Pinturas suaves en acuarela. Elegante y encantador, ideal para marcas premium.
sketch
Ilustraciones a lápiz con un aire hecho a mano.
pixel
Estilo retro de pixel art. Divertido para historias de videojuegos o nostálgicas.
flat
Ilustraciones modernas de diseño plano con líneas limpias y colores sólidos.
manga
Estilo manga japonés con personajes expresivos. Ideal para cómics por capítulos.
western
Estilo de cómic occidental con entintado dinámico y viñetas vibrantes.
graphic_novel
Estética de novela gráfica para lectores mayores, con viñetas detalladas y cinematográficas.
Planes y límites de páginas
Los límites de páginas y capítulos son por libro; la cantidad de libros es por mes. Esto es lo que desbloquea cada plan:
Free
- Una vista previa de un libro ilustrado o un libro para colorear
- Sin cómics ni novelas
- Sin acceso a la API
Plus
- 50 páginas ilustradas máx.
- 100 páginas de cómic máx.
- 20 capítulos de novela máx. Beta
- 15 libros / mes
Max
- 50 páginas ilustradas máx.
- 100 páginas de cómic máx.
- 30 capítulos de novela máx. Beta
- 50 libros / mes
- Acceso a la API incluido
Escuelas y organizaciones
- 100 páginas ilustradas máx.
- 100 páginas de cómic máx.
- 40 capítulos de novela máx. Beta
- 9,999 libros / mes
- 10 puestos para docentes o miembros del equipo incluidos
Developer
- 50 páginas ilustradas máx.
- 100 libros / mes
- 150 llamadas de prueba a la API
- Acceso completo a la API
- Sin cómics ni novelas
Escala visual de páginas
Mira cómo cambia el máximo de páginas según el plan:
Las páginas de cómic llegan hasta 100 en los planes creativos de pago. Las novelas están en Beta y llegan a un máximo de 40 capítulos en Escuelas y organizaciones.
Formatos de libro
| Formato | Valor | Resultado | Páginas máx. | Ideal para |
|---|---|---|---|---|
| Libro para colorear | coloring |
Dibujos en blanco y negro, una escena por página, portada a color; frases opcionales (coloring_variant: "story") |
Hasta 40 páginas (Free: vista previa) | Niños de 2 a 12 años, según el estilo de línea |
| Libro ilustrado | picture |
Ilustraciones a página completa con texto superpuesto | Hasta 100 páginas (según el plan) | Niños de 2 a 7 años, historias sencillas |
| Cómic | comic |
Páginas de cómic con viñetas y globos de diálogo | Hasta 100 páginas | Niños de 6 a 12 años, historias de acción |
| Cómic por capítulos (manga) | chapter_comic |
Cómic de varios capítulos con una portada por capítulo | Hasta 100 páginas | A partir de 8 años, historias por entregas |
| Novela Beta | novel |
Texto extenso con portada generada por IA y PDF con formato | 5–40 capítulos (según el plan) | A partir de 10 años, 15k–60k+ palabras |
Beta La generación de novelas está actualmente en beta. Las novelas usan IA para escribir libros completos por capítulos (15,000–60,000+ palabras) con portadas generadas automáticamente. Durante la beta:
- Una novela tarda más en crearse que un libro ilustrado, y una novela larga tarda más que una corta
- Las novelas más largas están disponibles en los planes superiores (consulta los límites de arriba)
- Puedes editar novelas por chat, aunque funciona mejor para ajustes pequeños
- El PDF incluye un formato profesional con encabezados de capítulo y números de página
- La cantidad de novelas al mes depende del plan: Plus 3, Max 10, Escuelas y organizaciones 9,999
Gestión de claves API
Lista todas tus claves API con su prefijo, etiqueta, fechas de creación y de último uso, y estado.
Crea una nueva clave API. La clave completa (sm_...) se devuelve solo una vez — guárdala de inmediato.
Solicitud
{ "label": "My Production App" }
Respuesta
{
"key": "sm_abc123xyz...",
"key_id": "k_8f2e1a",
"label": "My Production App"
}
Revoca una clave API. Queda inactiva de forma permanente. Crea una nueva si la necesitas.
Equipos (Escuelas y organizaciones)
Los usuarios de Escuelas y organizaciones pueden crear espacios de trabajo compartidos con puestos para docentes o miembros del equipo, invitar colaboradores por correo electrónico y compartir libros terminados en una biblioteca común.
GET lista tus equipos. POST crea un equipo nuevo.
Crear un equipo
resp = requests.post(f"{BASE}/api/teams",
headers={"Authorization": f"Bearer {ID_TOKEN}"},
json={"name": "Oakwood Elementary"})
team = resp.json()
print(f"Workspace: {team['id']} ({team['workspace_type']}), seats: {team['max_seats']}")
Invita a un miembro por correo electrónico. La respuesta incluye un ID de invitación que puedes usar en los flujos de aceptación.
{
"email": "teacher@school.edu"
}
Acepta una invitación pendiente después de que el usuario invitado inicie sesión. Devuelve el objeto del espacio de trabajo actualizado.
Lista todos los libros de la biblioteca compartida del equipo.
Comparte un libro terminado en la biblioteca del espacio de trabajo compartido para que todos los miembros puedan acceder a él.
Ejemplo completo — Python
Flujo completo de principio a fin: generar, consultar el estado y descargar.
import requests, time
API_KEY = "sm_your_key_here"
BASE = "https://api.storymint.ca"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# 1. Generar
gen = requests.post(f"{BASE}/api/generate", headers=HEADERS, json={
"prompt": "A cat astronaut discovers a candy planet",
"book_format": "comic",
"author": "Starlight Studios",
"art_style": "cartoon",
"num_pages": 30,
}).json()
job_id = gen["job_id"]
print(f"Job: {job_id}")
# 2. Consultar hasta que termine
while True:
status = requests.get(f"{BASE}/api/status/{job_id}",
headers=HEADERS).json()
print(f" [{status.get('pct', 0):3d}%] {status.get('msg', '')}")
if status["status"] in ("done", "error"):
break
time.sleep(3)
if status["status"] == "error":
print("Generation failed:", status.get("msg"))
exit(1)
# 3. Obtener los datos del libro
book = requests.get(f"{BASE}/api/book/{job_id}",
headers=HEADERS).json()
print(f"\nTitle: {book['title']}")
print(f"Pages: {len(book.get('pages', []))}")
# 4. Edición con IA
edit = requests.post(f"{BASE}/api/book/{job_id}/chat",
headers=HEADERS,
json={"message": "Add more humor to page 3"}).json()
print(f"Edit: {edit.get('assistant_message')}")
# 5. Descargar el PDF
dl = requests.get(f"{BASE}/api/download/{job_id}",
headers=HEADERS)
if dl.status_code == 200:
with open(f"{book['title']}.pdf", "wb") as f:
f.write(dl.content)
print("Downloaded!")
else:
print("Download error:", dl.json())
Ejemplo completo — JavaScript (Node.js / navegador)
const API_KEY = "sm_your_key_here";
const BASE = "https://api.storymint.ca";
const headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
};
// 1. Generar
const genResp = await fetch(`${BASE}/api/generate`, {
method: "POST", headers,
body: JSON.stringify({
prompt: "A cat astronaut discovers a candy planet",
book_format: "comic",
author: "Starlight Studios",
art_style: "cartoon",
num_pages: 30,
}),
});
const { job_id } = await genResp.json();
console.log("Job:", job_id);
// 2. Consultar el estado
let status;
do {
await new Promise(r => setTimeout(r, 3000));
const r = await fetch(`${BASE}/api/status/${job_id}`, { headers });
status = await r.json();
console.log(` [${status.pct x 0}%] ${status.msg x ""}`);
} while (status.status === "running");
// 3. Obtener el libro
const book = await (await fetch(`${BASE}/api/book/${job_id}`,
{ headers })).json();
console.log("Title:", book.title);
// 4. Edición por chat
const edit = await (await fetch(`${BASE}/api/book/${job_id}/chat`, {
method: "POST", headers,
body: JSON.stringify({ message: "Make the ending funnier" }),
})).json();
console.log("Edit:", edit.assistant_message);
// 5. Descargar (Node.js)
const dlResp = await fetch(`${BASE}/api/download/${job_id}`,
{ headers });
if (dlResp.ok) {
const fs = await import("fs");
const buf = Buffer.from(await dlResp.arrayBuffer());
fs.writeFileSync(`${book.title}.pdf`, buf);
console.log("Downloaded!");
}
// 5b. Descargar (navegador)
// const blob = await dlResp.blob();
// const a = document.createElement("a");
// a.href = URL.createObjectURL(blob);
// a.download = `${book.title}.pdf`;
// a.click();
Ejemplo completo — Java
import java.net.http.*;
import java.net.URI;
import java.nio.file.*;
public class StoryMintExample {
static final String API_KEY = "sm_your_key_here";
static final String BASE = "https://api.storymint.ca";
static final HttpClient client = HttpClient.newHttpClient();
static HttpRequest.Builder req(String path) {
return HttpRequest.newBuilder()
.uri(URI.create(BASE + path))
.header("X-API-Key", API_KEY)
.header("Content-Type", "application/json");
}
public static void main(String[] args) throws Exception {
// 1. Generar
String body = """
{
"prompt": "A cat astronaut discovers a candy planet",
"book_format": "comic",
"author": "Starlight Studios",
"art_style": "cartoon",
"num_pages": 30
}""";
var genResp = client.send(
req("/api/generate").POST(
HttpRequest.BodyPublishers.ofString(body)).build(),
HttpResponse.BodyHandlers.ofString());
System.out.println("Generate: " + genResp.body());
// Extrae el job_id de la respuesta JSON
String jobId = "PARSE_FROM_RESPONSE";
// 2. Consultar el estado
while (true) {
var statusResp = client.send(
req("/api/status/" + jobId).GET().build(),
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + statusResp.body());
if (statusResp.body().contains("\"done\"") ||
statusResp.body().contains("\"error\"")) break;
Thread.sleep(3000);
}
// 3. Descargar
var dlResp = client.send(
req("/api/download/" + jobId).GET().build(),
HttpResponse.BodyHandlers.ofByteArray());
if (dlResp.statusCode() == 200) {
Files.write(Path.of("book.pdf"), dlResp.body());
System.out.println("Downloaded!");
}
}
}
Ejemplo completo — cURL
# 1. Generar un libro
JOB=$(curl -s -X POST \
https://api.storymint.ca/api/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: sm_your_key_here" \
-d '{
"prompt": "A cat astronaut discovers a candy planet",
"book_format": "comic",
"author": "Starlight Studios",
"art_style": "cartoon",
"num_pages": 30
}')
echo "Generate response: $JOB"
JOB_ID=$(echo $JOB | grep -o '"job_id":"[^"]*"' | cut -d'"' -f4)
# 2. Consultar el estado hasta que termine
while true; do
STATUS=$(curl -s \
https://api.storymint.ca/api/status/$JOB_ID \
-H "X-API-Key: sm_your_key_here")
echo "Status: $STATUS"
echo "$STATUS" | grep -q '"done"\|"error"' && break
sleep 3
done
# 3. Obtener los datos del libro
curl -s \
https://api.storymint.ca/api/book/$JOB_ID \
-H "X-API-Key: sm_your_key_here" | python3 -m json.tool
# 4. Descargar el PDF
curl -o book.pdf \
https://api.storymint.ca/api/download/$JOB_ID \
-H "X-API-Key: sm_your_key_here"
Ejemplo completo — C#
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "sm_your_key_here");
var baseUrl = "https://api.storymint.ca";
// 1. Generar
var genPayload = JsonSerializer.Serialize(new {
prompt = "A cat astronaut discovers a candy planet",
book_format = "comic",
author = "Starlight Studios",
art_style = "cartoon",
num_pages = 30,
});
var genResp = await client.PostAsync($"{baseUrl}/api/generate",
new StringContent(genPayload, Encoding.UTF8, "application/json"));
var genJson = JsonDocument.Parse(await genResp.Content.ReadAsStringAsync());
var jobId = genJson.RootElement.GetProperty("job_id").GetString();
Console.WriteLine($"Job: {jobId}");
// 2. Consultar el estado
while (true) {
var statusResp = await client.GetStringAsync($"{baseUrl}/api/status/{jobId}");
Console.WriteLine($"Status: {statusResp}");
if (statusResp.Contains("\"done\"") || statusResp.Contains("\"error\"")) break;
await Task.Delay(3000);
}
// 3. Descargar
var dlResp = await client.GetAsync($"{baseUrl}/api/download/{jobId}");
if (dlResp.IsSuccessStatusCode) {
var bytes = await dlResp.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("book.pdf", bytes);
Console.WriteLine("Downloaded!");
}
Ejemplo completo — Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
const apiKey = "sm_your_key_here"
const base = "https://api.storymint.ca"
func apiReq(method, path string, body interface{}) (*http.Response, error) {
var buf io.Reader
if body != nil {
b, _ := json.Marshal(body)
buf = bytes.NewBuffer(b)
}
req, _ := http.NewRequest(method, base+path, buf)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", apiKey)
return http.DefaultClient.Do(req)
}
func main() {
// 1. Generar
resp, _ := apiReq("POST", "/api/generate", map[string]interface{}{
"prompt": "A cat astronaut discovers a candy planet",
"book_format": "comic",
"author": "Starlight Studios",
"art_style": "cartoon",
"num_pages": 30,
})
var gen map[string]interface{}
json.NewDecoder(resp.Body).Decode(&gen)
resp.Body.Close()
jobID := gen["job_id"].(string)
fmt.Println("Job:", jobID)
// 2. Consultar el estado
for {
resp, _ := apiReq("GET", "/api/status/"+jobID, nil)
var st map[string]interface{}
json.NewDecoder(resp.Body).Decode(&st)
resp.Body.Close()
fmt.Printf(" [%.0f%%] %s\n", st["pct"], st["msg"])
if st["status"] == "done" || st["status"] == "error" {
break
}
time.Sleep(3 * time.Second)
}
// 3. Descargar
resp, _ = apiReq("GET", "/api/download/"+jobID, nil)
defer resp.Body.Close()
if resp.StatusCode == 200 {
f, _ := os.Create("book.pdf")
io.Copy(f, resp.Body)
f.Close()
fmt.Println("Downloaded!")
}
}
Códigos de error
200Éxito201Recurso creado (clave API, equipo)400Solicitud incorrecta — faltan parámetros o no son válidos401No autorizado — falta la clave API / token o no es válida403Prohibido — se superó el límite de uso o la función no está disponible en tu plan404No encontrado — job_id o recurso no válido429Demasiadas solicitudes — se alcanzó el límite de solicitudes500Error interno del servidor — vuelve a intentarlo en unos segundos503Servicio no disponible — el motor de generación está temporalmente fuera de línea
Formato de la respuesta de error
{
"error": "Descriptive error message here",
"detail": "Additional context (optional)"
}
Manejo de errores (Python)
resp = requests.post(f"{BASE}/api/generate",
headers=HEADERS, json=payload)
if resp.status_code == 200:
job_id = resp.json()["job_id"]
elif resp.status_code == 403:
print("Quota exceeded:", resp.json().get("error"))
elif resp.status_code == 401:
print("Invalid API key. Check your X-API-Key header.")
else:
print(f"Error {resp.status_code}:", resp.json())
Webhooks
Los webhooks de generación completada todavía no están disponibles en esta versión pública. En su lugar, usa la consulta de estado o la transmisión por SSE para seguir el progreso del trabajo.
¿Te interesa? Escríbenos a support@storymint.ca.