All notable changes to this project are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.3.0
Synced with the official Ruby SDK 3.4.0 (this SDK was at 3.2.1). See DIVERGENCES.md for every intentional departure from it.
No public function was removed or changed arity.
Fixed
- Webhook replay tolerance rejected every notification.
Mercadopago.Webhook.Validatorcompared thetsfrom thex-signatureheader, which MercadoPago sends in seconds, against a clock in milliseconds. The computed drift was therefore around 55 years, so passingtolerance_seconds:rejected every webhook with:timestamp_out_of_tolerance— the option meant to harden replay protection was the one thing that broke validation. Callers who left it unset were unaffected, which is why this went unnoticed. The reference Ruby SDK carried the same defect until 3.3.0. The test fixture used a millisecondtsand a clock derived from it, so it agreed with the bug; it now uses a realistic ten-digittsand a real millisecond clock.Every version published before this one is affected — 0.1.0, 0.2.0 and 0.2.1. The defect dates from the first commit. Two things to check before deploying the upgrade, both covered in Upgrading from 0.2.x:- Your webhook endpoint has been rejecting everything, so MercadoPago has been retrying. Those retries will start succeeding — the handler must be idempotent.
- If you worked around the bug by passing
:nowin seconds, that inverts: it used to widen the window 1000×, and now rejects everything. Drop the option or return:os.system_time(:millisecond). The SDK warns when it is handed a clock in the wrong unit.
Added
Mercadopago.Pagination.stream/3and asearch_stream/3on every resource with asearch/3—AdvancedPayment,Chargeback,Customer,Invoice,MerchantOrder,Order,Payment,Preapproval,PreapprovalPlan,PreferenceandSubscription. Lazily walks thelimit/offsetpages and yields the records. Reads theresults,data(Orders v2) andelementsshapes, and acceptspaging.totalas an integer or a string. A failure mid-walk raises rather than truncating the stream silently.:kindonMercadopago.Error— the class of failure as an atom (:not_found,:rate_limit,:server, …), from the same status mapping the Ruby SDK gives its twelve exception subclasses. One struct with a matchable field, rather than twelve modules.:request_idand:retry_afteronMercadopago.Error, lifted from thex-request-idandRetry-Afterresponse headers.Mercadopago.Card.update/5,Mercadopago.Payment.capture/4,Mercadopago.Preference.search/3andMercadopago.Refund.get/4.Mercadopago.Subscription, mirroring the Ruby SDK'ssdk.subscription. The same/preapprovalendpointsMercadopago.Preapprovalalready exposed; every function delegates to it.:retry_on, on the client and per call, to choose which HTTP statuses make a GET worth retrying (default[429, 500, 502, 503, 504]). Retryable transport failures are retried regardless.- A warning when
Mercadopago.Webhook.Validatoris given a:nowfunction returning what looks like seconds rather than milliseconds — the shape of the pre-0.3.0 workaround for the bug above, which stops working once the unit is correct. [:mercadopago, :request, :retry]telemetry event, fired just before each backoff sleep with%{delay: milliseconds}and the failed attempt's metadata. This is the SDK's equivalent of the Ruby SDK'son_retrycallback.- Examples for Automatic Payments through Orders
(
examples/order/create_automatic_payment.exs, the two-step CIT → MIT flow) and for CREDENTIAL_ON_FILE payments (examples/payment/credential_on_file.exs). Note the field isprevious_transaction_reference; the Ruby SDK renamed it fromprev_transaction_refin 3.4.0.
Changed
- The response map carries two more keys:
:request_idand:retry_after, eachnilwhen the server sent no such header. So a completed request is now{:ok, %{status: _, response: _, request_id: _, retry_after: _}}. Pattern matches on maps are partial, so%{status: status, response: body}keeps working — the one thing that breaks is comparing the whole map for equality, e.g.result == {:ok, %{status: 200, response: body}}. Match instead of comparing.
0.2.1
Audited against MercadoPago's official MCP server
(https://mcp.mercadopago.com/mcp), walking the SDK's routes against the live
API documentation. Every finding was re-verified against the code before being
acted on; those that could not be confirmed were not acted on. See
DIVERGENCES.md for every intentional departure from the
reference Ruby SDK.
No public function was removed or changed arity in this release.
Fixed
- Webhook signatures for Orders notifications.
Mercadopago.Webhook.Validatornow lowercasesdata.idbefore building the HMAC manifest, as MercadoPago specifies:id:[data.id_lowercase];request-id:[x-request-id];ts:[ts];. Numeric payment ids have no case and were unaffected, which is why this went unnoticed — but the Orders API sends ULID-style ids such asORD01JQ4S4KY8HWQ6NA5PXB65B3D3, and every one of those notifications was being rejected as an invalid signature. Callers passdata.idthrough untouched; the lowercasing is internal to the manifest. Anyone who worked around this by lowercasing the id themselves is unaffected. The reference Ruby SDK 3.2.1 has the same defect. - The
mix cialias could never fail on formatting. It ranformatbeforeformat --check-formatted, so the first task rewrote the files and the check always passed. It also mutated the working tree. Only the check remains. Mercadopago.Order.create_online/3no longer mixes atom and string keys when injecting defaults into a string-keyed payload.
Added
Mercadopago.Order.create_online/3, replacing the misnamedcreate_checkout_pro/3(see Deprecated).Mercadopago.HTTP.patch/4, unblocking endpoints that take a partial update.- Multipart request bodies via
{:multipart, parts}onpost/4,put/4andpatch/4, for uploads such as chargeback documentation. Part content may be a stream, so large files need not be read into memory. Mercadopago.OAuth.generate_code_verifier/0andMercadopago.OAuth.code_challenge/1(PKCE, RFC 7636 S256), plus:code_challenge/:code_challenge_methodoptions onget_authorization_url/4.- Tokenless clients:
Mercadopago.new(nil)omits theAuthorizationheader instead of sending an emptyBearer. Previously the only way to bootstrap the OAuth authorization-code flow wasMercadopago.new(""). Mercadopago.OAuth.create/3andrefresh/3default their owngrant_type; an explicitly supplied one is never overwritten.Mercadopago.Errorand the opt-inMercadopago.HTTP.unwrap/1, for callers who prefer{:ok, body}/{:error, exception}over inspecting status codes. The default contract is unchanged: resource functions still return{:ok, %{status: _, response: _}}for every completed request.
Deprecated
Mercadopago.Order.create_checkout_pro/3— usecreate_online/3. The name is a misnomer inherited from the Ruby SDK:POST /v1/orderswithtype: "online"is the Checkout API via Orders, not Checkout Pro. Checkout Pro is the hosted flow built onPOST /checkout/preferences, available asMercadopago.Preference. The old name still works and delegates to the new one.
Security
- Updated all dependencies to close five transport-layer CVEs.
- Bounded
reqto the0.6line: it is pre-1.0 and breaks API across minors, and the SDK matches on%Req.TransportError{}and callsReq.Response.get_header/2andReq.Test.transport_error/2.
Changed
- Hardened the HTTP transport and restructured the integration suite into one
module per resource, so
async: trueactually parallelises the network round-trips.
0.2.0
- Synced with the official Ruby SDK 3.2.0.
0.1.0
- Initial release.