Studio API Code Examples
Copy-paste ready examples for TypeScript, Python, and cURL. All examples include error handling, credit management, and job polling.
Generate Event PosterImage Generation
import { StudioSvcClient } from '@eventzr/studio-client';
const client = new StudioSvcClient({
baseUrl: 'https://api.eventzr.com/studio/v1',
apiKey: process.env.EVENTZR_API_KEY!,
tenantId: process.env.EVENTZR_TENANT_ID!,
});
async function generateEventPoster() {
try {
// Check wallet balance
const balance = await client.wallet.getBalance();
console.log(`Available credits: ${balance.credits}`);
if (balance.credits < 10) {
throw new Error('Insufficient credits');
}
// Generate poster
const result = await client.images.generate({
prompt: `Modern tech conference poster with geometric shapes,
vibrant purple and blue gradient, futuristic design,
professional typography, clean composition`,
width: 1024,
height: 1792,
quality: 'standard',
variants: 2,
provider: 'ideogram',
stylePreset: 'realistic',
});
console.log(`Job created: ${result.jobId}`);
console.log(`Credits reserved: ${result.creditsReserved}`);
// Poll for completion
const job = await client.jobs.waitForCompletion(result.jobId, {
pollInterval: 2000, // 2 seconds
timeout: 300000, // 5 minutes
});
if (job.status === 'completed') {
console.log(`Job completed in ${job.duration}ms`);
console.log(`Credits charged: ${job.creditsCharged}`);
console.log(`Outputs:`);
job.outputs.forEach((output, index) => {
console.log(` Variant ${index + 1}: ${output.url}`);
});
return job.outputs;
} else if (job.status === 'failed') {
console.error(`Job failed: ${job.error}`);
console.log(`Credits refunded: ${job.creditsRefunded}`);
throw new Error(job.error);
}
} catch (error) {
if (error.code === 'ERR_INSUFFICIENT_CREDITS') {
console.error('Not enough credits. Please top up.');
} else if (error.code === 'ERR_QUOTA_EXCEEDED') {
console.error('Monthly quota exceeded. Upgrade tier.');
} else {
console.error('Unexpected error:', error);
}
throw error;
}
}
generateEventPoster();Generate Event Promo VideoVideo Generation
async function generatePromoVideo() {
const result = await client.videos.generate({
prompt: `Cinematic event teaser video, crowd dancing at outdoor
music festival, golden hour lighting, aerial drone shot,
energetic atmosphere, 4K quality`,
duration: 10,
quality: 'high',
provider: 'runway',
fps: 30,
aspectRatio: '16:9',
});
console.log(`Video job created: ${result.jobId}`);
console.log(`Credits reserved: ${result.creditsReserved}`); // 250
// Video generation takes 3-5 minutes
const job = await client.jobs.waitForCompletion(result.jobId, {
pollInterval: 5000,
timeout: 600000, // 10 minutes
onProgress: (progress) => {
console.log(`Progress: ${progress}%`);
},
});
if (job.status === 'completed') {
console.log(`Video URL: ${job.outputs[0].url}`);
console.log(`Duration: ${job.outputs[0].duration}s`);
console.log(`Resolution: ${job.outputs[0].width}x${job.outputs[0].height}`);
return job.outputs[0];
}
}Generate Event Announcement AudioText-to-Speech
async function generateAnnouncement() {
const text = `
Join us for TechConf 2026, the premier technology conference
bringing together innovators and thought leaders from around
the world. Experience cutting-edge demos, inspiring keynotes,
and unparalleled networking opportunities. Register now at
techconf dot com.
`;
const result = await client.audio.tts({
text,
voiceId: 'voice_professional_male_01',
language: 'en-US',
speed: 1.1, // Slightly faster
emotion: 'excited',
});
console.log(`TTS job created: ${result.jobId}`);
console.log(`Credits reserved: ${result.creditsReserved}`); // 5
const job = await client.jobs.waitForCompletion(result.jobId);
if (job.status === 'completed') {
console.log(`Audio URL: ${job.outputs[0].url}`);
console.log(`Duration: ${job.outputs[0].duration}s`);
console.log(`Format: ${job.outputs[0].format}`); // mp3
return job.outputs[0];
}
}
// Multi-speaker dialogue
async function generateDialogue() {
const speakers = [
{
text: "Welcome to our annual product showcase!",
voiceId: 'voice_professional_female_01',
emotion: 'excited',
},
{
text: "We're thrilled to unveil three groundbreaking innovations.",
voiceId: 'voice_professional_male_02',
emotion: 'confident',
},
];
const result = await client.audio.generateDialogue({
speakers,
backgroundMusic: true,
musicVolume: 0.2,
});
const job = await client.jobs.waitForCompletion(result.jobId);
return job.outputs[0];
}Clone Custom VoiceVoice Cloning
async function cloneAndUseCEOVoice() {
// Step 1: Clone voice from audio samples
const cloneResult = await client.audio.cloneVoice({
name: 'CEO Voice',
audioSamples: [
'https://storage.example.com/ceo-sample-1.mp3',
'https://storage.example.com/ceo-sample-2.mp3',
'https://storage.example.com/ceo-sample-3.mp3',
],
language: 'en-US',
quality: 'high',
});
console.log(`Voice cloning started: ${cloneResult.jobId}`);
console.log(`Credits reserved: ${cloneResult.creditsReserved}`); // 500
// Voice cloning takes 10-30 minutes
const cloneJob = await client.jobs.waitForCompletion(cloneResult.jobId, {
pollInterval: 10000, // 10 seconds
timeout: 3600000, // 1 hour
});
if (cloneJob.status === 'completed') {
const voiceModelId = cloneJob.outputs[0].voiceModelId;
console.log(`Voice model ready: ${voiceModelId}`);
// Step 2: Generate speech with cloned voice
const speechResult = await client.audio.generateSpeech({
text: `This is the CEO speaking with my custom cloned voice.
Our quarterly results exceeded expectations.`,
voiceModelId,
speed: 1.0,
});
const speechJob = await client.jobs.waitForCompletion(speechResult.jobId);
if (speechJob.status === 'completed') {
console.log(`Custom voice audio: ${speechJob.outputs[0].url}`);
return {
voiceModelId,
audioUrl: speechJob.outputs[0].url,
};
}
}
}Generate Talking Avatar VideoAvatar Animation
async function createTalkingAvatar() {
// Step 1: Create avatar from photo
const avatarResult = await client.avatars.generate({
sourceType: 'photo',
sourceData: 'https://storage.example.com/speaker-photo.jpg',
style: 'realistic',
quality: 'high',
});
console.log(`Avatar creation started: ${avatarResult.jobId}`);
const avatarJob = await client.jobs.waitForCompletion(avatarResult.jobId);
if (avatarJob.status === 'completed') {
const avatarModelId = avatarJob.outputs[0].avatarModelId;
// Step 2: Generate speech audio
const speechResult = await client.audio.tts({
text: `Hello everyone! I'm excited to welcome you to our
virtual conference. Let's explore the future of technology
together.`,
voiceId: 'voice_professional_female_01',
emotion: 'excited',
});
const speechJob = await client.jobs.waitForCompletion(speechResult.jobId);
const audioUrl = speechJob.outputs[0].url;
// Step 3: Animate avatar with speech
const animationResult = await client.avatars.animate({
avatarModelId,
audioUrl,
duration: 30,
backgroundType: 'solid-color',
backgroundColor: '#1a1a1a',
});
console.log(`Avatar animation started: ${animationResult.jobId}`);
console.log(`Credits reserved: ${animationResult.creditsReserved}`); // 1000
const animationJob = await client.jobs.waitForCompletion(
animationResult.jobId,
{
pollInterval: 10000,
timeout: 1800000, // 30 minutes
}
);
if (animationJob.status === 'completed') {
console.log(`Talking avatar video: ${animationJob.outputs[0].url}`);
return animationJob.outputs[0];
}
}
}Render Event TemplateTemplates
async function renderEventInvitation() {
// Browse templates
const templates = await client.templates.list({
category: 'event-invitations',
limit: 10,
});
const template = templates.data[0];
console.log(`Using template: ${template.name}`);
// Render with custom data
const result = await client.templates.render(template.id, {
data: {
eventTitle: 'Summer Music Festival 2026',
eventDate: 'July 15-17, 2026',
eventLocation: 'Central Park, NYC',
eventDescription: 'Three days of amazing music and art',
organizerLogo: 'https://storage.example.com/logo.png',
primaryColor: '#6366F1',
secondaryColor: '#EC4899',
},
outputFormat: 'png',
});
const job = await client.jobs.waitForCompletion(result.jobId);
if (job.status === 'completed') {
console.log(`Rendered invitation: ${job.outputs[0].url}`);
return job.outputs[0];
}
}Optimize for Social MediaSocial Media
async function optimizeForSocial() {
const sourceImage = 'https://storage.example.com/event-poster.jpg';
const result = await client.social.optimize({
sourceUrl: sourceImage,
platforms: ['instagram', 'tiktok', 'twitter', 'linkedin'],
includeText: true,
textOverlay: {
title: 'TechConf 2026',
subtitle: 'July 15-17 | NYC',
},
});
console.log(`Social optimization started: ${result.jobId}`);
const job = await client.jobs.waitForCompletion(result.jobId);
if (job.status === 'completed') {
console.log('Platform-specific variants:');
job.outputs.forEach((output) => {
console.log(` ${output.platform}: ${output.url}`);
console.log(` Size: ${output.width}x${output.height}`);
});
return job.outputs;
}
}
// Auto-publish to social media
async function publishToSocial() {
const variants = await optimizeForSocial();
const publishResult = await client.social.publish({
variants,
caption: 'Join us at TechConf 2026! 🚀 #TechConf #Innovation',
platforms: ['instagram', 'twitter'],
scheduleAt: '2026-06-01T09:00:00Z', // Schedule for later
});
console.log('Published to social media');
return publishResult;
}Best Practices
1. Always Check Credits Before Operations
Prevent failed operations by checking wallet balance first.
const balance = await client.wallet.getBalance();
if (balance.credits < requiredCredits) {
throw new Error('Insufficient credits');
}2. Implement Exponential Backoff for Polling
Reduce API calls with exponential backoff when polling job status.
let pollInterval = 2000; // Start at 2 seconds
const maxInterval = 30000; // Max 30 seconds
while (true) {
const job = await client.jobs.get(jobId);
if (job.status !== 'processing') break;
await sleep(pollInterval);
pollInterval = Math.min(pollInterval * 1.5, maxInterval);
}3. Handle Provider Fallbacks Gracefully
The Studio API automatically retries failed jobs with fallback providers. Check job.metadata.providersAttempted for details.
4. Use Idempotency Keys for Retries
Include idempotency-key header to safely retry failed requests.
const result = await client.images.generate(
{ prompt: '...' },
{ idempotencyKey: 'unique-operation-id' }
);5. Cache Generated Assets
Output URLs are permanent (CDN-cached). Store URLs in your database to avoid regenerating identical content.