Guia do Desenvolvedor

Construindo seu App

Construa um app frontend que conecta ao Venddor usando nossas APIs, SDKs e embeds.

Arquitetura do App

Existem tres formas de integrar seu app com o Venddor:

TipoDescriçãoMelhor para
App StandaloneSeu app roda em seu proprio servidor e chama as APIs do VenddorERPs, CRMs, ferramentas de BI
App EmbutidoSeu app carrega dentro do painel admin do Venddor via iframeDashboards, configuracoes avancadas
Widget StorefrontComponente JavaScript injetado na loja do tenantReviews, chat, recomendacoes

SDK JavaScript

Use o SDK JavaScript para simplificar chamadas API, autenticacao e tratamento de erros:

bash
npm install @venddor/sdk
javascript
import { VenddorClient } from '@venddor/sdk';

// Initialize the client
const venddor = new VenddorClient({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET', // server-side only!
  apiUrl: 'https://api.io.venddor.com.br',
});

// Authenticate with a tenant
const auth = await venddor.authenticate(tenantId, accessToken);

// List products
const products = await venddor.products.list({
  page: 1,
  limit: 20,
  status: 'active',
});

console.log(`Found ${products.total} products`);

// Create a product
const newProduct = await venddor.products.create({
  name: 'Camiseta Premium',
  price_cents: 8990,
  description: 'High quality cotton t-shirt',
  category_id: 'CAT_UUID',
});

// Get an order
const order = await venddor.orders.get('ORDER_ID');
console.log(`Order ${order.id}: R$ ${(order.total_cents / 100).toFixed(2)}`);

// Listen to webhooks (Express.js example)
app.post('/webhooks/venddor', venddor.webhooks.verify(), (req, res) => {
  const event = req.body;
  console.log(`Received ${event.event} for tenant ${event.tenant_id}`);

  switch (event.event) {
    case 'order.created':
      handleNewOrder(event.data);
      break;
    case 'product.updated':
      syncProduct(event.data);
      break;
  }

  res.status(200).send('OK');
});

SDK Python

bash
pip install venddor-sdk
python
from venddor import VenddorClient

# Initialize the client
client = VenddorClient(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    api_url='https://api.io.venddor.com.br'
)

# Authenticate
client.authenticate(tenant_id, access_token)

# List products
products = client.products.list(page=1, limit=20, status='active')
print(f"Found {products['total']} products")

# Create a product
new_product = client.products.create(
    name='Camiseta Premium',
    price_cents=8990,
    description='High quality cotton t-shirt',
    category_id='CAT_UUID'
)

# Process orders
orders = client.orders.list(status='pending')
for order in orders['items']:
    print(f"Order {order['id']}: R$ {order['total_cents'] / 100:.2f}")

# Webhook verification (Flask example)
@app.route('/webhooks/venddor', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Venddor-Signature')
    if not client.webhooks.verify(request.data, signature):
        return 'Invalid signature', 401

    event = request.json
    if event['event'] == 'order.created':
        process_new_order(event['data'])

    return 'OK', 200

Padrao de App Embutido

Apps embutidos rodam dentro do painel admin do Venddor via iframe. Isso permite uma experiencia integrada sem sair do admin.

html
<!-- Your embedded app's HTML -->
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.venddor.com.br/embed-sdk.js"></script>
</head>
<body>
  <div id="app"></div>

  <script>
    // The Venddor Embed SDK provides:
    // - Authentication context (token, tenant)
    // - Navigation helpers
    // - Toast notifications
    // - Theme synchronization (light/dark mode)

    const venddor = VenddorEmbed.init();

    venddor.on('ready', ({ token, tenantId, theme }) => {
      console.log('Embedded in Venddor admin');
      console.log('Token:', token);
      console.log('Tenant:', tenantId);
      console.log('Theme:', theme); // 'light' or 'dark'

      // Your app logic here
      fetchData(token, tenantId);
    });

    venddor.on('theme-change', (theme) => {
      document.body.className = theme;
    });

    // Show a toast in the Venddor admin
    venddor.toast('Product synced successfully!', 'success');

    // Navigate to another admin page
    venddor.navigate('/admin/products');
  </script>
</body>
</html>

Fluxo OAuth Redirect

Aqui esta um exemplo completo do fluxo OAuth redirect usando Node.js/Express:

javascript
const express = require('express');
const crypto = require('crypto');
const app = express();

const CLIENT_ID = process.env.VENDDOR_CLIENT_ID;
const CLIENT_SECRET = process.env.VENDDOR_CLIENT_SECRET;
const REDIRECT_URI = 'https://myapp.com/auth/callback';
const VENDDOR_API = 'https://api.io.venddor.com.br';

// Step 1: Redirect user to Venddor authorization
app.get('/auth/install', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  req.session.oauthState = state;

  const authUrl = new URL(`${VENDDOR_API}/oauth/authorize`);
  authUrl.searchParams.set('client_id', CLIENT_ID);
  authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
  authUrl.searchParams.set('response_type', 'code');
  authUrl.searchParams.set('scope', 'read_products write_inventory');
  authUrl.searchParams.set('state', state);

  res.redirect(authUrl.toString());
});

// Step 2: Handle callback and exchange code for token
app.get('/auth/callback', async (req, res) => {
  const { code, state, tenant_id } = req.query;

  // Validate state to prevent CSRF
  if (state !== req.session.oauthState) {
    return res.status(403).send('Invalid state');
  }

  // Exchange code for access token
  const tokenRes = await fetch(`${VENDDOR_API}/oauth/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      grant_type: 'authorization_code',
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      code,
      redirect_uri: REDIRECT_URI,
    }),
  });

  const tokens = await tokenRes.json();

  // Store tokens securely (database, encrypted session, etc.)
  await saveTokens(tenant_id, tokens);

  res.redirect('/dashboard');
});

Widgets Storefront

Widgets storefront sao componentes JavaScript que sao injetados na loja publica do tenant. Eles podem exibir conteudo adicional como reviews, chat ou recomendacoes.

javascript
// widget.js — loaded by the tenant's storefront
(function() {
  const WIDGET_API = 'https://api.myapp.com/widget';

  // Get the tenant context from the page
  const tenantId = document.querySelector('meta[name="venddor-tenant"]')?.content;
  const productId = document.querySelector('[data-product-id]')?.dataset.productId;

  if (!tenantId || !productId) return;

  // Fetch widget data
  fetch(`${WIDGET_API}/reviews?tenant=${tenantId}&product=${productId}`)
    .then(res => res.json())
    .then(data => {
      const container = document.createElement('div');
      container.id = 'venddor-reviews-widget';
      container.innerHTML = `
        <h3>Customer Reviews (${data.total})</h3>
        <div class="avg-rating">${'★'.repeat(Math.round(data.avg_rating))} ${data.avg_rating}/5</div>
        ${data.reviews.map(r => `
          <div class="review">
            <strong>${r.author}</strong> - ${'★'.repeat(r.rating)}
            <p>${r.body}</p>
          </div>
        `).join('')}
      `;

      // Insert after the product description
      const target = document.querySelector('.product-description');
      if (target) target.after(container);
    });
})();

Script Engine

O Script Engine do Venddor permite escrever scripts JavaScript que rodam dentro da plataforma. Scripts podem reagir a eventos e modificar comportamentos sem precisar de um servidor separado.

javascript
// Example script: Auto-apply discount for bulk orders
// This runs inside the Venddor Script Engine

venddor.on('checkout.validate', async (ctx) => {
  const cart = ctx.cart;

  // If total quantity > 10, apply 5% discount
  const totalQty = cart.items.reduce((sum, item) => sum + item.quantity, 0);

  if (totalQty > 10) {
    ctx.applyDiscount({
      type: 'percentage',
      value: 500, // 5.00% in basis points
      label: 'Bulk order discount (5%)',
    });
  }
});

venddor.on('order.created', async (ctx) => {
  const order = ctx.data;

  // Send notification to Slack
  await venddor.http.post('https://hooks.slack.com/services/...', {
    text: `New order #${order.id}: R$ ${(order.total_cents / 100).toFixed(2)}`,
  });
});
Scripts rodam em um ambiente sandboxed com acesso limitado. Eles podem fazer HTTP requests, acessar o contexto do evento e chamar APIs internas do Venddor.

Melhores Praticas

#PraticaDetalhes
1Nunca exponha secretsMantenha Client Secret no servidor. Nunca no frontend, git ou logs.
2Valide webhooksSempre verifique a assinatura HMAC antes de processar.
3Trate rate limitsImplemente exponential backoff para HTTP 429.
4Use HTTPSTodos os endpoints de callback e webhook devem usar HTTPS.
5Cache quando possivelCache respostas de API para reduzir chamadas e melhorar performance.
6Solicite escopos minimosSolicite apenas os escopos que seu app realmente precisa.