flashpi

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2026 License: MIT Imports: 27 Imported by: 0

README

Flashpi para Go

SDK oficial de Flashpi, la API de facturación electrónica del SRI de Ecuador, para Go.

English

  • Las 45 operaciones de la API: los seis comprobantes, documentos (XML, RIDE en PDF, correo), emisores con establecimientos, puntos de emisión y certificados .p12, webhooks y eventos.
  • Structs generados del documento OpenAPI de la API: tu editor y el compilador conocen cada campo.
  • context.Context en cada llamada, listas que se recorren con range y errores que se revisan con errors.As.
  • Reintentos seguros: cada emisión lleva un Idempotency-Key, así un reintento nunca emite dos veces.
  • Errores tipados (RFC 9457) con su Code, los errores por campo y el RequestID.
  • Verificación de firmas de webhooks (Standard Webhooks) con net/http o cualquier framework.
  • Go 1.26 o superior. Sin dependencias: solo la biblioteca estándar.

Instalación

go get github.com/flashpi1/flashpi-go

Primeros pasos

Crea una clave de API en la consola y guárdala en la variable de entorno FLASHPI_API_KEY. Una clave fp_test_ emite en el ambiente de pruebas del SRI; una fp_live_ emite comprobantes reales en producción.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/flashpi1/flashpi-go"
)

func main() {
	// Lee FLASHPI_API_KEY; también puedes pasarla: flashpi.NewClient(flashpi.WithAPIKey("fp_test_..."))
	client, err := flashpi.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	invoice, err := client.Invoices.Create(context.Background(), flashpi.CreateInvoice{
		IssuerID:      "<id del emisor demo o del tuyo>",
		Establishment: "001",
		EmissionPoint: "001",
		Customer: flashpi.DocumentParty{
			IDType:  flashpi.IDTypeRUC,
			ID:      new("1760013210001"),
			Name:    new("PRUEBAS SERVICIO DE RENTAS INTERNAS"),
			Address: new("Av. Amazonas y Villalengua, Quito"),
		},
		Items: []flashpi.DocumentItem{{
			Code:        new("P-001"),
			Description: "Servicio de prueba",
			Quantity:    "1",
			UnitPrice:   "1.00",
			Taxes:       []flashpi.DocumentTax{{Type: flashpi.TaxTypeVAT, Rate: "15"}},
		}},
		Payments: []flashpi.DocumentPayment{{Method: flashpi.PaymentMethodCash, Amount: "1.15"}},
		Options:  &flashpi.DocumentOptions{WaitForAuthorization: new(true)},
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(invoice.Status, invoice.AccessKey)
}

Las peticiones y las respuestas son structs con los campos de la API (invoice.AccessKey es accessKey). Los campos opcionales son punteros: new("valor") los crea (los que aceptan null son flashpi.Nullable, más abajo). Los montos y cantidades son textos ("1.15"), nunca números, para no perder decimales.

Con el emisor demo puedes emitir en pruebas sin subir un certificado: su id está en el Resumen de la consola (hasta 50 comprobantes al día). Más en Sandbox y emisor demo.

Un cliente mantiene sus conexiones abiertas y se puede usar desde varias goroutines: crea uno y reutilízalo.

Emitir comprobantes

Comprobante Método
Factura client.Invoices.Create(ctx, body)
Nota de crédito client.CreditNotes.Create(ctx, body)
Nota de débito client.DebitNotes.Create(ctx, body)
Liquidación de compra client.PurchaseSettlements.Create(ctx, body)
Guía de remisión client.Waybills.Create(ctx, body)
Retención client.Withholdings.Create(ctx, body)

Todos devuelven el documento. Por defecto la respuesta llega enseguida con el estado processing y el resultado del SRI llega por webhook. Con Options: &flashpi.DocumentOptions{WaitForAuthorization: new(true)} la API espera la respuesta del SRI (15 s por defecto, hasta 30 s con WaitTimeoutSeconds) y devuelve authorized, rejected o failed; si el SRI tarda más, devuelve processing o pending_sri y el documento sigue su curso.

Documentos

document, err := client.Documents.Get(ctx, invoice.ID)
if err != nil {
	return err
}
fmt.Println(document.Status)

xml, err := client.Documents.XML(ctx, invoice.ID)
if err != nil {
	return err
}
fmt.Println(xml.Kind) // flashpi.DocumentXMLKindAuthorized cuando ya lo autorizó el SRI

pdf, err := client.Documents.PDF(ctx, invoice.ID) // el RIDE, en bytes
if err != nil {
	return err
}
if err := os.WriteFile(invoice.AccessKey+".pdf", pdf, 0o644); err != nil {
	return err
}

// Reenvía RIDE y XML al correo del comprador.
if _, err := client.Documents.SendEmail(ctx, invoice.ID, nil); err != nil {
	return err
}

Listas y paginación

List recorre todas las páginas con range, pidiéndolas a medida que avanzas. Si una página falla, recibes el error en err:

params := &flashpi.DocumentListParams{
	Status:        new(flashpi.DocumentStatusAuthorized),
	IssueDateFrom: new("2026-11-01"),
}
for document, err := range client.Documents.List(ctx, params) {
	if err != nil {
		return err
	}
	fmt.Println(document.AccessKey)
}

ListPage devuelve una página a la vez, y NextPage la siguiente (nil después de la última):

page, err := client.Documents.ListPage(ctx, &flashpi.DocumentListParams{Limit: new(50)})
for page != nil && err == nil {
	fmt.Println(len(page.Data)) // los documentos de esta página
	page, err = page.NextPage(ctx)
}
if err != nil {
	return err
}

Los filtros usan los nombres de la API (IssueDateFrom, IssuerID), y nil significa sin filtros. Limit es el tamaño de cada página: List recorre todas, así que sal del for con break cuando tengas lo que buscabas.

Errores

Cada error de la API es un *flashpi.APIError, envuelto en un tipo propio cuando su estado HTTP lo tiene (los de la tabla; los demás, como 405 o 413, llegan como *flashpi.APIError). Revísalo con errors.As y decide según Code, que es estable y en inglés; Message sigue el idioma pedido.

_, err := client.Invoices.Create(ctx, body)

var invalid *flashpi.UnprocessableEntityError
var apiErr *flashpi.APIError
switch {
case errors.As(err, &invalid):
	fmt.Println(invalid.Code) // "validation_failed", "total_mismatch", ...
	for _, field := range invalid.Errors {
		fmt.Println(field.Field, field.Message)
	}
case errors.As(err, &apiErr):
	fmt.Println(apiErr.Status, apiErr.Code, apiErr.RequestID) // comparte RequestID con soporte
case err != nil:
	return err // sin respuesta de la API: *flashpi.ConnectionError, *flashpi.TimeoutError, ...
}
Tipo Estado Ejemplos de Code
BadRequestError 400 malformed_json, invalid_idempotency_key
AuthenticationError 401 authentication_required, invalid_api_key
PermissionDeniedError 403 key_read_only, key_scope_mismatch, ip_not_allowed
NotFoundError 404 not_found
ConflictError 409 sequential_already_used, ride_not_available
UnprocessableEntityError 422 validation_failed, total_mismatch
RateLimitError 429 demo_issuer_quota_exceeded, account_email_limit_reached
InternalServerError 5xx internal_error
ConnectionError — sin respuesta (red); TimeoutError si se agotó el plazo

Todos se leen también como *flashpi.Error con errors.As. Algunos errores traen datos extra en apiErr.Problem, por ejemplo DocumentID, Limit, ResetsAt o RIDEStatus. Para recibir los mensajes en español: flashpi.NewClient(flashpi.WithLanguage(flashpi.LanguageSpanish)).

Reintentos e idempotencia

El SDK reintenta hasta 2 veces, con espera creciente, los errores de red, los tiempos agotados y las respuestas 408, 429 y 5xx, salvo un 501, un 503 demo_issuer_unavailable y las que piden esperar (Retry-After) más de 60 s; también reintenta un 409 idempotency_key_in_progress. Cada POST lleva un Idempotency-Key que se repite en sus reintentos, así que la API nunca emite dos veces:

  • Si un reintento descubre que el primer intento sí creó el documento, el SDK devuelve ese documento.
  • Si el primer intento sigue en curso en la API (por ejemplo, se cortó la conexión mientras esperaba al SRI), el SDK espera a que termine con la misma clave, hasta el tiempo límite de la llamada, sin gastar reintentos.

Para usar tu propia clave (por ejemplo el id de tu pedido), pásala a la llamada:

_, err := client.Invoices.Create(ctx, body, flashpi.WithIdempotencyKey("pedido-"+order.ID))
if err != nil {
	return err
}

Si una emisión falla igual, el error trae la clave que usó en IdempotencyKey. Reintentar con flashpi.WithIdempotencyKey(key) nunca emite un segundo documento: dentro de 24 horas la API devuelve la primera respuesta; después (o si la API perdió el primer intento), la llamada falla con un 422 idempotency_key_reused cuyo Problem.DocumentID es el documento que ya existe (léelo con client.Documents.Get).

_, err := client.Invoices.Create(ctx, body)
var flashpiErr *flashpi.Error
if errors.As(err, &flashpiErr) && flashpiErr.IdempotencyKey != "" {
	saveForRetry(body, flashpiErr.IdempotencyKey) // tu cola de reintentos
}

El ctx limita la llamada entera, reintentos incluidos. Si se cancela o vence, la llamada se detiene sin reintentar y devuelve un *flashpi.Error con su clave, con el que errors.Is(err, context.Canceled) (o context.DeadlineExceeded) es verdadero. Un intento que agota su propio plazo (flashpi.WithTimeout) también cumple context.DeadlineExceeded, como en net/http: revisa primero *flashpi.TimeoutError o ctx.Err() para distinguirlos.

Los límites diarios (como la cuota del emisor demo) no se reintentan: llegan como *flashpi.RateLimitError, y su RetryAfter() dice cuánto esperar.

Webhooks

Verifica cada webhook con el cuerpo tal cual llegó (sin parsear) y el secreto whsec_ del endpoint. flashpi.UnwrapWebhook no necesita clave de API ni hace E/S, y devuelve el evento: usa un switch de tipos.

package main

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/flashpi1/flashpi-go"
)

func main() {
	http.HandleFunc("POST /webhooks/flashpi", flashpiWebhook)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func flashpiWebhook(w http.ResponseWriter, r *http.Request) {
	// El cuerpo llega antes de verificar la firma: limita su tamaño.
	body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 10<<20))
	if err != nil {
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		return
	}
	event, err := flashpi.UnwrapWebhook(body, r.Header, os.Getenv("FLASHPI_WEBHOOK_SECRET"))
	var invalid *flashpi.WebhookVerificationError
	switch {
	case errors.As(err, &invalid) && invalid.Reason == flashpi.WebhookInvalidSecret:
		// Un secreto vacío o mal copiado es tu configuración, no un webhook falso.
		log.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	case errors.As(err, &invalid):
		w.WriteHeader(http.StatusBadRequest)
		return
	case err != nil:
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	switch e := event.(type) {
	case *flashpi.WebhookEndpointVerificationEvent:
		// La activación del endpoint: responde el desafío.
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]string{"challenge": e.Data.Challenge})
		return
	case *flashpi.DocumentEvent: // e.Data es el documento
		switch e.Type {
		case flashpi.DocumentEventTypeInvoiceAuthorized:
			log.Println("Autorizada", e.Data.AccessKey)
		case flashpi.DocumentEventTypeInvoiceRejected:
			log.Println("Rechazada", e.Data.SRIMessages)
		}
	}
	w.WriteHeader(http.StatusNoContent)
}

Con Gin, Echo, chi o Fiber pasa igual el cuerpo crudo y las cabeceras de la petición. Responde 400 a un webhook que no pasa la verificación, salvo WebhookInvalidSecret: ese es tu secreto, no el webhook, así que regístralo y responde 500 (Flashpi lo reintentará).

Guarda event.Info().ID y descarta los repetidos: un evento puede llegar más de una vez. Durante una rotación del secreto, Flashpi firma con el nuevo y el anterior, así que cualquiera de los dos sirve. Si el endpoint usa el modo thin (sin data), el evento es un *flashpi.ThinEvent: pide el evento completo con client.Events.Get(ctx, e.ID). Un tipo de evento que esta versión no conoce llega como *flashpi.UnknownEvent.

Emisores y certificados

Estas operaciones necesitan una clave de toda la cuenta con acceso de lectura y escritura.

Un emisor nace de su firma electrónica (.p12): Flashpi la verifica, lee el RUC y consulta al SRI, y te devuelve un Prefill con lo que encontró para que armes el emisor.

p12, err := os.ReadFile("firma.p12")
if err != nil {
	return err
}
onboarding, err := client.IssuerOnboardings.Create(ctx, flashpi.CertificateUpload{
	File:     bytes.NewReader(p12),
	Password: os.Getenv("P12_PASSWORD"),
})
for err == nil && onboarding.Status == flashpi.IssuerOnboardingStatusVerifying {
	time.Sleep(2 * time.Second)
	onboarding, err = client.IssuerOnboardings.Get(ctx, onboarding.ID)
}
if err != nil {
	return err
}
if onboarding.Status != flashpi.IssuerOnboardingStatusReady {
	return fmt.Errorf("la firma no sirve: %v", onboarding.Rejection)
}

var completed *flashpi.CompletedIssuerOnboarding
if onboarding.ExistingIssuer != nil {
	// Ya tienes ese RUC: el certificado se agrega a ese emisor (una renovación).
	completed, err = client.IssuerOnboardings.Complete(ctx, onboarding.ID, nil)
} else {
	// Un RUC nuevo: tú confirmas los datos del emisor, partiendo del prefill.
	issuer := flashpi.CompleteIssuerOnboarding{
		LegalName:         new("MI EMPRESA S.A."),
		HeadOfficeAddress: new("Av. Amazonas N24-100, Quito"),
		TaxProfile:        &flashpi.IssuerTaxProfileInput{KeepsAccounting: false},
		// Si onboarding.RUCNeedsConfirmation es true, envía también RUC.
	}
	if prefill := onboarding.Prefill; prefill != nil {
		issuer.LegalName = cmp.Or(prefill.LegalName, issuer.LegalName)
		issuer.HeadOfficeAddress = cmp.Or(prefill.HeadOfficeAddress, issuer.HeadOfficeAddress)
		issuer.TaxProfile.KeepsAccounting = prefill.TaxProfile.KeepsAccounting != nil && *prefill.TaxProfile.KeepsAccounting
		if regime := prefill.TaxProfile.RIMPERegime; regime != nil && *regime != flashpi.IssuerOnboardingPrefillTaxProfileRIMPERegimeGeneral {
			issuer.TaxProfile.RIMPERegime = flashpi.NullableOf(flashpi.RIMPERegime(*regime))
		}
		// Si es contribuyente especial o agente de retención, agrega sus resoluciones.
	}
	completed, err = client.IssuerOnboardings.Complete(ctx, onboarding.ID, &issuer)
}
if err != nil {
	return err
}

for establishment, err := range client.Issuers.Establishments.List(ctx, completed.Issuer.ID, nil) {
	if err != nil {
		return err
	}
	fmt.Println(establishment.Code)
}

El File es un io.Reader (los bytes del .p12 con bytes.NewReader, o un *os.File abierto), de hasta 1 MiB. El SDK lo lee una vez, antes de enviar nada, y no lo cierra.

Para renovar la firma de un emisor, para pruebas y producción a la vez, repite el mismo flujo con el .p12 nuevo: Flashpi reconoce el RUC (ExistingIssuer) y Complete sin datos agrega el certificado. En cambio, client.Issuers.Certificates.Upload(ctx, issuerID, flashpi.CertificateUpload{...}) sube un certificado solo para el modo de la clave que usas (pruebas o producción).

Campos opcionales y null

Los campos opcionales son punteros (nil no se envía) y new(valor) los crea. Los campos que una petición puede enviar como null son flashpi.Nullable: flashpi.Null envía null (en una actualización, borra el campo), flashpi.NullableOf envía un valor y sin asignar no se envía. Están en las actualizaciones y también en algunas creaciones, como RIMPERegime del perfil tributario o Description de un endpoint de webhooks.

_, err := client.Issuers.Update(ctx, issuerID, flashpi.UpdateIssuer{
	TradeName:          flashpi.Null[string](), // borra el nombre comercial
	SendEmailByDefault: new(false),
	Branding:           &flashpi.IssuerBrandingInput{BrandColor: flashpi.NullableOf("#0C160D")},
})
if err != nil {
	return err
}

Opciones

client, err := flashpi.NewClient(
	flashpi.WithAPIKey(os.Getenv("FLASHPI_API_KEY")), // por defecto, la variable FLASHPI_API_KEY
	flashpi.WithLanguage(flashpi.LanguageSpanish),    // idioma de los mensajes: inglés (por defecto) o español
	flashpi.WithTimeout(60*time.Second),              // por intento (con waitForAuthorization, al menos la espera + 15 s)
	flashpi.WithMaxRetries(2),                        // 0 desactiva los reintentos
)
if err != nil {
	return err
}
fmt.Println(client) // muestra el ambiente y la URL, nunca la clave

Cada método acepta además, al final, opciones de esa llamada: flashpi.WithIdempotencyKey, flashpi.WithTimeout, flashpi.WithMaxRetries, flashpi.WithLanguage, flashpi.WithCorrelationID (tu propio id, que Flashpi registra) y flashpi.WithHeader.

document, err := client.Documents.Get(ctx, documentID,
	flashpi.WithTimeout(10*time.Second),
	flashpi.WithLanguage(flashpi.LanguageSpanish),
	flashpi.WithCorrelationID("pedido-42"),
)
if err != nil {
	return err
}
fmt.Println(document.Status)

Para ver la respuesta HTTP y el id de la petición, pasa flashpi.WithResponseInto:

var response flashpi.Response
document, err := client.Documents.Get(ctx, documentID, flashpi.WithResponseInto(&response))
if err != nil {
	return err
}
fmt.Println(document.Status, response.StatusCode, response.RequestID)

Para enviar las peticiones con tu propio *http.Client (un proxy, un transporte de pruebas), pásalo con flashpi.WithHTTPClient. El SDK nunca sigue redirecciones.

proxy, err := url.Parse("http://proxy.interno:3128")
if err != nil {
	return err
}
client, err := flashpi.NewClient(flashpi.WithHTTPClient(&http.Client{
	Transport: &http.Transport{Proxy: http.ProxyURL(proxy)},
}))
if err != nil {
	return err
}
fmt.Println(client.Environment())

En las pruebas, un httptest.Server (con flashpi.WithBaseURL) o un http.RoundTripper propio responde en lugar de la API.

Solo en el servidor

Tu clave de API es secreta: usa el SDK en tus servidores, nunca en código que corre en los dispositivos de tus usuarios. fmt.Println(client) muestra el ambiente y la URL, nunca la clave.

Licencia

MIT © 2026 SIGNIADIGITAL S.A.

Documentation

Overview

Package flashpi is the official Go SDK of Flashpi, the electronic invoicing API for Ecuador's SRI (https://flashpi.com.ec).

It covers the 45 operations of the API: the six document types, the issued documents (XML, RIDE as PDF, email), issuers with their establishments, emission points and .p12 certificates, webhook endpoints and events. It uses the standard library only.

client, err := flashpi.NewClient() // reads FLASHPI_API_KEY
if err != nil {
	log.Fatal(err)
}
invoice, err := client.Invoices.Create(ctx, flashpi.CreateInvoice{...})

Every method takes a context.Context first and options last (WithIdempotencyKey, WithTimeout, WithResponseInto, ...). Lists are iterators:

for document, err := range client.Documents.List(ctx, nil) {
	...
}

Errors are checked with errors.As: *APIError and its status types (*UnprocessableEntityError, *RateLimitError, ...), *ConnectionError and *TimeoutError, and *Error for everything else.

