# SDKs oficiais

> SDKs oficiais do Couryo para Node.js, PHP (com Laravel) e Python (com Django), com Idempotency-Key automático, novas tentativas, erros tipados e verificação de webhook.

Fonte: https://couryo.com/docs/sdks

Os três SDKs oficiais fazem a mesma coisa do mesmo jeito. Qualquer um deles poupa o trabalho repetitivo de falar com a [API REST](https://couryo.com/docs/sending.md):

- **`Idempotency-Key` automático** em todo POST, repetido nas novas tentativas: um envio que deu tempo esgotado mas passou nunca sai duplicado.
- **Novas tentativas com espera crescente** para erro de rede, `5xx` e `rate_limited`, respeitando o `Retry-After`. Erros que falhariam de novo (`domain_not_verified`, `daily_limit_reached`...) voltam na hora.
- **Erros tipados com o `code` estável** da API, a `message` no idioma escolhido (`pt-BR` por padrão) e o `request_id` para o suporte.
- **Verificação de webhook** (Standard Webhooks, segredo `whsec_`) numa chamada.
- E-mails, lote, templates, domínios, contatos, eventos, campanhas, supressões e webhooks.

| Linguagem | Pacote | Instalar | Integração pronta |
|---|---|---|---|
| Node.js 20.3+ | `@couryo/node` | `npm install @couryo/node` | Next.js e Express ([guia](https://couryo.com/docs/nextjs.md)) |
| PHP 8.1+ | `couryo/couryo-php` | `composer require couryo/couryo-php` | transporte de e-mail do Laravel ([guia](https://couryo.com/docs/laravel.md)) |
| Python 3.9+ | `couryo` | `pip install couryo` | backend de e-mail do Django ([guia](https://couryo.com/docs/django.md)) |

Não usa nenhuma dessas linguagens? A API é REST com JSON: qualquer cliente HTTP funciona, e o [SMTP](https://couryo.com/docs/smtp.md) serve para qualquer ferramenta que já envia e-mail.

## Enviar um e-mail

Todos leem a chave da variável `COURYO_API_KEY` quando você não passa nenhuma. Use uma chave `ck_test_` enquanto testa: nada é entregue e o e-mail aparece no painel ([modo de teste](https://couryo.com/docs/test-mode.md)).

```ts title="Node.js"
import { Couryo } from "@couryo/node";

const couryo = new Couryo(); // lê COURYO_API_KEY

const { id } = await couryo.emails.send({
  from: "Loja Exemplo <pedidos@exemplo.com.br>",
  to: "ana@exemplo.com.br",
  subject: "Pedido 1042 confirmado",
  html: "<p>Obrigado pela compra!</p>",
  text: "Obrigado pela compra!",
});
```

```php title="PHP"
<?php
require 'vendor/autoload.php';

$couryo = new Couryo\Couryo(getenv('COURYO_API_KEY'));

$email = $couryo->emails->send([
    'from' => 'Loja Exemplo <pedidos@exemplo.com.br>',
    'to' => 'ana@exemplo.com.br',
    'subject' => 'Pedido 1042 confirmado',
    'html' => '<p>Obrigado pela compra!</p>',
    'text' => 'Obrigado pela compra!',
]);
echo $email['id']; // msg_...
```

```python title="Python"
from couryo import Couryo

couryo = Couryo()  # lê COURYO_API_KEY

email = couryo.emails.send({
    "from": "Loja Exemplo <pedidos@exemplo.com.br>",
    "to": "ana@exemplo.com.br",
    "subject": "Pedido 1042 confirmado",
    "html": "<p>Obrigado pela compra!</p>",
    "text": "Obrigado pela compra!",
})
print(email["id"])  # msg_...
```

## Sua própria chave de idempotência

Quando o mesmo evento do seu sistema pode disparar duas vezes (um webhook de pagamento repetido, um job que roda de novo), passe uma chave que identifica o evento. A segunda chamada recebe a mesma resposta, sem enviar de novo.

```ts title="Node.js"
await couryo.emails.send(corpo, { idempotencyKey: "pedido-1042-confirmacao" });
```

```php title="PHP"
$couryo->emails->send($corpo, ['idempotency_key' => 'pedido-1042-confirmacao']);
```

```python title="Python"
couryo.emails.send(corpo, idempotency_key="pedido-1042-confirmacao")
```

## Tratar erros

```ts title="Node.js"
import { CouryoError } from "@couryo/node";

try {
  await couryo.emails.send(corpo);
} catch (e) {
  if (e instanceof CouryoError && e.code === "domain_not_verified") {
    // e.status, e.message (em português), e.param, e.requestId
  }
}
```

```php title="PHP"
use Couryo\Exception\CouryoException;

try {
    $couryo->emails->send($corpo);
} catch (CouryoException $e) {
    if ($e->getErrorCode() === 'domain_not_verified') {
        // $e->getStatus(), $e->getMessage(), $e->getParam(), $e->getRequestId()
    }
}
```

```python title="Python"
from couryo import CouryoError

try:
    couryo.emails.send(corpo)
except CouryoError as e:
    if e.code == "domain_not_verified":
        ...  # e.status, e.message, e.param, e.request_id
```

A lista de códigos, com causa e correção, está em [Erros](https://couryo.com/docs/errors.md).

## Verificar um webhook

Passe o corpo **cru**, exatamente como chegou. O SDK confere a assinatura e o horário (até 5 minutos) e devolve o evento.

```ts title="Node.js"
import { verifyWebhook } from "@couryo/node";

const evento = verifyWebhook({ secret: process.env.COURYO_WEBHOOK_SECRET!, headers: req.headers, body: corpoCru });
```

```php title="PHP"
$evento = Couryo\Webhook::verify(getenv('COURYO_WEBHOOK_SECRET'), getallheaders(), file_get_contents('php://input'));
```

```python title="Python"
from couryo import verify_webhook

evento = verify_webhook(os.environ["COURYO_WEBHOOK_SECRET"], request.headers, corpo_cru)
```

Detalhes do formato em [Webhooks](https://couryo.com/docs/webhooks.md).

## Contatos, eventos e campanhas

```ts title="Node.js"
await couryo.contacts.create({ email: "ana@exemplo.com.br", attributes: { nome: "Ana", plano: "pro" }, tags: ["cliente"] });
await couryo.events.track({ contact: { email: "ana@exemplo.com.br" }, name: "user.signed_up" });

const campanha = await couryo.campaigns.create({ name: "Novidades de outubro", audience: { type: "all" }, template_id: "novidades" });
await couryo.campaigns.preflight(campanha.id); // contagem real e revisão antes de disparar
```

Os eventos iniciam as [sequências](https://couryo.com/docs/sequences.md) com esse gatilho; as [campanhas](https://couryo.com/docs/campaigns.md) passam por uma checagem antes do disparo. Os mesmos métodos existem no PHP e no Python, com os nomes no estilo de cada linguagem.

## Código aberto

Os SDKs têm licença MIT. Os modelos de e-mail brasileiros (Pix, boleto, recuperação de senha e outros) também saem como um pacote React Email independente, que funciona com qualquer provedor.
