Sudrel API
Dashboard Create API key

Documentation › First steps

Guides

Get started

From the test key to the first authorized NFS-e, step by step, with curl, C# and Delphi.

Your first invoice

Everything starts in the test environment: the invoice really goes to the Sistema Nacional test environment, with no fiscal value, no charge, and it does not appear in the dashboard. Later, for production, only the key changes.

Which path is yours?

  • A. The company is already set up in the dashboard (A1 certificate and tax data): follow steps 1, 3, 4, 5, 6 and 7. It takes minutes.
  • B. First setup: start at step 2. The time depends on having the A1 certificate at hand and knowing the company's tax regime and service code.

1. Test key. In the dashboard, under Integrações › Chaves de API (Integrations › API keys), create a key with environment Teste (Test). It starts with sdr_test_. In the examples below it is in the SUDREL_API_KEY variable.

2. Company (path B only). Register the company and upload the A1 certificate in the dashboard, or through the API with a sdr_live_ key (POST /v1/companies and POST /v1/companies/{id}/certificate). The test key reads companies and issues on their behalf, but does not create or change a company. The tax data (tax regime, default service code) is in the dashboard, under Emissão › Empresa (Issuance › Company). Get each company's empresa_id from GET /v1/companies.

3. Readiness. Goal: know whether the company can issue now, before you try.

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

The response has situacao (ok, aviso or bloqueio) and one item per requirement, each with mensagem and correcao. Next step: with ok or aviso, continue. With bloqueio, fix the indicated item: issuance would be refused with 412. Details in Readiness.

4. Validate before you issue. POST /v1/nfse/validacoes takes the same JSON as issuance and returns the errors and the ajustes, without creating anything.

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"}}'

The response is always 200, with valida (true or false), erros (each with campo, mensagem and correcao) and ajustes (what Sudrel filled in or omitted because of the municipality). Next step: with valida: true, issue.

5. Issue. Always send referencia and Idempotency-Key: they make it safe to repeat the call. See Idempotency.

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"}}'

What can come back:

Status What happened Next step
201 Authorized. numero and chave_acesso are filled in. Done. Download the PDF from GET /v1/nfse/{id}/pdf.
202 Still transmitindo. Sudrel keeps handling it. Wait for the webhook or query (step 6). Do not issue again.
422 validacao The JSON has an error. Nothing was created. Fix the items in erros and send again.
422 nfse_rejeitada The Sistema Nacional refused it. The invoice exists as rejeitada. Read rejeicao, fix it and issue a new invoice, with a different referencia.
412 empresa_nao_pronta The company cannot issue. Nothing was created. Fix the items in bloqueio (step 3).

Without an SDK, the same call in plain HTTP:

C# (.NET 6 or newer):

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 or newer, 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;

There are also TypeScript and PHP SDKs: see SDKs.

6. Track it. Goal: know the result of an invoice that returned 202. Query it by your reference:

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

Next step: status tells where the invoice is (see NFS-e statuses). Do not query too often (every 30 seconds, for example); in production, prefer the webhook.

7. Webhook. Goal: get notified without querying. Register an endpoint of yours with the test key (it receives only test events):

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"]}'

Store the segredo from the response: it appears only here. Test it with POST /v1/webhooks/{id}/teste. How to check the signature of each delivery is in Webhooks.

8. Trigger the failures. With the X-Sudrel-Simular header (section Failure simulator) you see a timeout, Sefin down, an accrual period lock and falha_transmissao without touching the Sefin.

Got an error? Every response has the X-Request-Id header, and the issuance, batch, webhook and event errors repeat the value in requisicao_id. Search for it in the dashboard, under Integrações › Log da API (Integrations › API log): it shows what your system sent and what Sudrel answered, for 30 days. See also Troubleshooting.