Every POST carries an Idempotency-Key that its retries reuse, so a retry never issues a document twice. UnwrapWebhook verifies the webhooks Flashpi sends (Standard Webhooks).

Index

Constants

View Source
const DefaultBaseURL = "https://api.flashpi.com.ec"

DefaultBaseURL is the address of the Flashpi API.

View Source
const DefaultMaxRetries = 2

DefaultMaxRetries is how many times a request is retried by default.

View Source
const DefaultTimeout = 60 * time.Second

DefaultTimeout is how long each attempt of a request may take by default, from sending it to reading the whole answer.

View Source
const DefaultWebhookTolerance = 300 * time.Second

DefaultWebhookTolerance is the largest gap between a webhook's timestamp and the receiver's clock that UnwrapWebhook and VerifyWebhookSignature accept by default.

View Source
const MaxCertificateBytes = 1_048_576

MaxCertificateBytes is the largest .p12 the API accepts (413 payload_too_large above it).

View Source
const Version = "0.1.0" // x-release-please-version

Version is the version of this module, sent in the User-Agent of every request. release-please updates it on every release (the marker comment points it here).

Variables

This section is empty.

Functions

func VerifyWebhookSignature

func VerifyWebhookSignature(payload []byte, header http.Header, secret string, options ...WebhookOption) error

VerifyWebhookSignature checks that a webhook comes from Flashpi and is recent (Standard Webhooks). A webhook is signed with HMAC-SHA256 over webhook-id.webhook-timestamp.body using the endpoint's whsec_ secret; during a secret rotation Flashpi signs with both secrets, and either matches.

It returns a *WebhookVerificationError when the webhook must be refused (answer 400). Pass the raw body exactly as received: a body parsed and serialized again does not match. A negative tolerance is refused with an *Error, never by skipping the time check.

Types

type APIError

type APIError struct {
	// Message is the status, the code and the API's explanation: "422 validation_failed: ...".
	Message string

	// Status is the HTTP status of the answer.
	Status int

	// Code is the error code, or "" when the answer had no Problem Details (for example a 502
	// from a proxy). New codes may appear: handle an unknown one by its status.
	Code ErrorCode

	// Title is a short summary of the problem type.
	Title string

	// Detail says what went wrong in this request.
	Detail string

	// Errors lists the field-level problems of a request body or query (may be empty).
	Errors []FieldError

	// RequestID is Flashpi's id of the request (x-request-id): share it with support.
	RequestID string

	// Problem is the whole Problem Details body, with its extension members (DocumentID,
	// Limit, ResetsAt, ...; Extra for the ones this version does not declare), or nil.
	Problem *ProblemDetails

	// Header holds the headers of the answer.
	Header http.Header

	// IdempotencyKey is the Idempotency-Key of a failed POST: see Error.IdempotencyKey.
	IdempotencyKey string
}

APIError is an answer of the API with an error status. Its status has a type of its own (BadRequestError, UnprocessableEntityError, ...) that wraps it, so either can be asked for:

var invalid *flashpi.UnprocessableEntityError
if errors.As(err, &invalid) { ... }
var apiErr *flashpi.APIError
if errors.As(err, &apiErr) { ... } // any status

Branch on Code (stable English slugs such as validation_failed), never on Message, which follows the requested language.

func (*APIError) As

func (e *APIError) As(target any) bool

As lets errors.As read an APIError as an *Error.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) RetryAfter

func (e *APIError) RetryAfter() (time.Duration, bool)

RetryAfter is how long the API asked to wait before trying again (the Retry-After header), and whether it asked. Daily quota errors point at the next midnight in Ecuador, so it can be hours.

type AccountEmailSending

type AccountEmailSending struct {
	Environment Environment `json:"environment"`

	Status AccountEmailSendingStatus `json:"status"`

	// Format: date-time.
	PausedAt *time.Time `json:"pausedAt"`

	// Set while paused: `bounce_rate` (hard bounces), `complaint_rate` (complaints) or `staff`
	// (Flashpi's staff paused them).
	PauseReason *AccountEmailSendingPauseReason `json:"pauseReason"`

	Window AccountEmailSendingWindow `json:"window"`
}

AccountEmailSending: Whether the account's buyer emails of one mode go out. Flashpi pauses them when the last 7 days have at least 3 hard bounces and 3 % of the emails sent, or at least 2 complaints and 0.05 % (they protect the email provider's reputation that every customer shares). While paused, documents are still issued and authorized; their emails fail with `email_sending_paused` and resends answer 409 `email_sending_paused`. Only Flashpi's staff resume them.

type AccountEmailSendingPauseReason

type AccountEmailSendingPauseReason string

AccountEmailSendingPauseReason is a value of the API. Set while paused: `bounce_rate` (hard bounces), `complaint_rate` (complaints) or `staff` (Flashpi's staff paused them). The API may add values: keep a default case.

const (
	AccountEmailSendingPauseReasonBounceRate    AccountEmailSendingPauseReason = "bounce_rate"
	AccountEmailSendingPauseReasonComplaintRate AccountEmailSendingPauseReason = "complaint_rate"
	AccountEmailSendingPauseReasonStaff         AccountEmailSendingPauseReason = "staff"
)

The values of AccountEmailSendingPauseReason.

type AccountEmailSendingStatus

type AccountEmailSendingStatus string

AccountEmailSendingStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	AccountEmailSendingStatusActive AccountEmailSendingStatus = "active"
	AccountEmailSendingStatusPaused AccountEmailSendingStatus = "paused"
)

The values of AccountEmailSendingStatus.

type AccountEmailSendingWindow

type AccountEmailSendingWindow struct {
	// Where the counted period starts. Format: date-time.
	Since time.Time `json:"since"`

	// Emails the email provider accepted.
	Sent int `json:"sent"`

	// Of those, hard bounces (`bounce_permanent`: the address or the domain does not exist).
	HardBounces int `json:"hardBounces"`

	// Of those, emails the recipient marked as spam.
	Complaints int `json:"complaints"`
}

AccountEmailSendingWindow: The buyer emails the account sent in the last 7 days in this mode (since Flashpi's staff last resumed them, when that is later).

type AccountEvent

type AccountEvent struct {
	// Format: uuid.
	ID string `json:"id"`

	Type AccountEventType `json:"type"`

	// Mode of the resource.
	Environment Environment `json:"environment"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	Data AccountEmailSending `json:"data"`
}

AccountEvent: An event about the account's email sending: `data` is the AccountEmailSending as the API returned it when the event happened (texts in English).

func (*AccountEvent) Info

func (e *AccountEvent) Info() EventInfo

Info returns what every event has: its id, type, environment and creation time.

type AccountEventType

type AccountEventType string

AccountEventType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	AccountEventTypeAccountEmailPaused  AccountEventType = "account.email_paused"
	AccountEventTypeAccountEmailResumed AccountEventType = "account.email_resumed"
)

The values of AccountEventType.

type AuthenticationError

type AuthenticationError struct{ *APIError }

AuthenticationError is a 401: the API key is missing, malformed, unknown or revoked.

func (*AuthenticationError) Unwrap

func (e *AuthenticationError) Unwrap() error

Unwrap returns the APIError.

type BadRequestError

type BadRequestError struct{ *APIError }

BadRequestError is a 400: the request could not be read (malformed JSON, invalid Idempotency-Key, ...).

func (*BadRequestError) Unwrap

func (e *BadRequestError) Unwrap() error

Unwrap returns the APIError.

type Certificate

type Certificate struct {
	// Format: uuid.
	ID string `json:"id"`

	// Format: uuid.
	IssuerID string `json:"issuerId"`

	// Mode of the API key that uploaded it. A certificate of the issuer onboarding serves every
	// mode (`allModes`): it shows the mode of the API key that reads it.
	Environment Environment `json:"environment"`

	// Whether it serves every mode (test and live): a certificate uploaded through the issuer
	// onboarding (POST /v1/issuer-onboardings). False for one uploaded for one mode.
	AllModes bool `json:"allModes"`

	Status CertificateStatus `json:"status"`

	// Whether it signs documents now: accepted, within its validity and not blocked.
	Usable bool `json:"usable"`

	// Subject distinguished name.
	Subject *string `json:"subject"`

	// Distinguished name of the certification authority that issued it.
	IssuedBy *string `json:"issuedBy"`

	SerialNumber *string `json:"serialNumber"`

	// Format: date-time.
	ValidFrom *time.Time `json:"validFrom"`

	// Format: date-time.
	ValidUntil *time.Time `json:"validUntil"`

	// SHA-256 of the certificate, hex.
	SHA256Fingerprint *string `json:"sha256Fingerprint"`

	// The RUC found in the certificate, when its authority writes one.
	RUC *string `json:"ruc"`

	Revocation *CertificateRevocation `json:"revocation"`

	Rejection *CertificateRejection `json:"rejection"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

Certificate: An issuer's .p12 signing certificate. Flashpi checks the upload asynchronously (`processing`, then `accepted` or `rejected`); the file and its password are never returned.

type CertificateEvent

type CertificateEvent struct {
	// Format: uuid.
	ID string `json:"id"`

	Type CertificateEventType `json:"type"`

	// Mode of the resource.
	Environment Environment `json:"environment"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	Data Certificate `json:"data"`
}

CertificateEvent: An event about a .p12 certificate: `data` is the Certificate as the API returned it when the event happened (texts in English).

func (*CertificateEvent) Info

func (e *CertificateEvent) Info() EventInfo

Info returns what every event has: its id, type, environment and creation time.

type CertificateEventType

type CertificateEventType string

CertificateEventType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	CertificateEventTypeCertificateVerified    CertificateEventType = "certificate.verified"
	CertificateEventTypeCertificatePending     CertificateEventType = "certificate.pending"
	CertificateEventTypeCertificateBlocked     CertificateEventType = "certificate.blocked"
	CertificateEventTypeCertificateRevoked     CertificateEventType = "certificate.revoked"
	CertificateEventTypeCertificateReactivated CertificateEventType = "certificate.reactivated"
)

The values of CertificateEventType.

type CertificateListParams

type CertificateListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string
}

CertificateListParams holds the query of certificatesList (GET /v1/issuers/{issuerId}/certificates). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type CertificateRejection

type CertificateRejection struct {
	Code string `json:"code"`

	Message string `json:"message"`
}

CertificateRejection: Why the upload was rejected.

type CertificateRevocation

type CertificateRevocation struct {
	Status CertificateRevocationStatus `json:"status"`

	// Format: date-time.
	CheckedAt time.Time `json:"checkedAt"`

	// Format: date-time.
	NextCheckAt *time.Time `json:"nextCheckAt"`

	// Pending only: when it stops signing if still unverified. Format: date-time.
	BlockAt *time.Time `json:"blockAt"`

	BlockedReason *CertificateRevocationBlockedReason `json:"blockedReason"`
}

CertificateRevocation: Whether the certification authority revoked the certificate. `good`: verified not revoked. `pending`: could not be verified yet; it still signs until `blockAt` and is checked again hourly. `blocked`: still unverified after 7 days, or its chain is no longer trusted (`blockedReason`); it does not sign. `revoked`: never signs again.

type CertificateRevocationBlockedReason

type CertificateRevocationBlockedReason string

CertificateRevocationBlockedReason is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	CertificateRevocationBlockedReasonRevocationStatusUnverified CertificateRevocationBlockedReason = "revocation_status_unverified"
	CertificateRevocationBlockedReasonUntrustedCertificateChain  CertificateRevocationBlockedReason = "untrusted_certificate_chain"
)

The values of CertificateRevocationBlockedReason.

type CertificateRevocationStatus

type CertificateRevocationStatus string

CertificateRevocationStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	CertificateRevocationStatusGood    CertificateRevocationStatus = "good"
	CertificateRevocationStatusPending CertificateRevocationStatus = "pending"
	CertificateRevocationStatusBlocked CertificateRevocationStatus = "blocked"
	CertificateRevocationStatusRevoked CertificateRevocationStatus = "revoked"
)

The values of CertificateRevocationStatus.

type CertificateService

type CertificateService struct {
	// contains filtered or unexported fields
}

CertificateService manages the .p12 certificates (firmas electrónicas) of an issuer. See client.Issuers.Certificates.

func (*CertificateService) Get

func (s *CertificateService) Get(ctx context.Context, issuerID, certificateID string, options ...RequestOption) (*Certificate, error)

Get retrieves a certificate.

func (*CertificateService) List

func (s *CertificateService) List(ctx context.Context, issuerID string, params *CertificateListParams, options ...RequestOption) iter.Seq2[*Certificate, error]

List walks the certificates of an issuer, newest first, reading the pages as it goes. params may be nil.

func (*CertificateService) ListPage

func (s *CertificateService) ListPage(ctx context.Context, issuerID string, params *CertificateListParams, options ...RequestOption) (*Page[*Certificate], error)

ListPage reads the first page of an issuer's certificates, newest first; NextPage reads the next one.

func (*CertificateService) Upload

func (s *CertificateService) Upload(ctx context.Context, issuerID string, upload CertificateUpload, options ...RequestOption) (*Certificate, error)

Upload uploads a .p12 for the issuer, for the mode of the API key only (test or live). To renew the certificate of both modes, start an issuer onboarding with it instead.

Flashpi checks it in the background: the certificate starts processing, then becomes accepted (event certificate.verified, or certificate.pending while its revocation status cannot be checked) or rejected (no event: follow it with Get and read Rejection).

type CertificateStatus

type CertificateStatus string

CertificateStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	CertificateStatusProcessing CertificateStatus = "processing"
	CertificateStatusAccepted   CertificateStatus = "accepted"
	CertificateStatusRejected   CertificateStatus = "rejected"
)

The values of CertificateStatus.

type CertificateUpload

type CertificateUpload struct {
	// File is the .p12: bytes.NewReader(data), an *os.File, ... It is read once, to its end and
	// before anything is sent, so every retry sends the same bytes; a file over 1 MiB is
	// refused without reading it all. The SDK does not close it.
	File io.Reader

	// Password is the password of the .p12.
	Password string

	// Filename is the name sent with the file (default certificate.p12).
	Filename string
}

CertificateUpload is a .p12 certificate (firma electrónica) and its password, for client.Issuers.Certificates.Upload and client.IssuerOnboardings.Create.

type Client

type Client struct {
	// Invoices issues invoices (facturas).
	Invoices *InvoiceService

	// CreditNotes issues credit notes (notas de crédito).
	CreditNotes *CreditNoteService

	// DebitNotes issues debit notes (notas de débito).
	DebitNotes *DebitNoteService

	// PurchaseSettlements issues purchase settlements (liquidaciones de compra).
	PurchaseSettlements *PurchaseSettlementService

	// Waybills issues waybills (guías de remisión).
	Waybills *WaybillService

	// Withholdings issues withholding receipts (comprobantes de retención).
	Withholdings *WithholdingService

	// Documents reads every issued document: search, XML, RIDE (PDF) and email.
	Documents *DocumentService

	// Issuers manages the issuers (RUCs) with their establishments, emission points and
	// certificates.
	Issuers *IssuerService

	// IssuerOnboardings creates an issuer from its .p12 certificate.
	IssuerOnboardings *IssuerOnboardingService

	// WebhookEndpoints manages the URLs Flashpi sends events to.
	WebhookEndpoints *WebhookEndpointService

	// Events reads the events of documents, certificates and email sending.
	Events *EventService

	// Status reads the API's status.
	Status *StatusService
	// contains filtered or unexported fields
}

Client is the Flashpi API client. Create one with NewClient and reuse it: it is safe for concurrent use and keeps its connections open.

An fp_test_ key issues in the SRI test environment (pruebas); an fp_live_ key issues real documents in production. Use it on servers only: the key must stay secret.

func NewClient

func NewClient(options ...ClientOption) (*Client, error)

NewClient creates a client. Without WithAPIKey it reads the FLASHPI_API_KEY environment variable. It fails on a missing or malformed key and on settings it cannot use, before sending anything; the error never shows the key.

func (*Client) Environment

func (c *Client) Environment() Environment

Environment is EnvironmentTest for an fp_test_ key (SRI pruebas) and EnvironmentLive for an fp_live_ key (SRI production).

func (*Client) GoString

func (c *Client) GoString() string

GoString describes the client without its API key, for %#v.

func (*Client) String

func (c *Client) String() string

String describes the client without its API key.

type ClientOption

type ClientOption interface {
	// contains filtered or unexported methods
}

ClientOption configures a Client: pass it to NewClient.

func WithAPIKey

func WithAPIKey(key string) ClientOption

WithAPIKey sets the API key (fp_test_... or fp_live_...). Without it, NewClient reads the FLASHPI_API_KEY environment variable.

func WithBaseURL

func WithBaseURL(url string) ClientOption

WithBaseURL sets the API's address (default https://api.flashpi.com.ec).

func WithHTTPClient

func WithHTTPClient(client *http.Client) ClientOption

WithHTTPClient sends the requests with your own *http.Client (a proxy, a test transport). The SDK never follows redirects: it uses a copy of it whose CheckRedirect stops at the first answer. Its Timeout still applies on top of the SDK's.

type CompleteIssuerOnboarding

type CompleteIssuerOnboarding struct {
	// Required when the RUC did not come from the certificate (`rucNeedsConfirmation`): the
	// proposed RUC or another one whose first 10 digits are the holder's cédula. Otherwise it may
	// be left out, and must be the certificate's RUC when sent (422 `ruc_mismatch`).
	RUC *string `json:"ruc,omitempty"`

	// Razón social.
	LegalName *string `json:"legalName,omitempty"`

	// Nombre comercial.
	TradeName Nullable[string] `json:"tradeName,omitzero"`

	// Dirección matriz.
	HeadOfficeAddress *string `json:"headOfficeAddress,omitempty"`

	TaxProfile *IssuerTaxProfileInput `json:"taxProfile,omitempty"`

	Branding *IssuerBrandingInput `json:"branding,omitempty"`

	// As in POST /v1/issuers. Default: true.
	SendEmailByDefault *bool `json:"sendEmailByDefault,omitempty"`
}

CompleteIssuerOnboarding: The issuer to create, with the same fields as POST /v1/issuers (legalName, headOfficeAddress and taxProfile are required for a new issuer). For a renewal (`existingIssuer`) the body may be `{}`: the issuer is not changed (PATCH it if needed).

type CompletedIssuerOnboarding

type CompletedIssuerOnboarding struct {
	Issuer Issuer `json:"issuer"`

	Certificate Certificate `json:"certificate"`
}

CompletedIssuerOnboarding: The issuer (created, with establishment 001 and emission point 001, or the existing one for a renewal) and its new certificate, `processing` until Flashpi onboards it.

type ConflictError

type ConflictError struct{ *APIError }

ConflictError is a 409: the request conflicts with the current state (sequential used, RIDE not ready, ...).

func (*ConflictError) Unwrap

func (e *ConflictError) Unwrap() error

Unwrap returns the APIError.

type ConnectionError

type ConnectionError struct {
	// Message names the request and the reason.
	Message string

	// IdempotencyKey is the Idempotency-Key of a failed POST: see Error.IdempotencyKey.
	IdempotencyKey string

	// Err is the error of the HTTP client.
	Err error
}

ConnectionError means the request never got an answer (DNS, TLS, a connection reset, ...). Requests are retried automatically before it is returned.

func (*ConnectionError) As

func (e *ConnectionError) As(target any) bool

As lets errors.As read a ConnectionError as an *Error.

func (*ConnectionError) Error

func (e *ConnectionError) Error() string

func (*ConnectionError) Unwrap

func (e *ConnectionError) Unwrap() error

Unwrap returns the error of the HTTP client.

type CreateCreditNote

type CreateCreditNote struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// The buyer of the modified document. It cannot be a final consumer.
	Customer DocumentParty `json:"customer"`

	// The document the note modifies.
	ModifiedDocument ModifiedDocument `json:"modifiedDocument"`

	// Reason for the note.
	Reason string `json:"reason"`

	// The lines of the document.
	Items []DocumentItem `json:"items"`

	// The total you expect. Flashpi computes every total; when it differs from this value the
	// request is refused with 422 total_mismatch, which shows both values.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`
}

CreateCreditNote: A credit note (nota de crédito) that reduces the amount of a document, for example for returned goods. Flashpi computes the credited amount.

type CreateDebitNote

type CreateDebitNote struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// The buyer of the modified document. It cannot be a final consumer.
	Customer DocumentParty `json:"customer"`

	// The document the note modifies.
	ModifiedDocument ModifiedDocument `json:"modifiedDocument"`

	// The reasons and their amounts.
	Reasons []DebitNoteReason `json:"reasons"`

	// How the debit is paid; the payments must add up to the total.
	Payments []DocumentPayment `json:"payments"`

	// The total you expect. Flashpi computes every total; when it differs from this value the
	// request is refused with 422 total_mismatch, which shows both values.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`
}

CreateDebitNote: A debit note (nota de débito) that increases the amount of a document, for example for interest or fees. Flashpi computes the taxes and the total.

type CreateEmissionPoint

type CreateEmissionPoint struct {
	// Emission point code (punto de emisión), 3 digits. It cannot be changed later.
	Code string `json:"code"`
}

CreateEmissionPoint is a schema of the API.

type CreateEstablishment

type CreateEstablishment struct {
	// Establishment code (estab), 3 digits, as registered in the RUC. It cannot be changed later.
	Code string `json:"code"`

	// Address of the establishment (dirección del establecimiento).
	Address string `json:"address"`
}

CreateEstablishment is a schema of the API.

type CreateInvoice

type CreateInvoice struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// The buyer. `final_consumer` may omit `id` and `name`; the maximum amount of a final consumer
	// invoice is not enforced yet.
	Customer DocumentParty `json:"customer"`

	// The lines of the document.
	Items []DocumentItem `json:"items"`

	// How the invoice is paid; the payments must add up to the total.
	Payments []DocumentPayment `json:"payments"`

	// Tip (propina). Defaults to 0.
	Tip *string `json:"tip,omitempty"`

	// Number of the waybill (guía de remisión) that carried the goods.
	WaybillNumber *string `json:"waybillNumber,omitempty"`

	// The total you expect. Flashpi computes every total; when it differs from this value the
	// request is refused with 422 total_mismatch, which shows both values.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`
}

