> ## Documentation Index
> Fetch the complete documentation index at: https://docs.autorizou.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Integração com SDK

> Como usar o SDK do Autorizou para criptografar dados de cartão no frontend

## O que é o SDK?

O **SDK** do Autorizou é a biblioteca oficial para criptografia de dados de cartão de crédito no frontend. Ele garante que informações sensíveis nunca trafeguem em texto puro pela rede, atendendo aos requisitos de segurança PCI DSS.

## Principais Funcionalidades

### Criptografia de Cartões

* Criptografia AES-256-CBC no browser
* Suporte a todas as principais bandeiras
* Detecção automática de bandeira do cartão
* Validação de dados antes da criptografia

### 3D Secure 2.0

* Suporte completo ao protocolo 3DS2
* Interface de challenge integrada
* Callbacks configuráveis para sucesso/falha

### Google Pay

* Integração nativa com Google Pay
* Criação de botões personalizados
* Suporte a transações tokenizadas

## Instalação

### Via CDN

O domínio do script muda conforme o ambiente. Inclua-o na tag `<head>` ou antes do `</body>`:

| Ambiente | Script                                         |
| -------- | ---------------------------------------------- |
| Sandbox  | `https://sdk.autorizou.dev/embed/gateway.js`   |
| Produção | `https://sdk.autorizou.cloud/embed/gateway.js` |

<CodeGroup>
  ```html Sandbox theme={null}
  <script src="https://sdk.autorizou.dev/embed/gateway.js"></script>
  ```

  ```html Produção theme={null}
  <script src="https://sdk.autorizou.cloud/embed/gateway.js"></script>
  ```
</CodeGroup>

## Uso Básico

### 1. Incluir o Script

<CodeGroup>
  ```html Sandbox theme={null}
  <!DOCTYPE html>
  <html>
  <head>
    <title>Meu E-commerce</title>
    <script src="https://sdk.autorizou.dev/embed/gateway.js"></script>
  </head>
  <body>
    <!-- Seu conteúdo -->
  </body>
  </html>
  ```

  ```html Produção theme={null}
  <!DOCTYPE html>
  <html>
  <head>
    <title>Meu E-commerce</title>
    <script src="https://sdk.autorizou.cloud/embed/gateway.js"></script>
  </head>
  <body>
    <!-- Seu conteúdo -->
  </body>
  </html>
  ```
</CodeGroup>

### 2. Criptografar Dados do Cartão

```javascript theme={null}
// Preparar dados do cartão
const cardData = {
  number: '4111111111111111',
  holder: 'JOAO SILVA',
  expMonth: '12',
  expYear: '2030',
  securityCode: '123'
};

// Preparar dados do portador
const cardHolder = {
  name: 'João Silva',
  identification: {
    type: 'CPF',
    number: '12345678900'
  }
};

// Criptografar usando callbacks
await window.Autorizou.encryptCard(
  { cardData, cardHolder },
  {
    onSuccess: (response) => {
      console.log('Token criptografado:', response.token);
      // Enviar response.token para sua API
    },
    onError: (error) => {
      console.error('Erro na criptografia:', error.message);
    }
  }
);
```

### 3. Enviar para a API

```javascript theme={null}
const response = await fetch('https://zeus-sandbox.autorizou.dev/api/v1/cards', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    customer_id: 'cus_abc123',
    encrypted: result.token
  })
});

const card = await response.json();
console.log('Cartão salvo:', card);
```

## Integração React/Next.js

### Carregar SDK no Layout

<CodeGroup>
  ```jsx Sandbox theme={null}
  // app/layout.js ou pages/_app.js
  import Script from 'next/script';

  export default function RootLayout({ children }) {
    return (
      <html lang="pt-BR">
        <head>
          <Script
            src="https://sdk.autorizou.dev/embed/gateway.js"
            strategy="beforeInteractive"
          />
        </head>
        <body>{children}</body>
      </html>
    );
  }
  ```

  ```jsx Produção theme={null}
  // app/layout.js ou pages/_app.js
  import Script from 'next/script';

  export default function RootLayout({ children }) {
    return (
      <html lang="pt-BR">
        <head>
          <Script
            src="https://sdk.autorizou.cloud/embed/gateway.js"
            strategy="beforeInteractive"
          />
        </head>
        <body>{children}</body>
      </html>
    );
  }
  ```
</CodeGroup>

### Componente de Formulário

