Repository navigation
v0.3.0
[0.3.0] - 2026-09-22
Adopts the Automatic Payments OpenAPI document Khipu republished after the
2026-08-28 revision this SDK had pinned. One upstream document carries the
fixes for both #10 (subscription status contract) and #9
(max_amount_per_charge), so they land together.
Also re-syncs the Instant Payments document (#12), so both committed specs
match what Khipu publishes and the spec-drift watch is green for both.
Contains breaking changes to the Automatic Payments facade.
Fixed
-
PAC subscription retrieval raised on valid provider responses (#10).
Observed against the live developer-mode API in parle-cl/telemaco#377:- a pre-signing subscription with
status: "PENDING"raised
ValueError: 'PENDING' is not a valid SubscriptionStatusStatus; - a post-signing subscription that omitted
customer_bank_coderaised
KhipuResponseError (KeyError: 'customer_bank_code').
Khipu's current document resolves both:
PENDINGis a declared status, and
customer_bank_codehas been removed from the schema entirely. It also adds
DISCARDED, which would have caused the identical enum failure on an
unsubscribed mandate. - a pre-signing subscription with
-
create_chargecould not read a successful charge. Khipu now documents
POST /v1/automatic-payment/charge-intentas201 Created; the generated
client parsed only200, so a successful charge surfaced as
KhipuResponseError: "success status with no usable body". This had not been
hit in practice because no PAC charge had been attempted yet.
Added
max_amount_per_charge(#9) is now a required, typed parameter of
create_subscription, matching Khipu's required field. It is validated
against the currency's minor-unit scale likemax_amount.AutomaticSubscriptionStatusnow carriesdeveloperand
service_reference. Khipu returnsservice_referenceas an empty string
until the customer signs;""is passed through unchanged and never rewritten
toNone.- Charge rejections (
422) are raised asKhipuApiErrorwith Khipu's
error_messageas the message anderror_codereachable throughpayload. - The generated client now covers
DELETE /v1/automatic-payment/subscription/{id}
(unsubscribe). It is deliberately not exposed onKhipuClient: the
operation is irreversible and exposing it is a separate API-design decision. - A release-metadata regression (
tests/unit/test_release_metadata.py) ties
project.versionto a dated CHANGELOG section and to the README's pinned
install examples. Merging to master tags whatever versionpyproject.toml
declares, and silently does nothing when that tag already exists, so an
un-bumped version is a defect this now catches before merge.
Changed
create_subscriptionrequiresmax_amount_per_charge. Breaking for
callers of 0.2.0.create_chargemakesbody,customandtransaction_idoptional,
matching Khipu's revisedChargeRequest, which no longer requires them. An
omitted field is left out of the request entirely -- never sent asnull,
never given a fabricated value. Callers that pass them are unaffected. They
remain the only merchant-side correlation fields Khipu echoes back, so an
application reconciling charges against its own records should keep requiring
them in its own service layer; that is application policy, not a constraint
the SDK imposes on every consumer.AutomaticSubscriptionStatusgaineddeveloperandservice_reference
beforeraw. Keyword construction and attribute reads are unaffected;
positional construction of this result type would be.create_chargeaccepts Khipu's documented201and, for compatibility with
the contract Khipu published until 2026-09, a200carrying a usable
ChargeResult. That allowance is a closed set of exactly those two statuses:
any other 2xx --202 Acceptedmost importantly -- is reported as
KhipuResponseErrorrather than being given the meaning of a created charge.
Instant Payments spec sync (#12)
Khipu's Instant Payments revision is additive only. No endpoint, response
status, required field, enum or security scheme changed; the status
(pending / verifying / done) and status_detail vocabularies are
identical to the previous document. Most of the diff is Spanish terminology
(reversa -> devolución) and added response examples.
payment-get-paymentgains three optional fields:refunds,
total_refundedandvoid_payout_date. They refine when money actually
moved, whichstatus_detailalone cannot express: a refund with
status: expirednever pays out, andtotal_refundedexcludes those.- These are not promoted onto
InstantPaymentStatusin this release.
Promoting them is an API-design decision (refundsis a list of objects and
would need a stable result type of its own), not a spec-sync one. They are
reachable throughraw, and are covered by regressions so promoting them
later is a small step. - No facade change was required, and none was made. Every Instant Payments
invariant is unchanged: no idempotency primitive exists in the document (the
word does not appear in it at all),transaction_idremains correlation
only, there is still no automatic retry,get_instant_paymentremains the
authoritative retrieval primitive, incomplete success bodies remain
KhipuResponseError, payer PII stays unpromoted and out ofrepr, and money
stays exactDecimal. - Instant Payments declares exactly
200for both payment endpoints, and a
regression now pins that the Automatic Payments charge compatibility
allowance (201 plus 200) did not leak into them:201,202and204are
rejected there.
Notes
- Khipu's
ChargeErrorvocabulary mentionsIDEMPOTENCY_KEY_REUSED, but the
publishedChargeRequestdefines no idempotency field or header. The SDK
therefore sends none and treats no field as one --transaction_idincluded.
Retry guidance is unchanged: the SDK still performs no retries. Tracked for
investigation in parle-cl/telemaco#377.