Integrations
Custom Integrations

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:

MethodBest For
REST APIDirect HTTP integration
SDKsPython, TypeScript, Go applications
WebhooksEvent-driven workflows
MCP ServerAI 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

  1. Create an endpoint in your application
  2. Register it at Settings → Webhooks (opens in a new tab)
  3. 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

  1. Store API keys securely — Use environment variables
  2. Verify webhooks — Always validate signatures
  3. Use HTTPS — Encrypt all API communication
  4. Limit permissions — Create keys with minimal required scopes
  5. 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