CreateInvoice: An invoice (factura). Send quantities, prices and tax rates; Flashpi computes the line subtotals, the taxes per rate, the tip and the total with the SRI rounding rules.

type CreateIssuer

type CreateIssuer struct {
	// RUC: 13 digits ending in 001. Only the format is checked: newer RUCs fail the modulo-11 check
	// digit, so it is never verified. It cannot be changed later.
	RUC string `json:"ruc"`

	// Legal name (razón social) as registered in the RUC.
	LegalName string `json:"legalName"`

	// Trade name (nombre comercial).
	TradeName Nullable[string] `json:"tradeName,omitzero"`

	// Head office address (dirección matriz).
	HeadOfficeAddress string `json:"headOfficeAddress"`

	TaxProfile IssuerTaxProfileInput `json:"taxProfile"`

	Branding *IssuerBrandingInput `json:"branding,omitempty"`

	// Default of a document request's `options.sendEmail`: true emails every authorized document
	// (RIDE PDF and XML) to its buyer, false opts the issuer out. A request that sets
	// `options.sendEmail` decides for itself. Default: true.
	SendEmailByDefault *bool `json:"sendEmailByDefault,omitempty"`
}

CreateIssuer is a schema of the API.

type CreatePurchaseSettlement

type CreatePurchaseSettlement struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// The supplier. It cannot be a final consumer.
	Supplier DocumentParty `json:"supplier"`

	// The lines of the document.
	Items []DocumentItem `json:"items"`

	// How the purchase is paid; the payments must add up to the total and each one needs a `term`.
	Payments []DocumentPayment `json:"payments"`

	// The total you expect. Flashpi computes every total; when it differs from this value the
	// request is refused with 422 total_mismatch, which shows both values.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`
}

CreatePurchaseSettlement: A purchase settlement (liquidación de compra): the buyer documents a purchase from a supplier without a RUC or who cannot issue invoices. Lines take VAT only.

type CreateWaybill

type CreateWaybill struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// Where the transport starts.
	DepartureAddress string `json:"departureAddress"`

	// The carrier.
	Carrier WaybillCarrier `json:"carrier"`

	// License plate of the vehicle.
	LicensePlate string `json:"licensePlate"`

	// Start of the transport; not before the issue date. Format: date.
	TransportStartDate string `json:"transportStartDate"`

	// End of the transport; not before its start. Format: date.
	TransportEndDate string `json:"transportEndDate"`

	// The recipients and their goods.
	Recipients []WaybillRecipient `json:"recipients"`
}

CreateWaybill: A waybill (guía de remisión) that supports the transport of goods.

type CreateWebhookEndpoint

type CreateWebhookEndpoint struct {
	// Where Flashpi POSTs the events: a public HTTPS URL without credentials or fragment. Changing
	// it requires a new verification.
	URL string `json:"url"`

	// A label for your own reference.
	Description Nullable[string] `json:"description,omitzero"`

	// Event types the endpoint receives; `*` receives every type, including future ones.
	EnabledEvents []EnabledEvent `json:"enabledEvents"`

	// `full` (default): the event with a snapshot of its resource in `data`. `thin`: the event
	// without `data`, only `id`, `type`, `environment` and `createdAt` (read the snapshot with GET
	// /v1/events/{id}). Default: "full".
	PayloadMode *PayloadMode `json:"payloadMode,omitempty"`
}

CreateWebhookEndpoint is a schema of the API.

type CreateWithholding

type CreateWithholding struct {
	// The issuer (taxpayer) that issues the document. Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (3 digits) registered on the issuer.
	Establishment string `json:"establishment"`

	// Emission point code (3 digits) registered on the establishment.
	EmissionPoint string `json:"emissionPoint"`

	// Issue date, YYYY-MM-DD. Defaults to today in Ecuador; it cannot be later. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`

	// Sequential to use instead of the next one, for example when migrating from another system. It
	// must not be used yet; later automatic sequentials continue after the highest one used. Not
	// accepted with the shared demo issuer (422 demo_issuer_sequential_not_allowed).
	Sequential *int `json:"sequential,omitempty"`

	// Additional information printed on the document (name → value, 1 to 300 characters each). A
	// document carries at most 15 fields including the legends Flashpi adds (RUC Proveedor, and
	// Gran Contribuyente for large taxpayers), so at most 13 or 14 of yours.
	AdditionalInfo map[string]string `json:"additionalInfo,omitempty"`

	// Delivery options.
	Options *DocumentOptions `json:"options,omitempty"`

	// The withheld supplier.
	Subject WithheldSubject `json:"subject"`

	// Fiscal period, YYYY-MM. Defaults to the month of the issue date.
	FiscalPeriod *string `json:"fiscalPeriod,omitempty"`

	// The supporting documents and their withholdings.
	SupportingDocuments []SupportingDocument `json:"supportingDocuments"`

	// The total withheld you expect; when it differs from the computed one the request is refused
	// with 422 total_mismatch.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`
}

CreateWithholding: A withholding receipt (comprobante de retención). Flashpi computes every withheld amount and the total withheld.

type CreditNoteService

type CreditNoteService struct {
	// contains filtered or unexported fields
}

CreditNoteService issues credit notes (notas de crédito). See client.CreditNotes.

func (*CreditNoteService) Create

func (s *CreditNoteService) Create(ctx context.Context, body CreateCreditNote, options ...RequestOption) (*Document, error)

Create issues a credit note. See InvoiceService.Create for the answer and the retries.

type DebitNoteReason

type DebitNoteReason struct {
	// Reason.
	Description string `json:"description"`

	// Amount before taxes.
	Amount string `json:"amount"`

	// The VAT of this amount (exactly one `vat`).
	Taxes []DocumentTax `json:"taxes"`
}

DebitNoteReason: A reason for a debit note and its amount before taxes.

type DebitNoteService

type DebitNoteService struct {
	// contains filtered or unexported fields
}

DebitNoteService issues debit notes (notas de débito). See client.DebitNotes.

func (*DebitNoteService) Create

func (s *DebitNoteService) Create(ctx context.Context, body CreateDebitNote, options ...RequestOption) (*Document, error)

Create issues a debit note. See InvoiceService.Create for the answer and the retries.

type Document

type Document struct {
	// Format: uuid.
	ID string `json:"id"`

	Type DocumentType `json:"type"`

	// Mode of the API key that issued it: `test` (SRI pruebas) or `live`.
	Environment Environment `json:"environment"`

	// Tax status: `processing` (being signed and sent), `pending_sri` (waiting for the SRI),
	// `authorized`, `rejected`, `failed` or `voided`.
	Status DocumentStatus `json:"status"`

	// Format: uuid.
	IssuerID string `json:"issuerId"`

	Establishment string `json:"establishment"`

	EmissionPoint string `json:"emissionPoint"`

	Sequential int `json:"sequential"`

	// Establishment-emission point-sequential.
	Number string `json:"number"`

	// The 49-digit access key, also the authorization number.
	AccessKey string `json:"accessKey"`

	// Format: date.
	IssueDate string `json:"issueDate"`

	// Version of the SRI XML.
	XMLVersion string `json:"xmlVersion"`

	Counterparty *DocumentCounterparty `json:"counterparty"`

	// Null for waybills.
	Totals *DocumentTotals `json:"totals"`

	Authorization DocumentAuthorization `json:"authorization"`

	RIDE DocumentRIDE `json:"ride"`

	Email DocumentEmail `json:"email"`

	// Messages of the last SRI answer, mapped to Flashpi codes (the reasons of a rejection, or
	// warnings of an authorization). Texts follow Accept-Language (English or Spanish).
	SRIMessages []DocumentSRIMessage `json:"sriMessages"`

	// Set when `status` is `failed`.
	Failure *DocumentFailure `json:"failure"`

	// Format: date-time.
	VoidedAt *time.Time `json:"voidedAt"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

Document: An SRI document of any type.

type DocumentAuthorization

type DocumentAuthorization struct {
	// Authorization number (the access key), once authorized.
	Number *string `json:"number"`

	// Format: date-time.
	AuthorizedAt *time.Time `json:"authorizedAt"`
}

DocumentAuthorization: The SRI authorization.

type DocumentCounterparty

type DocumentCounterparty struct {
	ID string `json:"id"`

	Name string `json:"name"`
}

DocumentCounterparty: The buyer, supplier, withheld subject or carrier.

type DocumentEmail

type DocumentEmail struct {
	// Whether the email was requested.
	Requested bool `json:"requested"`

	// `not_requested` (opted out), `skipped` (no recipient), `queued` (sent once authorized), then
	// `sent`, `delivered`, `bounced`, `complained` or `failed`.
	Status DocumentEmailStatus `json:"status"`

	Deliveries []DocumentEmailDelivery `json:"deliveries"`

	// Warnings about the recipient's address, computed when the document is read: empty when
	// nothing looks wrong.
	Warnings []DocumentEmailWarning `json:"warnings"`
}

DocumentEmail: Email delivery, separate from the tax status: sent only once the document is authorized, when it was requested and there is a recipient.

type DocumentEmailDelivery

type DocumentEmailDelivery struct {
	// Format: uuid.
	ID string `json:"id"`

	Recipient string `json:"recipient"`

	Status DocumentEmailDeliveryStatus `json:"status"`

	// Format: date-time.
	SentAt *time.Time `json:"sentAt"`

	// Format: date-time.
	LastEventAt *time.Time `json:"lastEventAt"`

	// Why the email failed or bounced, as a code: for example `rejected`, `timeout`,
	// `invalid_address`, `bounce_permanent`, `bounce_suppressed` (the address is on the suppression
	// list of Flashpi's email provider after an earlier bounce or complaint), `complaint`,
	// `account_email_limit_reached` (the account's emails of the day were used up; nothing was
	// sent), `platform_email_limit_reached` (Flashpi's emails of the day across all accounts were
	// used up; nothing was sent), `email_sending_paused` (the account's emails of the mode are
	// paused; nothing was sent), `platform_email_sending_paused` (Flashpi paused the emails of its
	// email provider for every account after too many bounces or complaints; nothing was sent),
	// `test_recipient_not_allowed` (a test document whose recipient is not a verified member of the
	// account's team; nothing was sent: download the RIDE and the XML to send them) or
	// `invalid_domain` (the recipient's domain does not exist or receives no mail: no MX, A or AAAA
	// record, or a null MX; nothing was sent).
	Error *string `json:"error"`
}

DocumentEmailDelivery: One email to one recipient.

type DocumentEmailDeliveryStatus

type DocumentEmailDeliveryStatus string

DocumentEmailDeliveryStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentEmailDeliveryStatusQueued     DocumentEmailDeliveryStatus = "queued"
	DocumentEmailDeliveryStatusSent       DocumentEmailDeliveryStatus = "sent"
	DocumentEmailDeliveryStatusDelivered  DocumentEmailDeliveryStatus = "delivered"
	DocumentEmailDeliveryStatusBounced    DocumentEmailDeliveryStatus = "bounced"
	DocumentEmailDeliveryStatusComplained DocumentEmailDeliveryStatus = "complained"
	DocumentEmailDeliveryStatusFailed     DocumentEmailDeliveryStatus = "failed"
)

The values of DocumentEmailDeliveryStatus.

type DocumentEmailStatus

type DocumentEmailStatus string

DocumentEmailStatus is a value of the API. `not_requested` (opted out), `skipped` (no recipient), `queued` (sent once authorized), then `sent`, `delivered`, `bounced`, `complained` or `failed`. The API may add values: keep a default case.

const (
	DocumentEmailStatusNotRequested DocumentEmailStatus = "not_requested"
	DocumentEmailStatusSkipped      DocumentEmailStatus = "skipped"
	DocumentEmailStatusQueued       DocumentEmailStatus = "queued"
	DocumentEmailStatusSent         DocumentEmailStatus = "sent"
	DocumentEmailStatusDelivered    DocumentEmailStatus = "delivered"
	DocumentEmailStatusBounced      DocumentEmailStatus = "bounced"
	DocumentEmailStatusComplained   DocumentEmailStatus = "complained"
	DocumentEmailStatusFailed       DocumentEmailStatus = "failed"
)

The values of DocumentEmailStatus.

type DocumentEmailWarning

type DocumentEmailWarning struct {
	// `recipient_domain_typo`: the recipient's domain looks like a typo of a common mail domain
	// (for example gmial.com for gmail.com). The email is still sent to the address as given;
	// nothing changes it.
	Code DocumentEmailWarningCode `json:"code"`

	// Follows Accept-Language (English or Spanish).
	Message string `json:"message"`

	// The address with the suggested domain.
	SuggestedRecipient string `json:"suggestedRecipient"`
}

DocumentEmailWarning: Something about the email that looks wrong. A warning never stops or changes the email.

type DocumentEmailWarningCode

type DocumentEmailWarningCode string

DocumentEmailWarningCode is a value of the API. `recipient_domain_typo`: the recipient's domain looks like a typo of a common mail domain (for example gmial.com for gmail.com). The email is still sent to the address as given; nothing changes it. The API may add values: keep a default case.

const (
	DocumentEmailWarningCodeRecipientDomainTypo DocumentEmailWarningCode = "recipient_domain_typo"
)

The values of DocumentEmailWarningCode.

type DocumentEvent

type DocumentEvent struct {
	// Format: uuid.
	ID string `json:"id"`

	Type DocumentEventType `json:"type"`

	// Mode of the resource.
	Environment Environment `json:"environment"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	Data Document `json:"data"`
}

DocumentEvent: An event about a document (its tax outcome, RIDE or email): `data` is the Document as the API returned it when the event happened (texts in English).

func (*DocumentEvent) Info

func (e *DocumentEvent) Info() EventInfo

Info returns what every event has: its id, type, environment and creation time.

type DocumentEventType

type DocumentEventType string

DocumentEventType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentEventTypeInvoiceAuthorized            DocumentEventType = "invoice.authorized"
	DocumentEventTypeInvoiceRejected              DocumentEventType = "invoice.rejected"
	DocumentEventTypePurchaseSettlementAuthorized DocumentEventType = "purchase_settlement.authorized"
	DocumentEventTypePurchaseSettlementRejected   DocumentEventType = "purchase_settlement.rejected"
	DocumentEventTypeCreditNoteAuthorized         DocumentEventType = "credit_note.authorized"
	DocumentEventTypeCreditNoteRejected           DocumentEventType = "credit_note.rejected"
	DocumentEventTypeDebitNoteAuthorized          DocumentEventType = "debit_note.authorized"
	DocumentEventTypeDebitNoteRejected            DocumentEventType = "debit_note.rejected"
	DocumentEventTypeWaybillAuthorized            DocumentEventType = "waybill.authorized"
	DocumentEventTypeWaybillRejected              DocumentEventType = "waybill.rejected"
	DocumentEventTypeWithholdingAuthorized        DocumentEventType = "withholding.authorized"
	DocumentEventTypeWithholdingRejected          DocumentEventType = "withholding.rejected"
	DocumentEventTypeDocumentRIDEGenerated        DocumentEventType = "document.ride.generated"
	DocumentEventTypeDocumentRIDEFailed           DocumentEventType = "document.ride.failed"
	DocumentEventTypeDocumentEmailSent            DocumentEventType = "document.email.sent"
	DocumentEventTypeDocumentEmailDelivered       DocumentEventType = "document.email.delivered"
	DocumentEventTypeDocumentEmailBounced         DocumentEventType = "document.email.bounced"
	DocumentEventTypeDocumentEmailComplained      DocumentEventType = "document.email.complained"
	DocumentEventTypeDocumentEmailFailed          DocumentEventType = "document.email.failed"
)

The values of DocumentEventType.

type DocumentFailure

type DocumentFailure struct {
	Code DocumentFailureCode `json:"code"`

	Message string `json:"message"`
}

DocumentFailure: Why a `failed` document could not reach an SRI answer.

type DocumentFailureCode

type DocumentFailureCode string

DocumentFailureCode is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentFailureCodeCertificateRequired     DocumentFailureCode = "certificate_required"
	DocumentFailureCodeCertificateExpired      DocumentFailureCode = "certificate_expired"
	DocumentFailureCodeCertificateNotYetValid  DocumentFailureCode = "certificate_not_yet_valid"
	DocumentFailureCodeCertificateBlocked      DocumentFailureCode = "certificate_blocked"
	DocumentFailureCodeCertificateRevoked      DocumentFailureCode = "certificate_revoked"
	DocumentFailureCodeCertificateUnusable     DocumentFailureCode = "certificate_unusable"
	DocumentFailureCodeDocumentTooLarge        DocumentFailureCode = "document_too_large"
	DocumentFailureCodeDocumentInvalid         DocumentFailureCode = "document_invalid"
	DocumentFailureCodeSigningFailed           DocumentFailureCode = "signing_failed"
	DocumentFailureCodeSRIUnavailable          DocumentFailureCode = "sri_unavailable"
	DocumentFailureCodeSRIAuthorizationTimeout DocumentFailureCode = "sri_authorization_timeout"
	DocumentFailureCodeSRIRequestRefused       DocumentFailureCode = "sri_request_refused"
	DocumentFailureCodeSRIEnvironmentMismatch  DocumentFailureCode = "sri_environment_mismatch"
)

The values of DocumentFailureCode.

type DocumentItem

type DocumentItem struct {
	// Your product code. Required on invoices and purchase settlements.
	Code *string `json:"code,omitempty"`

	// A second code, for example the barcode.
	AuxiliaryCode *string `json:"auxiliaryCode,omitempty"`

	// Description.
	Description string `json:"description"`

	// Unit of measure (invoices and purchase settlements).
	Unit *string `json:"unit,omitempty"`

	// Quantity, up to 6 decimals.
	Quantity string `json:"quantity"`

	// Unit price without taxes, up to 6 decimals.
	UnitPrice string `json:"unitPrice"`

	// Discount amount of the line (not a percentage), up to 2 decimals. Defaults to 0.
	Discount *string `json:"discount,omitempty"`

	// The taxes of the line.
	Taxes []DocumentTax `json:"taxes"`

	// Up to 3 extra details printed with the line (name → value, 1 to 300 characters).
	AdditionalDetails map[string]string `json:"additionalDetails,omitempty"`
}

DocumentItem: A line of an invoice, credit note or purchase settlement. Flashpi computes its subtotal (quantity × unit price − discount, rounded to 2 decimals) and its taxes.

type DocumentListParams

type DocumentListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string

	// Only documents of this issuer. Format: uuid.
	IssuerID *string

	// Only this document type.
	Type *DocumentType

	// Only this tax status.
	Status *DocumentStatus

	// Only documents issued on or after this date. Format: date.
	IssueDateFrom *string

	// Only documents issued on or before this date. Format: date.
	IssueDateTo *string

	// Only documents of this buyer, supplier, withheld subject or carrier.
	CounterpartyID *string

	// The document with this access key.
	AccessKey *string
}

DocumentListParams holds the query of documentsList (GET /v1/documents). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type DocumentOptions

type DocumentOptions struct {
	// Email the authorized document (PDF and XML) to the counterparty, when it has an email
	// address. Defaults to the issuer's `sendEmailByDefault` (true unless the issuer opted out).
	SendEmail *bool `json:"sendEmail,omitempty"`

	// Sync mode: wait for the SRI before answering. The response is 200 with the document once it
	// is authorized, rejected or failed, or 202 with its current status (usually `pending_sri`)
	// when the wait ends first; the document then continues asynchronously. Defaults to false (202
	// at once).
	WaitForAuthorization *bool `json:"waitForAuthorization,omitempty"`

	// Sync mode: the longest wait, in seconds, from 1 to 30. Defaults to 15. A longer wait is
	// refused with `out_of_range`. Used only with `waitForAuthorization`.
	WaitTimeoutSeconds *int `json:"waitTimeoutSeconds,omitempty"`
}

DocumentOptions: How Flashpi delivers the document once the SRI authorizes it.

type DocumentParty

type DocumentParty struct {
	// Identification type: `ruc` (13 digits ending in 001, format only), `cedula` (10 digits, check
	// digit verified), `passport`, `final_consumer` (no identification; only invoices accept it) or
	// `foreign_id` (issued by the tax authority of another country).
	IDType IDType `json:"idType"`

	// Identification number. Required unless `idType` is `final_consumer`, whose number is always
	// 9999999999999.
	ID *string `json:"id,omitempty"`

	// Legal name or full name. Required unless `idType` is `final_consumer` (printed as CONSUMIDOR
	// FINAL).
	Name *string `json:"name,omitempty"`

	// Address. Credit and debit notes do not print it.
	Address *string `json:"address,omitempty"`

	// Where the authorized document is emailed (see `options.sendEmail`). Format: email.
	Email *string `json:"email,omitempty"`
}

DocumentParty: The buyer of an invoice, credit or debit note, or the supplier of a purchase settlement.

type DocumentPayment

type DocumentPayment struct {
	// Payment method: `cash` (without the financial system), `debt_offset`, `debit_card`,
	// `electronic_money`, `prepaid_card`, `credit_card`, `other_financial_system` (bank transfers,
	// checks and other payments through the financial system) or `securities_endorsement`.
	Method PaymentMethod `json:"method"`

	// Amount paid with this method.
	Amount string `json:"amount"`

	// Payment term in `termUnit` units. Required on purchase settlements.
	Term *string `json:"term,omitempty"`

	// Unit of `term`: `days` or `months`.
	TermUnit *DocumentPaymentTermUnit `json:"termUnit,omitempty"`
}

DocumentPayment: A payment. The payments must add up to the document total.

type DocumentPaymentTermUnit

type DocumentPaymentTermUnit string

DocumentPaymentTermUnit is a value of the API. Unit of `term`: `days` or `months`. The API may add values: keep a default case.

const (
	DocumentPaymentTermUnitDays   DocumentPaymentTermUnit = "days"
	DocumentPaymentTermUnitMonths DocumentPaymentTermUnit = "months"
)

The values of DocumentPaymentTermUnit.

type DocumentRIDE

type DocumentRIDE struct {
	Status RIDEStatus `json:"status"`

	Template *DocumentRIDETemplate `json:"template"`

	// Format: date-time.
	GeneratedAt *time.Time `json:"generatedAt"`
}

DocumentRIDE: The RIDE (printed PDF), generated once the document is authorized.

type DocumentRIDETemplate

type DocumentRIDETemplate string

DocumentRIDETemplate is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentRIDETemplateModern  DocumentRIDETemplate = "modern"
	DocumentRIDETemplateClassic DocumentRIDETemplate = "classic"
	DocumentRIDETemplateMinimal DocumentRIDETemplate = "minimal"
)

The values of DocumentRIDETemplate.

type DocumentSRIMessage

type DocumentSRIMessage struct {
	// Flashpi error code.
	Code string `json:"code"`

	Message string `json:"message"`

	Severity DocumentSRIMessageSeverity `json:"severity"`
}

DocumentSRIMessage: A message of the SRI, mapped by Flashpi.

type DocumentSRIMessageSeverity

type DocumentSRIMessageSeverity string

DocumentSRIMessageSeverity is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentSRIMessageSeverityError   DocumentSRIMessageSeverity = "error"
	DocumentSRIMessageSeverityWarning DocumentSRIMessageSeverity = "warning"
)

The values of DocumentSRIMessageSeverity.

type DocumentService

type DocumentService struct {
	// contains filtered or unexported fields
}

DocumentService reads every issued document, of any type: search, XML, RIDE (PDF) and email. See client.Documents.

func (*DocumentService) Get

func (s *DocumentService) Get(ctx context.Context, documentID string, options ...RequestOption) (*Document, error)

Get retrieves a document with its tax status, SRI messages, RIDE and email state.

func (*DocumentService) List

func (s *DocumentService) List(ctx context.Context, params *DocumentListParams, options ...RequestOption) iter.Seq2[*Document, error]

List walks the documents, newest first, with optional filters (params may be nil), reading the pages as it goes:

for document, err := range client.Documents.List(ctx, nil) {
	if err != nil {
		return err
	}
	fmt.Println(document.AccessKey)
}

func (*DocumentService) ListPage

func (s *DocumentService) ListPage(ctx context.Context, params *DocumentListParams, options ...RequestOption) (*Page[*Document], error)

ListPage reads the first page of documents, newest first; NextPage reads the next one.

func (*DocumentService) PDF

func (s *DocumentService) PDF(ctx context.Context, documentID string, options ...RequestOption) ([]byte, error)

PDF retrieves the RIDE (the printable PDF) of an authorized document. It fails with a *ConflictError whose Code is ride_not_available while the RIDE is still being generated.

func (*DocumentService) SendEmail

func (s *DocumentService) SendEmail(ctx context.Context, documentID string, body *SendDocumentEmail, options ...RequestOption) (*Document, error)

SendEmail emails the authorized document (RIDE and XML) again to the address of its request. The new delivery shows in Email.Deliveries; daily limits apply (*RateLimitError). body may be nil, which sends {}: the API has no options for it yet.

func (*DocumentService) XML

func (s *DocumentService) XML(ctx context.Context, documentID string, options ...RequestOption) (*DocumentXML, error)

XML retrieves the document's XML: the authorized one once the SRI authorizes it, otherwise the signed or unsigned one (see Kind).

type DocumentStatus

type DocumentStatus string

DocumentStatus is a value of the API. Tax status: `processing` (being signed and sent), `pending_sri` (waiting for the SRI), `authorized`, `rejected`, `failed` or `voided`. The API may add values: keep a default case.

const (
	DocumentStatusProcessing DocumentStatus = "processing"
	DocumentStatusPendingSRI DocumentStatus = "pending_sri"
	DocumentStatusAuthorized DocumentStatus = "authorized"
	DocumentStatusRejected   DocumentStatus = "rejected"
	DocumentStatusFailed     DocumentStatus = "failed"
	DocumentStatusVoided     DocumentStatus = "voided"
)

The values of DocumentStatus.

type DocumentTax

type DocumentTax struct {
	// `vat` (IVA) or `ice` (ICE).
	Type TaxType `json:"type"`

	// For `vat`, the rate: `0`, `5`, `8` (differentiated, tourism), `12`, `13`, `14`, `15`,
	// `exempt` or `not_subject`; it must be in force on the issue date (for credit and debit notes,
	// on the modified document issue date). For `ice`, the ad valorem percentage with up to 2
	// decimals (for example `75`).
	Rate string `json:"rate"`

	// For `ice` only (required): the 4-digit ICE code of TABLA 18.
	Code *string `json:"code,omitempty"`
}

DocumentTax: A tax of a line. Every line needs exactly one `vat`; invoices and credit notes accept one ad valorem `ice` too. Flashpi computes the bases and amounts.

type DocumentTaxTotal

type DocumentTaxTotal struct {
	Type TaxType `json:"type"`

	// VAT: the rate (`15`, `0`, `exempt`, ...). ICE: the percentage.
	Rate string `json:"rate"`

	// ICE: the TABLA 18 code.
	Code *string `json:"code,omitempty"`

	// Taxable base.
	TaxableBase string `json:"taxableBase"`

	// Tax amount.
	Amount string `json:"amount"`
}

DocumentTaxTotal: A tax total, grouped per tax and rate.

type DocumentTotals

type DocumentTotals struct {
	// Sum of the line subtotals.
	Subtotal *string `json:"subtotal,omitempty"`

	// Sum of the line discounts.
	Discount *string `json:"discount,omitempty"`

	Taxes []DocumentTaxTotal `json:"taxes,omitempty"`

	// Tip.
	Tip *string `json:"tip,omitempty"`

	// Total (credited amount of a credit note, total of a debit note).
	Total *string `json:"total,omitempty"`

	// Total withheld.
	Withheld *string `json:"withheld,omitempty"`
}

DocumentTotals: Totals computed by Flashpi. Invoices have every field but `withheld`; purchase settlements and credit notes have no `tip`; debit notes have no `discount` nor `tip`; withholding receipts only have `withheld`.

type DocumentType

type DocumentType string

DocumentType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	DocumentTypeInvoice            DocumentType = "invoice"
	DocumentTypePurchaseSettlement DocumentType = "purchase_settlement"
	DocumentTypeCreditNote         DocumentType = "credit_note"
	DocumentTypeDebitNote          DocumentType = "debit_note"
	DocumentTypeWaybill            DocumentType = "waybill"
	DocumentTypeWithholding        DocumentType = "withholding"
)

The values of DocumentType.

type DocumentXML

type DocumentXML struct {
	// XML is the document's XML.
	XML string

	// Kind is the stage of the XML: DocumentXMLKindAuthorized (the valid tax document, once
	// the SRI authorizes it), DocumentXMLKindSigned or DocumentXMLKindUnsigned; "" when the API
	// did not say.
	Kind DocumentXMLKind
}

DocumentXML is the XML of a document and the stage it comes from.

type DocumentXMLKind

type DocumentXMLKind string

DocumentXMLKind is the stage an XML comes from. Only DocumentXMLKindAuthorized is the valid tax document.

const (
	DocumentXMLKindAuthorized DocumentXMLKind = "authorized"
	DocumentXMLKindSigned     DocumentXMLKind = "signed"
	DocumentXMLKindUnsigned   DocumentXMLKind = "unsigned"
)

The stages of an XML.

type EmissionPoint

type EmissionPoint struct {
	// Format: uuid.
	ID string `json:"id"`

	// Format: uuid.
	IssuerID string `json:"issuerId"`

	// Format: uuid.
	EstablishmentID string `json:"establishmentId"`

	// Emission point code (punto de emisión), 3 digits.
	Code string `json:"code"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

EmissionPoint: An emission point of an establishment.

type EmissionPointListParams

type EmissionPointListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string
}

EmissionPointListParams holds the query of emissionPointsList (GET /v1/issuers/{issuerId}/establishments/{establishmentId}/emission-points). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type EmissionPointService

type EmissionPointService struct {
	// contains filtered or unexported fields
}

EmissionPointService manages the emission points (the second 3-digit series code) of an establishment. See client.Issuers.Establishments.EmissionPoints.

func (*EmissionPointService) Create

func (s *EmissionPointService) Create(ctx context.Context, issuerID, establishmentID string, body CreateEmissionPoint, options ...RequestOption) (*EmissionPoint, error)

Create creates an emission point of an establishment.

func (*EmissionPointService) Delete

func (s *EmissionPointService) Delete(ctx context.Context, issuerID, establishmentID, emissionPointID string, options ...RequestOption) error

Delete deletes an emission point.

func (*EmissionPointService) Get

func (s *EmissionPointService) Get(ctx context.Context, issuerID, establishmentID, emissionPointID string, options ...RequestOption) (*EmissionPoint, error)

Get retrieves an emission point.

func (*EmissionPointService) List

func (s *EmissionPointService) List(ctx context.Context, issuerID, establishmentID string, params *EmissionPointListParams, options ...RequestOption) iter.Seq2[*EmissionPoint, error]

List walks the emission points of an establishment, by code, reading the pages as it goes. params may be nil.

func (*EmissionPointService) ListPage

func (s *EmissionPointService) ListPage(ctx context.Context, issuerID, establishmentID string, params *EmissionPointListParams, options ...RequestOption) (*Page[*EmissionPoint], error)

ListPage reads the first page of an establishment's emission points, by code; NextPage reads the next one.

type EnabledEvent

type EnabledEvent string

EnabledEvent is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	EnabledEventInvoiceAuthorized            EnabledEvent = "invoice.authorized"
	EnabledEventInvoiceRejected              EnabledEvent = "invoice.rejected"
	EnabledEventPurchaseSettlementAuthorized EnabledEvent = "purchase_settlement.authorized"
	EnabledEventPurchaseSettlementRejected   EnabledEvent = "purchase_settlement.rejected"
	EnabledEventCreditNoteAuthorized         EnabledEvent = "credit_note.authorized"
	EnabledEventCreditNoteRejected           EnabledEvent = "credit_note.rejected"
	EnabledEventDebitNoteAuthorized          EnabledEvent = "debit_note.authorized"
	EnabledEventDebitNoteRejected            EnabledEvent = "debit_note.rejected"
	EnabledEventWaybillAuthorized            EnabledEvent = "waybill.authorized"
	EnabledEventWaybillRejected              EnabledEvent = "waybill.rejected"
	EnabledEventWithholdingAuthorized        EnabledEvent = "withholding.authorized"
	EnabledEventWithholdingRejected          EnabledEvent = "withholding.rejected"
	EnabledEventCertificateVerified          EnabledEvent = "certificate.verified"
	EnabledEventCertificatePending           EnabledEvent = "certificate.pending"
	EnabledEventCertificateBlocked           EnabledEvent = "certificate.blocked"
	EnabledEventCertificateRevoked           EnabledEvent = "certificate.revoked"
	EnabledEventCertificateReactivated       EnabledEvent = "certificate.reactivated"
	EnabledEventDocumentRIDEGenerated        EnabledEvent = "document.ride.generated"
	EnabledEventDocumentRIDEFailed           EnabledEvent = "document.ride.failed"
	EnabledEventDocumentEmailSent            EnabledEvent = "document.email.sent"
	EnabledEventDocumentEmailDelivered       EnabledEvent = "document.email.delivered"
	EnabledEventDocumentEmailBounced         EnabledEvent = "document.email.bounced"
	EnabledEventDocumentEmailComplained      EnabledEvent = "document.email.complained"
	EnabledEventDocumentEmailFailed          EnabledEvent = "document.email.failed"
	EnabledEventAccountEmailPaused           EnabledEvent = "account.email_paused"
	EnabledEventAccountEmailResumed          EnabledEvent = "account.email_resumed"
	EnabledEventAll                          EnabledEvent = "*"
)

The values of EnabledEvent.

type Environment

type Environment string

Environment is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	EnvironmentTest Environment = "test"
	EnvironmentLive Environment = "live"
)

The values of Environment.

type Error

type Error struct {
	// Message says what went wrong, in English.
	Message string

	// IdempotencyKey is the Idempotency-Key a failed POST used (yours, or the one the SDK made).
	// To try the same operation again later without issuing twice, pass it back with
	// WithIdempotencyKey. Empty for other methods and for failures before a request.
	IdempotencyKey string

	// Err is the cause, if any: context.Canceled or context.DeadlineExceeded when the call's
	// context ended, or the error of decoding an answer. An attempt that ran out of its own time
	// (a *TimeoutError, read as an *Error) wraps context.DeadlineExceeded too, as net/http's
	// timeouts do: check for *TimeoutError, or ctx.Err(), first to tell them apart.
	Err error
}

Error is a failure of the SDK itself: a setting or an argument it refuses before sending anything, an answer it cannot read, or a call whose context ended. Every error the SDK returns is an *Error or can be read as one with errors.As, *APIError and *ConnectionError included, so the Idempotency-Key of any failed POST is in reach:

var flashpiErr *flashpi.Error
if errors.As(err, &flashpiErr) && flashpiErr.IdempotencyKey != "" {
	// Try again later with flashpi.WithIdempotencyKey(flashpiErr.IdempotencyKey).
}

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the cause, so errors.Is(err, context.Canceled) works.

type ErrorCode

type ErrorCode string

ErrorCode is a value of the API. Stable machine-readable error code, the same in every language. Branch on it, never on `type`, `title` or `detail`. New codes may be added: handle an unknown one by its HTTP status. The API may add values: keep a default case.

const (
	ErrorCodeBadRequest                     ErrorCode = "bad_request"
	ErrorCodeMalformedJSON                  ErrorCode = "malformed_json"
	ErrorCodeInvalidCorrelationID           ErrorCode = "invalid_correlation_id"
	ErrorCodeValidationFailed               ErrorCode = "validation_failed"
	ErrorCodeAuthenticationRequired         ErrorCode = "authentication_required"
	ErrorCodeForbidden                      ErrorCode = "forbidden"
	ErrorCodeNotFound                       ErrorCode = "not_found"
	ErrorCodeMethodNotAllowed               ErrorCode = "method_not_allowed"
	ErrorCodeNotAcceptable                  ErrorCode = "not_acceptable"
	ErrorCodeConflict                       ErrorCode = "conflict"
	ErrorCodePayloadTooLarge                ErrorCode = "payload_too_large"
	ErrorCodeUnsupportedMediaType           ErrorCode = "unsupported_media_type"
	ErrorCodeRateLimited                    ErrorCode = "rate_limited"
	ErrorCodeInternalError                  ErrorCode = "internal_error"
	ErrorCodeServiceUnavailable             ErrorCode = "service_unavailable"
	ErrorCodeInvalidAPIKey                  ErrorCode = "invalid_api_key"
	ErrorCodeKeyScopeMismatch               ErrorCode = "key_scope_mismatch"
	ErrorCodeKeyReadOnly                    ErrorCode = "key_read_only"
	ErrorCodeIPNotAllowed                   ErrorCode = "ip_not_allowed"
	ErrorCodeInvalidIdempotencyKey          ErrorCode = "invalid_idempotency_key"
	ErrorCodeIdempotencyKeyReused           ErrorCode = "idempotency_key_reused"
	ErrorCodeIdempotencyKeyInProgress       ErrorCode = "idempotency_key_in_progress"
	ErrorCodeIssuerAlreadyExists            ErrorCode = "issuer_already_exists"
	ErrorCodeEstablishmentAlreadyExists     ErrorCode = "establishment_already_exists"
	ErrorCodeEmissionPointAlreadyExists     ErrorCode = "emission_point_already_exists"
	ErrorCodeResourceInUse                  ErrorCode = "resource_in_use"
	ErrorCodeIssuerOnboardingNotReady       ErrorCode = "issuer_onboarding_not_ready"
	ErrorCodeIssuerOnboardingExpired        ErrorCode = "issuer_onboarding_expired"
	ErrorCodeIssuerOnboardingCompleted      ErrorCode = "issuer_onboarding_completed"
	ErrorCodeIssuerOnboardingRejected       ErrorCode = "issuer_onboarding_rejected"
	ErrorCodeTotalMismatch                  ErrorCode = "total_mismatch"
	ErrorCodeSequentialAlreadyUsed          ErrorCode = "sequential_already_used"
	ErrorCodeSequentialsExhausted           ErrorCode = "sequentials_exhausted"
	ErrorCodeDocumentSchemaInvalid          ErrorCode = "document_schema_invalid"
	ErrorCodeDocumentTooLarge               ErrorCode = "document_too_large"
	ErrorCodeDocumentNotAuthorized          ErrorCode = "document_not_authorized"
	ErrorCodeRIDENotAvailable               ErrorCode = "ride_not_available"
	ErrorCodeEmailRecipientMissing          ErrorCode = "email_recipient_missing"
	ErrorCodeEmailAlreadyQueued             ErrorCode = "email_already_queued"
	ErrorCodeEmailResendLimitReached        ErrorCode = "email_resend_limit_reached"
	ErrorCodeAccountEmailLimitReached       ErrorCode = "account_email_limit_reached"
	ErrorCodeEmailSendingPaused             ErrorCode = "email_sending_paused"
	ErrorCodeTestRecipientNotAllowed        ErrorCode = "test_recipient_not_allowed"
	ErrorCodePlatformEmailLimitReached      ErrorCode = "platform_email_limit_reached"
	ErrorCodeWebhookEndpointDisabled        ErrorCode = "webhook_endpoint_disabled"
	ErrorCodeWebhookEndpointAlreadyVerified ErrorCode = "webhook_endpoint_already_verified"
	ErrorCodeWebhookEndpointNotVerified     ErrorCode = "webhook_endpoint_not_verified"
	ErrorCodeWebhookDeliveryInProgress      ErrorCode = "webhook_delivery_in_progress"
	ErrorCodeSandboxNotEnabled              ErrorCode = "sandbox_not_enabled"
	ErrorCodeDemoIssuerQuotaExceeded        ErrorCode = "demo_issuer_quota_exceeded"
	ErrorCodeDemoIssuerUnavailable          ErrorCode = "demo_issuer_unavailable"
	ErrorCodeAccountSuspended               ErrorCode = "account_suspended"
)

The values of ErrorCode.

type Establishment

type Establishment struct {
	// Format: uuid.
	ID string `json:"id"`

	// Format: uuid.
	IssuerID string `json:"issuerId"`

	// Establishment code (estab), 3 digits.
	Code string `json:"code"`

	// Address of the establishment (dirección del establecimiento).
	Address string `json:"address"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

Establishment: An establishment of an issuer.

type EstablishmentListParams

type EstablishmentListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string
}

