Saltar al contenido principal
El SDK de Go se distribuye como un módulo Go estándar. No hay registry separado — go get baja el código directo de GitHub. El SDK provee una función tipada por cada endpoint de OrigoID y sigue patrones Go idiomáticos (context.Context, structs exportados, errores explícitos).

Instalación

go get github.com/origoid/sdk-go@v0.1.0
O agrega a go.mod:
require github.com/origoid/sdk-go v0.1.0
Luego corre go mod tidy. Código en github.com/origoid/sdk-go (público, para auditar). Requiere Go 1.21 o más reciente.

Inicializa el cliente

package main

import (
    "fmt"
    "os"

    "github.com/origoid/sdk-go/client"
    "github.com/origoid/sdk-go/option"
)

func main() {
    c := client.NewClient(
        option.WithAPIKey(os.Getenv("ORIGOID_API_KEY")),
    )
    _ = c
    fmt.Println("client ready")
}
Ese es todo el setup — no hay nada más que configurar. Nunca hardcodees la key. Léela de os.Getenv, viper, o un secrets manager (HashiCorp Vault, 1Password, Doppler, etc.).

Tu primera llamada

El ejemplo usa PELJ900101HDFRRN09, un CURP sintético de los ejemplos del OpenAPI — no es CURP de persona real. Reemplázalo con el CURP que necesites validar.
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    origoid "github.com/origoid/sdk-go"
    "github.com/origoid/sdk-go/client"
    "github.com/origoid/sdk-go/option"
)

