A API retorna erros no formato RFC 7807 Problem Details. Todos os SDKs mapeiam os erros para exceções tipadas, facilitando o tratamento específico por tipo de erro.
Toda resposta de erro da API segue este formato:
{
"type": "https://api.signdocs.com.br/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Transaction tx-abc-123 not found",
"instance": "/v1/transactions/tx-abc-123"
}
| Campo | Descrição |
|---|---|
type |
URI que identifica o tipo de erro |
title |
Resumo legível do erro |
status |
Código HTTP |
detail |
Explicação específica desta ocorrência |
instance |
URI da requisição que causou o erro |
| Status | Exceção | Descrição |
|---|---|---|
| 400 | BadRequestError |
Requisição malformada ou parâmetros inválidos |
| 401 | UnauthorizedError |
Token ausente, expirado ou inválido |
| 403 | ForbiddenError |
Sem permissão para o recurso |
| 404 | NotFoundError |
Recurso não encontrado |
| 409 | ConflictError |
Conflito de estado (ex: transação já finalizada) |
| 422 | UnprocessableEntityError |
Dados válidos sintaticamente mas semanticamente incorretos |
| 429 | RateLimitError |
Limite de requisições excedido |
| 500 | InternalServerError |
Erro interno do servidor |
| 503 | ServiceUnavailableError |
Serviço temporariamente indisponível |
Erros de infraestrutura (não-HTTP):
| Exceção | Descrição |
|---|---|
AuthenticationError |
Falha na obtenção do token OAuth2 |
ConnectionError |
Falha de conexão de rede |
TimeoutError |
Timeout da requisição ou duração máxima de retry excedida |
import {
NotFoundError,
RateLimitError,
ConflictError,
SignDocsBrasilApiError,
SignDocsBrasilError,
} from '@signdocs-brasil/api';
try {
const tx = await client.transactions.get('tx-inexistente');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Não encontrado:', err.detail);
} else if (err instanceof RateLimitError) {
console.log('Rate limit, retry em:', err.retryAfterSeconds, 'segundos');
} else if (err instanceof ConflictError) {
console.log('Conflito:', err.detail);
} else if (err instanceof SignDocsBrasilApiError) {
console.log('Erro de API:', err.status, err.title, err.detail);
console.log('ProblemDetail:', err.problemDetail);
} else if (err instanceof SignDocsBrasilError) {
console.log('Erro de infraestrutura:', err.message);
}
}
from signdocs_brasil.errors import (
NotFoundError,
RateLimitError,
ConflictError,
SignDocsBrasilApiError,
SignDocsBrasilError,
)
try:
tx = client.transactions.get('tx-inexistente')
except NotFoundError as e:
print(f'Não encontrado: {e.problem_detail.detail}')
except RateLimitError as e:
print(f'Rate limit, retry em: {e.retry_after_seconds}s')
except ConflictError as e:
print(f'Conflito: {e.problem_detail.detail}')
except SignDocsBrasilApiError as e:
print(f'Erro de API: {e.problem_detail.status} {e.problem_detail.title}')
except SignDocsBrasilError as e:
print(f'Erro de infraestrutura: {e}')
import (
"errors"
signdocs "github.com/signdocsbrasil/signdocsbrasil-go"
)
tx, err := client.Transactions.Get(ctx, "tx-inexistente")
if err != nil {
var notFound *signdocs.NotFoundError
var rateLimit *signdocs.RateLimitError
var conflict *signdocs.ConflictError
var apiErr *signdocs.ApiError
if errors.As(err, ¬Found) {
fmt.Println("Não encontrado:", notFound.ProblemDetail.Detail)
} else if errors.As(err, &rateLimit) {
fmt.Println("Rate limit, retry em:", rateLimit.RetryAfterSeconds, "segundos")
} else if errors.As(err, &conflict) {
fmt.Println("Conflito:", conflict.ProblemDetail.Detail)
} else if errors.As(err, &apiErr) {
fmt.Println("Erro de API:", apiErr.StatusCode, apiErr.ProblemDetail.Title)
} else {
fmt.Println("Erro:", err)
}
}
// Funções auxiliares
if signdocs.IsNotFound(err) { /* ... */ }
if signdocs.IsRateLimit(err) { /* ... */ }
if signdocs.IsConflict(err) { /* ... */ }
import com.signdocsbrasil.api.exceptions.*;
try {
Transaction tx = client.transactions().get("tx-inexistente");
} catch (NotFoundException e) {
System.out.println("Não encontrado: " + e.getProblemDetail().getDetail());
} catch (RateLimitException e) {
System.out.println("Rate limit, retry em: " + e.getRetryAfterSeconds() + "s");
} catch (ConflictException e) {
System.out.println("Conflito: " + e.getProblemDetail().getDetail());
} catch (ApiException e) {
System.out.println("Erro de API: " + e.getStatus() + " " + e.getTitle());
} catch (SignDocsBrasilException e) {
System.out.println("Erro de infraestrutura: " + e.getMessage());
}
use SignDocsBrasil\Api\Exceptions\NotFoundException;
use SignDocsBrasil\Api\Exceptions\RateLimitException;
use SignDocsBrasil\Api\Exceptions\ConflictException;
use SignDocsBrasil\Api\Exceptions\ApiException;
use SignDocsBrasil\Api\Exceptions\SignDocsBrasilException;
try {
$tx = $client->transactions->get('tx-inexistente');
} catch (NotFoundException $e) {
echo 'Não encontrado: ' . $e->getProblemDetail()->detail;
} catch (RateLimitException $e) {
echo 'Rate limit, retry em: ' . $e->retryAfterSeconds . 's';
} catch (ConflictException $e) {
echo 'Conflito: ' . $e->getProblemDetail()->detail;
} catch (ApiException $e) {
echo 'Erro de API: ' . $e->getStatus() . ' ' . $e->getTitle();
} catch (SignDocsBrasilException $e) {
echo 'Erro de infraestrutura: ' . $e->getMessage();
}
Os SDKs fazem retry automaticamente em erros transientes:
| Parâmetro | Valor padrão |
|---|---|
| Status codes com retry | 429, 500, 503 |
| Máximo de tentativas | 5 |
| Backoff | Exponencial: 2^tentativa + jitter aleatório (0-1s) |
| Delay máximo por tentativa | 30 segundos |
| Duração total máxima | 60 segundos |
Header Retry-After |
Respeitado quando presente |
| Idempotência | X-Idempotency-Key gerado automaticamente em criação de transações |
O retry é transparente — se todas as tentativas falharem, a exceção correspondente ao último status é lançada.
NotFoundError em operações de leituraConflictError ao finalizar transações (pode já estar finalizada)RateLimitError em produção para ajustar volume de requisições