Sudrel API
Painel Criar chave de API

Documentação › Primeiros passos

Guias

Comece aqui

Da chave de teste à primeira NFS-e autorizada, passo a passo, com curl, C# e Delphi.

Sua primeira nota

Tudo começa no ambiente de teste: a nota vai de verdade ao ambiente de testes do Sistema Nacional, sem valor fiscal, sem cobrar e sem aparecer no painel. Para produção, depois, só a chave muda.

Qual caminho é o seu?

  • A. A empresa já está configurada no painel (certificado A1 e dados fiscais): faça os passos 1, 3, 4, 5, 6 e 7. Leva minutos.
  • B. Primeira configuração: comece pelo passo 2. O tempo depende de ter o certificado A1 em mãos e de conhecer o regime tributário e o código de serviço da empresa.

1. Chave de teste. No painel, em Integrações › Chaves de API, crie uma chave com ambiente Teste. Ela começa com sdr_test_. Nos exemplos abaixo ela está na variável SUDREL_API_KEY.

2. Empresa (só no caminho B). Cadastre a empresa e envie o certificado A1 pelo painel, ou pela API com uma chave sdr_live_ (POST /v1/companies e POST /v1/companies/{id}/certificate). A chave de teste lê as empresas e emite em nome delas, mas não cria nem altera empresa. Os dados fiscais (regime tributário, código de serviço padrão) ficam no painel, em Emissão › Empresa. O empresa_id de cada empresa sai de GET /v1/companies.

3. Prontidão. Objetivo: saber se a empresa pode emitir agora, antes de tentar.

curl https://api.sudrel.com.br/api/v1/companies/$EMPRESA/prontidao \
  -H "Authorization: Bearer $SUDREL_API_KEY"

A resposta tem situacao (ok, aviso ou bloqueio) e um item por requisito, cada um com mensagem e correcao. Próximo passo: com ok ou aviso, siga. Com bloqueio, resolva o item indicado: a emissão seria recusada com 412. Detalhes em Prontidão.

4. Valide antes de emitir. POST /v1/nfse/validacoes recebe o mesmo JSON da emissão e devolve os erros e os ajustes, sem criar nada.

curl https://api.sudrel.com.br/api/v1/nfse/validacoes \
  -H "Authorization: Bearer $SUDREL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"empresa_id":"'$EMPRESA'","referencia":"PED-1001","tomador":{"documento":"11222333000181"},"valor":"1500.00","servico":{"descricao":"Consultoria em sistemas"}}'

A resposta é sempre 200, com valida (true ou false), erros (cada um com campo, mensagem e correcao) e ajustes (o que a Sudrel preencheu ou omitiu pelo município). Próximo passo: com valida: true, emita.

5. Emita. Mande sempre referencia e Idempotency-Key: é o que torna seguro repetir a chamada. Veja Idempotência.

curl https://api.sudrel.com.br/api/v1/nfse \
  -H "Authorization: Bearer $SUDREL_API_KEY" \
  -H "Idempotency-Key: 7f1c0d9a-4a51-4e0e-9b1f-2b6f0d3c5a10" \
  -H "Prefer: wait=10" \
  -H "Content-Type: application/json" \
  -d '{"empresa_id":"'$EMPRESA'","referencia":"PED-1001","tomador":{"documento":"11222333000181"},"valor":"1500.00","servico":{"descricao":"Consultoria em sistemas"}}'

O que pode voltar:

Status O que aconteceu Próximo passo
201 Autorizada. numero e chave_acesso preenchidos. Pronto. Baixe o PDF em GET /v1/nfse/{id}/pdf.
202 Ainda transmitindo. A Sudrel continua cuidando. Espere o webhook ou consulte (passo 6). Não emita de novo.
422 validacao O JSON tem erro. Nada foi criado. Corrija os itens de erros e envie de novo.
422 nfse_rejeitada O Sistema Nacional recusou. A nota existe como rejeitada. Leia rejeicao, corrija e emita uma nota nova, com outra referencia.
412 empresa_nao_pronta A empresa não pode emitir. Nada foi criado. Resolva os itens em bloqueio (passo 3).

Sem SDK, a mesma chamada em HTTP puro:

C# (.NET 6 ou mais novo):

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Threading.Tasks;

public static class PrimeiraNota
{
    // A Idempotency-Key é sua: gere uma por nota, guarde junto do pedido e
    // reaproveite a MESMA se precisar repetir a chamada. Assim nunca sai nota dobrada.
    public static async Task<string> EmitirAsync(string empresaId, string idempotencyKey)
    {
        using var http = new HttpClient { BaseAddress = new Uri("https://api.sudrel.com.br/api/") };
        http.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("SUDREL_API_KEY"));

