Custom Integrations
Build custom integrations with the Canvelete (opens in a new tab) API to connect design automation to any system.
Overview
Canvelete provides multiple integration options:
| Method | Best For |
|---|---|
| REST API | Direct HTTP integration |
| SDKs | Python, TypeScript, Go applications |
| Webhooks | Event-driven workflows |
| MCP Server | AI assistant integration |
REST API Integration
Basic Request
curl -X POST "https://api.canvelete.com/v1/render/design/design_123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "png",
"dynamicData": {
"title": "Hello World"
}
}'Response Handling
const response = await fetch('https://api.canvelete.com/v1/render/design/design_123', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
format: 'png',
dynamicData: { title: 'Hello World' }
})
});
const result = await response.json();
if (result.success) {
const imageUrl = result.data.downloadUrl;
// Use the generated image
} else {
console.error(result.error);
}Webhook Integration
Receive notifications when renders complete:
Setup
- Create an endpoint in your application
- Register it at Settings → Webhooks (opens in a new tab)
- Handle incoming events
Example Handler
// Express.js
app.post('/webhooks/canvelete', (req, res) => {
const { eventType, data } = req.body;
switch (eventType) {
case 'render.completed':
// Download and process the image
processImage(data.downloadUrl);
break;
case 'render.failed':
// Handle failure
notifyAdmin(data.error);
break;
}
res.status(200).send('OK');
});Common Integration Patterns
Form Submission → Image Generation
// When user submits a form
app.post('/generate-certificate', async (req, res) => {
const { name, course, date } = req.body;
const result = await canvelete.render.create({
templateId: 'certificate_template',
format: 'pdf',
dynamicData: { name, course, date }
});
// Send certificate to user
await sendEmail(req.body.email, {
attachment: result.downloadUrl
});
res.json({ success: true });
});Database Trigger → Batch Generation
// When new products are added
async function onProductsAdded(products) {
const renders = products.map(product => ({
designId: 'product_card_template',
format: 'png',
dynamicData: {
name: product.name,
price: product.price,
image: product.imageUrl
}
}));
const results = await canvelete.render.batch(renders);
// Update products with generated images
for (let i = 0; i < products.length; i++) {
await db.products.update(products[i].id, {
cardImage: results[i].downloadUrl
});
}
}Scheduled Generation
// Daily social media post generation
const cron = require('node-cron');
cron.schedule('0 9 * * *', async () => {
const todayData = await fetchDailyContent();
const result = await canvelete.render.create({
templateId: 'daily_post_template',
format: 'png',
dynamicData: todayData
});
await postToSocialMedia(result.downloadUrl);
});Error Handling
try {
const result = await canvelete.render.create({
designId: 'design_123',
format: 'png'
});
} catch (error) {
if (error.code === 'RATE_LIMITED') {
// Wait and retry
await sleep(error.retryAfter * 1000);
return retry();
}
if (error.code === 'NOT_FOUND') {
// Design doesn't exist
console.error('Design not found');
}
if (error.code === 'VALIDATION_ERROR') {
// Invalid parameters
console.error('Invalid request:', error.details);
}
}Rate Limiting
Implement backoff for rate limits:
async function renderWithRetry(options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await canvelete.render.create(options);
} catch (error) {
if (error.code === 'RATE_LIMITED' && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
await sleep(delay);
continue;
}
throw error;
}
}
}Security Best Practices
- Store API keys securely — Use environment variables
- Verify webhooks — Always validate signatures
- Use HTTPS — Encrypt all API communication
- Limit permissions — Create keys with minimal required scopes
- Rotate keys — Periodically generate new API keys
Example: E-commerce Integration
// Shopify webhook handler
app.post('/shopify/product-created', async (req, res) => {
const product = req.body;
// Generate product card
const cardResult = await canvelete.render.create({
templateId: 'product_card',
format: 'png',
dynamicData: {
name: product.title,
price: `$${product.variants[0].price}`,
image: product.images[0]?.src
}
});
// Generate social share image
const socialResult = await canvelete.render.create({
templateId: 'product_social',
format: 'png',
width: 1200,
height: 630,
dynamicData: {
name: product.title,
description: product.body_html?.substring(0, 100)
}
});
// Update product metafields
await shopify.product.update(product.id, {
metafields: [
{ key: 'card_image', value: cardResult.downloadUrl },
{ key: 'og_image', value: socialResult.downloadUrl }
]
});
res.status(200).send('OK');
});Next Steps
- API Reference — Full API documentation
- SDKs — Official client libraries
- Webhooks — Event notifications
- Zapier — No-code automation