```jsx theme={null}
'use client';

import { useState } from 'react';

export default function CardForm({ customerId, onSuccess, onError }) {
  const [formData, setFormData] = useState({
    number: '',
    holder: '',
    expMonth: '',
    expYear: '',
    securityCode: ''
  });
  const [loading, setLoading] = useState(false);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);

    try {
      // 1. Verificar se o SDK está carregado
      if (!window.Autorizou?.encryptCard) {
        throw new Error('SDK não está carregado');
      }

      // 2. Criptografar dados usando callbacks
      await window.Autorizou.encryptCard(
        { cardData: formData },
        {
          onSuccess: async (encryptResult) => {
            try {
              // 3. Enviar para a API
              const response = await fetch('/api/cards', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                  customer_id: customerId,
                  encrypted: encryptResult.token
                })
              });

              if (!response.ok) {
                const error = await response.json();
                throw new Error(error.message || 'Erro ao salvar cartão');
              }

              const card = await response.json();
              onSuccess?.(card);

              // Limpar formulário
              setFormData({
                number: '',
                holder: '',
                expMonth: '',
                expYear: '',
                securityCode: ''
              });
            } catch (err) {
              console.error('Erro ao salvar:', err);
              onError?.(err);
            } finally {
              setLoading(false);
            }
          },
          onError: (error) => {
            console.error('Erro na criptografia:', error);
            onError?.(error);
            setLoading(false);
          }
        }
      );

    } catch (err) {
      console.error('Erro:', err);
      onError?.(err);
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div>
        <label htmlFor="number">Número do Cartão</label>
        <input
          id="number"
          name="number"
          type="text"
          value={formData.number}
          onChange={handleChange}
          placeholder="0000 0000 0000 0000"
          maxLength={19}
          required
        />
      </div>

      <div>
        <label htmlFor="holder">Nome no Cartão</label>
        <input
          id="holder"
          name="holder"
          type="text"
          value={formData.holder}
          onChange={handleChange}
          placeholder="NOME COMPLETO"
          style={{ textTransform: 'uppercase' }}
          required
        />
      </div>

      <div className="grid grid-cols-2 gap-4">
        <div>
          <label htmlFor="expMonth">Mês</label>
          <input
            id="expMonth"
            name="expMonth"
            type="text"
            value={formData.expMonth}
            onChange={handleChange}
            placeholder="MM"
            maxLength={2}
            required
          />
        </div>

        <div>
          <label htmlFor="expYear">Ano</label>
          <input
            id="expYear"
            name="expYear"
            type="text"
            value={formData.expYear}
            onChange={handleChange}
            placeholder="AAAA"
            maxLength={4}
            required
          />
        </div>
      </div>

      <div>
        <label htmlFor="securityCode">CVV</label>
        <input
          id="securityCode"
          name="securityCode"
          type="text"
          value={formData.securityCode}
          onChange={handleChange}
          placeholder="123"
          maxLength={4}
          required
        />
      </div>

      <button
        type="submit"
        disabled={loading}
        className="w-full bg-primary text-white py-2 rounded"
      >
        {loading ? 'Processando...' : 'Salvar Cartão'}
      </button>
    </form>
  );
}
```

### API Route (Next.js)

```javascript theme={null}
// app/api/cards/route.js
import { NextResponse } from 'next/server';

export async function POST(request) {
  try {
    const body = await request.json();
    const { customer_id, encrypted } = body;

    // Validar dados
    if (!customer_id || !encrypted) {
      return NextResponse.json(
        { message: 'customer_id e encrypted são obrigatórios' },
        { status: 400 }
      );
    }

    // Enviar para Zeus API
    const response = await fetch('https://zeus-sandbox.autorizou.dev/api/v1/cards', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.AUTORIZOU_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ customer_id, encrypted })
    });

    const data = await response.json();

    if (!response.ok) {
      return NextResponse.json(data, { status: response.status });
    }

    return NextResponse.json(data);

  } catch (error) {
    console.error('Erro na API de cartões:', error);
    return NextResponse.json(
      { message: 'Erro interno do servidor' },
      { status: 500 }
    );
  }
}
```

## Validações e Boas Práticas

### Validação de Número de Cartão

```javascript theme={null}
function validateCardNumber(number) {
  // Remover espaços e caracteres não numéricos
  const cleaned = number.replace(/\D/g, '');

  // Verificar tamanho (13-19 dígitos)
  if (cleaned.length < 13 || cleaned.length > 19) {
    return false;
  }

  // Algoritmo de Luhn
  let sum = 0;
  let isEven = false;

  for (let i = cleaned.length - 1; i >= 0; i--) {
    let digit = parseInt(cleaned.charAt(i), 10);

    if (isEven) {
      digit *= 2;
      if (digit > 9) {
        digit -= 9;
      }
    }

    sum += digit;
    isEven = !isEven;
  }

  return sum % 10 === 0;
}
```

### Validação de Data de Expiração

```javascript theme={null}
function validateExpiration(month, year) {
  const now = new Date();
  const currentYear = now.getFullYear();
  const currentMonth = now.getMonth() + 1;

  const expMonth = parseInt(month, 10);
  const expYear = parseInt(year, 10);

  // Validar mês
  if (expMonth < 1 || expMonth > 12) {
    return false;
  }

  // Validar ano (aceitar 2 ou 4 dígitos)
  const fullYear = expYear < 100 ? 2000 + expYear : expYear;

  // Verificar se não está expirado
  if (fullYear < currentYear) {
    return false;
  }

  if (fullYear === currentYear && expMonth < currentMonth) {
    return false;
  }

  return true;
}
```

### Detecção de Bandeira

```javascript theme={null}
function detectCardBrand(number) {
  const cleaned = number.replace(/\D/g, '');

  const patterns = {
    visa: /^4/,
    mastercard: /^(5[1-5]|2[2-7])/,
    amex: /^3[47]/,
    elo: /^(4011|4312|4389|4514|4576|5041|5066|5067|6277|6362|6363|6504|6505|6516)/,
    diners: /^(36|38|30[0-5])/,
    discover: /^6(?:011|5)/,
    jcb: /^35/,
    hipercard: /^606282/
  };

  for (const [brand, pattern] of Object.entries(patterns)) {
    if (pattern.test(cleaned)) {
      return brand;
    }
  }

  return 'unknown';
}
```

## Tratamento de Erros

### Erros Comuns

```javascript theme={null}
try {
  const result = await window.Autorizou.encryptCard({ cardData });

  if (result.errors) {
    // Erros de validação do SDK
    switch (result.errors.message[0]) {
      case 'Número de cartão inválido':
        alert('Por favor, verifique o número do cartão');
        break;
      case 'Data de expiração inválida':
        alert('Cartão expirado ou data inválida');
        break;
      case 'CVV inválido':
        alert('CVV deve ter 3 ou 4 dígitos');
        break;
      default:
        alert('Erro na validação do cartão');
    }
    return;
  }

  // Continuar com o envio...

} catch (error) {
  // Erro de rede ou exceção
  console.error('Erro:', error);
  alert('Erro ao processar cartão. Tente novamente.');
}
```

## Segurança

### Boas Práticas

1. **Nunca armazene dados de cartão no localStorage ou sessionStorage**
2. **Sempre use HTTPS** em produção
3. **Valide dados no frontend** antes de criptografar
4. **Implemente rate limiting** no backend
5. **Use CSP (Content Security Policy)** adequado

### Content Security Policy

```html theme={null}
<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' https://sdk.autorizou.cloud https://sdk.autorizou.dev;
  connect-src 'self' https://zeus.autorizou.cloud;
  style-src 'self' 'unsafe-inline';
">
```

## Fluxo Completo de Integração

### Passo a Passo

1. **Incluir o SDK** no projeto (via CDN)
2. **Coletar dados** do cartão no formulário
3. **Validar dados** localmente antes de enviar
4. **Criptografar** usando `window.Autorizou.encryptCard()`
5. **Enviar token** criptografado para sua API backend
6. **Backend encaminha** para Zeus API
7. **Processar resposta** e atualizar interface

### Diagrama de Fluxo

```
[Browser] → SDK → [Token Criptografado] → [Seu Backend] → Zeus API
                                                      ↓
                                              [Cartão Tokenizado]
```

## Troubleshooting

### SDK não está carregado

**Problema:** `window.Autorizou is undefined`

**Solução:**

```javascript theme={null}
// Verificar se o SDK está disponível
if (typeof window.Autorizou === 'undefined') {
  console.error('SDK não foi carregado. Verifique o script.');
  // Tentar recarregar ou mostrar mensagem ao usuário
}
```

### Erro de CORS

**Problema:** Erro de Cross-Origin ao chamar a API

**Solução:**

* Sempre envie o token criptografado do seu **backend** para o Zeus
* Nunca faça chamadas diretas do browser para `zeus.autorizou.cloud`

### Token inválido

**Problema:** Backend retorna "invalid\_encrypted\_card"

**Possíveis causas:**

* Script do SDK incorreto para o ambiente (sandbox vs produção)
* Dados do cartão em formato incorreto
* Token corrompido durante transmissão

**Solução:**

```javascript theme={null}
// Verificar se a criptografia foi bem-sucedida
await window.Autorizou.encryptCard(
  { cardData },
  {
    onSuccess: (response) => {
      console.log('Token válido:', response.token);
      // Verificar se token não está vazio
      if (!response.token) {
        console.error('Token vazio!');
      }
    },
    onError: (error) => {
      console.error('Erro na criptografia:', error);
    }
  }
);
```

## Perguntas Frequentes

<AccordionGroup>
  <Accordion title="Preciso configurar chaves de criptografia no frontend?">
    **Não.** Basta incluir o script do SDK no ambiente correto. A criptografia acontece no browser e a descriptografia apenas no backend seguro do Zeus.
  </Accordion>

  <Accordion title="O SDK funciona com frameworks modernos?">
    **Sim**, o SDK é compatível com:

    * React / Next.js
    * Vue / Nuxt.js
    * Angular
    * Svelte
    * Vanilla JavaScript

    Basta incluir o script via CDN e usar `window.Autorizou`.
  </Accordion>

  <Accordion title="Posso usar o SDK em múltiplos ambientes?">
    **Sim.** Use o script correspondente a cada ambiente:

    * Sandbox: `https://sdk.autorizou.dev/embed/gateway.js`
    * Produção: `https://sdk.autorizou.cloud/embed/gateway.js`
  </Accordion>

  <Accordion title="Preciso validar o cartão antes de criptografar?">
    **Recomendado mas não obrigatório**. Validar localmente melhora a UX:

    * Algoritmo de Luhn para número do cartão
    * Validação de data de expiração
    * Formato do CVV (3-4 dígitos)

    O SDK e o Zeus também fazem validações, mas feedback imediato é melhor.
  </Accordion>

  <Accordion title="O que acontece se o usuário desabilitar JavaScript?">
    Sem JavaScript, o SDK não funcionará. Considere:

    * Mostrar mensagem informativa
    * Oferecer método de pagamento alternativo
    * A maioria dos usuários tem JS habilitado
  </Accordion>
</AccordionGroup>

## Boas Práticas de Segurança

### ✅ Faça

* Use HTTPS em produção **sempre**
* Implemente rate limiting no backend
* Valide dados no frontend E backend
* Use CSP (Content Security Policy)
* Limpe o formulário após sucesso
* Implemente timeout nas requisições

### ❌ Não Faça

* Armazenar dados de cartão em localStorage/sessionStorage
* Enviar dados de cartão em texto puro
* Logar dados sensíveis no console em produção
* Reutilizar tokens criptografados
* Fazer chamadas diretas do browser para Zeus API

## Exemplos Avançados

### Formulário com Máscara

```javascript theme={null}
// Aplicar máscara no número do cartão
function formatCardNumber(value) {
  return value
    .replace(/\s/g, '')
    .replace(/(\d{4})/g, '$1 ')
    .trim();
}

<input
  type="text"
  value={cardNumber}
  onChange={(e) => {
    const formatted = formatCardNumber(e.target.value);
    setCardNumber(formatted);
  }}
  maxLength={19}
  placeholder="0000 0000 0000 0000"
/>
```

### Detecção Automática de Bandeira

```javascript theme={null}
function detectBrand(number) {
  const cleaned = number.replace(/\s/g, '');

  if (/^4/.test(cleaned)) return 'visa';
  if (/^5[1-5]/.test(cleaned)) return 'mastercard';
  if (/^3[47]/.test(cleaned)) return 'amex';
  if (/^6(?:011|5)/.test(cleaned)) return 'discover';
  if (/^3(?:0[0-5]|[68])/.test(cleaned)) return 'diners';
  if (/^35/.test(cleaned)) return 'jcb';
  if (/^(4011|4312|4389|4514|4576|5041|5066|5067|636368)/.test(cleaned)) return 'elo';
  if (/^606282/.test(cleaned)) return 'hipercard';

  return 'unknown';
}

// Uso
const [brand, setBrand] = useState('');

useEffect(() => {
  if (cardNumber.length >= 4) {
    setBrand(detectBrand(cardNumber));
  }
}, [cardNumber]);
```

### Loading States

```javascript theme={null}
const [loadingStates, setLoadingStates] = useState({
  encrypting: false,
  saving: false
});

const handleSubmit = async (e) => {
  e.preventDefault();

  setLoadingStates({ encrypting: true, saving: false });

  await window.Autorizou.encryptCard(
    { cardData },
    {
      onSuccess: async (encryptResult) => {
        setLoadingStates({ encrypting: false, saving: true });

        try {
          const response = await fetch('/api/cards', {
            method: 'POST',
            body: JSON.stringify({
              customer_id: customerId,
              encrypted: encryptResult.token
            })
          });

          if (!response.ok) throw new Error('Erro ao salvar');

          // Sucesso!
          setLoadingStates({ encrypting: false, saving: false });
        } catch (err) {
          setLoadingStates({ encrypting: false, saving: false });
          console.error(err);
        }
      },
      onError: () => {
        setLoadingStates({ encrypting: false, saving: false });
      }
    }
  );
};
```

## Suporte e Recursos

### Links Úteis

* [Criar Cartão - API Reference](/api-reference/cards/create-card)
* [Buscar Cartão - API Reference](/api-reference/cards/get-card)
* [Network Token - API Reference](/api-reference/cards/enroll-network-token)
* [Processar Pagamento - API Reference](/api-reference/charges/orders/create-order)

<Note>
  **Dúvidas?** Entre em contato com nosso time de suporte técnico. Estamos aqui para ajudar!
</Note>