        var pedido = new HttpRequestMessage(HttpMethod.Post, "v1/nfse")
        {
            Content = JsonContent.Create(new
            {
                empresa_id = empresaId,
                referencia = "PED-1001",
                tomador = new { documento = "11222333000181" },
                valor = "1500.00",
                servico = new { descricao = "Consultoria em sistemas" },
            }),
        };
        pedido.Headers.Add("Idempotency-Key", idempotencyKey);
        pedido.Headers.Add("Prefer", "wait=10");

        var resposta = await http.SendAsync(pedido);
        var corpo = await resposta.Content.ReadAsStringAsync();
        // 201: autorizada. 202: ainda transmitindo (acompanhe por webhook ou GET /v1/nfse/PED-1001).
        // 422: veja "codigo" e "erros" (ou a nota rejeitada em "nfse"). Todo erro traz "requisicao_id".
        return $"{(int)resposta.StatusCode} {corpo}";
    }
}

Delphi (10.3 ou mais novo, System.Net.HttpClient):

uses
  System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient;

// A Idempotency-Key é sua: gere uma por nota, guarde junto do pedido e
// reaproveite a MESMA se precisar repetir a chamada. Assim nunca sai nota dobrada.
function EmitirNota(const EmpresaId, IdempotencyKey: string): string;
var
  Cliente: THTTPClient;
  Corpo: TStringStream;
  Resposta: IHTTPResponse;
begin
  Cliente := THTTPClient.Create;
  Corpo := TStringStream.Create(
    '{"empresa_id":"' + EmpresaId + '","referencia":"PED-1001",' +
    '"tomador":{"documento":"11222333000181"},"valor":"1500.00",' +
    '"servico":{"descricao":"Consultoria em sistemas"}}', TEncoding.UTF8);
  try
    Cliente.ContentType := 'application/json';
    Cliente.CustomHeaders['Authorization'] := 'Bearer ' + GetEnvironmentVariable('SUDREL_API_KEY');
    Cliente.CustomHeaders['Idempotency-Key'] := IdempotencyKey;
    Cliente.CustomHeaders['Prefer'] := 'wait=10';
    Resposta := Cliente.Post('https://api.sudrel.com.br/api/v1/nfse', Corpo);
    // 201: autorizada. 202: ainda transmitindo (acompanhe por webhook ou GET /v1/nfse/PED-1001).
    // 422: veja "codigo" e "erros" (ou a nota rejeitada em "nfse"). Todo erro traz "requisicao_id".
    Result := IntToStr(Resposta.StatusCode) + ' ' + Resposta.ContentAsString(TEncoding.UTF8);
  finally
    Corpo.Free;
    Cliente.Free;
  end;
end;

Há também SDKs de TypeScript e PHP: veja SDKs.

6. Acompanhe. Objetivo: saber o resultado de uma nota que voltou 202. Consulte pela sua referência:

curl https://api.sudrel.com.br/api/v1/nfse/PED-1001 \
  -H "Authorization: Bearer $SUDREL_API_KEY"

Próximo passo: status diz onde a nota está (veja Estados da NFS-e). Consulte com calma (a cada 30 segundos, por exemplo); em produção, prefira o webhook.

7. Webhook. Objetivo: ser avisado sem consultar. Cadastre um endereço seu, com a chave de teste (ele recebe só eventos de teste):

curl https://api.sudrel.com.br/api/v1/webhooks \
  -H "Authorization: Bearer $SUDREL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://erp.exemplo.com.br/webhooks/sudrel","eventos":["NFSE_AUTORIZADA","NFSE_REJEITADA","NFSE_FALHA_TRANSMISSAO"]}'

Guarde o segredo da resposta: ele só aparece aqui. Teste com POST /v1/webhooks/{id}/teste. Como conferir a assinatura de cada entrega está em Webhooks.

8. Provoque as falhas. Com o cabeçalho X-Sudrel-Simular (seção Simulador de falhas) você vê timeout, Sefin fora, trava de competência e falha_transmissao sem tocar na Sefin.

Deu erro? Toda resposta traz o cabeçalho X-Request-Id, e os erros de emissão, lote, webhooks e eventos repetem o valor em requisicao_id. Procure por ele no painel, em Integrações › Log da API: está lá o que o seu sistema mandou e o que a Sudrel respondeu, por 30 dias. Veja também Problemas comuns.