EstablishmentListParams holds the query of establishmentsList (GET /v1/issuers/{issuerId}/establishments). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type EstablishmentService

type EstablishmentService struct {

	// EmissionPoints manages the emission points of an establishment.
	EmissionPoints *EmissionPointService
	// contains filtered or unexported fields
}

EstablishmentService manages the establishments (the 3-digit series codes such as 001) of an issuer. See client.Issuers.Establishments.

func (*EstablishmentService) Create

func (s *EstablishmentService) Create(ctx context.Context, issuerID string, body CreateEstablishment, options ...RequestOption) (*Establishment, error)

Create creates an establishment of an issuer.

func (*EstablishmentService) Delete

func (s *EstablishmentService) Delete(ctx context.Context, issuerID, establishmentID string, options ...RequestOption) error

Delete deletes an establishment.

func (*EstablishmentService) Get

func (s *EstablishmentService) Get(ctx context.Context, issuerID, establishmentID string, options ...RequestOption) (*Establishment, error)

Get retrieves an establishment.

func (*EstablishmentService) List

List walks the establishments of an issuer, by code, reading the pages as it goes. params may be nil.

func (*EstablishmentService) ListPage

func (s *EstablishmentService) ListPage(ctx context.Context, issuerID string, params *EstablishmentListParams, options ...RequestOption) (*Page[*Establishment], error)

ListPage reads the first page of an issuer's establishments, by code; NextPage reads the next one.

func (*EstablishmentService) Update

func (s *EstablishmentService) Update(ctx context.Context, issuerID, establishmentID string, body UpdateEstablishment, options ...RequestOption) (*Establishment, error)

Update changes an establishment (only the members set are sent).

type Event

type Event interface {
	WebhookEvent
	// contains filtered or unexported methods
}

Event is what happened to a resource, as client.Events returns it: one of *DocumentEvent, *CertificateEvent or *AccountEvent, or an *UnknownEvent for a type this version of the SDK does not know. Use a type switch. A webhook endpoint receives a WebhookEvent: see UnwrapWebhook.

type EventInfo

type EventInfo struct {
	// ID is the event's id, also its webhook-id: store it and drop repeated deliveries.
	ID string

	// Type is the event's type, such as EventTypeInvoiceAuthorized, or
	// "webhook_endpoint.verification" for the activation handshake.
	Type EventType

	// Environment is the mode of the resource.
	Environment Environment

	// CreatedAt is when the event happened.
	CreatedAt time.Time
}

EventInfo is what every event has.

type EventListParams

type EventListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string

	// Only events of this type.
	Type *EventType

	// Only events of this issuer. Format: uuid.
	IssuerID *string

	// Only events of this document. Format: uuid.
	DocumentID *string

	// Only events of this certificate. Format: uuid.
	CertificateID *string
}

EventListParams holds the query of eventsList (GET /v1/events). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type EventService

type EventService struct {
	// contains filtered or unexported fields
}

EventService reads the events of documents, certificates and email sending, newest first. See client.Events.

func (*EventService) Get

func (s *EventService) Get(ctx context.Context, eventID string, options ...RequestOption) (Event, error)

Get retrieves an event: the same object its webhook delivered.

func (*EventService) List

func (s *EventService) List(ctx context.Context, params *EventListParams, options ...RequestOption) iter.Seq2[Event, error]

List walks the events, newest first, optionally by type, issuer, document or certificate, reading the pages as it goes. params may be nil. Narrow each event with a type switch (see Event).

func (*EventService) ListPage

func (s *EventService) ListPage(ctx context.Context, params *EventListParams, options ...RequestOption) (*Page[Event], error)

ListPage reads the first page of events, newest first; NextPage reads the next one.

type EventType

type EventType string

EventType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	EventTypeInvoiceAuthorized            EventType = "invoice.authorized"
	EventTypeInvoiceRejected              EventType = "invoice.rejected"
	EventTypePurchaseSettlementAuthorized EventType = "purchase_settlement.authorized"
	EventTypePurchaseSettlementRejected   EventType = "purchase_settlement.rejected"
	EventTypeCreditNoteAuthorized         EventType = "credit_note.authorized"
	EventTypeCreditNoteRejected           EventType = "credit_note.rejected"
	EventTypeDebitNoteAuthorized          EventType = "debit_note.authorized"
	EventTypeDebitNoteRejected            EventType = "debit_note.rejected"
	EventTypeWaybillAuthorized            EventType = "waybill.authorized"
	EventTypeWaybillRejected              EventType = "waybill.rejected"
	EventTypeWithholdingAuthorized        EventType = "withholding.authorized"
	EventTypeWithholdingRejected          EventType = "withholding.rejected"
	EventTypeCertificateVerified          EventType = "certificate.verified"
	EventTypeCertificatePending           EventType = "certificate.pending"
	EventTypeCertificateBlocked           EventType = "certificate.blocked"
	EventTypeCertificateRevoked           EventType = "certificate.revoked"
	EventTypeCertificateReactivated       EventType = "certificate.reactivated"
	EventTypeDocumentRIDEGenerated        EventType = "document.ride.generated"
	EventTypeDocumentRIDEFailed           EventType = "document.ride.failed"
	EventTypeDocumentEmailSent            EventType = "document.email.sent"
	EventTypeDocumentEmailDelivered       EventType = "document.email.delivered"
	EventTypeDocumentEmailBounced         EventType = "document.email.bounced"
	EventTypeDocumentEmailComplained      EventType = "document.email.complained"
	EventTypeDocumentEmailFailed          EventType = "document.email.failed"
	EventTypeAccountEmailPaused           EventType = "account.email_paused"
	EventTypeAccountEmailResumed          EventType = "account.email_resumed"
)

The values of EventType.

type FieldError

type FieldError struct {
	// Path of the invalid field.
	Field string `json:"field"`

	// Stable machine-readable reason. New codes may be added: treat an unknown one like
	// `invalid_value`.
	Code FieldErrorCode `json:"code"`

	// Localized message.
	Message string `json:"message"`
}

FieldError is a schema of the API.

type FieldErrorCode

type FieldErrorCode string

FieldErrorCode is a value of the API. Stable machine-readable reason. New codes may be added: treat an unknown one like `invalid_value`. The API may add values: keep a default case.

const (
	FieldErrorCodeRequired                       FieldErrorCode = "required"
	FieldErrorCodeUnknownField                   FieldErrorCode = "unknown_field"
	FieldErrorCodeInvalidType                    FieldErrorCode = "invalid_type"
	FieldErrorCodeInvalidFormat                  FieldErrorCode = "invalid_format"
	FieldErrorCodeInvalidOption                  FieldErrorCode = "invalid_option"
	FieldErrorCodeTooShort                       FieldErrorCode = "too_short"
	FieldErrorCodeTooLong                        FieldErrorCode = "too_long"
	FieldErrorCodeOutOfRange                     FieldErrorCode = "out_of_range"
	FieldErrorCodeInvalidValue                   FieldErrorCode = "invalid_value"
	FieldErrorCodeUnsupportedCharacter           FieldErrorCode = "unsupported_character"
	FieldErrorCodeNotFound                       FieldErrorCode = "not_found"
	FieldErrorCodeInvalidDecimal                 FieldErrorCode = "invalid_decimal"
	FieldErrorCodeInvalidIdentification          FieldErrorCode = "invalid_identification"
	FieldErrorCodeInvalidCheckDigit              FieldErrorCode = "invalid_check_digit"
	FieldErrorCodeFinalConsumerNotAllowed        FieldErrorCode = "final_consumer_not_allowed"
	FieldErrorCodeNotInForce                     FieldErrorCode = "not_in_force"
	FieldErrorCodeTooManyAdditionalFields        FieldErrorCode = "too_many_additional_fields"
	FieldErrorCodeReservedName                   FieldErrorCode = "reserved_name"
	FieldErrorCodeAmountMismatch                 FieldErrorCode = "amount_mismatch"
	FieldErrorCodeFutureDate                     FieldErrorCode = "future_date"
	FieldErrorCodeDateTooEarly                   FieldErrorCode = "date_too_early"
	FieldErrorCodeDateTooLate                    FieldErrorCode = "date_too_late"
	FieldErrorCodeDiscountExceedsAmount          FieldErrorCode = "discount_exceeds_amount"
	FieldErrorCodeDuplicate                      FieldErrorCode = "duplicate"
	FieldErrorCodeVATRequired                    FieldErrorCode = "vat_required"
	FieldErrorCodeUnsupportedTax                 FieldErrorCode = "unsupported_tax"
	FieldErrorCodeRateMismatch                   FieldErrorCode = "rate_mismatch"
	FieldErrorCodeIncompatibleIssuerProfile      FieldErrorCode = "incompatible_issuer_profile"
	FieldErrorCodeURLNotAllowed                  FieldErrorCode = "url_not_allowed"
	FieldErrorCodeDemoIssuerTestOnly             FieldErrorCode = "demo_issuer_test_only"
	FieldErrorCodeDemoIssuerSequentialNotAllowed FieldErrorCode = "demo_issuer_sequential_not_allowed"
	FieldErrorCodeRUCMismatch                    FieldErrorCode = "ruc_mismatch"
)

The values of FieldErrorCode.

type IDType

type IDType string

IDType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	IDTypeRUC           IDType = "ruc"
	IDTypeCedula        IDType = "cedula"
	IDTypePassport      IDType = "passport"
	IDTypeFinalConsumer IDType = "final_consumer"
	IDTypeForeignID     IDType = "foreign_id"
)

The values of IDType.

type InternalServerError

type InternalServerError struct{ *APIError }

InternalServerError is a 5xx: Flashpi failed to answer. Requests are retried automatically before it is returned, except a 501, a 503 demo_issuer_unavailable and one that asks to wait (Retry-After) more than 60 seconds.

func (*InternalServerError) Unwrap

func (e *InternalServerError) Unwrap() error

Unwrap returns the APIError.

type InvoiceService

type InvoiceService struct {
	// contains filtered or unexported fields
}

InvoiceService issues invoices (facturas). See client.Invoices.

func (*InvoiceService) Create

func (s *InvoiceService) Create(ctx context.Context, body CreateInvoice, options ...RequestOption) (*Document, error)

Create issues an invoice. The answer is the document: processing right away (202), or, with options.waitForAuthorization, its outcome once the SRI decides (200), unless the wait ends first (202 with processing or pending_sri; follow it with webhooks or Documents.Get). Retries reuse the same Idempotency-Key, and when a retry finds the document already created, its current state is returned instead of an error.

type Issuer

type Issuer struct {
	// Format: uuid.
	ID string `json:"id"`

	// RUC: 13 digits ending in 001 (format only; the check digit is not verified).
	RUC string `json:"ruc"`

	// Legal name (razón social) as registered in the RUC.
	LegalName string `json:"legalName"`

	// Trade name (nombre comercial).
	TradeName *string `json:"tradeName"`

	// Head office address (dirección matriz).
	HeadOfficeAddress string `json:"headOfficeAddress"`

	TaxProfile IssuerTaxProfile `json:"taxProfile"`

	Branding IssuerBranding `json:"branding"`

	// Default of a document request's `options.sendEmail`: true emails every authorized document
	// (RIDE PDF and XML) to its buyer, false opts the issuer out. A request that sets
	// `options.sendEmail` decides for itself.
	SendEmailByDefault bool `json:"sendEmailByDefault"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

Issuer: A taxpayer (RUC) that issues documents.

type IssuerBranding

type IssuerBranding struct {
	// Brand color of the RIDE PDF, #RRGGBB (returned in lowercase).
	BrandColor *string `json:"brandColor"`
}

IssuerBranding: RIDE branding of the issuer.

type IssuerBrandingInput

type IssuerBrandingInput struct {
	// Brand color of the RIDE PDF, #RRGGBB (returned in lowercase).
	BrandColor Nullable[string] `json:"brandColor,omitzero"`
}

IssuerBrandingInput is a schema of the API.

type IssuerListParams

type IssuerListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string
}

IssuerListParams holds the query of issuersList (GET /v1/issuers). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type IssuerOnboarding

type IssuerOnboarding struct {
	// Format: uuid.
	ID string `json:"id"`

	Status IssuerOnboardingStatus `json:"status"`

	// When it expires unless completed. Format: date-time.
	ExpiresAt time.Time `json:"expiresAt"`

	Rejection *IssuerOnboardingRejection `json:"rejection"`

	Certificate *IssuerOnboardingCertificate `json:"certificate"`

	// The RUC to complete with: the certificate's, or the holder's cédula followed by 001.
	ProposedRUC *string `json:"proposedRuc"`

	// Whether the customer must confirm (or type) the RUC: it did not come from the certificate
	// itself. Then complete must send `ruc`.
	RUCNeedsConfirmation bool `json:"rucNeedsConfirmation"`

	ExistingIssuer *IssuerOnboardingExistingIssuer `json:"existingIssuer"`

	SRI *IssuerOnboardingSRI `json:"sri"`

	Prefill *IssuerOnboardingPrefill `json:"prefill"`

	Completed *IssuerOnboardingCompletion `json:"completed"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

IssuerOnboarding: An issuer onboarding from a .p12: Flashpi verifies the certificate (`verifying`), then it is `ready` with the certificate's facts, the RUC and, when the registry lookup is on, the SRI's profile, or `rejected`. Completing it creates the issuer (or renews an existing one) with the certificate, which serves test and live. It `expired` if not completed within 6 days, and it is deleted 30 days after it ends.

type IssuerOnboardingCertificate

type IssuerOnboardingCertificate struct {
	SerialNumber string `json:"serialNumber"`

	// Format: date-time.
	ValidFrom time.Time `json:"validFrom"`

	// Format: date-time.
	ValidTo time.Time `json:"validTo"`

	IssuingCA *IssuerOnboardingIssuingCA `json:"issuingCa"`

	Holder IssuerOnboardingHolder `json:"holder"`

	Identification IssuerOnboardingIdentification `json:"identification"`
}

IssuerOnboardingCertificate: Public facts of the verified certificate (no key material).

type IssuerOnboardingCompletion

type IssuerOnboardingCompletion struct {
	// Format: uuid.
	IssuerID string `json:"issuerId"`

	// Format: uuid.
	CertificateID string `json:"certificateId"`
}

IssuerOnboardingCompletion: What completing it produced.

type IssuerOnboardingExistingIssuer

type IssuerOnboardingExistingIssuer struct {
	// Format: uuid.
	ID string `json:"id"`

	LegalName string `json:"legalName"`
}

IssuerOnboardingExistingIssuer: The account's issuer that already has this RUC: completing renews its certificate instead of creating an issuer.

type IssuerOnboardingHolder

type IssuerOnboardingHolder struct {
	// Common name (CN): the holder's name.
	CommonName *string `json:"commonName"`

	// Organization (O): usually the company of a legal representative.
	Organization *string `json:"organization"`
}

IssuerOnboardingHolder: The certificate holder's names.

type IssuerOnboardingIdentification

type IssuerOnboardingIdentification struct {
	RUC *string `json:"ruc"`

	RUCSource *IssuerOnboardingIdentificationRUCSource `json:"rucSource"`

	Cedula *string `json:"cedula"`
}

IssuerOnboardingIdentification: The identification the certificate carries: its RUC (`rucSource` certificate), or the holder's cédula, from which Flashpi proposes the RUC cédula + 001 (`rucSource` cedula).

type IssuerOnboardingIdentificationRUCSource

type IssuerOnboardingIdentificationRUCSource string

IssuerOnboardingIdentificationRUCSource is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	IssuerOnboardingIdentificationRUCSourceCertificate IssuerOnboardingIdentificationRUCSource = "certificate"
	IssuerOnboardingIdentificationRUCSourceCedula      IssuerOnboardingIdentificationRUCSource = "cedula"
)

The values of IssuerOnboardingIdentificationRUCSource.

type IssuerOnboardingIssuingCA

type IssuerOnboardingIssuingCA struct {
	Code *string `json:"code"`

	DisplayName *string `json:"displayName"`
}

IssuerOnboardingIssuingCA: The Ecuadorian certification authority that issued the certificate.

type IssuerOnboardingPrefill

type IssuerOnboardingPrefill struct {
	RUC *string `json:"ruc"`

	LegalName *string `json:"legalName"`

	TradeName *string `json:"tradeName"`

	HeadOfficeAddress *string `json:"headOfficeAddress"`

	TaxProfile IssuerOnboardingPrefillTaxProfile `json:"taxProfile"`
}

IssuerOnboardingPrefill: Values for the issuer's tax profile: the SRI's legal name first, else the certificate's organization (companies) or common name (persons); the trade name, the head office address and the tax profile from the SRI when it answered (`sri.status` `found`), otherwise null. They are the customer's to check and edit.

type IssuerOnboardingPrefillTaxProfile

type IssuerOnboardingPrefillTaxProfile struct {
	KeepsAccounting *bool `json:"keepsAccounting"`

	// `general` means not in RIMPE (complete with `rimpeRegime: null`); null means unknown.
	RIMPERegime *IssuerOnboardingPrefillTaxProfileRIMPERegime `json:"rimpeRegime"`

	// The SRI says special taxpayer: ask for the resolution number.
	SpecialTaxpayer *bool `json:"specialTaxpayer"`

	// The SRI says withholding agent: ask for the resolution number.
	WithholdingAgent *bool `json:"withholdingAgent"`
}

IssuerOnboardingPrefillTaxProfile: The tax profile to start from; null where nothing is known.

type IssuerOnboardingPrefillTaxProfileRIMPERegime

type IssuerOnboardingPrefillTaxProfileRIMPERegime string

IssuerOnboardingPrefillTaxProfileRIMPERegime is a value of the API. `general` means not in RIMPE (complete with `rimpeRegime: null`); null means unknown. The API may add values: keep a default case.

const (
	IssuerOnboardingPrefillTaxProfileRIMPERegimeEntrepreneur    IssuerOnboardingPrefillTaxProfileRIMPERegime = "entrepreneur"
	IssuerOnboardingPrefillTaxProfileRIMPERegimePopularBusiness IssuerOnboardingPrefillTaxProfileRIMPERegime = "popular_business"
	IssuerOnboardingPrefillTaxProfileRIMPERegimeGeneral         IssuerOnboardingPrefillTaxProfileRIMPERegime = "general"
)

The values of IssuerOnboardingPrefillTaxProfileRIMPERegime.

type IssuerOnboardingRejection

type IssuerOnboardingRejection struct {
	Code string `json:"code"`

	// In the language of Accept-Language (Spanish or English).
	Message string `json:"message"`
}

IssuerOnboardingRejection: Why the certificate was rejected (the certificate rejection codes).

type IssuerOnboardingSRI

type IssuerOnboardingSRI struct {
	Status IssuerOnboardingSRIStatus `json:"status"`

	// Format: date-time.
	FetchedAt *time.Time `json:"fetchedAt"`

	Profile *IssuerOnboardingSRIProfile `json:"profile"`

	// `inactive`: the RUC is not ACTIVO; `ghost` and `nonexistent_transactions`: the SRI flags the
	// taxpayer; `head_office_closed`: its head office establishment is closed.
	Warnings []IssuerOnboardingSRIWarningsItem `json:"warnings"`
}

IssuerOnboardingSRI: What the SRI's public RUC registry said about the RUC (best effort). `unavailable`: it did not answer. `disabled`: Flashpi did not ask it (the lookup is off). In both cases `profile` is null and the customer fills in the tax profile. Warnings never block.

type IssuerOnboardingSRIProfile

type IssuerOnboardingSRIProfile struct {
	// Razón social.
	LegalName *string `json:"legalName"`

	// Nombre comercial.
	TradeName *string `json:"tradeName"`

	// The RUC status as the SRI writes it.
	TaxpayerStatus *string `json:"taxpayerStatus"`

	KeepsAccounting *bool `json:"keepsAccounting"`

	SpecialTaxpayer *bool `json:"specialTaxpayer"`

	WithholdingAgent *bool `json:"withholdingAgent"`

	// `general`: not in RIMPE. `unknown`: the SRI answer could not be mapped; the customer chooses.
	RIMPERegime IssuerOnboardingSRIProfileRIMPERegime `json:"rimpeRegime"`

	// The head office address.
	HeadOfficeAddress *string `json:"headOfficeAddress"`
}

IssuerOnboardingSRIProfile: The taxpayer's profile in the SRI's public RUC registry, normalized. The registry gives flags only for special taxpayer and withholding agent: the resolution numbers are the customer's to type.

type IssuerOnboardingSRIProfileRIMPERegime

type IssuerOnboardingSRIProfileRIMPERegime string

IssuerOnboardingSRIProfileRIMPERegime is a value of the API. `general`: not in RIMPE. `unknown`: the SRI answer could not be mapped; the customer chooses. The API may add values: keep a default case.

const (
	IssuerOnboardingSRIProfileRIMPERegimeEntrepreneur    IssuerOnboardingSRIProfileRIMPERegime = "entrepreneur"
	IssuerOnboardingSRIProfileRIMPERegimePopularBusiness IssuerOnboardingSRIProfileRIMPERegime = "popular_business"
	IssuerOnboardingSRIProfileRIMPERegimeGeneral         IssuerOnboardingSRIProfileRIMPERegime = "general"
	IssuerOnboardingSRIProfileRIMPERegimeUnknown         IssuerOnboardingSRIProfileRIMPERegime = "unknown"
)

The values of IssuerOnboardingSRIProfileRIMPERegime.

type IssuerOnboardingSRIStatus

type IssuerOnboardingSRIStatus string

IssuerOnboardingSRIStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	IssuerOnboardingSRIStatusFound       IssuerOnboardingSRIStatus = "found"
	IssuerOnboardingSRIStatusNotFound    IssuerOnboardingSRIStatus = "not_found"
	IssuerOnboardingSRIStatusUnavailable IssuerOnboardingSRIStatus = "unavailable"
	IssuerOnboardingSRIStatusDisabled    IssuerOnboardingSRIStatus = "disabled"
)

The values of IssuerOnboardingSRIStatus.

type IssuerOnboardingSRIWarningsItem

type IssuerOnboardingSRIWarningsItem string

IssuerOnboardingSRIWarningsItem is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	IssuerOnboardingSRIWarningsItemInactive                IssuerOnboardingSRIWarningsItem = "inactive"
	IssuerOnboardingSRIWarningsItemGhost                   IssuerOnboardingSRIWarningsItem = "ghost"
	IssuerOnboardingSRIWarningsItemNonexistentTransactions IssuerOnboardingSRIWarningsItem = "nonexistent_transactions"
	IssuerOnboardingSRIWarningsItemHeadOfficeClosed        IssuerOnboardingSRIWarningsItem = "head_office_closed"
)

The values of IssuerOnboardingSRIWarningsItem.

type IssuerOnboardingService

type IssuerOnboardingService struct {
	// contains filtered or unexported fields
}

IssuerOnboardingService creates an issuer from its .p12: upload the certificate, wait while the onboarding is verifying until it is ready (Flashpi reads the holder, RUC and SRI data) or rejected, review the prefill, then complete it. It needs an account-scoped API key with read_write access. See client.IssuerOnboardings.

func (*IssuerOnboardingService) Complete

Complete completes a ready onboarding: it creates the issuer from body, or, when the RUC already is an issuer of the account (ExistingIssuer), adds the certificate to it. body may be nil, which sends {} (a renewal).

func (*IssuerOnboardingService) Create

Create starts an onboarding with a .p12 and its password. It starts verifying.

func (*IssuerOnboardingService) Get

func (s *IssuerOnboardingService) Get(ctx context.Context, onboardingID string, options ...RequestOption) (*IssuerOnboarding, error)

Get retrieves an onboarding, to follow it while it is verifying.

type IssuerOnboardingStatus

type IssuerOnboardingStatus string

IssuerOnboardingStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	IssuerOnboardingStatusVerifying IssuerOnboardingStatus = "verifying"
	IssuerOnboardingStatusReady     IssuerOnboardingStatus = "ready"
	IssuerOnboardingStatusRejected  IssuerOnboardingStatus = "rejected"
	IssuerOnboardingStatusCompleted IssuerOnboardingStatus = "completed"
	IssuerOnboardingStatusExpired   IssuerOnboardingStatus = "expired"
)

The values of IssuerOnboardingStatus.

type IssuerService

type IssuerService struct {

	// Establishments manages the establishments of an issuer, with their emission points.
	Establishments *EstablishmentService

	// Certificates manages the .p12 certificates of an issuer.
	Certificates *CertificateService
	// contains filtered or unexported fields
}

IssuerService manages the issuers (RUCs) of the account, with their establishments, emission points and .p12 certificates. It needs an account-scoped API key with read_write access, also to read. See client.Issuers.

func (*IssuerService) Create

func (s *IssuerService) Create(ctx context.Context, body CreateIssuer, options ...RequestOption) (*Issuer, error)

Create creates an issuer. To start from its .p12 instead, see client.IssuerOnboardings.

func (*IssuerService) Delete

func (s *IssuerService) Delete(ctx context.Context, issuerID string, options ...RequestOption) error

Delete deletes an issuer that has no documents and no certificates, with its establishments, emission points and issuer-scoped API keys. Otherwise the API answers 409 resource_in_use: certificates cannot be deleted, so an issuer that ever had a .p12 (one from an issuer onboarding too) stays.

func (*IssuerService) Get

func (s *IssuerService) Get(ctx context.Context, issuerID string, options ...RequestOption) (*Issuer, error)

Get retrieves an issuer.

func (*IssuerService) List

func (s *IssuerService) List(ctx context.Context, params *IssuerListParams, options ...RequestOption) iter.Seq2[*Issuer, error]

List walks the issuers, newest first, reading the pages as it goes. params may be nil.

func (*IssuerService) ListPage

func (s *IssuerService) ListPage(ctx context.Context, params *IssuerListParams, options ...RequestOption) (*Page[*Issuer], error)

ListPage reads the first page of issuers, newest first; NextPage reads the next one.

func (*IssuerService) Update

func (s *IssuerService) Update(ctx context.Context, issuerID string, body UpdateIssuer, options ...RequestOption) (*Issuer, error)

Update changes an issuer's name, tax profile, branding or defaults: only the members set are sent, and flashpi.Null clears an optional one.

type IssuerTaxProfile

type IssuerTaxProfile struct {
	// Whether the taxpayer is required to keep accounting (obligado a llevar contabilidad).
	KeepsAccounting bool `json:"keepsAccounting"`

	// Special taxpayer (contribuyente especial) resolution number: 3 to 13 letters or digits.
	SpecialTaxpayerNumber *string `json:"specialTaxpayerNumber"`

	// Withholding agent (agente de retención) designation resolution number, digits only. Stored
	// without leading zeros (at most 8 digits).
	WithholdingAgentResolution *string `json:"withholdingAgentResolution"`

	// RIMPE regime: `entrepreneur` (CONTRIBUYENTE RÉGIMEN RIMPE) or `popular_business`
	// (CONTRIBUYENTE NEGOCIO POPULAR - RÉGIMEN RIMPE). Null when not in RIMPE.
	RIMPERegime *RIMPERegime `json:"rimpeRegime"`

	// Large taxpayer (gran contribuyente) designation resolution number.
	LargeTaxpayerResolution *string `json:"largeTaxpayerResolution"`
}

IssuerTaxProfile: Tax profile; Flashpi adds the mandatory tags and legends from it.

type IssuerTaxProfileInput

type IssuerTaxProfileInput struct {
	// Whether the taxpayer is required to keep accounting (obligado a llevar contabilidad).
	KeepsAccounting bool `json:"keepsAccounting"`

	// Special taxpayer (contribuyente especial) resolution number: 3 to 13 letters or digits.
	SpecialTaxpayerNumber Nullable[string] `json:"specialTaxpayerNumber,omitzero"`

	// Withholding agent (agente de retención) designation resolution number, digits only. Stored
	// without leading zeros (at most 8 digits).
	WithholdingAgentResolution Nullable[string] `json:"withholdingAgentResolution,omitzero"`

	// RIMPE regime: `entrepreneur` (CONTRIBUYENTE RÉGIMEN RIMPE) or `popular_business`
	// (CONTRIBUYENTE NEGOCIO POPULAR - RÉGIMEN RIMPE). Null when not in RIMPE.
	RIMPERegime Nullable[RIMPERegime] `json:"rimpeRegime,omitzero"`

	// Large taxpayer (gran contribuyente) designation resolution number.
	LargeTaxpayerResolution Nullable[string] `json:"largeTaxpayerResolution,omitzero"`
}

IssuerTaxProfileInput is a schema of the API.

type IssuerTaxProfilePatch

type IssuerTaxProfilePatch struct {
	// Whether the taxpayer is required to keep accounting (obligado a llevar contabilidad).
	KeepsAccounting *bool `json:"keepsAccounting,omitempty"`

	// Special taxpayer (contribuyente especial) resolution number: 3 to 13 letters or digits.
	SpecialTaxpayerNumber Nullable[string] `json:"specialTaxpayerNumber,omitzero"`

	// Withholding agent (agente de retención) designation resolution number, digits only. Stored
	// without leading zeros (at most 8 digits).
	WithholdingAgentResolution Nullable[string] `json:"withholdingAgentResolution,omitzero"`

	// RIMPE regime: `entrepreneur` (CONTRIBUYENTE RÉGIMEN RIMPE) or `popular_business`
	// (CONTRIBUYENTE NEGOCIO POPULAR - RÉGIMEN RIMPE). Null when not in RIMPE.
	RIMPERegime Nullable[RIMPERegime] `json:"rimpeRegime,omitzero"`

	// Large taxpayer (gran contribuyente) designation resolution number.
	LargeTaxpayerResolution Nullable[string] `json:"largeTaxpayerResolution,omitzero"`
}

IssuerTaxProfilePatch: Fields to change; null clears one.

type Language

type Language string

Language is the language of the API's messages. Error codes are the same in every language.

const (
	LanguageEnglish Language = "en"
	LanguageSpanish Language = "es"
)

The languages of the API's messages.

type ModifiedDocument

type ModifiedDocument struct {
	// Type of the modified document. Defaults to `invoice`.
	Type *ModifiedDocumentType `json:"type,omitempty"`

	// Number of the modified document: establishment-emission point-sequential.
	Number string `json:"number"`

	// Issue date of the modified document (on or before the note). Its VAT rates are the ones in
	// force on this date. Format: date.
	IssueDate string `json:"issueDate"`
}

ModifiedDocument: The document a credit or debit note modifies.

type ModifiedDocumentType

type ModifiedDocumentType string

ModifiedDocumentType is a value of the API. Type of the modified document. Defaults to `invoice`. The API may add values: keep a default case.

const (
	ModifiedDocumentTypeInvoice ModifiedDocumentType = "invoice"
)

The values of ModifiedDocumentType.

type NotFoundError

type NotFoundError struct{ *APIError }

NotFoundError is a 404: the resource does not exist in this mode (test or live) for this account.

func (*NotFoundError) Unwrap

func (e *NotFoundError) Unwrap() error

Unwrap returns the APIError.

type Nullable

type Nullable[T any] struct {
	// contains filtered or unexported fields
}

Nullable is an optional member of a request that may also be sent as null: in an update (PATCH), null clears the field; in a create, it means none. Its zero value is not sent at all:

flashpi.UpdateIssuer{
	TradeName: flashpi.Null[string](),              // clears the trade name
	Branding: &flashpi.IssuerBrandingInput{
		BrandColor: flashpi.NullableOf("#0C160D"), // sets the color
	},
	// Members left as they are keep their value.
}

func Null

func Null[T any]() Nullable[T]

Null is a Nullable sent as null.

func NullableOf

func NullableOf[T any](value T) Nullable[T]

NullableOf is a Nullable sent as value.

func (Nullable[T]) IsNull

func (n Nullable[T]) IsNull() bool

IsNull reports whether n is sent as null.

func (Nullable[T]) IsZero

func (n Nullable[T]) IsZero() bool

IsZero reports whether n is unset, so a member tagged omitzero is left out.

func (Nullable[T]) MarshalJSON

func (n Nullable[T]) MarshalJSON() ([]byte, error)

MarshalJSON writes the value, or null when n is null or unset.

func (*Nullable[T]) UnmarshalJSON

func (n *Nullable[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON reads null as Null and anything else as a value.

func (Nullable[T]) Value

func (n Nullable[T]) Value() (T, bool)

Value returns the value of n, and whether it has one.

type Option

type Option interface {
	ClientOption
	RequestOption
}

Option configures a Client or one call: WithTimeout, WithMaxRetries, WithLanguage and WithHeader. On a call it overrides the client's setting.

func WithHeader

func WithHeader(name, value string) Option

WithHeader sends a header with every request of the client, or with one call. It never replaces the API key. On a client it cannot be Idempotency-Key, which is per operation: use WithIdempotencyKey on the call.

func WithLanguage

func WithLanguage(language Language) Option

WithLanguage sets the language of the API's messages: LanguageEnglish (the API's default) or LanguageSpanish. Error codes do not change. An empty language is not sent.

func WithMaxRetries

func WithMaxRetries(retries int) Option

WithMaxRetries sets how many times a request is retried (default 2; 0 turns retries off). Retried: network errors, timeouts, 408, 429 and 5xx, except a 501, a 503 demo_issuer_unavailable and answers that ask to wait (Retry-After) more than 60 seconds, and a 409 idempotency_key_in_progress. POSTs keep their Idempotency-Key, so a retry never issues twice.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets how long each attempt of a request may take, from sending it to reading the whole answer (default 60 seconds). Issuing with options.waitForAuthorization raises it to the wait plus 15 seconds. The context of the call bounds the whole call, retries included.

type Page

type Page[E any] struct {
	// Data holds the items of this page.
	Data []E

	// HasMore reports whether more items follow this page.
	HasMore bool

	// NextCursor is the cursor of the next page, or "" on the last one.
	NextCursor string
	// contains filtered or unexported fields
}

Page is one page of a list, newest first (establishments and emission points: by code). E is the type of its items: *Document, *Issuer, ..., or Event.

The List methods walk every page for you; ListPage returns one page at a time:

page, err := client.Documents.ListPage(ctx, &flashpi.DocumentListParams{Limit: new(50)})
for page != nil && err == nil {
	for _, document := range page.Data { ... }
	page, err = page.NextPage(ctx)
}

func (*Page[E]) HasNextPage

func (p *Page[E]) HasNextPage() bool

HasNextPage reports whether NextPage returns a page.

func (*Page[E]) NextPage

func (p *Page[E]) NextPage(ctx context.Context) (*Page[E], error)

NextPage reads the next page, with the same filters and options. After the last page it returns nil and no error.

type PayloadMode

type PayloadMode string

PayloadMode is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	PayloadModeFull PayloadMode = "full"
	PayloadModeThin PayloadMode = "thin"
)

The values of PayloadMode.

type PaymentMethod

type PaymentMethod string

PaymentMethod is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	PaymentMethodCash                  PaymentMethod = "cash"
	PaymentMethodDebtOffset            PaymentMethod = "debt_offset"
	PaymentMethodDebitCard             PaymentMethod = "debit_card"
	PaymentMethodElectronicMoney       PaymentMethod = "electronic_money"
	PaymentMethodPrepaidCard           PaymentMethod = "prepaid_card"
	PaymentMethodCreditCard            PaymentMethod = "credit_card"
	PaymentMethodOtherFinancialSystem  PaymentMethod = "other_financial_system"
	PaymentMethodSecuritiesEndorsement PaymentMethod = "securities_endorsement"
)

The values of PaymentMethod.

type PermissionDeniedError

type PermissionDeniedError struct{ *APIError }

PermissionDeniedError is a 403: the key may not do this (read-only, another issuer, IP allowlist, suspended account).

func (*PermissionDeniedError) Unwrap

func (e *PermissionDeniedError) Unwrap() error

Unwrap returns the APIError.

type ProblemDetails

