Símbolo da AmivuSímbolo da AmivuDevelopers

Clientes e SDKs

O cliente mínimo em Node, Python e PHP — e por que não publicamos um pacote.

A Amivu não publica pacote em npm, PyPI ou Packagist. O que existe aqui é o que um pacote faria — em vinte linhas que você cola no seu projeto e passa a manter.

Por que não há SDK

Um SDK oficial é um contrato a mais para manter: ele versiona junto com a API, atrasa quando a API anda, e trava quem usa numa versão do cliente enquanto o servidor já mudou. Para uma superfície REST com autenticação por cabeçalho e JSON dos dois lados, ele resolve pouco e custa caro.

Enquanto isso não muda, dizer que existe um SDK seria pior que não ter: quem procurasse o pacote não acharia, e a documentação teria mentido no primeiro contato. Preferimos entregar o pedaço de código que resolve o mesmo problema.

O que um cliente precisa fazer
Três coisas: mandar o cabeçalho de autorização, transformar erro em exceção com o code preservado, e gerar a chave de idempotência nas escritas. O resto é fetch.

O cliente, em vinte linhas

É o mesmo amivu(...) que os guias usam. Cole no seu projeto, e a partir daí toda chamada é uma linha.

const BASE = "https://api.amivu.com.br/v1";

export async function amivu(path, { method = "GET", body, idempotencyKey } = {}) {
  const headers = { Authorization: `Bearer ${process.env.AMIVU_API_KEY}` };

  if (body) {
    headers["Content-Type"] = "application/json";
    // Sem chave, um reenvio depois de timeout manda a mensagem duas vezes.
    headers["Idempotency-Key"] = idempotencyKey ?? crypto.randomUUID();
  }

  const response = await fetch(BASE + path, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  const payload = await response.json();
  if (!response.ok) throw new AmivuError(payload.error);
  return payload;
}

export class AmivuError extends Error {
  constructor(error) {
    super(error?.message ?? "Falha na chamada à Amivu.");
    this.type = error?.type;
    this.code = error?.code;
    this.requestId = error?.request_id;
  }
}

Tratar erro uma vez só

Com o cliente acima, o erro chega como exceção e carrega o type, o code e o request_id. Decida pelo type, registre o code — um switch exaustivo sobre code quebra no dia em que a API ganhar um caso novo.

try {
  await amivu("/messages", { method: "POST", body: mensagem });
} catch (erro) {
  if (erro.type === "rate_limit_error") return repetirDepois(erro);
  if (erro.type === "validation_error") return corrigirEDesistir(erro);

  // Guarde o request_id: é o que transforma "deu erro ontem" numa linha exata.
  registrar({ code: erro.code, requestId: erro.requestId });
  throw erro;
}

Gerar um cliente da especificação

Se o seu time prefere um cliente tipado, gere-o do openapi.json — ele é a mesma especificação que a API valida, e um cliente gerado dela nunca fica atrás da API por esquecimento.

npx openapi-typescript https://api.amivu.com.br/v1/openapi.json \
  -o src/amivu.d.ts

Veja também Erros e Idempotência.

Escrevemos sobre operação de atendimento, canais e IA no blog da Amivu.