Skip to content

fix: OpenAPI guardian sweep 2026-08-11 (customers, billing entities, organizations) - #563

Merged
annvelents merged 5 commits into
mainfrom
openapi-guardian/2026-08-11
Aug 27, 2026
Merged

fix: OpenAPI guardian sweep 2026-08-11 (customers, billing entities, organizations)#563
annvelents merged 5 commits into
mainfrom
openapi-guardian/2026-08-11

Conversation

@sarkissianraffi

Copy link
Copy Markdown
Contributor

OpenAPI Guardian sweep — 2026-08-11 (slice 2: customers, billing_entities, organizations)

Automated twice-weekly spec sweep vs lago-api and the SDK clients.
A human must review and merge — this agent never merges.
npm run build and npm run test pass on this branch.

Fixed in this PR

Type Count
Typos / definitions 4
Required vs optional 2
Inaccuracies (types, nullability, enums, shapes) 12
Filters / query params / paths 2

Field-level evidence

  • src/schemas/_index.yaml + file rename: CustomerIntegratrionErrorObjectCustomerIntegrationErrorObject (2 webhook refs updated) — typo in component and file name.
  • src/schemas/_index.yaml: index key CustomerPaymentProvidernErrorObjectCustomerPaymentProviderErrorObject — typo'd key was the source of the oas3-unused-component lint warning.
  • src/resources/billing_entity.yaml path param code: was "The ID of the billing entity" with format: uuid — it is the entity's code (plain string). Evidence: routes.rb resources :billing_entities, param: :code; controller BillingEntity.find_by(code: params[:code]).
  • src/schemas/IntegrationCustomer.yaml type description: "Accepted values: netsuite, anrok" was stale vs its own enum.
  • src/schemas/CustomerCreateInput.yaml metadata items: dropped display_in_invoice from requiredcustomer_metadata.display_in_invoice is DEFAULT false NOT NULL (structure.sql) and the controller permits its absence.
  • src/resources/billing_entity.yaml PUT requestBody: added required: trueparams.require(:billing_entity) 400s without a body.
  • src/resources/customers.yaml: added external_id query filter — permitted in CustomersController#index params.permit(:external_id, ...) but undocumented.
  • src/resources/organizations.yaml: added GET /organizationsroutes.rb get "/organizations", to: "organizations#show" exists; the spec only had PUT.
  • src/schemas/CustomerCreateInput.yaml + CustomerBaseObject.yaml: added external_salesforce_id — permitted in create_params and always emitted by V1::CustomerSerializer (nullable varchar in structure.sql).
  • src/schemas/CustomerCreateInput.yaml integration_customers: added targeted_object (permitted) and extended integration_type enum with avalara, hubspot, salesforce — all map to integration customer classes in IntegrationCustomers::BaseCustomer.customer_type.
  • src/schemas/CustomerBillingConfiguration.yaml payment_provider enum: added cashfree, flutterwave, moneyhashCustomer::PAYMENT_PROVIDERS validates 6 values, spec listed 3.
  • src/schemas/BillingEntityObject.yaml + BillingEntityCreateInput.yaml + BillingEntityUpdateInput.yaml: added phone and einvoicing — both permitted by the controller and always serialized by V1::BillingEntitySerializer.
  • src/schemas/BillingEntityUpdateInput.yaml: wrapped payload under a required billing_entity root key — update_params is params.require(:billing_entity).permit(...); a request built from the old spec shape fails. The sibling create input was already wrapped.
  • src/resources/billing_entities.yaml POST + billing_entity.yaml PUT responses: wrapped in {"billing_entity": ...} — the controller renders with root_name: "billing_entity"; GET was already documented wrapped.
  • Billing entity country (all 3 schemas): switched to CountryOrNull — column is nullable; the previous nullable: true next to a $ref is a no-op in OpenAPI 3.1.
  • Billing entity and organization email_settings input enums: added payment_receipt.created — present in both models' EMAIL_SETTINGS.
  • src/schemas/OrganizationObject.yaml: added slug and defined email_settings (it was listed in required but had no property definition — a published inconsistency); both always emitted by V1::OrganizationSerializer.
  • src/schemas/OrganizationUpdateInput.yaml: added slug — permitted in input_params.

[BREAKING-DOC] flags

  • Component renames (CustomerIntegrationErrorObject, CustomerPaymentProviderErrorObject index key): type names in generated clients (JS) change on next regeneration.
  • BillingEntityUpdateInput wrapper and the POST/PUT billing entity response wrappers: generated request/response types change shape. The old shapes did not work against the API (unwrapped update payloads are rejected; responses were always wrapped), so this aligns docs with reality rather than changing behavior.

SDK drift (spec is right — needs an sdk-clients-update run)

Resource Client(s) Divergence
customers ruby, python, go account_type, external_salesforce_id, integration_customers[].targeted_object missing from create/update params
customers go list filters missing external_id, account_type[], billing_entity_codes[]; CustomerInput missing logo_url
customers rust payment_provider enum has 3 of 6 values; integration type enum has netsuite/anrok only; single list filter (external_customer_id, which is not an API filter name)
billing_entities python create/update send logo_url but the API permits logo — logo upload silently no-ops
billing_entities ruby, python, go einvoicing missing everywhere; go also misses phone; input email_settings enums lack payment_receipt.created where typed
billing_entities rust resource absent (known partial-coverage gap)
organizations ruby sends webhook_urls on update, which the API does not permit (ignored)
organizations go OrganizationInput includes name, which the API does not permit (ignored); result lacks lago_id
organizations ruby, python, go slug missing from update params and response models
all javascript generated from the published spec at release (currently v1.50.0 vs spec 1.51.0) — regenerating after this merge picks up all fixes automatically

Needs human confirmation (not changed)

  • V1::IntegrationCustomerSerializer#type has no avalara branch: an Avalara integration customer serializes as "type": null, violating the response schema (type required, non-null enum). Looks like a lago-api bug rather than a spec fix; the response enum was left without avalara.
  • GET /organizations/grpc_token exists in routes but is undocumented — assumed internal, left out.
  • IntegrationCustomers::BaseCustomer.customer_type also accepts okta — assumed SSO-internal, not added to the public enum.

Deferred to next run

  • None. Slice 2 fully swept.

@annvelents annvelents left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 🚀

@annvelents

Copy link
Copy Markdown
Contributor

Note: I've updated BE to not ignore "alavara" for serialising integration_customer (PR)

@sarkissianraffi

Copy link
Copy Markdown
Contributor Author

Guardian follow-up (sweep of 2026-08-17): thanks for the approval and for the heads-up on the backend change — no action needed on this branch. avalara on IntegrationCustomer.type is covered by #564, and this PR already adds it to CustomerCreateInput.integration_customers[].integration_type, so the two land the same value on both sides.

This PR is still open and unmerged, so today's sweep (#566) deliberately covered only the parts of slice 2 that this branch does not touch. Please merge this one first — the only file both touch is src/schemas/CustomerCreateInput.yaml, in non-adjacent hunks.

@annvelents
annvelents force-pushed the openapi-guardian/2026-08-11 branch from d228faf to bc7da0d Compare August 27, 2026 15:11
@annvelents
annvelents merged commit b913bda into main Aug 27, 2026
3 checks passed
@annvelents
annvelents deleted the openapi-guardian/2026-08-11 branch August 27, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants