Pago Ruby SDK
Ruby client for the Pago API, generated from its OpenAPI
specification. Requires Ruby 3.1 or newer and has no runtime dependencies —
only net/http, json and openssl from the standard library.
gem "pago-sdk"
Usage
require "pago"
client = Pago::Client.new(access_token: ENV.fetch("PAGO_ACCESS_TOKEN"))
Pago::Client always tracks the latest API version (2026-04).
Pin a version explicitly to opt out of that:
client = Pago::V2026_04::Client.new(access_token: token)
The base URL defaults to https://api.pago.sh and reads PAGO_BASE_URL when
set; the sandbox lives at Pago::BaseClient::SANDBOX_BASE_URL.
Models
Models are immutable value objects built with keyword arguments. Required properties are required keyword arguments; everything else defaults to unset.
order = Pago::Models::Order.from_json(payload)
order.id
order.to_json_hash # Hash ready for JSON.generate
order.to_json # String
Only the attributes you actually set are serialized, so a partial update never
sends null for the fields it does not touch. Properties this SDK release does
not know about survive a from_json / to_json round trip untouched.
Pagination
Every paginated operation gets an _each companion returning a
Pago::Paginator, a plain Enumerable over the items that fetches pages on
demand:
client.products.list_each(organization_id: id).each { |product| puts product.name }
client.products.list_each(organization_id: id).first(50)
client.products.list_each(organization_id: id) { |product| puts product.name }
client.products.list_each(organization_id: id).pages.count # page objects
Errors
Every declared error response has its own class, inheriting from the generic error matching its status code:
begin
client.products.get(product_id)
rescue Pago::Errors::ResourceNotFound => e
e.status_code # 404
e.data # deserialized error payload
rescue Pago::NotFoundError
# any 404 of the API
rescue Pago::APIError => e
# anything the API rejected
rescue Pago::NetworkError
# the request never reached the API
end
Webhooks
Signature verification follows the Standard Webhooks specification, and the payload comes back as the model matching its event type:
event = Pago::Webhooks.validate_event(
body: request.body.read,
headers: request.headers,
secret: ENV.fetch("PAGO_WEBHOOK_SECRET")
)
case event
when Pago::Models::WebhookOrderPaidPayload then fulfill(event.data)
end
The secret is the one shown when the endpoint is created — the whsec_ prefix
followed by the base64 encoded signing key. Pass it verbatim: the SDK strips the
prefix and base64 decodes the rest to obtain the HMAC key, exactly like every
other Standard Webhooks implementation.
It raises Pago::WebhookVerificationError on a bad signature or a timestamp
outside the five minute window, Pago::WebhookSecretError (a subclass of it)
when the secret is not in whsec_<base64> form, and
Pago::WebhookUnknownTypeError for an event type this SDK release does not know.
Custom HTTP adapter
The client talks to any object answering call(Pago::HTTP::Request) and
returning a Pago::HTTP::Response — useful for instrumentation, retries or
tests:
class LoggingAdapter
def initialize(inner) = @inner = inner
def call(request)
warn "#{request.http_method} #{request.url}"
@inner.call(request)
end
end
Pago::Client.new(access_token: token, adapter: LoggingAdapter.new(Pago::HTTP::NetHTTPAdapter.new))
Types
The gem ships RBS signatures under sig/, and
every public method carries YARD documentation.
License
MIT