func main() {
    c := client.NewClient(
        option.WithAPIKey(os.Getenv("ORIGOID_API_KEY")),
    )

    env, err := c.Renapo.ValidateCurp(
        context.Background(),
        &origoid.ValidateCurpRequest{
            Curp: "PELJ900101HDFRRN09", // sintético — reemplazar con input real
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    if env.Status == "OK" && env.Type == "SUCCESS" {
        // env.Data trae el registro RENAPO.
        fmt.Println("Titular del CURP:", env.Data)
    } else {
        // Otro tipo de resultado — revisa el catálogo de respuestas del endpoint para tu lógica.
        fmt.Println(env.Type, "—", env.Message)
    }
}
Cada método devuelve (*origoid.Envelope, error). La shape del envelope es { Status, Type, Message, Data, TransactionId, ProcessedAt, Billable, Errors }. Ver Envelope de respuesta para el contrato.

Métodos por recurso

El cliente agrupa operaciones por dominio regulatorio.

c.Authentication

c.Authentication.IssueToken(ctx, &origoid.IssueTokenRequest{ExpireAfter: 1800})

c.Renapo

c.Renapo.ValidateCurp(ctx, &origoid.ValidateCurpRequest{
    Curp: "PELJ900101HDFRRN09",
})

c.Renapo.LookupCurp(ctx, &origoid.LookupCurpRequest{
    GivenNames:     "JUAN",
    FirstSurname:   "PEREZ",
    SecondSurname:  origoid.String("LOPEZ"),
    DateOfBirth:    "1990-01-01",
    Gender:         origoid.LookupCurpRequestGenderH,
    BirthStateCode: "DF",
})
origoid.String(...) es un helper para campos string opcionales (Go no tiene Option<T>; la opcionalidad se modela con punteros).

c.Sat

c.Sat.ValidateRfc(ctx, &origoid.ValidateRfcRequest{Rfc: "PEZJ811011KI1"})

c.Sat.ExtractCsf(ctx, map[string]any{
    "rfc": "PEZJ811011KI1",
    "cif": "17060597619",
})

c.Sat.ValidateCfdi(ctx, map[string]any{
    "uuid":        "7C8BD4EA-AE86-4CB5-88B8-C6E61E988A8B",
    "rfcEmisor":   "PEZJ811011KI1",
    "rfcReceptor": "EMP170623KI3",
    "total":       "999999.99",
})
ExtractCsf y ValidateCfdi aceptan map[string]any porque los schemas permiten shapes alternativas (identificadores directos O upload de documento).

c.Imss

c.Imss.LookupNss(ctx, &origoid.LookupNssRequest{Curp: "PELJ900101HDFRRN09"})

c.Imss.GetEmploymentStatus(ctx, &origoid.GetEmploymentStatusRequest{
    Curp: "PELJ900101HDFRRN09",
    Nss:  "92038109713",
})

c.Ine

c.Ine.ValidateVoterList(ctx, map[string]any{
    "cic":               "123456789",
    "citizenIdentifier": "987654321",
})

c.Ine.ExtractVoterIdData(ctx, &origoid.ExtractVoterIdDataRequest{
    Front: "<jpg base64>",
    Back:  origoid.String("<jpg base64>"),
})

c.Ine.ExtractQrData(ctx, &origoid.ExtractQrDataRequest{
    Back: "<jpg base64 del reverso>",
})

c.Compliance

c.Compliance.SearchSat69(ctx, map[string]any{"rfc": "PEZJ811011KI1"})
c.Compliance.SearchSat69B(ctx, map[string]any{"rfc": "PEZJ811011KI1"})

c.Compliance.SearchOfac(ctx, &origoid.SearchOfacRequest{
    Name:               "John Doe",
    MinSimilarityScore: origoid.Int(85),
})

c.Compliance.SearchPeps(ctx, map[string]any{
    "givenNames":    "JUAN",
    "firstSurname":  "PEREZ",
    "secondSurname": "LOPEZ",
})

c.Biometrics

c.Biometrics.MatchFaces(ctx, &origoid.MatchFacesRequest{
    Face:         "<selfie base64>",
    Front:        "<frente id base64>",
    Threshold:    origoid.Int(80),
    DocumentType: origoid.MatchFacesRequestDocumentTypeIne.Ptr(),
})

c.Biometrics.CheckLiveness(ctx, &origoid.CheckLivenessRequest{
    Selfie: "<selfie base64>",
})

c.Email

c.Email.ValidateEmail(ctx, &origoid.ValidateEmailRequest{
    Email: "user@example.com",
})

c.ProofOfAddress

c.ProofOfAddress.ExtractProofOfAddress(ctx, &origoid.ExtractProofOfAddressRequest{
    File: "<pdf o jpg base64>",
})

Manejo de errores

El SDK distingue entre errores de negocio (vienen dentro del envelope) y errores de transporte (devueltos como error no nulo).

Errores de negocio — inspecciona el envelope

Para cualquier HTTP 200, incluyendo INVALID_REQUEST, el SDK devuelve un *Envelope normal. Revisa Status y Type antes de usar Data:
env, err := c.Renapo.ValidateCurp(ctx, &origoid.ValidateCurpRequest{Curp: "BAD"})
if err != nil {
    log.Fatal(err)
}

switch env.Type {
case "SUCCESS":
    // env.Data trae el registro
case "CURP_NOT_FOUND":
    // sin match
case "INVALID_REQUEST":
    for _, e := range env.Errors {
        fmt.Printf("  %s: %s%s\n", e.Field, e.Code, e.Message)
    }
}

Errores de transporte — error no nulo

Para 401, 429, fallas de red, el SDK devuelve un error tipado:
import "errors"

env, err := c.Renapo.ValidateCurp(ctx, req)
if err != nil {
    var unauth *origoid.UnauthorizedError
    var rl *origoid.TooManyRequestsError
    switch {
    case errors.As(err, &unauth):
        // 401
    case errors.As(err, &rl):
        // 429 — lee rl.Body para el envelope de rate-limit
    default:
        // red / timeout / inesperado
        log.Fatal(err)
    }
}

Configuración por llamada (avanzado)

Usa helpers option.With* como argumentos adicionales:
import "time"

env, err := c.Ine.ValidateVoterList(
    ctx,
    map[string]any{"cic": "123456789", "citizenIdentifier": "987654321"},
    option.WithRequestTimeout(120 * time.Second),
    option.WithMaxAttempts(3),
)
Pasa un context.Context para respetar deadlines o cancelaciones del caller; el SDK respeta ctx.Done() y aborta requests en vuelo.
Lee esto antes de tunear timeouts o retries. El SDK sólo reintenta errores 5xx y fallas de red, nunca respuestas de negocio exitosas — entonces los retries no crean llamadas duplicadas facturables cuando el API respondió correctamente. crean llamadas extra cuando el request realmente falló: un request que hace timeout tres veces puede consumir tres créditos si la llamada eventualmente tuvo éxito en un intento posterior.
  • Los defaults (60 s, 2 reintentos) son correctos para casi cualquier workload. Cambia sólo con razón específica.
  • Combinar timeout largo con MaxAttempts alto (ej. 120 s × 5) significa que un único request fallando puede ocupar una goroutine hasta 10 minutos — malo para tu throughput y tu infraestructura.
  • Sobrescribe per-call sólo en endpoints con cold starts lentos conocidos.

Punteros para campos opcionales

Go no tiene Option<T>, así que los campos opcionales en structs de request son tipos puntero. El SDK expone helpers para hacerlo menos verboso:
origoid.String("valor opcional")  // *string
origoid.Int(42)                   // *int
origoid.Bool(true)                // *bool
Para enums:
origoid.MatchFacesRequestDocumentTypeIne.Ptr()