Exemplos de Integração

Aprenda como integrar sua aplicação com a API do CFS Brasil usando diversas linguagens.

Voltar para Home

Autenticação e Consulta de Códigos Oficiais

Abaixo você encontra exemplos de como realizar a autenticação (login) para obter o token JWT e, em seguida, utilizar esse token para consultar a lista de códigos oficiais (EAN-13, NBS, etc.).

Delphi (Console) - Uses System.Net.HttpClient Baixar
program CFSBrasilClient;

{$APPTYPE CONSOLE}

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

var
  objClient: TNetHTTPClient;
  objResponse: IHTTPResponse;
  objJson: TJSONObject;
  objJsonResp: TJSONObject;
  objSource: TStringStream;
  strToken: string;
  strBaseUrl: string;
  strXmlExemplo: string;
begin
  // Configuração Inicial
  strBaseUrl := 'https://cfsbrasil.com.br/api';
  objClient := TNetHTTPClient.Create(nil);
  try
    try
      // -----------------------------------------------------------------------
      // 1. Autenticação (Login)
      // -----------------------------------------------------------------------
      Writeln('1. Realizando autenticacao...');
      
      objJson := TJSONObject.Create;
      try
        objJson.AddPair('email', 'seu@email.com');
        objJson.AddPair('password', 'sua_senha');
        
        objSource := TStringStream.Create(objJson.ToString, TEncoding.UTF8);
        try
          objClient.ContentType := 'application/json';
          
          // POST /api/login
          objResponse := objClient.Post(strBaseUrl + '/login', objSource);
        finally
          objSource.Free;
        end;
      finally
        objJson.Free;
      end;

      // Verifica sucesso (200-299)
      if (objResponse.StatusCode >= 200) and (objResponse.StatusCode <= 299) then
      begin
        objJson := TJSONObject.ParseJSONValue(objResponse.ContentAsString) as TJSONObject;
        try
          if Assigned(objJson) then
          begin
            strToken := objJson.GetValue<string>('token');
            Writeln('Login com sucesso!');
            Writeln('Token recebido: ' + Copy(strToken, 1, 20) + '...');
          end;
        finally
          objJson.Free;
        end;
        
        Writeln('');

        // -----------------------------------------------------------------------
        // 2. Consultar Serviços Oficiais (Requer Token)
        // -----------------------------------------------------------------------
        if strToken <> '' then
        begin
          Writeln('2. Consultando Servicos Oficiais...');
          
          // Configura Header de Autorização
          objClient.CustomHeaders['Authorization'] := 'Bearer ' + strToken;
          
          // GET /api/official-services
          objResponse := objClient.Get(strBaseUrl + '/official-services');
          
          if (objResponse.StatusCode >= 200) and (objResponse.StatusCode <= 299) then
          begin
             Writeln('Status: ' + objResponse.StatusCode.ToString);
             Writeln('Dados (primeiros 100 chars): ' + Copy(objResponse.ContentAsString, 1, 100) + '...');
          end
          else
          begin
            Writeln('Erro na consulta: ' + objResponse.StatusCode.ToString);
            Writeln('Mensagem: ' + objResponse.StatusText);
          end;
          
          Writeln('');

          // -----------------------------------------------------------------------
          // 3. Enviar Nota Fiscal de Serviço (XML)
          // -----------------------------------------------------------------------
          Writeln('3. Enviando Nota Fiscal (XML)...');

          strXmlExemplo := '<Rps><InfRps><DataEmissao>2023-10-25</DataEmissao><Servico><ValorServico>100.00</ValorServico></Servico></InfRps></Rps>';

          objJson := TJSONObject.Create;
          try
            objJson.AddPair('xmlContent', strXmlExemplo);
            
            objSource := TStringStream.Create(objJson.ToString, TEncoding.UTF8);
            try
              objClient.ContentType := 'application/json';
              // IMPORTANTE: Este endpoint requer autenticação para vincular os créditos ao usuário.
              // O token JWT já foi configurado globalmente em objClient.CustomHeaders['Authorization']
              // POST /api/service-invoices
              objResponse := objClient.Post(strBaseUrl + '/service-invoices', objSource);
              
              if (objResponse.StatusCode = 201) then
              begin
                Writeln('Nota enviada com sucesso!');
                
                objJsonResp := TJSONObject.ParseJSONValue(objResponse.ContentAsString) as TJSONObject;
                try
                  if Assigned(objJsonResp) then
                  begin
                    // Tenta ler como string, se for numero o Delphi converte
                    if objJsonResp.GetValue('creditsAdded') <> nil then
                      Writeln('Creditos adicionados: ' + objJsonResp.GetValue('creditsAdded').Value);
                      
                    if objJsonResp.GetValue('currentCredits') <> nil then
                      Writeln('Saldo atual: ' + objJsonResp.GetValue('currentCredits').Value);
                  end;
                finally
                  objJsonResp.Free;
                end;
              end
              else
              begin
                Writeln('Erro ao enviar nota: ' + objResponse.StatusCode.ToString);
                Writeln('Detalhe: ' + objResponse.ContentAsString);
              end;

            finally
              objSource.Free;
            end;
          finally
            objJson.Free; 
          end;

        end;
      end
      else
      begin
        Writeln('Falha no login: ' + objResponse.StatusCode.ToString);
        Writeln('Resposta: ' + objResponse.ContentAsString);
      end;

    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    objClient.Free;
  end;
  
  Writeln('');
  Writeln('Pressione ENTER para sair...');
  Readln;
end.
C# (.NET Console) - Uses System.Net.Http Baixar
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

// Classe para mapear resposta de Login
public class LoginResponse
{
    [JsonPropertyName("token")]
    public string Token { get; set; }
}

public class InvoiceResponse
{
    [JsonPropertyName("creditsAdded")]
    public int CreditsAdded { get; set; }

    [JsonPropertyName("currentCredits")]
    public int CurrentCredits { get; set; }
}

class CFSBrasilClient
{
    static async Task Main(string[] args)
    {
        var strBaseUrl = "https://cfsbrasil.com.br/api";
        using var objClient = new HttpClient();

        try
        {
            // -------------------------------------------------------------------
            // 1. Autenticação (Login)
            // -------------------------------------------------------------------
            Console.WriteLine("1. Realizando autenticação...");

            var objLoginData = new
            {
                email = "seu@email.com",
                password = "sua_senha"
            };

            var strJsonLogin = JsonSerializer.Serialize(objLoginData);
            var objContent = new StringContent(strJsonLogin, Encoding.UTF8, "application/json");

            var objResponse = await objClient.PostAsync($"{strBaseUrl}/login", objContent);

            if (!objResponse.IsSuccessStatusCode)
            {
                Console.WriteLine($"Erro no login: {objResponse.StatusCode}");
                return;
            }

            var strResponseBody = await objResponse.Content.ReadAsStringAsync();
            var objLoginResponse = JsonSerializer.Deserialize<LoginResponse>(strResponseBody);
            var strToken = objLoginResponse?.Token;

            if (string.IsNullOrEmpty(strToken))
            {
                Console.WriteLine("Token não recebido.");
                return;
            }

            Console.WriteLine($"Login com sucesso! Token: {strToken.Substring(0, 20)}...");
            Console.WriteLine();

            // Configura Header de Autorização para próximas requisições
            objClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", strToken);

            // -------------------------------------------------------------------
            // 2. Consultar Serviços Oficiais (Requer Token)
            // -------------------------------------------------------------------
            Console.WriteLine("2. Consultando Serviços Oficiais...");

            // GET /api/official-services
            objResponse = await objClient.GetAsync($"{strBaseUrl}/official-services");

            if (objResponse.IsSuccessStatusCode)
            {
                var strServicesJson = await objResponse.Content.ReadAsStringAsync();
                Console.WriteLine($"Status: {objResponse.StatusCode}");
                
                // Exibe apenas os primeiros 100 caracteres para não poluir o console
                var strDisplay = strServicesJson.Length > 100 ? strServicesJson.Substring(0, 100) + "..." : strServicesJson;
                Console.WriteLine($"Dados: {strDisplay}");
            }
            else
            {
                Console.WriteLine($"Erro ao consultar serviços: {objResponse.StatusCode}");
            }
            Console.WriteLine();

            // -------------------------------------------------------------------
            // 3. Enviar Nota Fiscal de Serviço (XML)
            // -------------------------------------------------------------------
            Console.WriteLine("3. Enviando Nota Fiscal (XML)...");

            var strXmlExemplo = @"
<Rps>
  <InfRps>
    <DataEmissao>2023-10-25</DataEmissao>
    <Servico>
      <ValorServico>100.00</ValorServico>
    </Servico>
  </InfRps>
</Rps>";

            var objInvoiceData = new { xmlContent = strXmlExemplo };
            var strJsonInvoice = JsonSerializer.Serialize(objInvoiceData);
            var objInvoiceContent = new StringContent(strJsonInvoice, Encoding.UTF8, "application/json");

            // IMPORTANTE: Este endpoint requer autenticação para vincular os créditos ao usuário.
            // O token JWT já foi configurado globalmente em objClient.DefaultRequestHeaders.Authorization
            // POST /api/service-invoices
            objResponse = await objClient.PostAsync($"{strBaseUrl}/service-invoices", objInvoiceContent);

            if (objResponse.IsSuccessStatusCode)
            {
                var strInvoiceBody = await objResponse.Content.ReadAsStringAsync();
                var objInvoiceResponse = JsonSerializer.Deserialize<InvoiceResponse>(strInvoiceBody);
                
                Console.WriteLine("Nota enviada com sucesso!");
                Console.WriteLine($"Créditos adicionados: {objInvoiceResponse?.CreditsAdded}");
                Console.WriteLine($"Saldo atual: {objInvoiceResponse?.CurrentCredits}");
            }
            else
            {
                Console.WriteLine($"Erro ao enviar nota: {objResponse.StatusCode}");
                var strError = await objResponse.Content.ReadAsStringAsync();
                Console.WriteLine($"Detalhe: {strError}");
            }
        }
        catch (Exception objEx)
        {
            Console.WriteLine($"Exceção: {objEx.Message}");
        }

        Console.WriteLine("\nPressione qualquer tecla para sair...");
        Console.ReadKey();
    }
}
Go (Golang) Baixar
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

