Skip to main content

🛠️ Guia Técnico de Integração

API Krayin CRM - Implementação Prática

Para Desenvolvedores e Integradores Nível: Intermediário a Avançado


🎯 CONFIGURAÇÃO INICIAL

Pré-requisitos

  • Conhecimento: REST APIs, JSON, HTTP
  • Ferramentas: cURL, Postman, ou client HTTP
  • Acesso: Credenciais do Krayin CRM
  • Conectividade: HTTPS obrigatório

Variáveis de Ambiente

# .env ou configuração do sistema
KRAYIN_API_BASE=https://crm.memudecore.com.br/api/v1
KRAYIN_API_TOKEN=seu_token_aqui
KRAYIN_LOGIN_EMAIL=admin@example.com
KRAYIN_LOGIN_PASSWORD=admin123

🔐 AUTENTICAÇÃO DETALHADA

Fluxo de Autenticação

  1. Login Inicial
curl -X POST "${KRAYIN_API_BASE}/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -d "email=${KRAYIN_LOGIN_EMAIL}&password=${KRAYIN_LOGIN_PASSWORD}&device_name=MeuSistema"
  1. Armazenar Token
// JavaScript exemplo
class KrayinAPI {
  constructor() {
    this.baseURL = process.env.KRAYIN_API_BASE;
    this.token = null;
  }

  async login(email, password, deviceName = 'DefaultApp') {
    const response = await fetch(`${this.baseURL}/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json'
      },
      body: new URLSearchParams({
        email,
        password,
        device_name: deviceName
      })
    });

    const data = await response.json();

    if (response.ok) {
      this.token = data.token;
      localStorage.setItem('krayin_token', this.token);
      return data;
    }

    throw new Error(data.message || 'Login failed');
  }

  getHeaders() {
    return {
      'Authorization': `Bearer ${this.token}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };
  }
}
  1. Renovação de Token
<?php
// PHP - Classe para gerenciar tokens
class KrayinAuth {
    private $token;
    private $expires_at;

    public function __construct($token = null) {
        $this->token = $token;
        $this->expires_at = $this->getTokenExpiration($token);
    }

    public function isTokenValid() {
        return $this->token && $this->expires_at > time();
    }

    public function refreshTokenIfNeeded() {
        if (!$this->isTokenValid()) {
            return $this->login();
        }
        return true;
    }

    private function login() {
        // Implementar renovação
        $data = [
            'email' => env('KRAYIN_LOGIN_EMAIL'),
            'password' => env('KRAYIN_LOGIN_PASSWORD'),
            'device_name' => 'PHPApp'
        ];

        $response = $this->makeRequest('POST', '/login', $data, false);

        if (isset($response['token'])) {
            $this->token = $response['token'];
            return true;
        }

        return false;
    }
}
?>

📊 ESTRUTURAS DE DADOS

Lead Object

{
  "id": 1,
  "title": "Lead da Empresa XYZ",
  "description": "Interesse em produto premium",
  "lead_value": 15000.00,
  "status": 1,
  "lost_reason": null,
  "closed_at": null,
  "user_id": 1,
  "lead_source_id": 1,
  "lead_type_id": 1,
  "lead_pipeline_id": 1,
  "lead_pipeline_stage_id": 1,
  "person": {
    "id": 1,
    "name": "João Silva",
    "emails": [
      {
        "id": 1,
        "value": "joao@empresaxyz.com",
        "label": "work"
      }
    ],
    "contact_numbers": [
      {
        "id": 1,
        "value": "+5511999999999",
        "label": "mobile"
      }
    ],
    "organization": {
      "id": 1,
      "name": "Empresa XYZ Ltda"
    }
  },
  "products": [],
  "created_at": "2026-01-18T10:30:00.000000Z",
  "updated_at": "2026-01-18T10:30:00.000000Z"
}

Activity Object

