Repository navigation
feat: Add the API fields missing from wallets, customers and more - #431
Merged
Merged
Conversation
## Context The `alert.triggered` and `alert.resolved` webhooks have no typed model in the client, so consumers parse the payloads by hand. ## Description `TriggeredAlert` and `ResolvedAlert` were added to `models/alert.py` and exported from `lago_python_client.models`. Crossed and recovered thresholds use a new `AlertCrossedThreshold` model, since `AlertThresholdResponse` also carries `notify_on` and a required `recurring`. Decimal values stay strings. The deprecated `subscription_external_id` and `customer_external_id` fields are kept as optional because the API still sends them.
## Context The Lago API accepts and returns customer fields that the Python client does not declare yet, so SDK users cannot send or read them. ## Description `Customer` now accepts `account_type` and `external_salesforce_id`, and `IntegrationCustomer` accepts `code`. Fields left unset are not sent. `CustomerResponse` exposes `account_type`, `external_salesforce_id`, `sequential_id` and `slug`. `IntegrationCustomerResponse` exposes `code`, `is_default` and `category`.
## Context The Lago API returns several payment fields that `PaymentResponse` did not declare, so they were not available on the parsed object. ## Description `PaymentResponse` now exposes `lago_customer_id`, `external_customer_id`, `lago_payable_id`, `payable_type`, `status`, `payment_provider_code`, `payment_provider_type`, `provider_payment_id`, `provider_customer_id` and `next_action` (a dict). All of them are optional, since payment receipts embed a payment and their fixtures do not carry these keys. The fixtures now include a provider payment and a manual payment, whose provider fields are null and whose `next_action` is empty. A test for `payments.find` was added.
## Context The Lago API documents an `einvoicing` flag on billing entities and a `slug` (plus `lago_id`) on the organization. The Python client could neither send nor read these fields. ## Description `BillingEntity`, `BillingEntityUpdate` and `BillingEntityResponse` now have an optional `einvoicing` boolean. The `Organization` input accepts an optional `slug`, and `OrganizationResponse` exposes `lago_id` and `slug`. Fields left unset are still dropped from the request body, and an explicit `einvoicing=False` is sent.
## Context The Lago API accepts and returns `progressive_billing_disabled` on subscriptions, and accepts `usage_thresholds` on subscription create and update. The Python client did not declare them, so they were dropped from requests and responses. `SubscriptionResponse` also declared `subscription_date`, which the API no longer returns. ## Description The `Subscription` input now has `progressive_billing_disabled` and `usage_thresholds` (reusing `UsageThresholdsOverrides`), and `SubscriptionResponse` exposes `progressive_billing_disabled`. `SubscriptionResponse.subscription_date` was removed. This is a breaking change for code that reads it; `subscription_at` holds the same date.
## Context The plan object returned by the Lago API documents `pending_deletion`, `entitlements` and `applicable_usage_thresholds`, but `PlanResponse` did not declare them, so they were dropped when parsing. ## Description `PlanResponse` now exposes the three fields. Entitlements are parsed into new models in `models/entitlement.py`. A privilege `value` is typed `Any` so it keeps its JSON type (an integer, a boolean or a string like `"10"`); a `Union` would make pydantic v1 coerce `true` to `1` and `"10"` to `10`. Applicable usage thresholds use a new `ApplicableUsageThresholdResponse`, since these items have no `lago_id` and `UsageThresholdResponse` requires one.
## Context The Lago API accepts `transaction_priority` when a wallet is created, and `priority` and `voided_transaction_id` when a wallet transaction is created. The input models of the client did not declare these fields, so they could not be sent. ## Description `Wallet` now declares `transaction_priority`, and `WalletTransaction` declares `priority` and `voided_transaction_id`. The response models are unchanged.
## Context `client.wallet_transactions.create` serializes the input model without excluding unset fields, so every unset field is sent as `null`. The Lago API treats a `null` `priority` or `voided_transaction_id` the same as an absent one. ## Description A test now shows that `priority` and `voided_transaction_id` are sent as `null` when they are not set.
## Context The wallet transaction specs for priority and voided_transaction_id read the sent request body and checked a few keys, so other fields of the body were not checked. ## Description Both specs now pass the full expected body to match_json, like the other client specs. Unset fields are expected as null, which is how WalletTransactionClient serializes them.
## Context The alert webhook tests only parsed subscription alerts, so the Optional subscription fields and the deprecated keys were never absent or null in a test. ## Description New tests parse `alert.triggered` and `alert.resolved` payloads for a wallet alert, with the subscription fields set to null and the deprecated keys removed.
## Context lago-api's void path passes the raw `priority` param to the wallet transaction create service, which requires a priority. Sending `priority: null` makes void requests without a priority fail. ## Description `WalletTransactionClient.create` now leaves out `priority` and `voided_transaction_id` when they are None. Other fields keep their current serialization.
The plan entitlement and applicable usage threshold response models are now re-exported from lago_python_client.models, like the other response models.
A priority of 0 is valid and must be sent. This test guards the None check that leaves out an unset priority.
groyoh
marked this pull request as ready for review
October 29, 2026 08:31
vincent-pochet
approved these changes
Oct 29, 2026
vincent-pochet
left a comment
Contributor
There was a problem hiding this comment.
LGTM. A few non-blocking follow-ups inline, most important first: SubscriptionResponse doesn't parse the applicable_usage_thresholds / entitlements the API returns.
TriggeredAlert and ResolvedAlert now inherit their common fields from AlertWebhookBase. Crossed and recovered thresholds have the same shape as alert thresholds, so they reuse AlertThresholdResponseList instead of a separate model. The resolved alert fixture no longer holds the deprecated subscription_external_id and customer_external_id keys, which the API only sends on triggered alerts.
The wallet transaction create now sends input_object.dict(exclude_none=True), like the other create calls, instead of a hand-written list of keys to drop. On create, an unset field and a null field have the same effect on the API. A priority of 0 is still sent.
The API returns applicable_usage_thresholds on subscription create, update and show, and entitlements on create and show. SubscriptionResponse now parses both, so callers can read back the thresholds that apply after sending usage_thresholds. Subscription entitlements get their own models: each privilege carries the plan_value and override_value next to the value, and the entitlement holds the overrides map.
Contributor
Author
|
Thanks @vincent-pochet for the review! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
The Python client could not send or read several fields that the Lago API accepts and returns today, as documented in the OpenAPI spec. Users had to fall back to raw HTTP calls to set them, and the values the API returned were dropped when a response was parsed. The gaps were in wallets, wallet transactions, payments, customers, subscriptions, billing entities, plans, the organization and the alert webhooks.
Description
The models now carry the missing fields:
transaction_priority, and wallet transactions acceptpriorityandvoided_transaction_id.statusandnext_action.account_typeandexternal_salesforce_id, and exposesequential_idandslug. Integration customers getcode,is_defaultandcategory.progressive_billing_disabled, and send top-levelusage_thresholds.einvoicing, and the organization sends and readsslugand exposeslago_id.pending_deletion,entitlements(privilege values keep their JSON type) andapplicable_usage_thresholds.TriggeredAlertandResolvedAlertmodels parse thealert.triggeredandalert.resolvedwebhook payloads.wallet_transactions.createnow leaves outpriorityandvoided_transaction_idwhen they are not set. Sending them asnullwould make the API reject a void request that has no priority.Breaking change:
SubscriptionResponse.subscription_dateis removed, because the API no longer returns it. Code that reads it should usesubscription_at.Each change is covered by unit tests, and the create, update and read calls were also checked through the client against a local Lago API on
main.Fixes ING-771