type LoginRequest struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

type LoginResponse struct {
	Token string `json:"token"`
}

type InvoiceRequest struct {
	XmlContent string `json:"xmlContent"`
}

type InvoiceResponse struct {
	CreditsAdded   int `json:"creditsAdded"`
	CurrentCredits int `json:"currentCredits"`
}

const strBaseUrl = "https://cfsbrasil.com.br/api"

func main() {
	// -------------------------------------------------------------------
	// 1. Autenticação (Login)
	// -------------------------------------------------------------------
	fmt.Println("1. Realizando autenticação...")

	objLoginData := LoginRequest{
		Email:    "seu@email.com",
		Password: "sua_senha",
	}

	strJsonLogin, _ := json.Marshal(objLoginData)
	
	objClient := &http.Client{Timeout: 10 * time.Second}
	objResp, err := objClient.Post(strBaseUrl+"/login", "application/json", bytes.NewBuffer(strJsonLogin))
	if err != nil {
		fmt.Printf("Erro na requisicao: %s\n", err)
		return
	}
	defer objResp.Body.Close()

	if objResp.StatusCode >= 200 && objResp.StatusCode <= 299 {
		bodyBytes, _ := ioutil.ReadAll(objResp.Body)
		var objLoginResp LoginResponse
		json.Unmarshal(bodyBytes, &objLoginResp)
		
		strToken := objLoginResp.Token
		if strToken != "" {
			fmt.Printf("Login com sucesso! Token: %s...\n\n", strToken[:20])

			// -------------------------------------------------------------------
			// 2. Consultar Serviços Oficiais (Requer Token)
			// -------------------------------------------------------------------
			fmt.Println("2. Consultando Serviços Oficiais...")

			req, _ := http.NewRequest("GET", strBaseUrl+"/official-services", nil)
			req.Header.Set("Authorization", "Bearer "+strToken)

			objRespServices, err := objClient.Do(req)
			if err != nil {
				fmt.Printf("Erro na requisicao: %s\n", err)
				return
			}
			defer objRespServices.Body.Close()

			if objRespServices.StatusCode >= 200 && objRespServices.StatusCode <= 299 {
				fmt.Printf("Status: %d\n", objRespServices.StatusCode)
				bodyServices, _ := ioutil.ReadAll(objRespServices.Body)
				
				// Exibe apenas os primeiros 100 caracteres
				strBody := string(bodyServices)
				if len(strBody) > 100 {
					strBody = strBody[:100] + "..."
				}
				fmt.Printf("Dados: %s\n", strBody)
			} else {
				fmt.Printf("Erro ao consultar servicos: %d\n", objRespServices.StatusCode)
			}
			fmt.Println()

			// -------------------------------------------------------------------
			// 3. Enviar Nota Fiscal de Serviço (XML)
			// -------------------------------------------------------------------
			fmt.Println("3. Enviando Nota Fiscal (XML)...")

			strXmlExemplo := "<Rps><InfRps><DataEmissao>2023-10-25</DataEmissao><Servico><ValorServico>100.00</ValorServico></Servico></InfRps></Rps>"

			objInvoiceData := InvoiceRequest{
				XmlContent: strXmlExemplo,
			}
			strJsonInvoice, _ := json.Marshal(objInvoiceData)

			reqInvoice, _ := http.NewRequest("POST", strBaseUrl+"/service-invoices", bytes.NewBuffer(strJsonInvoice))
			reqInvoice.Header.Set("Content-Type", "application/json")
			reqInvoice.Header.Set("Authorization", "Bearer "+strToken)

			objRespInvoice, err := objClient.Do(reqInvoice)
			if err != nil {
				fmt.Printf("Erro ao enviar nota: %s\n", err)
				return
			}
			defer objRespInvoice.Body.Close()

			if objRespInvoice.StatusCode == 201 {
				bodyInvoice, _ := ioutil.ReadAll(objRespInvoice.Body)
				var objInvoiceResp InvoiceResponse
				json.Unmarshal(bodyInvoice, &objInvoiceResp)

				fmt.Println("Nota enviada com sucesso!")
				fmt.Printf("Créditos adicionados: %d\n", objInvoiceResp.CreditsAdded)
				fmt.Printf("Saldo atual: %d\n", objInvoiceResp.CurrentCredits)
			} else {
				fmt.Printf("Erro ao enviar nota: %d\n", objRespInvoice.StatusCode)
			}

		} else {
			fmt.Println("Token nao encontrado.")
		}
	} else {
		fmt.Printf("Erro no login: %d\n", objResp.StatusCode)
	}
}
Java 11+ (HttpClient) Baixar
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse.BodyHandlers;

public class CFSBrasilClient {

    private static final String STR_BASE_URL = "https://cfsbrasil.com.br/api";
    private static final String STR_EMAIL = "seu@email.com";
    private static final String STR_PASSWORD = "sua_senha";

    public static void main(String[] args) {
        HttpClient objClient = HttpClient.newHttpClient();

        try {
            // -------------------------------------------------------------------
            // 1. Autenticação (Login)
            // -------------------------------------------------------------------
            System.out.println("1. Realizando autenticacao...");

            String strJsonLogin = String.format("{\"email\":\"%s\", \"password\":\"%s\"}", STR_EMAIL, STR_PASSWORD);

            HttpRequest objLoginRequest = HttpRequest.newBuilder()
                    .uri(URI.create(STR_BASE_URL + "/login"))
                    .header("Content-Type", "application/json")
                    .POST(BodyPublishers.ofString(strJsonLogin))
                    .build();

            HttpResponse<String> objLoginResponse = objClient.send(objLoginRequest, BodyHandlers.ofString());

            if (objLoginResponse.statusCode() >= 200 && objLoginResponse.statusCode() <= 299) {
                // Parse simples do Token (em producao, use uma lib JSON como Jackson ou Gson)
                String strBody = objLoginResponse.body();
                String strToken = extractToken(strBody);

                if (strToken != null) {
                    System.out.println("Login com sucesso! Token: " + strToken.substring(0, 20) + "...");
                    System.out.println();

                    // -------------------------------------------------------------------
                    // 2. Consultar Serviços Oficiais (Requer Token)
                    // -------------------------------------------------------------------
                    System.out.println("2. Consultando Servicos Oficiais...");

                    HttpRequest objServicesRequest = HttpRequest.newBuilder()
                            .uri(URI.create(STR_BASE_URL + "/official-services"))
                            .header("Authorization", "Bearer " + strToken)
                            .GET()
                            .build();

                    HttpResponse<String> objServicesResponse = objClient.send(objServicesRequest, BodyHandlers.ofString());

                    if (objServicesResponse.statusCode() >= 200 && objServicesResponse.statusCode() <= 299) {
                        System.out.println("Status: " + objServicesResponse.statusCode());
                        String strServicesBody = objServicesResponse.body();
                        System.out.println("Dados (primeiros 100 chars): " + 
                            (strServicesBody.length() > 100 ? strServicesBody.substring(0, 100) + "..." : strServicesBody));
                    } else {
                        System.out.println("Erro ao consultar servicos: " + objServicesResponse.statusCode());
                    }
                    System.out.println();

                    // -------------------------------------------------------------------
                    // 3. Enviar Nota Fiscal de Serviço (XML)
                    // -------------------------------------------------------------------
                    System.out.println("3. Enviando Nota Fiscal (XML)...");
                    
                    // Escapando aspas duplas dentro do XML se necessário (aqui é simples)
                    String strXmlExemplo = "<Rps><InfRps><DataEmissao>2023-10-25</DataEmissao><Servico><ValorServico>100.00</ValorServico></Servico></InfRps></Rps>";
                    
                    // JSON manual: {"xmlContent": "..."}
                    String strJsonInvoice = String.format("{\"xmlContent\": \"%s\"}", strXmlExemplo);

                    HttpRequest objInvoiceRequest = HttpRequest.newBuilder()
                            .uri(URI.create(STR_BASE_URL + "/service-invoices"))
                            .header("Content-Type", "application/json")
                            .header("Authorization", "Bearer " + strToken)
                            .POST(BodyPublishers.ofString(strJsonInvoice))
                            .build();

                    HttpResponse<String> objInvoiceResponse = objClient.send(objInvoiceRequest, BodyHandlers.ofString());

                    if (objInvoiceResponse.statusCode() == 201) {
                        System.out.println("Nota enviada com sucesso!");
                        System.out.println("Resposta: " + objInvoiceResponse.body());
                    } else {
                        System.out.println("Erro ao enviar nota: " + objInvoiceResponse.statusCode());
                        System.out.println("Detalhe: " + objInvoiceResponse.body());
                    }

                } else {
                    System.out.println("Token nao encontrado na resposta.");
                }
            } else {
                System.out.println("Erro no login: " + objLoginResponse.statusCode());
                System.out.println("Resposta: " + objLoginResponse.body());
            }

        } catch (Exception objEx) {
            objEx.printStackTrace();
        }
    }

    // Helper simples para extrair token sem depender de lib externa neste exemplo
    private static String extractToken(String json) {
        String search = "\"token\":\"";
        int start = json.indexOf(search);
        if (start == -1) return null;
        start += search.length();
        int end = json.indexOf("\"", start);
        if (end == -1) return null;
        return json.substring(start, end);
    }
}
Node.js (Axios) Baixar
const axios = require('axios');

const strBaseUrl = 'https://cfsbrasil.com.br/api';
const strEmail = 'seu@email.com';
const strPassword = 'sua_senha';

async function main() {
    try {
        // -------------------------------------------------------------------
        // 1. Autenticação (Login)
        // -------------------------------------------------------------------
        console.log('1. Realizando autenticação...');

        const objLoginResponse = await axios.post(`${strBaseUrl}/login`, {
            email: strEmail,
            password: strPassword
        });

        if (objLoginResponse.status !== 200) {
            console.error('Erro no login:', objLoginResponse.status);
            return;
        }

        const strToken = objLoginResponse.data.token;
        if (!strToken) {
            console.error('Token não recebido');
            return;
        }

        console.log('Login com sucesso! Token:', strToken.substring(0, 20) + '...');
        console.log('');

        // -------------------------------------------------------------------
        // 2. Consultar Serviços Oficiais (Requer Token)
        // -------------------------------------------------------------------
        console.log('2. Consultando Serviços Oficiais...');

        const objServicesResponse = await axios.get(`${strBaseUrl}/official-services`, {
            headers: {
                'Authorization': `Bearer ${strToken}`
            }
        });

        if (objServicesResponse.status === 200) {
            console.log('Status:', objServicesResponse.status);
            
            // Exibe apenas os 2 primeiros itens para não poluir o console
            const arrData = objServicesResponse.data;
            console.log('Dados (2 primeiros itens):', arrData.slice(0, 2));
        } else {
            console.error('Erro ao consultar serviços:', objServicesResponse.status);
        }
        console.log('');

        // -------------------------------------------------------------------
        // 3. Enviar Nota Fiscal de Serviço (XML)
        // -------------------------------------------------------------------
        console.log('3. Enviando Nota Fiscal (XML)...');
        
        const strXmlExemplo = `
<Rps>
  <InfRps>
    <DataEmissao>2023-10-25</DataEmissao>
    <Servico>
      <ValorServico>100.00</ValorServico>
    </Servico>
  </InfRps>
</Rps>`;

        const objInvoiceResponse = await axios.post(`${strBaseUrl}/service-invoices`, {
            xmlContent: strXmlExemplo
        }, {
            headers: {
                'Authorization': `Bearer ${strToken}`
            }
        });

        if (objInvoiceResponse.status === 201) {
            console.log('Nota enviada com sucesso!');
            console.log('Créditos adicionados:', objInvoiceResponse.data.creditsAdded);
            console.log('Saldo atual:', objInvoiceResponse.data.currentCredits);
        } else {
            console.error('Erro ao enviar nota:', objInvoiceResponse.status);
        }

    } catch (objError) {
        if (objError.response) {
            console.error('Erro na API:', objError.response.status, objError.response.data);
        } else {
            console.error('Erro:', objError.message);
        }
    }
}

main();
PHP (cURL) Baixar
<?php

$strBaseUrl = 'https://cfsbrasil.com.br/api';
$strEmail = 'seu@email.com';
$strPassword = 'sua_senha';

function makeRequest($strUrl, $strMethod = 'GET', $arrData = null, $strToken = null) {
    $objCurl = curl_init();

    $arrHeaders = ['Content-Type: application/json'];
    if ($strToken) {
        $arrHeaders[] = 'Authorization: Bearer ' . $strToken;
    }

    $arrOptions = [
        CURLOPT_URL => $strUrl,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $strMethod,
        CURLOPT_HTTPHEADER => $arrHeaders,
    ];

    if ($arrData) {
        $arrOptions[CURLOPT_POSTFIELDS] = json_encode($arrData);
    }

    curl_setopt_array($objCurl, $arrOptions);
    
    $strResponse = curl_exec($objCurl);
    $iHttpCode = curl_getinfo($objCurl, CURLINFO_HTTP_CODE);
    
    curl_close($objCurl);

    return ['code' => $iHttpCode, 'body' => $strResponse];
}

echo "1. Realizando autenticacao...\n";

// 1. Login
$arrLoginData = [
    'email' => $strEmail,
    'password' => $strPassword
];

$arrLoginResponse = makeRequest($strBaseUrl . '/login', 'POST', $arrLoginData);

if ($arrLoginResponse['code'] >= 200 && $arrLoginResponse['code'] <= 299) {
    $objBody = json_decode($arrLoginResponse['body']);
    $strToken = $objBody->token ?? null;

    if ($strToken) {
        echo "Login com sucesso! Token: " . substr($strToken, 0, 20) . "...\n\n";

        // 2. Consultar Serviços Oficiais
        echo "2. Consultando Servicos Oficiais...\n";
        
        $arrServicesResponse = makeRequest($strBaseUrl . '/official-services', 'GET', null, $strToken);
        
        if ($arrServicesResponse['code'] >= 200 && $arrServicesResponse['code'] <= 299) {
            echo "Status: " . $arrServicesResponse['code'] . "\n";
            echo "Dados (primeiros 100 chars): " . substr($arrServicesResponse['body'], 0, 100) . "...\n";
        } else {
            echo "Erro ao consultar servicos: " . $arrServicesResponse['code'] . "\n";
        }
        echo "\n";

        // -------------------------------------------------------------------
        // 3. Enviar Nota Fiscal de Serviço (XML)
        // -------------------------------------------------------------------
        echo "3. Enviando Nota Fiscal (XML)...\n";
        
        $strXmlExemplo = "<Rps><InfRps><DataEmissao>2023-10-25</DataEmissao><Servico><ValorServico>100.00</ValorServico></Servico></InfRps></Rps>";
        
        $arrInvoiceResponse = makeRequest($strBaseUrl . '/service-invoices', 'POST', [
            'xmlContent' => $strXmlExemplo
        ], $strToken);
        
        if ($arrInvoiceResponse['code'] == 201) {
            $objInvoiceBody = json_decode($arrInvoiceResponse['body']);
            echo "Nota enviada com sucesso!\n";
            echo "Créditos adicionados: " . $objInvoiceBody->creditsAdded . "\n";
            echo "Saldo atual: " . $objInvoiceBody->currentCredits . "\n";
        } else {
            echo "Erro ao enviar nota: " . $arrInvoiceResponse['code'] . "\n";
            echo "Resposta: " . $arrInvoiceResponse['body'] . "\n";
        }

    } else {
        echo "Token nao encontrado na resposta.\n";
    }
} else {
    echo "Erro no login: " . $arrLoginResponse['code'] . "\n";
    echo "Resposta: " . $arrLoginResponse['body'] . "\n";
}