{
  "id": 1,
  "title": "Reunião de apresentação",
  "type": "meeting",
  "comment": "Apresentar proposta comercial",
  "schedule_from": "2026-01-20T14:00:00.000000Z",
  "schedule_to": "2026-01-20T15:00:00.000000Z",
  "is_done": false,
  "lead_id": 1,
  "user_id": 1,
  "participants": [],
  "files": [],
  "created_at": "2026-01-18T10:30:00.000000Z"
}

Person Object

{
  "id": 1,
  "name": "Maria Santos",
  "emails": [
    {"value": "maria@empresa.com", "label": "work"},
    {"value": "maria.pessoal@gmail.com", "label": "home"}
  ],
  "contact_numbers": [
    {"value": "+5511888888888", "label": "work"},
    {"value": "+5511999999999", "label": "mobile"}
  ],
  "organization_id": 2,
  "organization": {
    "id": 2,
    "name": "Tech Solutions Ltda",
    "address": "Rua das Empresas, 123"
  },
  "job_title": "Gerente de TI",
  "created_at": "2026-01-15T09:00:00.000000Z"
}

🔄 OPERAÇÕES CRUD AVANÇADAS

Leads - Operações Completas

1. Criar Lead Completo

# Python - Criar lead com relacionamentos
import requests

class KrayinLeads:
    def __init__(self, api_token):
        self.base_url = "https://crm.memudecore.com.br/api/v1"
        self.headers = {
            'Authorization': f'Bearer {api_token}',
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }

    def criar_lead_completo(self, lead_data):
        """Criar lead com pessoa e organização"""
        endpoint = f"{self.base_url}/leads"

        payload = {
            "title": lead_data['titulo'],
            "description": lead_data.get('descricao', ''),
            "lead_value": lead_data.get('valor', 0),
            "lead_source_id": lead_data.get('fonte_id', 1),
            "lead_type_id": lead_data.get('tipo_id', 1),
            "person": {
                "name": lead_data['pessoa']['nome'],
                "job_title": lead_data['pessoa'].get('cargo'),
                "emails": [
                    {"value": email, "label": "work"}
                    for email in lead_data['pessoa']['emails']
                ],
                "contact_numbers": [
                    {"value": telefone, "label": "mobile"}
                    for telefone in lead_data['pessoa']['telefones']
                ]
            }
        }

        # Adicionar organização se fornecida
        if 'organizacao' in lead_data:
            payload['person']['organization'] = {
                "name": lead_data['organizacao']['nome'],
                "address": lead_data['organizacao'].get('endereco', '')
            }

        response = requests.post(endpoint, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def atualizar_lead(self, lead_id, updates):
        """Atualizar apenas campos específicos"""
        endpoint = f"{self.base_url}/leads/{lead_id}"
        response = requests.put(endpoint, json=updates, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def buscar_leads_com_filtros(self, **filtros):
        """Buscar leads com filtros avançados"""
        params = {}

        if 'data_inicio' in filtros:
            params['created_at_from'] = filtros['data_inicio']
        if 'data_fim' in filtros:
            params['created_at_to'] = filtros['data_fim']
        if 'valor_min' in filtros:
            params['lead_value_from'] = filtros['valor_min']
        if 'valor_max' in filtros:
            params['lead_value_to'] = filtros['valor_max']
        if 'status' in filtros:
            params['status'] = filtros['status']

        endpoint = f"{self.base_url}/leads"
        response = requests.get(endpoint, params=params, headers=self.headers)
        response.raise_for_status()
        return response.json()

2. Atividades - Gestão Completa

// JavaScript - Gerenciar atividades
class KrayinActivities {
  constructor(apiToken) {
    this.baseURL = 'https://crm.memudecore.com.br/api/v1';
    this.headers = {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };
  }

  async criarAtividade(dadosAtividade) {
    const payload = {
      title: dadosAtividade.titulo,
      type: dadosAtividade.tipo, // 'call', 'meeting', 'lunch', 'task'
      comment: dadosAtividade.comentario || '',
      schedule_from: dadosAtividade.dataInicio, // ISO 8601
      schedule_to: dadosAtividade.dataFim,
      lead_id: dadosAtividade.leadId,
      user_id: dadosAtividade.userId || 1,
      participants: dadosAtividade.participantes || []
    };

    const response = await fetch(`${this.baseURL}/activities`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(payload)
    });

    if (!response.ok) {
      throw new Error(`Erro ${response.status}: ${await response.text()}`);
    }

    return response.json();
  }

  async obterAtividadesPorLead(leadId) {
    const response = await fetch(
      `${this.baseURL}/activities?lead_id=${leadId}`,
      { headers: this.headers }
    );

    if (!response.ok) {
      throw new Error(`Erro ${response.status}: ${await response.text()}`);
    }

    return response.json();
  }

  async marcarAtividadeComoConcluida(atividadeId) {
    const payload = {
      is_done: true,
      completed_at: new Date().toISOString()
    };

    const response = await fetch(`${this.baseURL}/activities/${atividadeId}`, {
      method: 'PUT',
      headers: this.headers,
      body: JSON.stringify(payload)
    });

    return response.json();
  }

  async agendarSequenciaAtividades(leadId, sequencia) {
    const atividades = [];

    for (const [index, atividade] of sequencia.entries()) {
      const dataInicio = new Date();
      dataInicio.setDate(dataInicio.getDate() + (index * 7)); // 1 semana entre cada

      const dataFim = new Date(dataInicio);
      dataFim.setHours(dataInicio.getHours() + 1); // 1 hora de duração

      const novaAtividade = await this.criarAtividade({
        titulo: atividade.titulo,
        tipo: atividade.tipo,
        comentario: atividade.comentario,
        dataInicio: dataInicio.toISOString(),
        dataFim: dataFim.toISOString(),
        leadId: leadId
      });

      atividades.push(novaAtividade);
    }

    return atividades;
  }
}

// Exemplo de uso
const activities = new KrayinActivities('seu_token');

// Agendar sequência de follow-up
await activities.agendarSequenciaAtividades(123, [
  {
    titulo: 'Primeiro contato',
    tipo: 'call',
    comentario: 'Apresentação inicial da empresa'
  },
  {
    titulo: 'Envio de proposta',
    tipo: 'task',
    comentario: 'Elaborar e enviar proposta comercial'
  },
  {
    titulo: 'Reunião de negociação',
    tipo: 'meeting',
    comentario: 'Discussão dos termos da proposta'
  }
]);

🔄 SINCRONIZAÇÃO E WEBHOOKS

Implementar Sincronização Bidirecional

<?php
// PHP - Sincronização com sistema externo
class SincronizacaoKrayin {
    private $api;
    private $ultimaSync;

    public function __construct($token) {
        $this->api = new KrayinAPI($token);
        $this->ultimaSync = $this->obterUltimaSync();
    }

    public function sincronizarNovosLeads() {
        // Obter leads criados desde última sync
        $leads = $this->api->get("/leads", [
            'created_at_from' => $this->ultimaSync,
            'limit' => 100
        ]);

        foreach ($leads['data'] as $lead) {
            $this->processarNovoLead($lead);
        }

        $this->atualizarUltimaSync();
    }

    private function processarNovoLead($lead) {
        // Verificar se lead já existe no sistema local
        if (!$this->leadExisteLocalmente($lead['id'])) {
            // Criar no sistema local
            $this->criarLeadLocal($lead);

            // Log da sincronização
            error_log("Lead {$lead['id']} sincronizado: {$lead['title']}");
        }
    }

    public function sincronizarLeadModificado($leadId, $dadosModificados) {
        try {
            // Atualizar no Krayin
            $leadAtualizado = $this->api->put("/leads/{$leadId}", $dadosModificados);

            // Atualizar sistema local
            $this->atualizarLeadLocal($leadId, $dadosModificados);

            return $leadAtualizado;
        } catch (Exception $e) {
            // Tratar conflitos de sincronização
            $this->resolverConflito($leadId, $dadosModificados, $e);
            throw $e;
        }
    }

    private function resolverConflito($leadId, $dadosLocais, $erro) {
        // Estratégias de resolução:
        // 1. Last-write-wins
        // 2. Merge automático
        // 3. Flag para revisão manual

        if (strpos($erro->getMessage(), '409') !== false) {
            // Conflito detectado - obter versão atual
            $leadAtual = $this->api->get("/leads/{$leadId}");

            // Implementar merge ou notificar conflito
            $this->notificarConflito($leadId, $dadosLocais, $leadAtual);
        }
    }
}
?>

Webhooks para Tempo Real

// Node.js - Servidor webhook
const express = require('express');
const app = express();

app.use(express.json());

// Endpoint para receber webhooks do Krayin
app.post('/webhook/krayin-leads', async (req, res) => {
  try {
    const { event, data } = req.body;

    switch (event) {
      case 'lead.created':
        await processarNovoLead(data);
        break;

      case 'lead.updated':
        await processarLeadAtualizado(data);
        break;

      case 'lead.deleted':
        await processarLeadRemovido(data);
        break;

      case 'activity.created':
        await processarNovaAtividade(data);
        break;

      default:
        console.log(`Evento desconhecido: ${event}`);
    }

    res.status(200).json({ status: 'processed' });
  } catch (error) {
    console.error('Erro processando webhook:', error);
    res.status(500).json({ error: 'Processing failed' });
  }
});

async function processarNovoLead(lead) {
  // Enviar notificação
  await enviarNotificacaoSlack({
    text: `🎯 Novo lead: ${lead.title}`,
    details: `Valor: R$ ${lead.lead_value}\nContato: ${lead.person.name}`
  });

  // Criar atividade automática
  await criarAtividadeFollowUp(lead.id);

  // Atualizar dashboard
  await atualizarDashboard();
}

async function criarAtividadeFollowUp(leadId) {
  const atividade = {
    title: 'Follow-up inicial',
    type: 'call',
    comment: 'Entrar em contato em até 24h',
    schedule_from: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
    schedule_to: new Date(Date.now() + 25 * 60 * 60 * 1000).toISOString(),
    lead_id: leadId,
    user_id: 1
  };

  return await krayin.post('/activities', atividade);
}

app.listen(3000, () => {
  console.log('Servidor webhook rodando na porta 3000');
});

⚡ OTIMIZAÇÕES E PERFORMANCE

Batch Operations

# Python - Operações em lote
class KrayinBatchOps:
    def __init__(self, api_token):
        self.api = KrayinAPI(api_token)
        self.batch_size = 50

    def importar_leads_em_lote(self, arquivo_csv):
        """Importar leads de arquivo CSV em lotes"""
        import pandas as pd

        df = pd.read_csv(arquivo_csv)
        leads_criados = []
        erros = []

        # Processar em lotes
        for i in range(0, len(df), self.batch_size):
            lote = df.iloc[i:i+self.batch_size]

            for _, row in lote.iterrows():
                try:
                    lead = self.criar_lead_from_csv_row(row)
                    leads_criados.append(lead)

                    # Rate limiting - pausa entre requests
                    time.sleep(0.1)

                except Exception as e:
                    erros.append({
                        'linha': i + row.name,
                        'dados': row.to_dict(),
                        'erro': str(e)
                    })

            # Pausa entre lotes
            time.sleep(1)

        return {
            'criados': len(leads_criados),
            'erros': erros,
            'leads': leads_criados
        }

    def criar_lead_from_csv_row(self, row):
        """Converter linha CSV em lead"""
        lead_data = {
            'title': row['empresa'] + ' - ' + row['contato'],
            'description': row.get('observacoes', ''),
            'lead_value': float(row.get('valor_estimado', 0)),
            'person': {
                'name': row['contato'],
                'emails': [
                    {'value': row['email'], 'label': 'work'}
                ] if pd.notna(row['email']) else [],
                'contact_numbers': [
                    {'value': row['telefone'], 'label': 'mobile'}
                ] if pd.notna(row['telefone']) else []
            }
        }

        if pd.notna(row.get('empresa')):
            lead_data['person']['organization'] = {
                'name': row['empresa']
            }

        return self.api.post('/leads', lead_data)

Caching Estratégico

// Node.js - Cache com Redis
const redis = require('redis');
const client = redis.createClient();

class KrayinCache {
  constructor(api) {
    this.api = api;
    this.cacheTTL = {
      leads: 300,      // 5 minutos
      activities: 180, // 3 minutos
      config: 3600     // 1 hora
    };
  }

  async getLeadsCached(filters = {}) {
    const cacheKey = `leads:${JSON.stringify(filters)}`;

    // Tentar cache primeiro
    const cached = await client.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    // Buscar da API
    const leads = await this.api.getLeads(filters);

    // Armazenar no cache
    await client.setex(cacheKey, this.cacheTTL.leads, JSON.stringify(leads));

    return leads;
  }

  async invalidateLeadCache(leadId = null) {
    if (leadId) {
      // Invalidar cache específico do lead
      await client.del(`lead:${leadId}`);
    }

    // Invalidar cache de listagens
    const keys = await client.keys('leads:*');
    if (keys.length > 0) {
      await client.del(keys);
    }
  }

  async preaquecerCache() {
    // Pré-carregar dados frequentemente acessados
    await Promise.all([
      this.getLeadsCached({ status: 'active' }),
      this.getLeadsCached({ created_today: true }),
      this.api.getConfig() // Configurações raramente mudam
    ]);
  }
}

🚨 TRATAMENTO DE ERROS

Error Handling Robusto

// TypeScript - Tratamento completo de erros
interface KrayinError {
  status: number;
  message: string;
  errors?: Record<string, string[]>;
  retryable?: boolean;
}

class KrayinAPIClient {
  private maxRetries = 3;
  private retryDelay = 1000; // 1 segundo

  async makeRequest<T>(
    method: string,
    endpoint: string,
    data?: any,
    retryCount = 0
  ): Promise<T> {
    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, {
        method,
        headers: this.getHeaders(),
        body: data ? JSON.stringify(data) : undefined
      });

      if (!response.ok) {
        throw await this.handleAPIError(response);
      }

      return await response.json();

    } catch (error) {
      if (this.shouldRetry(error, retryCount)) {
        await this.delay(this.retryDelay * Math.pow(2, retryCount));
        return this.makeRequest(method, endpoint, data, retryCount + 1);
      }

      throw this.enhanceError(error, endpoint);
    }
  }

  private async handleAPIError(response: Response): Promise<KrayinError> {
    const errorData = await response.json().catch(() => ({}));

    return {
      status: response.status,
      message: errorData.message || `HTTP ${response.status}`,
      errors: errorData.errors,
      retryable: this.isRetryableStatus(response.status)
    };
  }

  private shouldRetry(error: any, retryCount: number): boolean {
    if (retryCount >= this.maxRetries) return false;

    // Retry em erros temporários
    if (error.status >= 500) return true;
    if (error.status === 429) return true; // Rate limit
    if (error.code === 'NETWORK_ERROR') return true;

    return false;
  }

  private isRetryableStatus(status: number): boolean {
    return [429, 500, 502, 503, 504].includes(status);
  }

  private enhanceError(error: any, endpoint: string): KrayinError {
    return {
      ...error,
      endpoint,
      timestamp: new Date().toISOString(),
      context: `Erro na requisição para ${endpoint}`
    };
  }

  private async delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// Uso com tratamento específico por tipo de erro
async function exemploUsoComTratamento() {
  const api = new KrayinAPIClient();

  try {
    const lead = await api.makeRequest('POST', '/leads', leadData);
    console.log('Lead criado:', lead);

  } catch (error: KrayinError) {
    switch (error.status) {
      case 422:
        // Erro de validação
        console.error('Dados inválidos:', error.errors);
        // Mostrar erros específicos ao usuário
        break;

      case 401:
        // Token expirado
        console.error('Token inválido, renovando...');
        await api.refreshToken();
        // Retry automático
        break;

      case 429:
        // Rate limit
        console.error('Rate limit atingido, aguardando...');
        // Implementar backoff
        break;

      case 500:
        // Erro do servidor
        console.error('Erro do servidor, tentando novamente...');
        // Log para monitoramento
        break;

      default:
        console.error('Erro desconhecido:', error);
    }
  }
}

📊 MONITORAMENTO E MÉTRICAS

Implementar Logging Estruturado

# Python - Logging e métricas
import logging
import time
from dataclasses import dataclass
from typing import Optional

@dataclass
class APIMetrics:
    endpoint: str
    method: str
    status_code: int
    response_time: float
    payload_size: Optional[int] = None
    error_type: Optional[str] = None

class KrayinMonitoring:
    def __init__(self, api_client):
        self.api = api_client
        self.metrics = []
        self.setup_logging()

    def setup_logging(self):
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('krayin_api.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger('krayin_api')

    def track_request(self, method: str, endpoint: str, payload=None):
        """Decorator para trackear requests"""
        def decorator(func):
            def wrapper(*args, **kwargs):
                start_time = time.time()

                try:
                    result = func(*args, **kwargs)

                    # Log sucesso
                    response_time = time.time() - start_time

                    metrics = APIMetrics(
                        endpoint=endpoint,
                        method=method,
                        status_code=200,
                        response_time=response_time,
                        payload_size=len(str(payload)) if payload else 0
                    )

                    self.record_metrics(metrics)

                    self.logger.info(f"✅ {method} {endpoint} - {response_time:.2f}s")

                    return result

                except Exception as e:
                    # Log erro
                    response_time = time.time() - start_time

                    metrics = APIMetrics(
                        endpoint=endpoint,
                        method=method,
                        status_code=getattr(e, 'status', 500),
                        response_time=response_time,
                        error_type=type(e).__name__
                    )

                    self.record_metrics(metrics)

                    self.logger.error(f"❌ {method} {endpoint} - {str(e)}")
                    raise

            return wrapper
        return decorator

    def record_metrics(self, metrics: APIMetrics):
        """Armazenar métricas para análise"""
        self.metrics.append(metrics)

        # Enviar para sistema de monitoramento (ex: Prometheus)
        if hasattr(self, 'prometheus_client'):
            self.prometheus_client.record(metrics)

    def get_performance_report(self, hours: int = 24):
        """Gerar relatório de performance"""
        cutoff = time.time() - (hours * 3600)
        recent_metrics = [m for m in self.metrics if m.timestamp > cutoff]

        if not recent_metrics:
            return "Nenhuma métrica disponível"

        total_requests = len(recent_metrics)
        avg_response_time = sum(m.response_time for m in recent_metrics) / total_requests
        error_rate = len([m for m in recent_metrics if m.status_code >= 400]) / total_requests

        slowest_endpoints = sorted(
            recent_metrics,
            key=lambda m: m.response_time,
            reverse=True
        )[:5]

        return {
            'period_hours': hours,
            'total_requests': total_requests,
            'average_response_time': f"{avg_response_time:.2f}s",
            'error_rate': f"{error_rate:.2%}",
            'slowest_endpoints': [
                f"{m.method} {m.endpoint} - {m.response_time:.2f}s"
                for m in slowest_endpoints
            ]
        }

    def setup_alerts(self):
        """Configurar alertas automáticos"""

        def check_error_rate():
            recent_errors = [
                m for m in self.metrics[-100:]
                if m.status_code >= 400
            ]

            if len(recent_errors) > 20:  # >20% error rate
                self.send_alert("High error rate detected!")

        def check_response_time():
            recent_times = [m.response_time for m in self.metrics[-50:]]
            avg_time = sum(recent_times) / len(recent_times)

            if avg_time > 2.0:  # >2s average
                self.send_alert(f"Slow API responses: {avg_time:.2f}s avg")

        # Executar checks periodicamente
        import threading
        import time

        def monitor_loop():
            while True:
                check_error_rate()
                check_response_time()
                time.sleep(300)  # Check a cada 5 minutos

        monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
        monitor_thread.start()

    def send_alert(self, message: str):
        """Enviar alerta via Slack/email/etc"""
        self.logger.warning(f"🚨 ALERT: {message}")

        # Implementar notificação real
        # slack_webhook_send(message)
        # send_email_alert(message)

🔒 SEGURANÇA AVANÇADA

Implementar Segurança Robusta

<?php
// PHP - Classe de segurança
class KrayinSecurity {
    private $encryptionKey;
    private $allowedOrigins;

    public function __construct() {
        $this->encryptionKey = env('KRAYIN_ENCRYPTION_KEY');
        $this->allowedOrigins = explode(',', env('ALLOWED_ORIGINS', ''));
    }

    public function encryptToken($token) {
        $iv = random_bytes(16);
        $encrypted = openssl_encrypt($token, 'AES-256-CBC', $this->encryptionKey, 0, $iv);
        return base64_encode($iv . $encrypted);
    }

    public function decryptToken($encryptedToken) {
        $data = base64_decode($encryptedToken);
        $iv = substr($data, 0, 16);
        $encrypted = substr($data, 16);
        return openssl_decrypt($encrypted, 'AES-256-CBC', $this->encryptionKey, 0, $iv);
    }

    public function validateOrigin($origin) {
        return in_array($origin, $this->allowedOrigins);
    }

    public function sanitizeInput($data) {
        if (is_array($data)) {
            return array_map([$this, 'sanitizeInput'], $data);
        }

        // Remove tags HTML e caracteres especiais
        return htmlspecialchars(strip_tags(trim($data)), ENT_QUOTES, 'UTF-8');
    }

    public function validateRequestSignature($payload, $signature, $secret) {
        $expectedSignature = hash_hmac('sha256', $payload, $secret);
        return hash_equals($signature, $expectedSignature);
    }

    public function implementRateLimit($identifier, $maxRequests = 60, $window = 3600) {
        $cacheKey = "rate_limit:{$identifier}";
        $current = $this->cache->get($cacheKey, 0);

        if ($current >= $maxRequests) {
            throw new Exception('Rate limit exceeded', 429);
        }

        $this->cache->put($cacheKey, $current + 1, $window);
        return true;
    }
}

// Implementar middleware de segurança
class SecurityMiddleware {
    public function handle($request, $next) {
        $security = new KrayinSecurity();

        // Validar origem
        if (!$security->validateOrigin($request->header('Origin'))) {
            return response()->json(['error' => 'Origin not allowed'], 403);
        }

        // Rate limiting por IP
        $security->implementRateLimit($request->ip());

        // Sanitizar entrada
        $request->merge($security->sanitizeInput($request->all()));

        return $next($request);
    }
}
?>

📈 CONCLUSÃO

Este guia técnico fornece uma base sólida para integração robusta com a API Krayin CRM. Implementando essas práticas, você terá:

  • Autenticação segura e renovação automática
  • Tratamento robusto de erros com retry automático
  • Operações batch para high-volume
  • Caching estratégico para performance
  • Monitoramento completo com métricas
  • Sincronização bidirecional confiável
  • Segurança enterprise-grade

Próximos Passos Recomendados

  1. Implementar testes automatizados para todas as integrações
  2. Configurar monitoramento em ambiente produção
  3. Documentar APIs específicas do seu domínio
  4. Implementar backup/disaster recovery para dados críticos
  5. Planejar estratégia de versionamento para futuras atualizações

Guia técnico atualizado - Janeiro 2026 API Krayin CRM v2.1.1