Skip to content

mopx/efacturapty-ruby

Repository files navigation

efacturapty

Disclaimer: This gem is an independent, unofficial Ruby client library. It is not affiliated with, endorsed by, or supported by efacturapty or the Dirección General de Ingresos (DGI) of Panama. For official documentation and support, visit efacturapty.com and the DGI e-factura portal.

AI-generated code notice: This library was generated with the assistance of AI tools. Review the source carefully before using it in production, and test against the sandbox environment before going live.

Ruby client gem for Panama's DGI e-invoicing (e-factura / SFEP) system, powered by the efacturapty service.

Handles authentication, PAC authorization, invoice creation, cancellation, file downloads, and all reference catalogs — compatible with Ruby 2.6+ / Rails 5.2+ and modern stacks.


Table of Contents


Installation

Add to your Gemfile:

gem "efacturapty"

Or install directly:

gem install efacturapty

Quick start

require "efacturapty"

Efacturapty.configure do |c|
  c.api_key = ENV["EFACTURAPTY_API_KEY"]
end

client = Efacturapty.client

# List countries catalog
countries = client.catalogs.countries

# Create and authorize an invoice
response = client.invoices.create(invoice_payload, include_qr: true)
puts response.cufe        # CUFE assigned by DGI
puts response.autorizada  # true when successfully authorized

Configuration

Rails

Run the install generator:

rails generate efacturapty:install

This creates config/initializers/efacturapty.rb:

Efacturapty.configure do |config|
  config.api_key = ENV.fetch("EFACTURAPTY_API_KEY", nil)

  # config.open_timeout  = 5
  # config.read_timeout  = 30
  # config.logger        = Rails.logger
end

Plain Ruby

require "efacturapty"

Efacturapty.configure do |c|
  c.api_key = "your-api-key"
end

client = Efacturapty.client

Multiple clients

client = Efacturapty::Client.new(
  api_key: "your-api-key",
  logger:  Logger.new($stdout)
)

All configuration options

Option Default Description
api_key Required. Bearer token issued by efacturapty
api_base_url https://api.efacturapty.com Override API base URL
open_timeout 5 TCP connect timeout (seconds)
read_timeout 30 Read timeout (seconds)
logger nil Any Logger-compatible object

Authentication

Set config.api_key to the Bearer token issued by your efacturapty account. The token is sent as the Authorization: Bearer … header on every request. No token exchange or refresh logic is needed.


Usage

Invoices

Create and authorize an invoice

Accepts a plain Ruby Hash matching the DGI InvoiceRequest structure. See docs/invoices.md for the full payload schema.

resp = client.invoices.create(
  {
    "datosGenerales" => {
      "tipoDocumento"   => "01",
      "naturalezaOperacion" => "01",
      # ...
    },
    "listaItems" => [ { ... } ],
    "totales"    => { ... }
  },
  include_qr:  true,   # include QR image (Base64) in response
  include_xml: true    # include raw authorized XML in response
)

resp.cufe                     # => "CUFE-xxxx..."
resp.autorizada                # => true
resp.qrContent                 # => "https://efacturapty.com/qr?cufe=..."
resp.qrContentImageBase64      # => "iVBORw0KGgo..."
resp.xml                       # => "<?xml version=\"1.0\"...>"

Response keys are looked up as-is (no camelCase→snake_case translation), so use the exact DGI field name — resp.qrContentImageBase64, not resp.qr_content_image_base64 — or hash-style resp["qrContentImageBase64"].

Create from XML

resp = client.invoices.create_from_xml(xml_string)

List invoices (paginated)

page = client.invoices.list(
  date_from:    "2026-01-01",
  date_to:      "2026-06-30",
  status:       "Authorized",
  page:         1,
  page_size:    50
)

Available filter keys: date_from, date_to, ruc, name, status, page, page_size, and environment (deprecated by the API, accepted but discouraged). Any other key is silently dropped rather than sent as a meaningless query param — see docs/invoices.md for the full list of what earlier gem versions accepted but the real API never supported.

Pass locale: "en" to override the Accept-Language header.

Get invoice detail

resp = client.invoices.find(cufe_id)

Authorization protocol + QR

resp = client.invoices.authorization(cufe)
resp = client.invoices.authorization_admin(cufe)  # admin: any taxpayer

QR image

resp = client.invoices.qr_image(cufe)  # Base64-encoded PNG

Files (binary downloads)

pdf  = client.invoices.cafe_file(cufe_id)   # => binary PDF String
xml  = client.invoices.xml_file(cufe_id)    # => binary XML String
xml  = client.invoices.xml_from_dgi(cufe)   # => XML from DGI
html = client.invoices.html_cafe(cufe_id)   # => Response (HTML body)

Processing result

resp = client.invoices.taxpayer_response(invoice_id)

Invoice Events (cancellation)

resp = client.invoice_events.cancel(
  cufe:   "CUFE-xxxx...",
  reason: "Error en los datos del receptor"
)

Catalogs

client.catalogs.countries       # list of countries
client.catalogs.currencies      # list of currencies
client.catalogs.locations       # districts / provinces / corregimientos
client.catalogs.cpbs_families   # CPBS product/service families
client.catalogs.cpbs_segments   # CPBS product/service segments

Response objects

All non-binary endpoints return an Efacturapty::Response object. Keys are accessible as methods or with []:

resp = client.catalogs.countries
resp["name"]   # hash-style
resp.name      # method-style
resp.to_h      # underlying Hash
resp.to_a      # underlying Array (for list responses)
resp.status    # HTTP status code

Error handling

begin
  client.invoices.create(payload)
rescue Efacturapty::ValidationError => e
  # client-side pre-flight check failed — no HTTP request was made
  puts e.errors  # Array of every violation found
rescue Efacturapty::AuthenticationError => e
  # 401 or bad credentials
  puts e.message
rescue Efacturapty::BadRequestError => e
  # 400 / 422
  puts e.body    # parsed response body
  puts e.status  # 400
rescue Efacturapty::NotFoundError
  # 404
rescue Efacturapty::RateLimitError
  # 429
rescue Efacturapty::ServerError
  # 5xx
rescue Efacturapty::ApiError => e
  # any other API error
rescue Efacturapty::ConfigurationError
  # missing credentials
rescue Efacturapty::Error => e
  # catch-all
end

Error hierarchy

Efacturapty::Error
├── ConfigurationError
├── ValidationError        (client-side only — has .errors, no HTTP status/body)
└── ApiError
    ├── AuthenticationError  (401)
    ├── BadRequestError      (400, 422)
    ├── NotFoundError        (404)
    ├── RateLimitError       (429)
    └── ServerError          (5xx)

Development

git clone https://github.com/mopx/efacturapty-ruby
cd efacturapty-ruby
bundle install

bundle exec rspec        # run tests
bundle exec rubocop      # lint
bin/console              # interactive console with gem loaded

gem build efacturapty.gemspec  # build .gem file

Ruby version compatibility

Runtime requires Ruby 2.6+. Development tools (RuboCop, RSpec) run on modern Ruby. Use a version manager (rbenv / rvm) to test on Ruby 2.6.10 with bundle exec rspec.


Contributing

Bug reports and pull requests welcome at https://github.com/mopx/efacturapty-ruby.

License

MIT — see LICENSE.

About

Ruby client gem for Panama's DGI e-invoicing (e-factura / SFEP) system, powered by the efacturapty service.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages