Ejemplo en GO

Ejemplo de uso del API SAT en go.

Archivo fuente: go.go

// Ejemplo Go — POST /api/v1/usuario/datos-fiscales

// Uso:

//   export SAT_API_KEY="sat_xxxxxxxxxxxx"

//   go run go.go [RFC]


package main

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

type SatApiClient struct {
	APIKey    string
	BaseURL   string
	UserAgent string
	HTTP      *http.Client
}

type ApiResponse struct {
	Body struct {
		CfdiCodigo      int                    `json:"cfdi_codigo"`
		CfdiTexto       string                 `json:"cfdi_texto"`
		CfdiDescripcion string                 `json:"cfdi_descripcion"`
		Saldo           int                    `json:"saldo"`
		Data            map[string]interface{} `json:"data"`
	} `json:"body"`
	HTTPStatus int `json:"http_status"`
	LatenciaMs int `json:"latencia_ms"`
}

func NewClient(apiKey string) *SatApiClient {
	return &SatApiClient{
		APIKey:    apiKey,
		BaseURL:   "https://api.cfdi4.com",

		UserAgent: "go-sat-api/1.0",
		HTTP:      &http.Client{Timeout: 30 * time.Second},
	}
}

func (c *SatApiClient) post(endpoint string, body map[string]string) (*ApiResponse, error) {
	url := c.BaseURL + endpoint
	jsonBody, _ := json.Marshal(body)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+c.APIKey)
	req.Header.Set("User-Agent", c.UserAgent)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var apiResp ApiResponse
	if err := json.Unmarshal(data, &apiResp); err != nil {
		return nil, fmt.Errorf("respuesta no parseable: %s", string(data))
	}

	return &apiResp, nil
}

func (c *SatApiClient) DatosFiscales(rfc string) (*ApiResponse, error) {
	return c.post("/api/v1/usuario/datos-fiscales", map[string]string{
		"rfc": strings.ToUpper(strings.TrimSpace(rfc)),
	})
}

func main() {
	apiKey := os.Getenv("SAT_API_KEY")
	if apiKey == "" {
		fmt.Fprintln(os.Stderr, "ERROR: configura la variable de entorno SAT_API_KEY")
		fmt.Fprintln(os.Stderr, "  export SAT_API_KEY=\"sat_xxxxxxxxxxxx\"")
		os.Exit(1)
	}

	rfc := "XAXX010101000"
	if len(os.Args) > 1 {
		rfc = os.Args[1]
	}

	client := NewClient(apiKey)
	fmt.Printf("Consultando datos fiscales de RFC: %s\n\n", rfc)

	result, err := client.DatosFiscales(rfc)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("  Código:    %d\n", result.Body.CfdiCodigo)
	fmt.Printf("  Texto:     %s\n", result.Body.CfdiTexto)
	fmt.Printf("  Detalle:   %s\n", result.Body.CfdiDescripcion)
	fmt.Printf("  Saldo:     %d créditos\n", result.Body.Saldo)
	fmt.Printf("  Latencia:  %dms\n", result.LatenciaMs)

	if result.Body.CfdiCodigo == 1 {
		fmt.Println("\n  Datos fiscales:")
		dataJSON, _ := json.MarshalIndent(result.Body.Data, "  ", "  ")
		fmt.Printf("  %s\n", dataJSON)
		os.Exit(0)
	}

	if result.Body.CfdiCodigo == 1004 {
		fmt.Println("\n  ⚠️  Saldo insuficiente. Recarga en https://panel.cfdi4.com/saldos")

	} else if result.Body.CfdiCodigo == 1001 {
		fmt.Println("\n  ⚠️  API key inválida. Verifica la variable SAT_API_KEY")
	}
	os.Exit(1)
}