type ProblemDetails struct {
	// URI of the problem type: the page that documents `code`, in the language of the response
	// (`https://flashpi.com.ec/docs/en/errors/{code}` in English,
	// `https://flashpi.com.ec/docs/errors/{code}` with Accept-Language: es). It changes with the
	// language, so branch on `code`, never on `type`. Format: uri.
	Type string `json:"type"`

	// Localized summary of the type.
	Title string `json:"title"`

	// HTTP status code.
	Status int `json:"status"`

	// Localized explanation of this occurrence.
	Detail string `json:"detail"`

	// Path of the request.
	Instance string `json:"instance"`

	// Stable machine-readable error code, the same in every language. Branch on it, never on
	// `type`, `title` or `detail`. New codes may be added: handle an unknown one by its HTTP
	// status.
	Code ErrorCode `json:"code"`

	// Field-level errors (may be empty).
	Errors []FieldError `json:"errors"`

	// Request ID (UUIDv7); include it when contacting support.
	RequestID string `json:"requestId"`

	// `idempotency_key_reused`: the document the Idempotency-Key already created. Format: uuid.
	DocumentID *string `json:"documentId,omitempty"`

	// The daily limit that was reached (`email_resend_limit_reached`,
	// `account_email_limit_reached`, `demo_issuer_quota_exceeded`).
	Limit *int `json:"limit,omitempty"`

	// When the daily limit resets: the next midnight in Ecuador (the three codes above and
	// `platform_email_limit_reached`). Retry-After gives the same in seconds. Format: date-time.
	ResetsAt *time.Time `json:"resetsAt,omitempty"`

	// `ride_not_available`: the status of the RIDE.
	RIDEStatus *RIDEStatus `json:"rideStatus,omitempty"`

	// `document_not_authorized`: the status of the document.
	DocumentStatus *DocumentStatus `json:"documentStatus,omitempty"`

	// `email_sending_paused`: the mode whose email sending is paused.
	Environment *Environment `json:"environment,omitempty"`

	// `total_mismatch`: the `expectedTotal` you sent.
	ExpectedTotal *string `json:"expectedTotal,omitempty"`

	// `total_mismatch`: the total Flashpi computed.
	ComputedTotal *string `json:"computedTotal,omitempty"`

	// Extra holds the members the API sent that this version of the SDK does not declare, as raw
	// JSON.
	Extra map[string]json.RawMessage `json:"-"`
}

ProblemDetails: RFC 9457 problem details, in the language of Content-Language (`en`, or `es` with Accept-Language: es). Some codes add extension members, listed below; others may appear.

func (ProblemDetails) MarshalJSON

func (v ProblemDetails) MarshalJSON() ([]byte, error)

MarshalJSON writes the declared members and the ones in Extra.

func (*ProblemDetails) UnmarshalJSON

func (v *ProblemDetails) UnmarshalJSON(data []byte) error

UnmarshalJSON reads the declared members, and keeps the others in Extra.

type PurchaseSettlementService

type PurchaseSettlementService struct {
	// contains filtered or unexported fields
}

PurchaseSettlementService issues purchase settlements (liquidaciones de compra). See client.PurchaseSettlements.

func (*PurchaseSettlementService) Create

Create issues a purchase settlement. See InvoiceService.Create for the answer and the retries.

type RIDEStatus

type RIDEStatus string

RIDEStatus is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	RIDEStatusPending   RIDEStatus = "pending"
	RIDEStatusGenerated RIDEStatus = "generated"
	RIDEStatusFailed    RIDEStatus = "failed"
)

The values of RIDEStatus.

type RIMPERegime

type RIMPERegime string

RIMPERegime is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	RIMPERegimeEntrepreneur    RIMPERegime = "entrepreneur"
	RIMPERegimePopularBusiness RIMPERegime = "popular_business"
)

The values of RIMPERegime.

type RateLimitError

type RateLimitError struct{ *APIError }

RateLimitError is a 429: a limit was reached; see RetryAfter and the Limit and ResetsAt members of Problem.

func (*RateLimitError) Unwrap

func (e *RateLimitError) Unwrap() error

Unwrap returns the APIError.

type RequestOption

type RequestOption interface {
	// contains filtered or unexported methods
}

RequestOption configures one call: pass it to any method, after its other arguments.

func WithCorrelationID

func WithCorrelationID(id string) RequestOption

WithCorrelationID sends your own id for the request (X-Correlation-Id, 1 to 128 of A-Za-z0-9._:/+=-), which Flashpi echoes back and logs.

func WithIdempotencyKey

func WithIdempotencyKey(key string) RequestOption

WithIdempotencyKey sets the Idempotency-Key of a POST: 1 to 255 visible ASCII characters (no spaces), unique per operation, such as your order id or a UUID. The SDK creates one when it is missing and reuses it on its retries, so a retry never issues a document twice. Other methods ignore it.

func WithResponseInto

func WithResponseInto(response *Response) RequestOption

WithResponseInto fills response with the HTTP answer of a successful call: its status, its headers and Flashpi's request id. On a list, it holds the answer of the last page read.

type Response

type Response struct {
	// StatusCode is the HTTP status.
	StatusCode int

	// Header holds the headers of the answer.
	Header http.Header

	// RequestID is Flashpi's id of the request (x-request-id): share it with support.
	RequestID string
}

Response is the HTTP answer of a call, for WithResponseInto. Its body was already read into what the method returns.

type RotateWebhookEndpointSecret

type RotateWebhookEndpointSecret struct {
	// Hours the previous secret keeps signing deliveries next to the new one (default 24, at most
	// 168); 0 drops it at once.
	PreviousSecretExpiresInHours *int `json:"previousSecretExpiresInHours,omitempty"`
}

RotateWebhookEndpointSecret is a schema of the API.

type SendDocumentEmail

type SendDocumentEmail struct {
}

SendDocumentEmail: No options yet: send an empty object or no body.

type Status

type Status struct {
	// Overall status of Flashpi.
	Status StatusStatus `json:"status"`
}

Status: Public status of Flashpi. Placeholder until the status monitors exist.

type StatusService

type StatusService struct {
	// contains filtered or unexported fields
}

StatusService reads the API's own status. See client.Status.

func (*StatusService) Get

func (s *StatusService) Get(ctx context.Context, options ...RequestOption) (*Status, error)

Get reports whether Flashpi is operational.

type StatusStatus

type StatusStatus string

StatusStatus is a value of the API. Overall status of Flashpi. The API may add values: keep a default case.

const (
	StatusStatusOperational StatusStatus = "operational"
)

The values of StatusStatus.

type SupportingDocument

type SupportingDocument struct {
	// Tax support code (Catálogo ATS tabla 5), for example `01`.
	TaxSupportCode string `json:"taxSupportCode"`

	// Document type code (Catálogo ATS tabla 4), for example `01` for an invoice.
	DocumentTypeCode string `json:"documentTypeCode"`

	// Its number.
	Number string `json:"number"`

	// Its issue date, on or before the withholding. Format: date.
	IssueDate string `json:"issueDate"`

	// Accounting record date. Format: date.
	AccountingDate *string `json:"accountingDate,omitempty"`

	// Its authorization number (10, 37 or 49 digits).
	AuthorizationNumber *string `json:"authorizationNumber,omitempty"`

	// Whether the payment is `local` or `foreign`. Defaults to `local`.
	PaymentResidence *SupportingDocumentPaymentResidence `json:"paymentResidence,omitempty"`

	// Foreign payment details; required for a `foreign` payment.
	ForeignPayment *WithholdingForeignPayment `json:"foreignPayment,omitempty"`

	// Its subtotal before taxes.
	Subtotal string `json:"subtotal"`

	// Its total.
	Total string `json:"total"`

	// Its taxes.
	Taxes []SupportingDocumentTax `json:"taxes"`

	// What is withheld from it.
	Withholdings []Withholding `json:"withholdings"`

	// How it is paid; the payments must add up to its total.
	Payments []WithholdingPayment `json:"payments"`
}

SupportingDocument: The supplier document whose taxes are withheld, usually an invoice.

type SupportingDocumentPaymentResidence

type SupportingDocumentPaymentResidence string

SupportingDocumentPaymentResidence is a value of the API. Whether the payment is `local` or `foreign`. Defaults to `local`. The API may add values: keep a default case.

const (
	SupportingDocumentPaymentResidenceLocal   SupportingDocumentPaymentResidence = "local"
	SupportingDocumentPaymentResidenceForeign SupportingDocumentPaymentResidence = "foreign"
)

The values of SupportingDocumentPaymentResidence.

type SupportingDocumentTax

type SupportingDocumentTax struct {
	// Tax type: `vat`.
	Type SupportingDocumentTaxType `json:"type"`

	// VAT rate in force on the supporting document issue date.
	Rate SupportingDocumentTaxRate `json:"rate"`

	// Taxable base.
	TaxableBase string `json:"taxableBase"`

	// The supporting document's VAT amount. Defaults to base × rate, rounded.
	Amount *string `json:"amount,omitempty"`
}

SupportingDocumentTax: A VAT of the supporting document.

type SupportingDocumentTaxRate

type SupportingDocumentTaxRate string

SupportingDocumentTaxRate is a value of the API. VAT rate in force on the supporting document issue date. The API may add values: keep a default case.

const (
	SupportingDocumentTaxRate0          SupportingDocumentTaxRate = "0"
	SupportingDocumentTaxRate5          SupportingDocumentTaxRate = "5"
	SupportingDocumentTaxRate8          SupportingDocumentTaxRate = "8"
	SupportingDocumentTaxRate12         SupportingDocumentTaxRate = "12"
	SupportingDocumentTaxRate13         SupportingDocumentTaxRate = "13"
	SupportingDocumentTaxRate14         SupportingDocumentTaxRate = "14"
	SupportingDocumentTaxRate15         SupportingDocumentTaxRate = "15"
	SupportingDocumentTaxRateExempt     SupportingDocumentTaxRate = "exempt"
	SupportingDocumentTaxRateNotSubject SupportingDocumentTaxRate = "not_subject"
)

The values of SupportingDocumentTaxRate.

type SupportingDocumentTaxType

type SupportingDocumentTaxType string

SupportingDocumentTaxType is a value of the API. Tax type: `vat`. The API may add values: keep a default case.

const (
	SupportingDocumentTaxTypeVAT SupportingDocumentTaxType = "vat"
)

The values of SupportingDocumentTaxType.

type TaxType

type TaxType string

TaxType is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	TaxTypeVAT TaxType = "vat"
	TaxTypeIce TaxType = "ice"
)

The values of TaxType.

type ThinEvent

type ThinEvent struct {
	// Format: uuid.
	ID string `json:"id"`

	Type EventType `json:"type"`

	Environment Environment `json:"environment"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`
}

ThinEvent: The body sent to `thin` endpoints: the event without its snapshot. Read it with GET /v1/events/{id}.

func (*ThinEvent) Info

func (e *ThinEvent) Info() EventInfo

Info returns what every event has: its id, type, environment and creation time.

type TimeoutError

type TimeoutError struct{ *ConnectionError }

TimeoutError means an attempt took longer than its timeout (WithTimeout), from sending it to reading the whole answer. It wraps a ConnectionError.

func (*TimeoutError) Timeout

func (e *TimeoutError) Timeout() bool

Timeout reports true, as net.Error does for timeouts.

func (*TimeoutError) Unwrap

func (e *TimeoutError) Unwrap() error

Unwrap returns the ConnectionError.

type UnknownEvent

type UnknownEvent struct {
	ID          string          `json:"id"`
	Type        EventType       `json:"type"`
	Environment Environment     `json:"environment"`
	CreatedAt   time.Time       `json:"createdAt"`
	Data        json.RawMessage `json:"data,omitempty"`
}

UnknownEvent is an event of a type this version of the SDK does not know. Its data is kept as raw JSON.

func (*UnknownEvent) Info

func (e *UnknownEvent) Info() EventInfo

Info returns what every event has: its id, type, environment and creation time.

type UnprocessableEntityError

type UnprocessableEntityError struct{ *APIError }

UnprocessableEntityError is a 422: the request is well formed but invalid (validation_failed, total_mismatch, ...).

func (*UnprocessableEntityError) Unwrap

func (e *UnprocessableEntityError) Unwrap() error

Unwrap returns the APIError.

type UpdateEstablishment

type UpdateEstablishment struct {
	// Address of the establishment (dirección del establecimiento).
	Address *string `json:"address,omitempty"`
}

UpdateEstablishment: Fields to change. The code cannot be changed.

type UpdateIssuer

type UpdateIssuer struct {
	// Legal name (razón social) as registered in the RUC.
	LegalName *string `json:"legalName,omitempty"`

	// Trade name (nombre comercial).
	TradeName Nullable[string] `json:"tradeName,omitzero"`

	// Head office address (dirección matriz).
	HeadOfficeAddress *string `json:"headOfficeAddress,omitempty"`

	TaxProfile *IssuerTaxProfilePatch `json:"taxProfile,omitempty"`

	Branding *IssuerBrandingInput `json:"branding,omitempty"`

	// Default of a document request's `options.sendEmail`: true emails every authorized document
	// (RIDE PDF and XML) to its buyer, false opts the issuer out. A request that sets
	// `options.sendEmail` decides for itself.
	SendEmailByDefault *bool `json:"sendEmailByDefault,omitempty"`
}

UpdateIssuer: Fields to change; null clears an optional field. The RUC cannot be changed.

type UpdateWebhookEndpoint

type UpdateWebhookEndpoint struct {
	// Where Flashpi POSTs the events: a public HTTPS URL without credentials or fragment. Changing
	// it requires a new verification.
	URL *string `json:"url,omitempty"`

	// A label for your own reference.
	Description Nullable[string] `json:"description,omitzero"`

	// Event types the endpoint receives; `*` receives every type, including future ones.
	EnabledEvents []EnabledEvent `json:"enabledEvents,omitempty"`

	// `full` (default): the event with a snapshot of its resource in `data`. `thin`: the event
	// without `data`, only `id`, `type`, `environment` and `createdAt` (read the snapshot with GET
	// /v1/events/{id}).
	PayloadMode *PayloadMode `json:"payloadMode,omitempty"`

	// true disables the endpoint (pending deliveries end); false enables it again (a new
	// verification is sent when it was never verified).
	Disabled *bool `json:"disabled,omitempty"`
}

UpdateWebhookEndpoint: Fields to change; null clears the description.

type WaybillCarrier

type WaybillCarrier struct {
	// Identification type of the carrier (not `final_consumer`).
	IDType IDType `json:"idType"`

	// Identification number.
	ID string `json:"id"`

	// Legal name.
	Name string `json:"name"`
}

WaybillCarrier: Who carries the goods.

type WaybillItem

type WaybillItem struct {
	// Your product code.
	Code *string `json:"code,omitempty"`

	// A second code.
	AuxiliaryCode *string `json:"auxiliaryCode,omitempty"`

	// Description.
	Description string `json:"description"`

	// Quantity, up to 6 decimals.
	Quantity string `json:"quantity"`

	// Up to 3 extra details (name → value).
	AdditionalDetails map[string]string `json:"additionalDetails,omitempty"`
}

WaybillItem: Goods carried for a recipient.

type WaybillRecipient

type WaybillRecipient struct {
	// Identification number.
	ID string `json:"id"`

	// Legal name.
	Name string `json:"name"`

	// Delivery address.
	Address string `json:"address"`

	// Reason for the transfer.
	TransferReason string `json:"transferReason"`

	// Single customs document (DAU), for imports and exports.
	CustomsDocument *string `json:"customsDocument,omitempty"`

	// Destination establishment code of the recipient.
	DestinationEstablishment *string `json:"destinationEstablishment,omitempty"`

	// Route.
	Route *string `json:"route,omitempty"`

	// The supporting document.
	SupportingDocument *WaybillSupportingDocument `json:"supportingDocument,omitempty"`

	// The goods carried for this recipient.
	Items []WaybillItem `json:"items"`
}

WaybillRecipient: Who receives the goods, and what.

type WaybillService

type WaybillService struct {
	// contains filtered or unexported fields
}

WaybillService issues waybills (guías de remisión). See client.Waybills.

func (*WaybillService) Create

func (s *WaybillService) Create(ctx context.Context, body CreateWaybill, options ...RequestOption) (*Document, error)

Create issues a waybill. See InvoiceService.Create for the answer and the retries.

type WaybillSupportingDocument

type WaybillSupportingDocument struct {
	// Type of the supporting document.
	Type *DocumentType `json:"type,omitempty"`

	// Its number.
	Number *string `json:"number,omitempty"`

	// Its authorization number (the 49-digit access key of electronic documents).
	AuthorizationNumber *string `json:"authorizationNumber,omitempty"`

	// Its issue date. Format: date.
	IssueDate *string `json:"issueDate,omitempty"`
}

WaybillSupportingDocument: The document that supports the transfer, usually the sales invoice.

type WebhookDelivery

type WebhookDelivery struct {
	// Format: uuid.
	ID string `json:"id"`

	// Format: uuid.
	WebhookEndpointID string `json:"webhookEndpointId"`

	// The event, also the webhook-id header. Format: uuid.
	EventID string `json:"eventId"`

	EventType EventType `json:"eventType"`

	PayloadMode PayloadMode `json:"payloadMode"`

	// `pending` (an attempt is scheduled or running), `succeeded` or `failed`.
	Status WebhookDeliveryStatus `json:"status"`

	AttemptCount int `json:"attemptCount"`

	// Format: date-time.
	NextAttemptAt *time.Time `json:"nextAttemptAt"`

	// Format: date-time.
	LastAttemptAt *time.Time `json:"lastAttemptAt"`

	LastResponseStatus *int `json:"lastResponseStatus"`

	// Why it failed: `unexpected_status` (an answer other than 2xx, see the status), `timeout`,
	// `connection_failed`, `dns_resolution_failed`, `tls_error`, `address_not_allowed`,
	// `invalid_url`, or without an attempt `endpoint_disabled` and `endpoint_not_verified`.
	LastError *string `json:"lastError"`

	// Format: date-time.
	SucceededAt *time.Time `json:"succeededAt"`

	// No automatic attempt after this time. Format: date-time.
	RetryUntil time.Time `json:"retryUntil"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

WebhookDelivery: One event sent to one endpoint, retried with backoff for 72 hours until it gets a 2xx.

type WebhookDeliveryAttempt

type WebhookDeliveryAttempt struct {
	// 1 for the first attempt.
	Number int `json:"number"`

	Trigger WebhookDeliveryAttemptTrigger `json:"trigger"`

	// Format: date-time.
	StartedAt time.Time `json:"startedAt"`

	DurationMs int `json:"durationMs"`

	ResponseStatus *int `json:"responseStatus"`

	// Why it failed: `unexpected_status` (an answer other than 2xx, see the status), `timeout`,
	// `connection_failed`, `dns_resolution_failed`, `tls_error`, `address_not_allowed`,
	// `invalid_url`, or without an attempt `endpoint_disabled` and `endpoint_not_verified`.
	Error *string `json:"error"`

	Succeeded bool `json:"succeeded"`
}

WebhookDeliveryAttempt: One HTTP attempt of a delivery.

type WebhookDeliveryAttemptTrigger

type WebhookDeliveryAttemptTrigger string

WebhookDeliveryAttemptTrigger is a value of the API. One of the constants below. The API may add values: keep a default case.

const (
	WebhookDeliveryAttemptTriggerAutomatic WebhookDeliveryAttemptTrigger = "automatic"
	WebhookDeliveryAttemptTriggerReplay    WebhookDeliveryAttemptTrigger = "replay"
)

The values of WebhookDeliveryAttemptTrigger.

type WebhookDeliveryDetail

type WebhookDeliveryDetail struct {
	// Format: uuid.
	ID string `json:"id"`

	// Format: uuid.
	WebhookEndpointID string `json:"webhookEndpointId"`

	// The event, also the webhook-id header. Format: uuid.
	EventID string `json:"eventId"`

	EventType EventType `json:"eventType"`

	PayloadMode PayloadMode `json:"payloadMode"`

	// `pending` (an attempt is scheduled or running), `succeeded` or `failed`.
	Status WebhookDeliveryStatus `json:"status"`

	AttemptCount int `json:"attemptCount"`

	// Format: date-time.
	NextAttemptAt *time.Time `json:"nextAttemptAt"`

	// Format: date-time.
	LastAttemptAt *time.Time `json:"lastAttemptAt"`

	LastResponseStatus *int `json:"lastResponseStatus"`

	// Why it failed: `unexpected_status` (an answer other than 2xx, see the status), `timeout`,
	// `connection_failed`, `dns_resolution_failed`, `tls_error`, `address_not_allowed`,
	// `invalid_url`, or without an attempt `endpoint_disabled` and `endpoint_not_verified`.
	LastError *string `json:"lastError"`

	// Format: date-time.
	SucceededAt *time.Time `json:"succeededAt"`

	// No automatic attempt after this time. Format: date-time.
	RetryUntil time.Time `json:"retryUntil"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`

	// Oldest first.
	Attempts []WebhookDeliveryAttempt `json:"attempts"`
}

WebhookDeliveryDetail: A delivery with its attempts.

type WebhookDeliveryListParams

type WebhookDeliveryListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string

	// Only deliveries in this status.
	Status *WebhookDeliveryStatus

	// Only deliveries of this event type.
	EventType *EventType

	// Only the delivery of this event. Format: uuid.
	EventID *string
}

WebhookDeliveryListParams holds the query of webhookEndpointsDeliveriesList (GET /v1/webhook-endpoints/{endpointId}/deliveries). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type WebhookDeliveryService

type WebhookDeliveryService struct {
	// contains filtered or unexported fields
}

WebhookDeliveryService reads the deliveries of events to one endpoint. See client.WebhookEndpoints.Deliveries.

func (*WebhookDeliveryService) Get

func (s *WebhookDeliveryService) Get(ctx context.Context, endpointID, deliveryID string, options ...RequestOption) (*WebhookDeliveryDetail, error)

Get retrieves a delivery with its attempts.

func (*WebhookDeliveryService) List

List walks the deliveries of an endpoint, newest first, optionally by status, event type or event, reading the pages as it goes. params may be nil.

func (*WebhookDeliveryService) ListPage

func (s *WebhookDeliveryService) ListPage(ctx context.Context, endpointID string, params *WebhookDeliveryListParams, options ...RequestOption) (*Page[*WebhookDelivery], error)

ListPage reads the first page of an endpoint's deliveries, newest first; NextPage reads the next one.

func (*WebhookDeliveryService) Replay

func (s *WebhookDeliveryService) Replay(ctx context.Context, endpointID, deliveryID string, options ...RequestOption) (*WebhookDeliveryDetail, error)

Replay sends the delivery's event again, with the same webhook-id.

type WebhookDeliveryStatus

type WebhookDeliveryStatus string

WebhookDeliveryStatus is a value of the API. `pending` (an attempt is scheduled or running), `succeeded` or `failed`. The API may add values: keep a default case.

const (
	WebhookDeliveryStatusPending   WebhookDeliveryStatus = "pending"
	WebhookDeliveryStatusSucceeded WebhookDeliveryStatus = "succeeded"
	WebhookDeliveryStatusFailed    WebhookDeliveryStatus = "failed"
)

The values of WebhookDeliveryStatus.

type WebhookEndpoint

type WebhookEndpoint struct {
	// Format: uuid.
	ID string `json:"id"`

	// Where Flashpi POSTs the events: a public HTTPS URL without credentials or fragment. Changing
	// it requires a new verification.
	URL string `json:"url"`

	// A label for your own reference.
	Description *string `json:"description"`

	// Event types the endpoint receives; `*` receives every type, including future ones.
	EnabledEvents []EnabledEvent `json:"enabledEvents"`

	// `full` (default): the event with a snapshot of its resource in `data`. `thin`: the event
	// without `data`, only `id`, `type`, `environment` and `createdAt` (read the snapshot with GET
	// /v1/events/{id}).
	PayloadMode PayloadMode `json:"payloadMode"`

	// `pending_verification` (receives nothing until it echoes the challenge), `active` or
	// `disabled`.
	Status WebhookEndpointStatus `json:"status"`

	// Mode of the events it receives.
	Environment Environment `json:"environment"`

	Verification WebhookEndpointVerification `json:"verification"`

	// After a rotation: until when deliveries are also signed with the previous secret. Format:
	// date-time.
	PreviousSecretExpiresAt *time.Time `json:"previousSecretExpiresAt"`

	// Format: date-time.
	DisabledAt *time.Time `json:"disabledAt"`

	// Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	// Format: date-time.
	UpdatedAt time.Time `json:"updatedAt"`
}

WebhookEndpoint: A URL that receives Standard Webhooks, signed with a whsec_ secret (read it with GET .../secret). It receives the events of the mode of the API key that created it (test or live).

type WebhookEndpointListParams

type WebhookEndpointListParams struct {
	// Maximum number of items to return. Default: 20.
	Limit *int

	// The `pagination.nextCursor` of the previous page. Omit it for the first page.
	Cursor *string
}

WebhookEndpointListParams holds the query of webhookEndpointsList (GET /v1/webhook-endpoints). Nil members are not sent. Limit is the size of each page: List walks every page, so break out of the loop to stop early.

type WebhookEndpointSecret

type WebhookEndpointSecret struct {
	// The current whsec_ secret (Standard Webhooks): base64 of the HMAC-SHA256 key after the
	// prefix.
	Secret string `json:"secret"`

	// After a rotation: until when the previous secret also signs. Format: date-time.
	PreviousSecretExpiresAt *time.Time `json:"previousSecretExpiresAt"`
}

WebhookEndpointSecret: The signing secret of an endpoint.

type WebhookEndpointService

type WebhookEndpointService struct {

	// Deliveries reads the deliveries of an endpoint.
	Deliveries *WebhookDeliveryService
	// contains filtered or unexported fields
}

WebhookEndpointService manages the URLs Flashpi sends events to, and the deliveries of those events. It needs an account-scoped API key with read_write access. To check the signature of a webhook you receive, use UnwrapWebhook instead. See client.WebhookEndpoints.

func (*WebhookEndpointService) Create

Create creates an endpoint. Flashpi sends it the activation handshake (webhook_endpoint.verification) right away.

func (*WebhookEndpointService) Delete

func (s *WebhookEndpointService) Delete(ctx context.Context, endpointID string, options ...RequestOption) error

Delete deletes an endpoint.

func (*WebhookEndpointService) Get

func (s *WebhookEndpointService) Get(ctx context.Context, endpointID string, options ...RequestOption) (*WebhookEndpoint, error)

Get retrieves an endpoint.

func (*WebhookEndpointService) GetSecret

func (s *WebhookEndpointService) GetSecret(ctx context.Context, endpointID string, options ...RequestOption) (*WebhookEndpointSecret, error)

GetSecret retrieves the endpoint's signing secret (whsec_...), for UnwrapWebhook.

func (*WebhookEndpointService) List

List walks the endpoints, newest first, reading the pages as it goes. params may be nil.

func (*WebhookEndpointService) ListPage

ListPage reads the first page of endpoints, newest first; NextPage reads the next one.

func (*WebhookEndpointService) RotateSecret

func (s *WebhookEndpointService) RotateSecret(ctx context.Context, endpointID string, body *RotateWebhookEndpointSecret, options ...RequestOption) (*WebhookEndpoint, error)

RotateSecret creates a new signing secret. The previous one keeps signing next to it for body.PreviousSecretExpiresInHours (default 24). body may be nil, which sends no body.

func (*WebhookEndpointService) Update

func (s *WebhookEndpointService) Update(ctx context.Context, endpointID string, body UpdateWebhookEndpoint, options ...RequestOption) (*WebhookEndpoint, error)

Update changes an endpoint (only the members set are sent; flashpi.Null clears the description).

func (*WebhookEndpointService) Verify

func (s *WebhookEndpointService) Verify(ctx context.Context, endpointID string, options ...RequestOption) (*WebhookEndpoint, error)

Verify sends the activation handshake again, to activate an endpoint that did not answer it.

type WebhookEndpointStatus

type WebhookEndpointStatus string

WebhookEndpointStatus is a value of the API. `pending_verification` (receives nothing until it echoes the challenge), `active` or `disabled`. The API may add values: keep a default case.

const (
	WebhookEndpointStatusPendingVerification WebhookEndpointStatus = "pending_verification"
	WebhookEndpointStatusActive              WebhookEndpointStatus = "active"
	WebhookEndpointStatusDisabled            WebhookEndpointStatus = "disabled"
)

The values of WebhookEndpointStatus.

type WebhookEndpointVerification

type WebhookEndpointVerification struct {
	// Format: date-time.
	VerifiedAt *time.Time `json:"verifiedAt"`

	// Whether a handshake attempt is scheduled or running.
	InProgress bool `json:"inProgress"`

	// Attempts of the current handshake.
	Attempts int `json:"attempts"`

	// Format: date-time.
	LastAttemptAt *time.Time `json:"lastAttemptAt"`

	// Why the last attempt failed: `challenge_mismatch`, `unexpected_status`, `timeout`,
	// `connection_failed`, `dns_resolution_failed`, `tls_error`, `address_not_allowed` or
	// `invalid_url`.
	LastError *string `json:"lastError"`

	LastResponseStatus *int `json:"lastResponseStatus"`
}

WebhookEndpointVerification: The activation handshake: Flashpi POSTs a signed `webhook_endpoint.verification` body with a `challenge`, and the endpoint must answer 2xx echoing it.

type WebhookEndpointVerificationEvent

type WebhookEndpointVerificationEvent struct {
	// This attempt's id, also its webhook-id header: new on every attempt. Format: uuid.
	ID string `json:"id"`

	Type string `json:"type"`

	Environment Environment `json:"environment"`

	// When this attempt was sent. Format: date-time.
	CreatedAt time.Time `json:"createdAt"`

	Data WebhookEndpointVerificationEventData `json:"data"`
}

WebhookEndpointVerificationEvent: The activation handshake of an endpoint, sent when it is created, when its URL changes and on POST /v1/webhook-endpoints/{id}/verify; every attempt has a new id and challenge. It is signed like every webhook; answer 2xx with `{"challenge": "<data.challenge>"}` (or the challenge as plain text).

func (*WebhookEndpointVerificationEvent) Info

Info returns what every event has: its id, type, environment and creation time.

type WebhookEndpointVerificationEventData

type WebhookEndpointVerificationEventData struct {
	// Format: uuid.
	WebhookEndpointID string `json:"webhookEndpointId"`

	// Random value to echo back, new on every attempt: echo the one of this request.
	Challenge string `json:"challenge"`
}

WebhookEndpointVerificationEventData is a schema of the API.

type WebhookEvent

type WebhookEvent interface {
	// Info returns what every event has: its id, type, environment and creation time.
	Info() EventInfo
	// contains filtered or unexported methods
}

WebhookEvent is what a webhook endpoint receives, as UnwrapWebhook returns it: one of

  • *DocumentEvent, *CertificateEvent and *AccountEvent (an Event, in full mode),
  • *ThinEvent (an event of an endpoint in thin mode, without its data: read it with client.Events.Get),
  • *WebhookEndpointVerificationEvent (the activation handshake: answer it with {"challenge": e.Data.Challenge}),
  • *UnknownEvent (a type this version of the SDK does not know).

Use a type switch:

switch e := event.(type) {
case *flashpi.WebhookEndpointVerificationEvent:
	// answer {"challenge": e.Data.Challenge}
case *flashpi.DocumentEvent:
	fmt.Println(e.Type, e.Data.AccessKey)
}

func UnwrapWebhook

func UnwrapWebhook(payload []byte, header http.Header, secret string, options ...WebhookOption) (WebhookEvent, error)

UnwrapWebhook verifies a webhook (see VerifyWebhookSignature) and returns its event. It needs no API key and does no I/O.

Pass the raw body exactly as received, before any JSON parsing, and the request's headers. When it fails with a *WebhookVerificationError, answer 400 and ignore the request. Narrow the event with a type switch (see WebhookEvent):

event, err := flashpi.UnwrapWebhook(body, r.Header, os.Getenv("FLASHPI_WEBHOOK_SECRET"))

type WebhookOption

type WebhookOption func(*webhookSettings)

WebhookOption configures UnwrapWebhook and VerifyWebhookSignature.

func WithNow

func WithNow(now time.Time) WebhookOption

WithNow sets the current time, for tests (default: the clock).

func WithTolerance

func WithTolerance(tolerance time.Duration) WebhookOption

WithTolerance sets the largest gap between a webhook's timestamp and now (default 5 minutes).

type WebhookVerificationError

type WebhookVerificationError struct {
	// Reason says why it was rejected.
	Reason WebhookVerificationReason

	// Message explains it, in English.
	Message string

	// Err is the cause, if any (the JSON error of a body that is not an event).
	Err error
}

WebhookVerificationError means a webhook did not come from Flashpi, was altered, or is too old: answer 400 and ignore it. With the reason WebhookInvalidSecret the secret you passed is empty or not a whsec_ secret: that is your configuration, so log it and answer 500.

func (*WebhookVerificationError) As

func (e *WebhookVerificationError) As(target any) bool

As lets errors.As read a WebhookVerificationError as an *Error.

func (*WebhookVerificationError) Error

func (e *WebhookVerificationError) Error() string

func (*WebhookVerificationError) Unwrap

func (e *WebhookVerificationError) Unwrap() error

Unwrap returns the cause, if any.

type WebhookVerificationReason

type WebhookVerificationReason string

WebhookVerificationReason says why a webhook was rejected.

const (
	// The webhook-id, webhook-timestamp or webhook-signature header is missing.
	WebhookMissingHeaders WebhookVerificationReason = "missing_headers"
	// The webhook-timestamp is not Unix seconds.
	WebhookInvalidTimestamp WebhookVerificationReason = "invalid_timestamp"
	// The webhook-timestamp is too far from now (more than the tolerance).
	WebhookTimestampOutOfRange WebhookVerificationReason = "timestamp_out_of_range"
	// No signature matches the body and the secret.
	WebhookNoMatchingSignature WebhookVerificationReason = "no_matching_signature"
	// The secret is empty or not a whsec_ secret.
	WebhookInvalidSecret WebhookVerificationReason = "invalid_secret"
	// The body is not a JSON object.
	WebhookInvalidPayload WebhookVerificationReason = "invalid_payload"
)

The reasons of a WebhookVerificationError.

type WithheldSubject

type WithheldSubject struct {
	// Identification type (not `final_consumer`).
	IDType IDType `json:"idType"`

	// Identification number.
	ID string `json:"id"`

	// Legal name.
	Name string `json:"name"`

	// Whether the supplier is a related party.
	RelatedParty bool `json:"relatedParty"`

	// Required when `idType` is `foreign_id`: `individual` or `company`.
	SubjectType *WithheldSubjectSubjectType `json:"subjectType,omitempty"`

	// Where the authorized receipt is emailed (see `options.sendEmail`). Format: email.
	Email *string `json:"email,omitempty"`
}

WithheldSubject: The supplier whose taxes are withheld.

type WithheldSubjectSubjectType

type WithheldSubjectSubjectType string

WithheldSubjectSubjectType is a value of the API. Required when `idType` is `foreign_id`: `individual` or `company`. The API may add values: keep a default case.

const (
	WithheldSubjectSubjectTypeIndividual WithheldSubjectSubjectType = "individual"
	WithheldSubjectSubjectTypeCompany    WithheldSubjectSubjectType = "company"
)

The values of WithheldSubjectSubjectType.

type Withholding

type Withholding struct {
	// Tax withheld: `income_tax`, `vat` or `isd`.
	Tax WithholdingTax `json:"tax"`

	// Withholding code: TABLA 20 for `vat` (for example `1` = 30%, `2` = 70%, `3` = 100%) and
	// `isd`, the Catálogo ATS for `income_tax` (for example `312`).
	Code string `json:"code"`

	// Taxable base of the withholding.
	TaxableBase string `json:"taxableBase"`

	// Percentage. Required for `income_tax`; for `vat` and `isd` Flashpi takes it from the code,
	// and a different value is refused.
	Rate *string `json:"rate,omitempty"`

	// Dividend details.
	Dividends *WithholdingDividends `json:"dividends,omitempty"`

	// Banana box purchase.
	BananaBoxes *WithholdingBananaBoxes `json:"bananaBoxes,omitempty"`
}

Withholding: A withholding. Flashpi computes the withheld amount: taxable base × percentage, rounded to 2 decimals.

type WithholdingBananaBoxes

type WithholdingBananaBoxes struct {
	// Number of boxes.
	Count int `json:"count"`

	// Price per box.
	PricePerBox string `json:"pricePerBox"`
}

WithholdingBananaBoxes: Required for the banana box income tax codes (338, 340, 341, 342, 342A, 342B).

type WithholdingDividends

type WithholdingDividends struct {
	// Dividend payment date. Format: date.
	PaymentDate string `json:"paymentDate"`

	// Corporate income tax attributable to the dividends.
	CorporateIncomeTax string `json:"corporateIncomeTax"`

	// Fiscal year of the distributed profits.
	ProfitFiscalYear string `json:"profitFiscalYear"`
}

WithholdingDividends: Required when `taxSupportCode` is 10.

type WithholdingForeignPayment

type WithholdingForeignPayment struct {
	// Tax regime of the country of payment: `general`, `tax_haven` or `preferential` (preferential
	// regime or lower-tax jurisdiction).
	Regime WithholdingForeignPaymentRegime `json:"regime"`

	// Country of payment, as the SRI country code (3 or 4 digits).
	Country string `json:"country"`

	// Whether a double taxation treaty applies.
	DoubleTaxationTreatyApplies bool `json:"doubleTaxationTreatyApplies"`

	// Whether the payment is subject to withholding under the law. Required when no double taxation
	// treaty applies.
	SubjectToWithholdingUnderLaw *bool `json:"subjectToWithholdingUnderLaw,omitempty"`

	// Whether it is a payment to a preferential tax regime.
	PreferentialTaxRegime bool `json:"preferentialTaxRegime"`
}

WithholdingForeignPayment: Required when the payment goes abroad (`paymentResidence` is `foreign`).

type WithholdingForeignPaymentRegime

type WithholdingForeignPaymentRegime string

WithholdingForeignPaymentRegime is a value of the API. Tax regime of the country of payment: `general`, `tax_haven` or `preferential` (preferential regime or lower-tax jurisdiction). The API may add values: keep a default case.

const (
	WithholdingForeignPaymentRegimeGeneral      WithholdingForeignPaymentRegime = "general"
	WithholdingForeignPaymentRegimeTaxHaven     WithholdingForeignPaymentRegime = "tax_haven"
	WithholdingForeignPaymentRegimePreferential WithholdingForeignPaymentRegime = "preferential"
)

The values of WithholdingForeignPaymentRegime.

type WithholdingPayment

type WithholdingPayment struct {
	// Payment method (same values as `DocumentPayment.method`).
	Method PaymentMethod `json:"method"`

	// Amount.
	Amount string `json:"amount"`
}

WithholdingPayment: A payment of the supporting document.

type WithholdingService

type WithholdingService struct {
	// contains filtered or unexported fields
}

WithholdingService issues withholding receipts (comprobantes de retención). See client.Withholdings.

func (*WithholdingService) Create

func (s *WithholdingService) Create(ctx context.Context, body CreateWithholding, options ...RequestOption) (*Document, error)

Create issues a withholding receipt. See InvoiceService.Create for the answer and the retries.

type WithholdingTax

type WithholdingTax string

WithholdingTax is a value of the API. Tax withheld: `income_tax`, `vat` or `isd`. The API may add values: keep a default case.

const (
	WithholdingTaxIncomeTax WithholdingTax = "income_tax"
	WithholdingTaxVAT       WithholdingTax = "vat"
	WithholdingTaxIsd       WithholdingTax = "isd"
)

The values of WithholdingTax.

Directories

Path Synopsis
internal
cmd/openapi command
Command openapi keeps the SDK's copy of the Flashpi API contract and the Go types generated from it in sync.
Command openapi keeps the SDK's copy of the Flashpi API contract and the Go types generated from it in sync.
cmd/readme command
Command readme keeps the Go examples of the READMEs compiling.
Command readme keeps the Go examples of the READMEs compiling.
readme/en
Package en compiles the Go examples of README.en.md, which internal/cmd/readme writes here.
Package en compiles the Go examples of README.en.md, which internal/cmd/readme writes here.
readme/es
Package es compiles the Go examples of README.md, which internal/cmd/readme writes here.
Package es compiles the Go examples of README.md, which internal/cmd/readme writes here.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL