From c8a449beecaf541e6c6945227c330fb6dcb87850 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 01:47:44 +0200 Subject: [PATCH 01/33] docs: align OpenAPI specifications with the public API --- .github/workflows/openapi.yml | 30 + website/openapi_v2.en.yaml | 1349 ++++++++++++++------- website/openapi_v2.yaml | 1514 +++++++++++++----------- website/package.json | 5 +- website/pnpm-lock.yaml | 432 +++---- website/scripts/check-openapi.mjs | 134 +++ website/test/openapi-types.fixture.txt | 49 + website/tsconfig.json | 1 + 8 files changed, 2168 insertions(+), 1346 deletions(-) create mode 100644 .github/workflows/openapi.yml create mode 100644 website/scripts/check-openapi.mjs create mode 100644 website/test/openapi-types.fixture.txt diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml new file mode 100644 index 000000000..45ef9f9f4 --- /dev/null +++ b/.github/workflows/openapi.yml @@ -0,0 +1,30 @@ +name: OpenAPI contract + +on: + pull_request: + paths: + - website/openapi_v2*.yaml + - website/scripts/check-openapi.mjs + - website/test/openapi-types.fixture.txt + - website/package.json + - website/pnpm-lock.yaml + - .github/workflows/openapi.yml + workflow_dispatch: + +jobs: + contract: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 11.5.1 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + cache: pnpm + cache-dependency-path: website/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + working-directory: website + - run: pnpm test:openapi + working-directory: website diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 43ca827de..6c828cf3e 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -28,7 +28,7 @@ info: authentication, and verbs. During development, you can use the Facturapi API in the Test environment, and the invoices you issue will not be sent to the SAT (Mexican Tax Authority) and will not have fiscal validity. - + The secret key you use to authenticate will determine both the environment in which the invoice will be created (Test or Live), as well as the organization to use as the issuer of your invoice or as the owner of the resource you request to create. Send `Accept-Language: en` for English Facturapi error messages, or @@ -66,7 +66,7 @@ tags: x-displayName: Keys from SAT's catálogos description: | These are the main catalogs from SAT, included here for convenience. This is by no means the full list. You can find these and more catalogs on the official SAT website: http://omawww.sat.gob.mx/tramitesyservicios/Paginas/anexo_20_version3-3.htm - + ### Forma de Pago (Payment Form) @@ -108,7 +108,7 @@ tags: ### Uso del CFDI (CFDI use) - + Key | Description (Spanish) | Description (English) | Allowed Fiscal Regimes :-----:|:----------- |:----------- |:----------- "G01" | Adquisición de mercancías. | Purchase of goods | 601, 603, 606, 612, 620, 621, 622, 623, 624, 625, 626 @@ -985,11 +985,12 @@ x-tagGroups: - receipt_model - retention_model - organization_model - + paths: /catalogs/cartaporte/3.1/air-transport-codes: get: + operationId: searchAirTransportCodes tags: - carta_porte_keys summary: Search air transport codes @@ -1047,10 +1048,9 @@ paths: ["limit"] = 10 }); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - + - $ref: '#/components/parameters/SearchPagination' + - $ref: '#/components/parameters/SearchAfter' + - $ref: '#/components/parameters/SearchBefore' - in: query name: q schema: @@ -1062,7 +1062,6 @@ paths: schema: type: integer minimum: 1 - required: false description: Page of results to return, starting from page 1. The maximum is not fixed; together with `limit` it must fit within the 3,000-result cap. - in: query name: limit @@ -1070,7 +1069,6 @@ paths: type: integer minimum: 1 maximum: 100 - required: false description: Number from 1 to 100 representing the maximum amount of results to return for pagination purposes. responses: '200': @@ -1078,10 +1076,21 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/SearchKeyDescriptionResult" + $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/transport-configs: get: + operationId: searchTransportConfigs tags: - carta_porte_keys summary: Search auto transport configurations @@ -1168,9 +1177,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/comercioexterior/2.0/tariff-fractions: get: + operationId: searchTariffFractions tags: - comercio_exterior_keys summary: Search tariff fractions @@ -1227,10 +1247,9 @@ paths: ["limit"] = 10 }); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - + - $ref: '#/components/parameters/SearchPagination' + - $ref: '#/components/parameters/SearchAfter' + - $ref: '#/components/parameters/SearchBefore' - in: query name: q schema: @@ -1242,7 +1261,6 @@ paths: schema: type: integer minimum: 1 - required: false description: Page of results to return, starting from page 1. The maximum is not fixed; together with `limit` it must fit within the 3,000-result cap. - in: query name: limit @@ -1250,7 +1268,6 @@ paths: type: integer minimum: 1 maximum: 100 - required: false description: Number from 1 to 100 representing the maximum amount of results to return for pagination purposes. responses: '200': @@ -1272,6 +1289,7 @@ paths: /catalogs/cartaporte/3.1/rights-of-passage: get: + operationId: searchRightsOfPassage tags: - carta_porte_keys summary: Search rights of passage @@ -1358,9 +1376,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/customs-documents: get: + operationId: searchCustomsDocuments tags: - carta_porte_keys summary: Search customs documents @@ -1447,9 +1476,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/packaging-types: get: + operationId: searchPackagingTypes tags: - carta_porte_keys summary: Search packaging types @@ -1536,9 +1576,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/trailer-types: get: + operationId: searchTrailerTypes tags: - carta_porte_keys summary: Search trailer types @@ -1625,9 +1676,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/hazardous-materials: get: + operationId: searchHazardousMaterials tags: - carta_porte_keys summary: Search hazardous materials @@ -1714,9 +1776,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/naval-authorizations: get: + operationId: searchNavalAuthorizations tags: - carta_porte_keys summary: Search naval authorizations @@ -1803,7 +1876,7 @@ paths: application/json: schema: allOf: - - $ref: "#/components/schemas/SearchResult" + - $ref: '#/components/schemas/SearchResult' - type: object properties: data: @@ -1813,9 +1886,20 @@ paths: properties: key: type: string + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/port-stations: get: + operationId: searchPortStations tags: - carta_porte_keys summary: Search port stations @@ -1902,9 +1986,20 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/marine-containers: get: + operationId: searchMarineContainers tags: - carta_porte_keys summary: Search marine containers @@ -1991,6 +2086,16 @@ paths: application/json: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthenticated' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/RateLimited' + '500': + $ref: '#/components/responses/UnexpectedError' /customers: post: operationId: createCustomer @@ -2007,7 +2112,7 @@ paths: Once the customer is created and a response object is obtained, we recommend saving the ID in your database along with the customer information. Later, you can call the Create Invoice endpoint by passing the customer ID instead of repeating the information. - + Finally, keep in mind that the customers you create in the Test environment **are not shared** with the Live environment. x-codeSamples: @@ -2577,7 +2682,7 @@ paths: Validates that the customer's fiscal information matches the SAT records. Its main function is to validate that the registered customer data continues to meet the SAT validation. - + > **Note:** > The operations of creating a customer, editing a customer, and creating an invoice already perform a > validation of the customer's information, so it is **not** necessary to call this endpoint @@ -3286,7 +3391,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + get: operationId: listInvoices tags: @@ -4473,7 +4578,7 @@ paths: type: string description: | ID of the invoice that replaces the invoice being canceled. - + You can use either the ID assigned by Facturapi or the fiscal folio (UUID). security: - "SecretLiveKey": [] @@ -4665,7 +4770,7 @@ paths: curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/xml \ -H "Authorization: Bearer sk_test_API_KEY" \ -X GET - + # Cancellation receipt pdf curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/pdf \ -H "Authorization: Bearer sk_test_API_KEY" \ @@ -4709,7 +4814,7 @@ paths: // Cancellation receipt xml $facturapi->Invoices->downloadCancellationReceiptXml("58e93bd8e86eb318b019743d"); - + // Cancellation receipt pdf $facturapi->Invoices->downloadCancellationReceiptPdf("58e93bd8e86eb318b019743d"); parameters: @@ -4831,8 +4936,7 @@ paths: type: number description: Invoice folio number. Omitted when the invoice has none registered. series: - type: string - nullable: true + type: ["string","null"] description: Invoice series installment: type: number @@ -5266,7 +5370,7 @@ paths: summary: Create e-receipt description: | Creates a new e-Receipt, which acts as a sales note. - + Every receipt will have an auto-generated URL that the client can visit to fill in their fiscal data in a microsite with the organization's branding. x-codeSamples: - lang: Bash @@ -5767,7 +5871,7 @@ paths: summary: Cancel e-receipt description: | Cancel a receipt by changing its `status` property to `"canceled"`. - + Once canceled, the receipt cannot be invoiced. x-codeSamples: - lang: Bash @@ -6063,7 +6167,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + /receipts/{receipt_id}/invoice: post: operationId: invoiceReceipt @@ -6889,6 +6993,7 @@ paths: items: type: string enum: + - all - draft - pending - valid @@ -7165,7 +7270,7 @@ paths: description: | ID of the retention that replaces the one being canceled. You can use the Facturapi ID or the fiscal folio (UUID). - + security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -7608,12 +7713,12 @@ paths: summary: Create organization description: | Create a new Organization that will belong to your user account. - + After creating the organization and before being able to issue invoices with the organization, you will need to finish setting it up by calling the [Update legal data](#tag/organization/operation/editOrganizationLegal) and [Upload certificates (CSD)](#tag/organization/operation/uploadOrganizationCertificate) methods. - + After creating the organization and before you can issue invoices with the organization, you must finish configuring it by calling the methods [Update legal information](#tag/organization/operation/editOrganizationLegal) and @@ -8239,7 +8344,7 @@ paths: summary: Upload logo description: | Upload the organization's logo. The logo will be displayed on the PDFs and emails sent to your customers. - + The file must be an image in JPG or PNG format and have a size not greater than 500 KB. The recommended dimensions are 800 × 500px. If the organization already has a logo, this call replaces the previous logo. @@ -9465,7 +9570,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + post: operationId: createSeriesGroup tags: @@ -9924,7 +10029,7 @@ paths: summary: Invite user to organization description: | Creates or updates a user invite. By default, invited users get full admin access; to limit access, create a role and send its ID in `role`. - + Each organization can invite one user at no additional cost. Starting from the second invited user, each additional user will incur a monthly fee. This charge is applied automatically when the user accepts the invitation, whether from the dashboard or via the API. You can check the current pricing on our [pricing page](https://www.facturapi.io/pricing). x-codeSamples: @@ -11037,9 +11142,9 @@ paths: summary: Create webhook description: | Register a new webhook in your Facturapi organization. - + Use this call to receive notifications of asynchronous events to the API. - + Test and live environment webhooks are independent. x-codeSamples: - lang: Bash @@ -11103,12 +11208,6 @@ paths: application/json: schema: $ref: "#/components/schemas/Webhook" - "200": - description: An existing `Webhook` object with the same URL was found - content: - application/json: - schema: - $ref: "#/components/schemas/Webhook" "400": $ref: "#/components/responses/BadRequest" "401": @@ -11489,6 +11588,7 @@ paths: "signature" => "Signature_FROM_HEADER" ]); requestBody: + required: true content: application/json: schema: @@ -11498,11 +11598,18 @@ paths: type: string description: Secret key of the webhook, found in the webhook settings or upon creation. payload: - type: object - description: Event object received through a webhook. + oneOf: + - type: string + - type: object + additionalProperties: true + description: Signed payload. Use the original JSON text to preserve the signed bytes. signature: type: string description: Signature from the header "Facturapi-Signature". + required: + - secret + - payload + - signature security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -11512,26 +11619,11 @@ paths: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" + oneOf: + - type: string - type: object - properties: - type: - type: string - description: Type of event - example: "invoice.status_updated" - enum: - - invoice.status_updated - data: - type: object - properties: - type: - type: string - description: Type of object affected by the event - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" + additionalProperties: true + description: "Returns the original payload when the signature is valid: a string for JSON text, or an object for object input. It does not parse a string into an object." "400": $ref: "#/components/responses/BadRequest" "401": @@ -11542,10 +11634,11 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + /check: get: + operationId: checkApiKey tags: - tools summary: Health check @@ -11569,9 +11662,10 @@ paths: description: Error de autenticación. Asegúrate de estar usando tu llave secreta. "502": description: Servicio temporalmente no disponible. - + /tools/tax_id_validation: get: + operationId: validateTaxId tags: - tools summary: Validate RFC (tax_id) @@ -11605,7 +11699,7 @@ paths: label: C# source: | var facturapi = new FacturapiClient("sk_test_API_KEY"); - + var customer = await facturapi.Tool.ValidateTaxIdAsync("BBA830831LJ2"); - lang: Java label: Java @@ -11622,7 +11716,7 @@ paths: - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - + $customer = $facturapi->Tools->validateTaxId("BBA830831LJ2"); parameters: - in: query @@ -11652,6 +11746,7 @@ paths: $ref: "#/components/responses/UnexpectedError" /catalogs/products: get: + operationId: searchProducts tags: - sat_keys summary: Product/Service Key @@ -11739,6 +11834,7 @@ paths: $ref: "#/components/responses/UnexpectedError" /catalogs/units: get: + operationId: searchUnits tags: - sat_keys summary: Units of Measure @@ -12073,8 +12169,8 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" -x-webhooks: - "Global invoice created": +webhooks: + invoice.global_invoice_created: post: summary: Global invoice created description: | @@ -12086,27 +12182,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - example: "invoice.global_invoice_created" - enum: - - invoice.global_invoice_created - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - "Invoice status updated": + $ref: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + operationId: onInvoiceGlobalInvoiceCreated + responses: + '200': + description: OK + invoice.status_updated: post: summary: Invoice status updated description: | @@ -12120,37 +12201,13 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - example: "invoice.status_updated" - enum: - - invoice.status_updated - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - related_resource_messages: - type: array - description: Messages related to the resource associated with the event. - items: - $ref: "#/components/schemas/RelatedResourceMessage" + $ref: '#/components/schemas/InvoiceStatusUpdatedEvent' examples: with_related_messages: summary: With related messages value: id: evt_xxx - created_at: "2026-07-01T12:00:00.000Z" + created_at: '2026-07-01T12:00:00.000Z' livemode: true organization: org_xxx type: invoice.status_updated @@ -12164,12 +12221,12 @@ x-webhooks: source: stamping_async_task severity: error message: The receiver RFC is not valid - created_at: "2026-01-01T00:00:00.000Z" + created_at: '2026-01-01T00:00:00.000Z' without_related_messages: summary: Without related messages value: id: evt_xxx - created_at: "2026-07-01T12:00:00.000Z" + created_at: '2026-07-01T12:00:00.000Z' livemode: true organization: org_xxx type: invoice.status_updated @@ -12178,7 +12235,11 @@ x-webhooks: object: id: invoice_xxx related_resource_messages: [] - "Invoice created from dashboard": + operationId: onInvoiceStatusUpdated + responses: + '200': + description: OK + invoice.created_from_dashboard: post: summary: Invoice created from dashboard description: | @@ -12190,28 +12251,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - example: "invoice.created_from_dashboard" - enum: - - invoice.created_from_dashboard - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - - "Cancellation status updated": + $ref: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + operationId: onInvoiceCreatedFromDashboard + responses: + '200': + description: OK + invoice.cancellation_status_updated: post: tags: - events @@ -12223,26 +12268,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - enum: - - invoice.cancellation_status_updated - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - "Self-invoice completed": + $ref: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + operationId: onInvoiceCancellationStatusUpdated + responses: + '200': + description: OK + receipt.self_invoice_complete: post: tags: - events @@ -12254,27 +12285,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - example: "receipt.self_invoice_complete" - enum: - - receipt.self_invoice_complete - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - receipt - object: - $ref: "#/components/schemas/Receipt" - "Receipt status updated": + $ref: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + operationId: onReceiptSelfInvoiceComplete + responses: + '200': + description: OK + receipt.status_updated: post: tags: - events @@ -12286,25 +12302,26 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Type of event - enum: - - receipt.status_updated - data: - type: object - properties: - type: - type: string - description: Type of object associated with the event - enum: - - receipt - object: - $ref: "#/components/schemas/Receipt" + $ref: '#/components/schemas/ReceiptStatusUpdatedEvent' + operationId: onReceiptStatusUpdated + responses: + '200': + description: OK + customer.edit_link_completed: + post: + summary: Customer edit completed + tags: + - events + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CustomerEditLinkCompletedEvent' + responses: + '200': + description: OK + operationId: onCustomerEditLinkCompleted components: responses: BadRequest: @@ -12686,25 +12703,233 @@ components: Returns the results before the given cursor. Only with `pagination=cursor`; mutually exclusive with `after`. schemas: - SignedDownloadUrl: - type: object - description: Temporary download URL for a file. - required: - - url - - expires_at - - content_type - - filename - properties: - url: - type: string - description: Download URL. It grants access to the file while it is valid. - expires_at: - type: string - format: date-time - description: Moment at which the URL stops working. - content_type: - type: string - description: Content type of the file. + InvoiceGlobalInvoiceCreatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + example: invoice.global_invoice_created + enum: + - invoice.global_invoice_created + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + InvoiceStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + example: invoice.status_updated + enum: + - invoice.status_updated + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + related_resource_messages: + type: array + description: Messages related to the resource associated with the event. + items: + $ref: '#/components/schemas/RelatedResourceMessage' + required: + - type + - data + InvoiceCreatedFromDashboardEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + example: invoice.created_from_dashboard + enum: + - invoice.created_from_dashboard + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + InvoiceCancellationStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + enum: + - invoice.cancellation_status_updated + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + ReceiptSelfInvoiceCompleteEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + example: receipt.self_invoice_complete + enum: + - receipt.self_invoice_complete + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - receipt + object: + $ref: '#/components/schemas/Receipt' + required: + - type + - object + required: + - type + - data + ReceiptStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Type of event + enum: + - receipt.status_updated + data: + type: object + properties: + type: + type: string + description: Type of object associated with the event + enum: + - receipt + object: + $ref: '#/components/schemas/Receipt' + required: + - type + - object + required: + - type + - data + CustomerEditLinkCompletedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + enum: + - customer.edit_link_completed + data: + type: object + properties: + type: + type: string + enum: + - customer + object: + $ref: '#/components/schemas/Customer' + required: + - type + - object + required: + - type + - data + ApiEvent: + oneOf: + - $ref: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + - $ref: '#/components/schemas/InvoiceStatusUpdatedEvent' + - $ref: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + - $ref: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + - $ref: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + - $ref: '#/components/schemas/ReceiptStatusUpdatedEvent' + - $ref: '#/components/schemas/CustomerEditLinkCompletedEvent' + discriminator: + propertyName: type + mapping: + invoice.global_invoice_created: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + invoice.status_updated: '#/components/schemas/InvoiceStatusUpdatedEvent' + invoice.created_from_dashboard: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + invoice.cancellation_status_updated: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + receipt.self_invoice_complete: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + receipt.status_updated: '#/components/schemas/ReceiptStatusUpdatedEvent' + customer.edit_link_completed: '#/components/schemas/CustomerEditLinkCompletedEvent' + SignedDownloadUrl: + type: object + description: Temporary download URL for a file. + required: + - url + - expires_at + - content_type + - filename + properties: + url: + type: string + description: Download URL. It grants access to the file while it is valid. + expires_at: + type: string + format: date-time + description: Moment at which the URL stops working. + content_type: + type: string + description: Content type of the file. example: application/pdf filename: type: string @@ -12753,7 +12978,7 @@ components: type: string format: date-time description: Creation date and time of the event - example: 2022-03-30T00:00:00Z + example: '2022-03-30T00:00:00Z' livemode: type: boolean description: Indicates if the event was generated in Test mode (false) or Live mode (true). @@ -12762,6 +12987,11 @@ components: type: string description: ID of the organization this event is related to example: 61f81a7fbd4661b11b9b3f27 + required: + - id + - created_at + - livemode + - organization DateRange: type: object properties: @@ -12884,12 +13114,14 @@ components: type: integer example: 1 title: Página - description: The current page number within the search results + description: Page number. Zero when no matches exist; omitted in cursor pagination. + minimum: 0 total_pages: type: integer example: 1 title: Total pages - description: The total number of pages available in the search results + description: Total pages. Omitted in cursor pagination. + minimum: 0 total_results: type: integer example: 1 @@ -12897,12 +13129,16 @@ components: description: | The total number of results available in the search. In `pagination=cursor` mode it is only included on the first page of the search (no `after`/`before`); the total does not change between pages. previous_cursor: - type: [string, "null"] + type: + - string + - 'null' example: null title: Previous cursor description: Cursor to fetch the previous page of results. It is `null` on the first page. Only available with `pagination=cursor`. next_cursor: - type: [string, "null"] + type: + - string + - 'null' example: null title: Next cursor description: Cursor to fetch the next page of results. It is `null` when there are no more results. Only available with `pagination=cursor`. @@ -13022,7 +13258,7 @@ components: example: 08/06/2021 format: "DD/MM/YYYY" description: Date of favorable sentence. - + ProductCatalogResult: type: object properties: @@ -13094,7 +13330,7 @@ components: type: string description: Description of the catalog entry - + LocalTax: type: object required: @@ -13103,11 +13339,10 @@ components: properties: rate: type: number - example: 0.10 + example: 0.1 description: Tax rate in decimal format. base: type: number - default: 100% of subtotal description: Tax base amount. type: type: string @@ -13116,6 +13351,12 @@ components: type: boolean default: false description: Indicates if it is a withholding tax (`true`) or a transferred tax (`false`). + factor: + type: string + enum: + - Tasa + - Cuota + - Exento BaseTax: title: Tax type: object @@ -13134,7 +13375,6 @@ components: description: Tax rate in decimal format. base: type: number - default: 100% of subtotal description: Tax base amount. type: type: string @@ -13180,7 +13420,7 @@ components: `"unit"`: Apply the IEPS before the unit price, and use the original unit price as the base for the rest of the taxes. `"subtract_before_break_down"`: Apply the IEPS only to calculate taxes like IVA de traslado and retentions, and use the original unit price as the base for the rest of the taxes. - + Consult with your accountant which case applies to your company and product. Stamp: @@ -13192,8 +13432,8 @@ components: description: Digital signature of the fiscal document. date: type: string - format: date-time - description: Stamp date in ISO8601 format (UTC String). + description: "SAT FechaTimbrado: local date and time without a timezone offset. Preserved as text." + example: "2026-09-17T06:59:16" sat_cert_number: type: string description: SAT certificate serial number used for stamping. @@ -13593,7 +13833,6 @@ components: fecha_pago: type: string format: date - default: now description: Payment date of the payroll to the worker. fecha_inicial_pago: type: string @@ -14122,7 +14361,7 @@ components: - IM description: | Key of the origin of the resource. - + - `“IP”`: Ingresos Propios (Own income) - `“IF”`: Ingresos Federales (Federal income) - `“IM”`: Ingresos mixtos (Mixed income) @@ -15334,16 +15573,28 @@ components: description: | ID of the organization for which the webhook is being created. livemode: - type: boolean + type: boolean example: false description: Environment in which the webhook is being created. enabled_events: - type: string - example: ["receipt.cancellation_status"] + type: array + example: + - receipt.status_updated description: Events enabled for the webhook to listen to. + items: + type: string + enum: + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed + - "*" url: type: string - format: email + format: uri description: Full URL of the webhook listener. example: http://my-website.com/my/webhook status: @@ -15353,6 +15604,13 @@ components: - enabled - disabled example: enabled + secret: + type: string + readOnly: true + description: Secret for verifying signatures. Returned when creating the webhook. + description: + type: string + type: object WebhookCreateInput: title: Webhook allOf: @@ -15365,72 +15623,93 @@ components: type: string description: Full URL of the webhook listener. example: http://webhook_api.com + format: uri enabled_events: type: array items: type: string - enum: - - "invoice.global_invoice_created" - - "invoice.status_updated" - - "invoice.cancellation_status_updated" - - "invoice.created_from_dashboard" - - "receipt.self_invoice_complete" - - "receipt.status_updated" - - "receipt.cancellation_status_updated" + enum: + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed description: Events enabled for the webhook to listen to. - example: ["receipt.self_invoice_complete"] + example: + - receipt.self_invoice_complete + minItems: 1 WebhookCreateEdit: title: Webhook allOf: - type: object required: - enabled_events + - status properties: status: type: string description: Status of the webhook. enum: - - "disabled" - - "enabled" + - disabled + - enabled example: disabled enabled_events: type: array items: type: string - enum: - - "invoice.global_invoice_created" - - "invoice.status_updated" - - "invoice.cancellation_status_updated" - - "receipt.self_invoice_complete" - - "receipt.status_updated" - - "receipt.cancellation_status_updated" - description: Events enabled for the webhook to listen to. - example: ["receipt.self_invoice_complete"] + enum: + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed + description: Events enabled for the webhook to listen to. + example: + - receipt.self_invoice_complete + minItems: 1 Customer: title: Customer object allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/CustomerNonEditableProperties" - - $ref: "#/components/schemas/CustomerProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/CustomerNonEditableProperties' + - $ref: '#/components/schemas/CustomerProperties' + - type: object + properties: + organization: + type: string + curp: + type: string + external_id: + type: string CustomerNonEditableProperties: type: object properties: edit_link: - type: string + type: + - string + - 'null' description: Link to a hosted page where the customer can edit their information once. example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: string + type: + - string + - 'null' format: date-time description: Expiration date of the edit link. - example: 2022-12-31T23:59:59Z + example: '2022-12-31T23:59:59Z' sat_validated_at: - type: string + type: + - string + - 'null' format: date-time description: Date when the customer's tax information was validated by the SAT. - example: 2022-12-31T23:59:59Z + example: '2022-12-31T23:59:59Z' CustomerSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -15526,7 +15805,7 @@ components: title: Product allOf: - $ref: "#/components/schemas/ProductProperties" - + LineItemProductEgresoInput: title: Product allOf: @@ -15608,8 +15887,15 @@ components: Product: title: Product object allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/ProductProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/ProductProperties' + - type: object + properties: + organization: + type: string + required: + - organization + - unit_key ProductSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -15622,10 +15908,7 @@ components: ProductProperties: type: object required: - - description - - product_key - - unit_key - - price + ["description","product_key","price"] properties: description: type: string @@ -15883,9 +16166,6 @@ components: description: Indicates if the tax is a withholding (`true`) or a transfer (`false`). taxability: type: string - default: | - "01" if the `taxes` array is empty; "02" if the `taxes` array has at least one element. - enum: - "01" - "02" - "03" @@ -15947,7 +16227,6 @@ components: date: type: string format: date-time - default: now description: Date on which the payment was received. It is only necessary to include it if the payment was made on a date prior to the issuance of this document. Future dates are not allowed. numOperacion: type: string @@ -16014,9 +16293,14 @@ components: country: type: string format: ISO 3166-1 alpha-3 - # description: Código de País acorde al estándar ISO 3166-1 alpha-3, del Catálogo de Países. description: Country code according to the standard [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3). example: MEX + zip: + type: string + tax_system: + type: + - string + - 'null' CustomerComercioExterior: type: object description: Objeto con información parcial del cliente receptor del comprobante. Para obtener el objeto `Customer` completo, deberás consultarlo con el método de [Obtener Cliente]('#/operation/getCustomer'). @@ -16102,7 +16386,7 @@ components: InvoiceZipRequest: title: InvoiceZipRequest object allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' - type: object required: - organization @@ -16125,13 +16409,13 @@ components: description: Organization identifier. example: 65a1f0000000000000000000 issuer_type: - $ref: "#/components/schemas/IssuingType" + $ref: '#/components/schemas/IssuingType' invoice_types: type: array description: Normalized invoice types included in the request. uniqueItems: true items: - $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" + $ref: '#/components/schemas/InvoiceZipRequestInvoiceType' example: - E - I @@ -16139,14 +16423,14 @@ components: type: string format: date-time description: Inclusive start of the requested month. - example: "2025-03-01T06:00:00.000Z" + example: '2025-03-01T06:00:00.000Z' end_date: type: string format: date-time description: Inclusive end of the requested month. - example: "2025-04-01T04:59:59.999Z" + example: '2025-04-01T04:59:59.999Z' status: - $ref: "#/components/schemas/InvoiceZipRequestStatus" + $ref: '#/components/schemas/InvoiceZipRequestStatus' document_count: type: integer minimum: 0 @@ -16167,7 +16451,11 @@ components: type: string format: date-time description: Date when processing was scheduled. - example: "2026-08-04T18:00:01.000Z" + example: '2026-08-04T18:00:01.000Z' + processing_started_at: + type: string + format: date-time + description: Time processing started, when present. InvoiceZipRequestSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -16234,7 +16522,9 @@ components: Current status of the cancellation request, if it has been made. `verifying` means the SAT has received the request and is validating it; Facturapi will keep checking until it changes to a final status. You can read more in the [Cancel Invoice](#tag/invoice/operation/deleteInvoice) section. example: none canceled_at: - type: string + type: + - string + - 'null' format: date-time description: Date on which CFDI was canceled, with approximate time. verification_url: @@ -16243,14 +16533,14 @@ components: description: URL to verify the status of the CFDI on the SAT portal. This link is the same as the one that appears in the QR code on the invoice PDF. example: https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=45BEC0CA-5F1E-491E-9417-698EA48C382A&re=AAA010101AAA&rr=ABC101010111&tt=345.600000&fe=bWApPw== date: - type: string + type: + - string + - 'null' format: date-time - default: now - description: | - Date of issuance of the invoice in ISO8601 format (UTC String). + description: Issue date in ISO8601 format. May be null for drafts. address: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object description: Address where the invoice was issued. properties: @@ -16264,12 +16554,14 @@ components: - I - E - P - - N + - 'N' - T description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. customer: - $ref: "#/components/schemas/CustomerInfo" + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' total: type: number description: Total amount invoiced. @@ -16296,7 +16588,7 @@ components: payment_form: type: string description: Payment form code according to the [Payment Form catalog](#payment-form). - example: 06 + example: 6 total_payment_amount: type: number description: Total amount of the Payment complement when the invoice is type P. @@ -16311,21 +16603,21 @@ components: try to stamp the invoice with the [Stamp Invoice]('#/operation/stampInvoice') method. If the value is `false`, you must use the [Update Invoice]('#/operation/updateDraftInvoice') method to complete the missing fields. - + In an invoice with a status other than `draft`, this field will always be `false`. items: type: array description: Concepts included in the document. items: - $ref: "#/components/schemas/LineItem" + $ref: '#/components/schemas/LineItem' related_documents: type: array description: Documents related to the invoice. items: - $ref: "#/components/schemas/RelatedDocument" + $ref: '#/components/schemas/RelatedDocument' received_payment_ids: type: array - items: + items: type: string description: | On invoices with type I (Income) and payment method PPD, this field lists the @@ -16355,7 +16647,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + $ref: '#/components/schemas/NominaOrCustomComplementProperties' description: Complements to include in the invoice. pdf_custom_section: type: string @@ -16369,9 +16661,91 @@ components: type: array description: Namespaces to insert in the root node of the invoice. Required for `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' stamp: - $ref: "#/components/schemas/Stamp" + anyOf: + - $ref: '#/components/schemas/Stamp' + - type: 'null' + cancellation: + type: object + properties: + requested_at: + type: + - string + - 'null' + format: date-time + last_checked: + type: string + format: date-time + canceled_at: + type: + - string + - 'null' + format: date-time + status: + type: string + enum: + - none + - verifying + - pending + - accepted + - rejected + - expired + description: | + Current status of the cancellation request, if it has been made. `verifying` means the SAT has received the request and is validating it; Facturapi will keep checking until it changes to a final status. You can read more in the [Cancel Invoice](#tag/invoice/operation/deleteInvoice) section. + example: none + motive: + type: string + substitutionUUID: + type: string + cancellation_type: + type: string + organization: + type: + - string + - 'null' + issuer_type: + $ref: '#/components/schemas/IssuingType' + cfdi_version: + type: number + example: 4 + issuer_info: + $ref: '#/components/schemas/CustomerInfo' + payment_method: + type: string + enum: + - PUE + - PPD + use: + type: string + amount_due: + type: number + verification_carta_porte: + type: string + format: uri + conditions: + type: string + export: + type: string + global: + type: object + required: + - periodicity + - months + - year + properties: + periodicity: + type: string + enum: + - day + - week + - fortnight + - month + - two_months + months: + type: string + year: + type: integer InvoiceDraftProperties: type: object properties: @@ -16403,14 +16777,16 @@ components: description: URL to verify the status of the CFDI on the SAT portal. This link is the same as the one that appears in the QR code on the invoice PDF. example: null date: - type: string + type: + - string + - 'null' format: date-time example: null description: | Date of issuance of the invoice in ISO8601 format (UTC String). If the status is `draft`, this field is null. address: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object description: Address where the invoice was issued. properties: @@ -16424,12 +16800,12 @@ components: - I - E - P - - N + - 'N' - T description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. customer: - $ref: "#/components/schemas/CustomerInfo" + $ref: '#/components/schemas/CustomerInfo' total: type: number description: Total amount invoiced. @@ -16456,17 +16832,17 @@ components: payment_form: type: string description: Payment form code according to the [Payment Form catalog](#forma-de-pago). - example: 06 + example: 6 items: type: array description: Concepts included in the document. items: - $ref: "#/components/schemas/LineItem" + $ref: '#/components/schemas/LineItem' related_documents: type: array description: Documents related to the invoice. items: - $ref: "#/components/schemas/RelatedDocument" + $ref: '#/components/schemas/RelatedDocument' currency: type: string example: MXN @@ -16480,7 +16856,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + $ref: '#/components/schemas/NominaOrCustomComplementProperties' description: Complements to include in the invoice. pdf_custom_section: type: string @@ -16494,7 +16870,7 @@ components: type: array description: Namespaces to insert in the root node of the invoice. Required for `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' is_ready_to_stamp: type: boolean description: | @@ -16507,7 +16883,7 @@ components: In an invoice with a status other than `draft`, this field will always be `false`. stamp: allOf: - - $ref: "#/components/schemas/Stamp" + - $ref: '#/components/schemas/Stamp' - type: object example: null @@ -16516,7 +16892,6 @@ components: properties: folio_number: type: integer - default: autoincremental description: | Number of folio assigned by the company for internal control. If omitted, the autoincremental value of the organization will be assigned. series: @@ -16763,7 +17138,7 @@ components: default: pending description: | Initial status of the invoice. - + If `draft` is sent, the invoice will be saved as a draft and will not be stamped or sent to the SAT. Also, when sending `draft`, all required fields become optional. @@ -16776,7 +17151,6 @@ components: date: type: string format: date-time - default: now description: | Date of issuance of the invoice in ISO8601 format (UTC String). It cannot be earlier than 72 hours in the past, nor later than the present. address: @@ -16856,37 +17230,135 @@ components: - $ref: "#/components/schemas/InvoiceableCommonEditInput" InvoiceCreateInput: type: object + description: Invoice data according to its type and initial status. Omit status to stamp; use draft to save a draft. oneOf: - - title: Income - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceIngresoInput" - draft: "#/components/schemas/InvoiceIngresoEditInput" - - title: Egress - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceEgresoInput" - draft: "#/components/schemas/InvoiceEgresoEditInput" - - title: Payment - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoicePagoInput" - draft: "#/components/schemas/InvoicePagoEditInput" - - title: Payroll - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceNominaInput" - draft: "#/components/schemas/InvoiceNominaEditInput" - - title: Transfer - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceTrasladoInput" - draft: "#/components/schemas/InvoiceTrasladoEditInput" + - allOf: + - $ref: '#/components/schemas/InvoiceIngresoInput' + - type: object + properties: + type: + type: string + const: I + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceIngresoEditInput' + - type: object + required: + - status + properties: + type: + type: string + const: I + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceEgresoInput' + - type: object + required: + - type + properties: + type: + type: string + const: E + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceEgresoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: E + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoicePagoInput' + - type: object + required: + - type + properties: + type: + type: string + const: P + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoicePagoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: P + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceNominaInput' + - type: object + required: + - type + properties: + type: + type: string + const: 'N' + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceNominaEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: 'N' + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceTrasladoInput' + - type: object + required: + - type + properties: + type: + type: string + const: T + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceTrasladoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: T + status: + type: string + const: draft InvoiceIngresoInput: title: Income required: @@ -16936,7 +17408,7 @@ components: default: G01 description: | Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. - + For global invoices you must use the code `S01`. currency: type: string @@ -17257,7 +17729,7 @@ components: example: G01 description: | Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. - + For global invoices you must use the code `S01`. currency: type: string @@ -17376,7 +17848,7 @@ components: maxItems: 5000 description: | Concepts to include in the credit note. - + The maximum number of elements that you can include in a document is 5,000. If you need to issue a document with more than 5,000 concepts, you can divide the transaction into several documents. items: @@ -17522,8 +17994,12 @@ components: Receipt: title: Receipt object allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/ReceiptProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/ReceiptProperties' + - type: object + properties: + organization: + type: string ReceiptProperties: allOf: - type: object @@ -17629,7 +18105,7 @@ components: to issue a receipt with more than 5,000 concepts, you can divide the transaction into several receipts. items: $ref: "#/components/schemas/LineItemInput" - + - $ref: "#/components/schemas/ReceiptEditableProperties" - type: object properties: @@ -17732,7 +18208,6 @@ components: from: type: string format: date - default: Start of the last period example: 2022-01-01T00:00:00.000 description: | Initial date of the receipts that will be included in the global invoice. @@ -17742,7 +18217,6 @@ components: to: type: string format: date - default: End of the last period example: 2022-01-31T23:59:59.999 description: | End date of the receipts that will be included in the global invoice. @@ -17752,7 +18226,6 @@ components: periodicity: type: string # default: Propiedad `periodicity` de la configuración de recibos de la organización. - default: "`periodicity` property from the organization's receipt configuration." enum: - day - week @@ -17765,14 +18238,12 @@ components: on the value of `periodicity`. months: type: string - default: Month contained in the range of dates used. description: | Key representing the month or bimester of the invoice. Consult the possible values in the [Months and Bimesters catalog](#meses-y-bimestres). example: "01" folio_number: type: integer - default: autoincremental description: | Number of the folio assigned by the company for internal control. If omitted, the incremental value of the organization will be assigned. @@ -17784,7 +18255,6 @@ components: date: type: string format: date - default: Value of the `to` field example: 2022-01-01T00:00:00.000 description: | Date of issuance of the invoice. By default, it takes the value of the `to` field. @@ -17853,8 +18323,7 @@ components: default: false description: If `true`, only validates data and returns a summary without creating the invoice. payment_form: - type: string - nullable: true + type: ["string","null"] minLength: 2 maxLength: 2 example: "03" @@ -17875,13 +18344,13 @@ components: description: Receipt key. example: ticket_1001 customer: - nullable: true oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" + - $ref: '#/components/schemas/CustomerCreateInput' - type: string title: customer_id description: ID of a customer previously registered in Facturapi. example: 58e93bd8e86eb318b0197456 + - type: 'null' description: | Optional customer used for preview rendering. If you omit it, all receipts must already have the same assigned customer. @@ -17895,9 +18364,13 @@ components: Retention: title: Retention object allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/RetentionReadOnlyProperties" - - $ref: "#/components/schemas/RetentionProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/RetentionReadOnlyProperties' + - $ref: '#/components/schemas/RetentionProperties' + - type: object + properties: + organization: + type: string RetentionReadOnlyProperties: type: object properties: @@ -17929,9 +18402,13 @@ components: Fiscal folio of the retention, assigned by the SAT. example: 39c85a3f-275b-4341-b259-e8971d9f8a94 stamp: - $ref: "#/components/schemas/Stamp" + anyOf: + - $ref: '#/components/schemas/Stamp' + - type: 'null' customer: - $ref: "#/components/schemas/CustomerInfo" + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' is_ready_to_stamp: type: boolean description: | @@ -17943,13 +18420,15 @@ components: properties: cve_retenc: type: string - example: 01 + example: 1 description: | Key of the retention or payment information according to the SAT catalog. fecha_exp: - type: string + type: + - string + - 'null' format: date-time - example: "2021-09-15T06:03:23.000Z" + example: '2021-09-15T06:03:23.000Z' description: Date of issuance of the document in ISO8601 format (UTC String). desc_retenc: type: string @@ -18023,10 +18502,10 @@ components: tipo_pago_ret: type: string enum: - - 01 - - 02 - - 03 - - 04 + - 1 + - 2 + - 3 + - 4 description: | Key of the type of payment according to the SAT catalog. @@ -18048,7 +18527,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CustomComplementData" + $ref: '#/components/schemas/CustomComplementData' description: | Array of complements to include in the retention. Each element contains a `string` with the XML code of the complement. pdf_custom_section: @@ -18064,7 +18543,7 @@ components: type: array description: Namespaces to insert in the root node of the invoice. Required for `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' RetentionSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -18130,16 +18609,15 @@ components: example: draft customer: description: Customer receiving the invoice. - nullable: true oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" + - $ref: '#/components/schemas/CustomerCreateInput' - type: string title: customer_id description: ID of the 'customer' object previously registered in Facturapi. example: 58e93bd8e86eb318b0197456 + - type: 'null' cve_retenc: - type: string - nullable: true + type: ["string","null"] example: 26 description: Key of the retention or payment information according to the [SAT catalog](#clave-de-retencion). fecha_exp: @@ -18156,8 +18634,7 @@ components: example: R123 description: Alphanumeric identifier for internal control of the company and without fiscal relevance. periodo: - type: object - nullable: true + type: ["object","null"] description: Information about the retention period. required: - mes_ini @@ -18181,8 +18658,7 @@ components: example: 2021 description: Fiscal year in which the retention was made. totales: - type: object - nullable: true + type: ["object","null"] description: Information about the total of retentions made in the corresponding period. required: - monto_tot_operacion @@ -18307,21 +18783,21 @@ components: id: type: string description: ID of the organization, assigned by Facturapi. - example: "5a2a307be93a2f00129ea035" + example: 5a2a307be93a2f00129ea035 created_at: type: string format: date-time description: Date and time of creation of the organization. - example: "2017-05-05T20:55:33.468Z" + example: '2017-05-05T20:55:33.468Z' logo_url: type: string format: uri description: URL of the organization's logo. - example: "https://storage.googleapis.com/cdn.facturapi.io/organization/6c100efa5c6f5d7db0379ca643476a4183526007/logo.jpg" + example: https://storage.googleapis.com/cdn.facturapi.io/organization/6c100efa5c6f5d7db0379ca643476a4183526007/logo.jpg timezone: type: string description: Time zone of the organization, in IANA format. - example: "America/Mexico_City" + example: America/Mexico_City is_production_ready: type: boolean description: Indicates if the organization has the necessary information to issue invoices in the Live environment. @@ -18356,7 +18832,7 @@ components: Fiscal or Legal Name of the organization, *without* the corporate regime (e.g.: S.A. de C.V.). tax_system: type: string - example: "601" + example: '601' maxLength: 3 minLength: 3 description: Fiscal Regime Code, from the [SAT catalog](#régimen-fiscal). @@ -18370,7 +18846,7 @@ components: allOf: - type: object description: Fiscal address of the organization. - - $ref: "#/components/schemas/OrganizationAddress" + - $ref: '#/components/schemas/OrganizationAddress' customization: type: object description: | @@ -18490,16 +18966,16 @@ components: updated_at: type: string format: date-time - example: "2023-05-05T20:55:33.468Z" + example: '2023-05-05T20:55:33.468Z' description: Date of the last update of the certificate. expires_at: type: string format: date-time - example: "2025-05-05T20:55:33.468Z" + example: '2025-05-05T20:55:33.468Z' description: Expiration date of the certificate. serial_number: type: string - example: "20001000000300000000" + example: '20001000000300000000' description: Serial number of the certificate. fiel: type: object @@ -18512,16 +18988,16 @@ components: updated_at: type: string format: date-time - example: "2023-05-05T20:55:33.468Z" + example: '2023-05-05T20:55:33.468Z' description: Date of the last update of the FIEL certificate. expires_at: type: string format: date-time - example: "2025-05-05T20:55:33.468Z" + example: '2025-05-05T20:55:33.468Z' description: Expiration date of the FIEL certificate. serial_number: type: string - example: "20001000000300000000" + example: '20001000000300000000' description: Serial number of the FIEL certificate. receipts: type: object @@ -18593,6 +19069,49 @@ components: support_email_verified: type: boolean description: Indicates if the support email has been verified. If false, the email used in the self-invoice portal will be the main account's email. + plan: + type: + - string + - 'null' + deprecated: true + description: Legacy organization plan. + add_ons: + type: array + description: Additional features contracted for the organization. + items: + type: string + pending_plan_update: + type: + - object + - 'null' + description: Scheduled plan change, when present. + properties: + plan: + type: string + scheduled_for: + type: string + format: date-time + pending_add_ons_update: + type: + - object + - 'null' + description: Scheduled additional-feature change, when present. + properties: + add_ons: + type: array + items: + type: string + scheduled_for: + type: string + format: date-time + domain: + type: + - string + - 'null' + custom_domain: + type: + - string + - 'null' OrganizationDeleteCerts: type: object @@ -18977,12 +19496,10 @@ components: type: string description: Name of the organization that sent the invite. role: - type: string - nullable: true + type: ["string","null"] description: ID of the role assigned in the invite, if any. role_name: - type: string - nullable: true + type: ["string","null"] description: Name of the role assigned in the invite, if any. roles: type: array @@ -18990,9 +19507,8 @@ components: items: type: string expires_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Date and time when the invite expires. OrganizationInviteList: type: array @@ -19009,12 +19525,10 @@ components: type: string description: Role name. template_code: - type: string - nullable: true + type: ["string","null"] description: Base template code for the role, if it comes from a system template. organization: - type: string - nullable: true + type: ["string","null"] description: ID of the organization the role belongs to. used_by: type: integer @@ -19035,14 +19549,12 @@ components: items: type: string created_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Date and time when the role was created. updated_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Date and time when the role was last updated. OrganizationPermissionRoleList: type: array @@ -19093,16 +19605,13 @@ components: format: email description: User email address. role: - type: string - nullable: true + type: ["string","null"] description: ID of the role assigned to the user, if any. For the owner, this value is `null` because the access is implicit. role_name: - type: string - nullable: true + type: ["string","null"] description: Name of the assigned role or of the user's implicit access. For the owner, this value is `owner`. organization: - type: string - nullable: true + type: ["string","null"] description: ID of the organization this access belongs to. operations: type: array @@ -19152,14 +19661,14 @@ components: type: string description: Role name. template_code: - type: string - nullable: true + type: ["string","null"] enum: - org-admin - org-readonly - org-billing - org-developer - org-team-manager + - null description: Base template code used to initialize the role, if any. add: type: array @@ -19178,14 +19687,14 @@ components: type: string description: New role name. template_code: - type: string - nullable: true + type: ["string","null"] enum: - org-admin - org-readonly - org-billing - org-developer - org-team-manager + - null description: New base template code for the role, if any. add: type: array diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 1491a0772..da60449c2 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -33,7 +33,7 @@ info: Durante el desarrollo, puedes usar la API de Facturapi en ambiente Test y las facturas que emitas no se enviarán al SAT ni tendrán validez fiscal. - + La llave secreta que utilices para autenticarte determinará tanto el ambiente en el que se creará la factura (Test o Live), así como la organización a utilizar como emisor @@ -961,6 +961,7 @@ x-tagGroups: paths: /catalogs/cartaporte/3.1/air-transport-codes: get: + operationId: searchAirTransportCodes tags: - carta_porte_keys summary: Buscar códigos de transporte aéreo @@ -1018,10 +1019,9 @@ paths: ["limit"] = 10 }); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - + - $ref: '#/components/parameters/SearchPagination' + - $ref: '#/components/parameters/SearchAfter' + - $ref: '#/components/parameters/SearchBefore' - in: query name: q schema: @@ -1049,34 +1049,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/comercioexterior/2.0/tariff-fractions: get: + operationId: searchTariffFractions tags: - comercio_exterior_keys summary: Buscar fracciones arancelarias @@ -1133,10 +1118,9 @@ paths: ["limit"] = 10 }); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - + - $ref: '#/components/parameters/SearchPagination' + - $ref: '#/components/parameters/SearchAfter' + - $ref: '#/components/parameters/SearchBefore' - in: query name: q schema: @@ -1164,34 +1148,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/transport-configs: get: + operationId: searchTransportConfigs tags: - carta_porte_keys summary: Buscar configuraciones de autotransporte @@ -1279,34 +1248,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/rights-of-passage: get: + operationId: searchRightsOfPassage tags: - carta_porte_keys summary: Buscar derechos de paso @@ -1394,34 +1348,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/customs-documents: get: + operationId: searchCustomsDocuments tags: - carta_porte_keys summary: Buscar documentos aduaneros @@ -1509,34 +1448,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/packaging-types: get: + operationId: searchPackagingTypes tags: - carta_porte_keys summary: Buscar tipos de empaque @@ -1624,34 +1548,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/trailer-types: get: + operationId: searchTrailerTypes tags: - carta_porte_keys summary: Buscar tipos de remolque @@ -1739,34 +1648,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/hazardous-materials: get: + operationId: searchHazardousMaterials tags: - carta_porte_keys summary: Buscar materiales peligrosos @@ -1854,34 +1748,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/naval-authorizations: get: + operationId: searchNavalAuthorizations tags: - carta_porte_keys summary: Buscar autorizaciones navales @@ -1968,7 +1847,7 @@ paths: application/json: schema: allOf: - - $ref: "#/components/schemas/SearchResult" + - $ref: '#/components/schemas/SearchResult' - type: object properties: data: @@ -1979,34 +1858,19 @@ paths: key: type: string '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/port-stations: get: + operationId: searchPortStations tags: - carta_porte_keys summary: Buscar estaciones/puertos @@ -2094,34 +1958,19 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /catalogs/cartaporte/3.1/marine-containers: get: + operationId: searchMarineContainers tags: - carta_porte_keys summary: Buscar contenedores marítimos @@ -2209,31 +2058,15 @@ paths: schema: $ref: '#/components/schemas/SearchKeyDescriptionResult' '400': - description: Error en parámetros de la petición - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/BadRequest' '401': - description: Error de autenticación - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/Unauthenticated' '404': - description: No se encontró el recurso especificado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' '500': - description: Error inesperado - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: '#/components/responses/UnexpectedError' /customers: post: operationId: createCustomer @@ -2251,7 +2084,7 @@ paths: te recomendamos guardar el ID en tu base de datos junto a la información de tu cliente. Posteriormente, puedes llamar al endpoint de Crear Factura pasando el ID del cliente en lugar de repetir la información. - + Por último, ten en cuenta que los clientes que crees en ambiente _Test_ **no se comparten** con el ambiente _Live_. x-codeSamples: @@ -3528,7 +3361,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + get: operationId: listInvoices tags: @@ -4947,7 +4780,7 @@ paths: // Acuse de factura cancelada xml $facturapi->Invoices->downloadCancellationReceiptXml("58e93bd8e86eb318b019743d"); - + // Acuse de factura cancelada pdf $facturapi->Invoices->downloadCancellationReceiptPdf("58e93bd8e86eb318b019743d"); parameters: @@ -5069,8 +4902,7 @@ paths: type: number description: Folio de la factura. Se omite si la factura no lo tiene registrado. series: - type: string - nullable: true + type: ["string","null"] description: Serie de la factura installment: type: number @@ -6146,7 +5978,7 @@ paths: summary: Enviar recibo por correo electrónico description: | Envía un correo electrónico a la dirección de tu cliente. - + El correo enviado estará personalizado con el logotipo y los colores de la organización que lo creó, e incluirá un botón para facturar el recibo, así con el recibo en formato PDF adjunto al mensaje. x-codeSamples: @@ -6294,7 +6126,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + /receipts/{receipt_id}/invoice: post: operationId: invoiceReceipt @@ -7121,10 +6953,12 @@ paths: items: type: string enum: + - all - draft - pending - valid - canceled + - failed description: Filtrar por uno o más estados de retención. - $ref: "#/components/parameters/SearchDate" - $ref: "#/components/parameters/SearchPage" @@ -7372,7 +7206,7 @@ paths: description: ID de la retención a cancelar - in: query name: motive - required: true + required: false schema: type: string enum: @@ -7845,8 +7679,8 @@ paths: la organización, deberás de terminar de configurarla llamando a los métodos de [Actualizar datos fiscales](#tag/organization/operation/editOrganizationLegal) y [Subir certificados (CSD)](#tag/organization/operation/uploadOrganizationCertificate) - - + + Después de crear la organización y antes de poder emitir facturas con la organización, deberás de terminar de configurarla llamando a los métodos de [Actualizar datos fiscales](#tag/organization/operation/editOrganizationLegal) y @@ -9693,7 +9527,7 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + post: operationId: createSeriesGroup tags: @@ -10152,7 +9986,7 @@ paths: summary: Invitar usuario a organización description: | Crea o actualiza una invitación de usuario. Por defecto, el acceso es de administrador con permisos completos; para limitarlo, crea un rol y envía su ID en `role`. - + Cada organización puede invitar a un usuario sin costo adicional. A partir del segundo usuario invitado, cada usuario adicional tendrá un costo mensual. Este cargo se aplica automáticamente cuando el usuario acepta la invitación. Puedes consultar el precio vigente en nuestra [página de precios](https://www.facturapi.io/pricing). x-codeSamples: @@ -11329,12 +11163,6 @@ paths: application/json: schema: $ref: "#/components/schemas/Webhook" - "200": - description: Un objeto `Webhook` con la misma información ya existía - content: - application/json: - schema: - $ref: "#/components/schemas/Webhook" "400": $ref: "#/components/responses/BadRequest" "401": @@ -11710,6 +11538,7 @@ paths: "signature" => "Signature_FROM_HEADER" ]); requestBody: + required: true content: application/json: schema: @@ -11719,11 +11548,18 @@ paths: type: string description: Llave secreta del webhook. Se obtiene al crear un webhook o desde el dashboard de Facturapi. payload: - type: object - description: Objeto ApiEvent recibido mediante el webhook + oneOf: + - type: string + - type: object + additionalProperties: true + description: Payload firmado. Usa el texto JSON original para conservar los bytes que se firmaron. signature: type: string description: Firma del webhook recibida en el header `Facturapi-Signature` + required: + - secret + - payload + - signature security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -11733,26 +11569,11 @@ paths: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" + oneOf: + - type: string - type: object - properties: - type: - type: string - description: Tipo de evento - example: "invoice.status_updated" - enum: - - invoice.status_updated - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" + additionalProperties: true + description: "Devuelve el payload original cuando la firma es válida: un string si enviaste texto JSON, o un objeto si enviaste un objeto. No convierte el string a objeto." "400": $ref: "#/components/responses/BadRequest" "401": @@ -11763,9 +11584,10 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - + /check: get: + operationId: checkApiKey tags: - tools summary: Health check (Pulso) @@ -11788,9 +11610,10 @@ paths: description: Error de autenticación. Asegúrate de estar usando tu llave secreta. "502": description: Servicio temporalmente no disponible. - + /tools/tax_id_validation: get: + operationId: validateTaxId tags: - tools summary: Validar RFC @@ -11805,7 +11628,7 @@ paths: booleana `is_valid`, que Facturapi resuelve interpretando la respuesta. Un valor de `true` para esta propiedad indica que el RFC no tiene asuntos por resolver y está libre de problemas; y lo contrario para `false`. - + Adicionalmente puedes consultar la propiedad data para ver los valores en bruto de la consulta al SAT. x-codeSamples: @@ -11825,7 +11648,7 @@ paths: label: C# source: | var facturapi = new FacturapiClient("sk_test_API_KEY"); - + var customer = await facturapi.Tool.ValidateTaxIdAsync("BBA830831LJ2"); - lang: Java label: Java @@ -11842,7 +11665,7 @@ paths: - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - + $customer = $facturapi->Tools->validateTaxId("BBA830831LJ2"); parameters: - in: query @@ -11872,6 +11695,7 @@ paths: $ref: "#/components/responses/UnexpectedError" /catalogs/products: get: + operationId: searchProducts tags: - sat_keys summary: Clave Producto/Servicio @@ -11959,6 +11783,7 @@ paths: $ref: "#/components/responses/UnexpectedError" /catalogs/units: get: + operationId: searchUnits tags: - sat_keys summary: Unidades de medida @@ -12293,8 +12118,8 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" -x-webhooks: - "Factura global creada": +webhooks: + invoice.global_invoice_created: post: summary: Factura global creada description: | @@ -12306,27 +12131,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - example: "invoice.global_invoice_created" - enum: - - invoice.global_invoice_created - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - "Estatus de factura actualizado": + $ref: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + operationId: onInvoiceGlobalInvoiceCreated + responses: + '200': + description: OK + invoice.status_updated: post: summary: Estatus de factura actualizado description: | @@ -12340,37 +12150,13 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - example: "invoice.status_updated" - enum: - - invoice.status_updated - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - related_resource_messages: - type: array - description: Mensajes relacionados con el recurso asociado al evento. - items: - $ref: "#/components/schemas/RelatedResourceMessage" + $ref: '#/components/schemas/InvoiceStatusUpdatedEvent' examples: with_related_messages: summary: Con mensajes relacionados value: id: evt_xxx - created_at: "2026-07-01T12:00:00.000Z" + created_at: '2026-07-01T12:00:00.000Z' livemode: true organization: org_xxx type: invoice.status_updated @@ -12384,12 +12170,12 @@ x-webhooks: source: stamping_async_task severity: error message: El RFC del receptor no es válido - created_at: "2026-01-01T00:00:00.000Z" + created_at: '2026-01-01T00:00:00.000Z' without_related_messages: summary: Sin mensajes relacionados value: id: evt_xxx - created_at: "2026-07-01T12:00:00.000Z" + created_at: '2026-07-01T12:00:00.000Z' livemode: true organization: org_xxx type: invoice.status_updated @@ -12398,7 +12184,11 @@ x-webhooks: object: id: invoice_xxx related_resource_messages: [] - "Creación de factura desde dashboard": + operationId: onInvoiceStatusUpdated + responses: + '200': + description: OK + invoice.created_from_dashboard: post: summary: Creación de factura desde dashboard description: | @@ -12410,27 +12200,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - example: "invoice.created_from_dashboard" - enum: - - invoice.created_from_dashboard - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - "Estatus de cancelación actualizado": + $ref: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + operationId: onInvoiceCreatedFromDashboard + responses: + '200': + description: OK + invoice.cancellation_status_updated: post: tags: - events @@ -12442,26 +12217,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - enum: - - invoice.cancellation_status_updated - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - invoice - object: - $ref: "#/components/schemas/Invoice" - "Autofactura completada": + $ref: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + operationId: onInvoiceCancellationStatusUpdated + responses: + '200': + description: OK + receipt.self_invoice_complete: post: tags: - events @@ -12473,27 +12234,12 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - example: "receipt.self_invoice_complete" - enum: - - receipt.self_invoice_complete - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - receipt - object: - $ref: "#/components/schemas/Receipt" - "Estatus de recibo actualizado": + $ref: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + operationId: onReceiptSelfInvoiceComplete + responses: + '200': + description: OK + receipt.status_updated: post: tags: - events @@ -12505,25 +12251,26 @@ x-webhooks: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventBase" - - type: object - properties: - type: - type: string - description: Tipo de evento - enum: - - receipt.status_updated - data: - type: object - properties: - type: - type: string - description: Tipo de objeto asociado al evento - enum: - - receipt - object: - $ref: "#/components/schemas/Receipt" + $ref: '#/components/schemas/ReceiptStatusUpdatedEvent' + operationId: onReceiptStatusUpdated + responses: + '200': + description: OK + customer.edit_link_completed: + post: + summary: Edición de cliente completada + tags: + - events + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CustomerEditLinkCompletedEvent' + responses: + '200': + description: OK + operationId: onCustomerEditLinkCompleted components: responses: BadRequest: @@ -12906,6 +12653,214 @@ components: Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. schemas: + InvoiceGlobalInvoiceCreatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + example: invoice.global_invoice_created + enum: + - invoice.global_invoice_created + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + InvoiceStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + example: invoice.status_updated + enum: + - invoice.status_updated + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + related_resource_messages: + type: array + description: Mensajes relacionados con el recurso asociado al evento. + items: + $ref: '#/components/schemas/RelatedResourceMessage' + required: + - type + - data + InvoiceCreatedFromDashboardEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + example: invoice.created_from_dashboard + enum: + - invoice.created_from_dashboard + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + InvoiceCancellationStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + enum: + - invoice.cancellation_status_updated + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - invoice + object: + $ref: '#/components/schemas/Invoice' + required: + - type + - object + required: + - type + - data + ReceiptSelfInvoiceCompleteEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + example: receipt.self_invoice_complete + enum: + - receipt.self_invoice_complete + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - receipt + object: + $ref: '#/components/schemas/Receipt' + required: + - type + - object + required: + - type + - data + ReceiptStatusUpdatedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + description: Tipo de evento + enum: + - receipt.status_updated + data: + type: object + properties: + type: + type: string + description: Tipo de objeto asociado al evento + enum: + - receipt + object: + $ref: '#/components/schemas/Receipt' + required: + - type + - object + required: + - type + - data + CustomerEditLinkCompletedEvent: + allOf: + - $ref: '#/components/schemas/EventBase' + - type: object + properties: + type: + type: string + enum: + - customer.edit_link_completed + data: + type: object + properties: + type: + type: string + enum: + - customer + object: + $ref: '#/components/schemas/Customer' + required: + - type + - object + required: + - type + - data + ApiEvent: + oneOf: + - $ref: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + - $ref: '#/components/schemas/InvoiceStatusUpdatedEvent' + - $ref: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + - $ref: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + - $ref: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + - $ref: '#/components/schemas/ReceiptStatusUpdatedEvent' + - $ref: '#/components/schemas/CustomerEditLinkCompletedEvent' + discriminator: + propertyName: type + mapping: + invoice.global_invoice_created: '#/components/schemas/InvoiceGlobalInvoiceCreatedEvent' + invoice.status_updated: '#/components/schemas/InvoiceStatusUpdatedEvent' + invoice.created_from_dashboard: '#/components/schemas/InvoiceCreatedFromDashboardEvent' + invoice.cancellation_status_updated: '#/components/schemas/InvoiceCancellationStatusUpdatedEvent' + receipt.self_invoice_complete: '#/components/schemas/ReceiptSelfInvoiceCompleteEvent' + receipt.status_updated: '#/components/schemas/ReceiptStatusUpdatedEvent' + customer.edit_link_completed: '#/components/schemas/CustomerEditLinkCompletedEvent' SignedDownloadUrl: type: object description: Enlace temporal de descarga de un archivo. @@ -12946,14 +12901,6 @@ components: description: type: string description: Descripción de la entrada del catálogo - ErrorMessage: - type: object - required: - - message - properties: - message: - type: string - description: Descripción del error y posible sugerencia. RelatedResourceMessage: type: object properties: @@ -12997,7 +12944,7 @@ components: type: string format: date-time description: Fecha y hora de creación del evento - example: 2022-03-30T00:00:00Z + example: '2022-03-30T00:00:00Z' livemode: type: boolean description: Indica si el evento se generó en modo test (false) o en modo producción (true). @@ -13006,6 +12953,11 @@ components: type: string description: ID de la organización a la que pertenece el evento example: 61f81a7fbd4661b11b9b3f27 + required: + - id + - created_at + - livemode + - organization DateRange: type: object properties: @@ -13128,12 +13080,14 @@ components: type: integer example: 1 title: Página - description: Número de página de resultados + description: Número de página. Vale 0 cuando no hay coincidencias; se omite en paginación por cursor. + minimum: 0 total_pages: type: integer example: 1 title: Páginas totales - description: Número total de páginas de resultados + description: Total de páginas. Se omite en paginación por cursor. + minimum: 0 total_results: type: integer example: 1 @@ -13141,12 +13095,16 @@ components: description: | Número de elementos individuales en todas las páginas de resultados. En modo `pagination=cursor` solo se incluye en la primera página de la búsqueda (sin `after`/`before`); el total no cambia entre páginas. previous_cursor: - type: [string, "null"] + type: + - string + - 'null' example: null title: Cursor anterior description: Cursor para obtener la página anterior de resultados. Es `null` en la primera página. Solo disponible con `pagination=cursor`. next_cursor: - type: [string, "null"] + type: + - string + - 'null' example: null title: Cursor siguiente description: Cursor para obtener la página siguiente de resultados. Es `null` cuando no hay más resultados. Solo disponible con `pagination=cursor`. @@ -13267,7 +13225,7 @@ components: example: 08/06/2021 format: "DD/MM/YYYY" description: Fecha de sentencia favorable - + ProductCatalogResult: type: object properties: @@ -13322,7 +13280,7 @@ components: items: $ref: "#/components/schemas/UnitCatalogResult" - + LocalTax: type: object required: @@ -13331,11 +13289,10 @@ components: properties: rate: type: number - example: 0.10 + example: 0.1 description: Tasa del impuesto en fracción decimal. base: type: number - default: 100% del subtotal description: Base del impuesto type: type: string @@ -13344,6 +13301,12 @@ components: type: boolean default: false description: Indica si se trata de un impuesto retenido (`true`), o un impuesto trasladado (`false`) + factor: + type: string + enum: + - Tasa + - Cuota + - Exento BaseTax: title: Tax type: object @@ -13362,7 +13325,6 @@ components: description: Tasa del impuesto en fracción decimal. base: type: number - default: 100% del subtotal description: Base del impuesto. type: type: string @@ -13420,8 +13382,8 @@ components: description: Sello digital del comprobante fiscal. date: type: string - format: date-time - description: Fecha de timbrado en formato ISO8601 (UTC String). + description: "FechaTimbrado del SAT: fecha y hora local sin offset de zona horaria. Se conserva como texto." + example: "2026-09-17T06:59:16" sat_cert_number: type: string description: Número de serie del certificado del SAT usado para timbrar. @@ -13819,7 +13781,6 @@ components: fecha_pago: type: string format: date - default: now description: Fecha de pago de la nómina al trabajador. fecha_inicial_pago: type: string @@ -15608,25 +15569,44 @@ components: description: | Id de la organización la cual se está dando de alta el webhook. livemode: - type: boolean + type: boolean example: false description: Ambiente en el cual se está dando de alta el webhook. enabled_events: - type: string - example: ["receipt.cancellation_status"] + type: array + example: + - receipt.status_updated description: Eventos dados de alta para el webhook. + items: + type: string + enum: + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed + - "*" url: type: string - format: email + format: uri description: Http ruta para el webhook example: http://my-website.com/my/webhook status: type: string - description: Status del webhook + description: Status del webhook enum: - enabled - disabled example: enabled + secret: + type: string + readOnly: true + description: Secreto para verificar las firmas. Se entrega al crear el webhook. + description: + type: string + type: object WebhookCreateInput: title: Webhook allOf: @@ -15639,56 +15619,70 @@ components: type: string description: URL del webhook a dar de alta para recibir notificaciones. example: http://my-website.com/my/webhook + format: uri enabled_events: type: array items: type: string enum: - - "invoice.global_invoice_created" - - "invoice.status_updated" - - "invoice.created_from_dashboard" - - "invoice.cancellation_status_updated" - - "receipt.self_invoice_complete" - - "receipt.status_updated" - - "receipt.cancellation_status_updated" + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed description: Los eventos a los que el webhook se suscribirá. - example: ["receipt.self_invoice_complete"] + example: + - receipt.self_invoice_complete + minItems: 1 WebhookCreateEdit: title: Webhook allOf: - type: object required: - enabled_events + - status properties: status: type: string description: Estatus del webhook enum: - - "disabled" - - "enabled" + - disabled + - enabled example: disabled enabled_events: type: array items: type: string enum: - - "invoice.global_invoice_created" - - "invoice.status_updated" - - "invoice.cancellation_status_updated" - - "invoice.created_from_dashboard" - - "receipt.self_invoice_complete" - - "receipt.cancellation_status_updated" - - "receipt.status_updated" + - receipt.self_invoice_complete + - invoice.cancellation_status_updated + - receipt.status_updated + - invoice.global_invoice_created + - invoice.status_updated + - invoice.created_from_dashboard + - customer.edit_link_completed description: Los eventos a los que el webhook se suscribirá. - example: ["receipt.self_invoice_complete"] + example: + - receipt.self_invoice_complete + minItems: 1 Customer: title: Objeto Customer allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/CustomerNonEditableProperties" - - $ref: "#/components/schemas/CustomerProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/CustomerNonEditableProperties' + - $ref: '#/components/schemas/CustomerProperties' + - type: object + properties: + organization: + type: string + curp: + type: string + external_id: + type: string CustomerSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -15702,23 +15696,29 @@ components: type: object properties: edit_link: - type: string + type: + - string + - 'null' description: | Enlace a una página alojada donde el cliente puede editar su información una vez. Ejemplo: https://auto.facturapi.io/tax-info/abcdWXYZ1234 example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: string + type: + - string + - 'null' format: date-time description: | Fecha de expiración del enlace de edición. - example: 2022-12-31T23:59:59Z + example: '2022-12-31T23:59:59Z' sat_validated_at: - type: string + type: + - string + - 'null' format: date-time description: | Fecha en la que la información fiscal fue validado por el SAT. - example: 2022-12-31T23:59:59Z + example: '2022-12-31T23:59:59Z' CustomerProperties: allOf: - $ref: "#/components/schemas/CustomerCommonProperties" @@ -15803,7 +15803,7 @@ components: title: Product allOf: - $ref: "#/components/schemas/ProductProperties" - + LineItemProductEgresoInput: title: Product allOf: @@ -15883,8 +15883,15 @@ components: Product: title: Objeto Product allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/ProductProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/ProductProperties' + - type: object + properties: + organization: + type: string + required: + - organization + - unit_key ProductSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -15897,10 +15904,7 @@ components: ProductProperties: type: object required: - - description - - product_key - - unit_key - - price + ["description","product_key","price"] properties: description: type: string @@ -16136,9 +16140,6 @@ components: description: Indica si el impuesto es una retención (`true`) o un traslado (`false`). taxability: type: string - default: | - '01' si el array `taxes` está vacío; '02' si el array `taxes` tiene por lo menos un elemento. - enum: - "01" - "02" - "03" @@ -16188,7 +16189,6 @@ components: date: type: string format: date-time - default: now description: Fecha en que se recibió el pago. Sólo es necesario incluirla si el pago se efectuó en una fecha anterior a la emisión de este comprobante. No se permiten fechas futuras. numOperacion: type: string @@ -16251,6 +16251,12 @@ components: format: ISO 3166-1 alpha-3 description: Código de País acorde al estándar ISO 3166-1 alpha-3, del Catálogo de Países. example: MEX + zip: + type: string + tax_system: + type: + - string + - 'null' CustomerComercioExterior: type: object description: Objeto con información parcial del cliente receptor del comprobante. Para obtener el objeto `Customer` completo, deberás consultarlo con el método de [Obtener Cliente]('#/operation/getCustomer'). @@ -16335,7 +16341,7 @@ components: InvoiceZipRequest: title: Objeto InvoiceZipRequest allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' - type: object required: - organization @@ -16358,13 +16364,13 @@ components: description: Identificador de la organización. example: 65a1f0000000000000000000 issuer_type: - $ref: "#/components/schemas/IssuingType" + $ref: '#/components/schemas/IssuingType' invoice_types: type: array description: Tipos normalizados de las facturas incluidas. uniqueItems: true items: - $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" + $ref: '#/components/schemas/InvoiceZipRequestInvoiceType' example: - E - I @@ -16372,14 +16378,14 @@ components: type: string format: date-time description: Inicio inclusivo del mes solicitado. - example: "2025-03-01T06:00:00.000Z" + example: '2025-03-01T06:00:00.000Z' end_date: type: string format: date-time description: Fin inclusivo del mes solicitado. - example: "2025-04-01T04:59:59.999Z" + example: '2025-04-01T04:59:59.999Z' status: - $ref: "#/components/schemas/InvoiceZipRequestStatus" + $ref: '#/components/schemas/InvoiceZipRequestStatus' document_count: type: integer minimum: 0 @@ -16400,7 +16406,11 @@ components: type: string format: date-time description: Fecha en que se programó el procesamiento. - example: "2026-08-04T18:00:01.000Z" + example: '2026-08-04T18:00:01.000Z' + processing_started_at: + type: string + format: date-time + description: Momento en que comenzó el procesamiento, si existe. InvoiceZipRequestSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -16462,26 +16472,30 @@ components: - accepted - rejected - expired + - verifying description: | Estado actual de la solicitud de cancelación, en caso de haberla realizado. Puedes leer más a detalle en la sección de [Cancelar Factura](#tag/invoice/operation/deleteInvoice)). example: none canceled_at: - type: string + type: + - string + - 'null' format: date-time - description: Fecha en la que se canceló el CFDI con hora aproximada. + description: Fecha en la que se canceló el CFDI con hora aproximada. verification_url: type: string format: uri description: Dirección URL para verificar el estado del CFDI en el portal del SAT. Este link es el mismo que aparece en el código QR, en el PDF de la factura. example: https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=45BEC0CA-5F1E-491E-9417-698EA48C382A&re=AAA010101AAA&rr=ABC101010111&tt=345.600000&fe=bWApPw== date: - type: string + type: + - string + - 'null' format: date-time - default: now - description: Fecha de expedición del comprobante en formato ISO8601 (UTC String). + description: Fecha de expedición en formato ISO8601. Puede ser null en borradores. address: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object description: Domicilio de expedición de la factura. properties: @@ -16495,12 +16509,14 @@ components: - I - E - P - - N + - 'N' - T description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. customer: - $ref: "#/components/schemas/CustomerInfo" + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' total: type: number description: Monto total facturado. @@ -16527,7 +16543,7 @@ components: payment_form: type: string description: Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). - example: 06 + example: 6 total_payment_amount: type: number description: Total del complemento de Pago cuando la factura es tipo P. @@ -16548,12 +16564,12 @@ components: type: array description: Conceptos incluidos en el comprobante items: - $ref: "#/components/schemas/LineItem" + $ref: '#/components/schemas/LineItem' related_documents: type: array description: Documentos relacionados con la factura. items: - $ref: "#/components/schemas/RelatedDocument" + $ref: '#/components/schemas/RelatedDocument' received_payment_ids: type: array items: @@ -16586,7 +16602,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + $ref: '#/components/schemas/NominaOrCustomComplementProperties' description: Complementos a incluir en la factura. pdf_custom_section: type: string @@ -16600,9 +16616,91 @@ components: type: array description: Namespaces a insertar en el nodo raíz de la factura. Requerido en `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' stamp: - $ref: "#/components/schemas/Stamp" + anyOf: + - $ref: '#/components/schemas/Stamp' + - type: 'null' + cancellation: + type: object + properties: + requested_at: + type: + - string + - 'null' + format: date-time + last_checked: + type: string + format: date-time + canceled_at: + type: + - string + - 'null' + format: date-time + status: + type: string + enum: + - none + - pending + - accepted + - rejected + - expired + - verifying + description: | + Estado actual de la solicitud de cancelación, en caso de haberla realizado. Puedes leer más a detalle en la sección de [Cancelar Factura](#tag/invoice/operation/deleteInvoice)). + example: none + motive: + type: string + substitutionUUID: + type: string + cancellation_type: + type: string + organization: + type: + - string + - 'null' + issuer_type: + $ref: '#/components/schemas/IssuingType' + cfdi_version: + type: number + example: 4 + issuer_info: + $ref: '#/components/schemas/CustomerInfo' + payment_method: + type: string + enum: + - PUE + - PPD + use: + type: string + amount_due: + type: number + verification_carta_porte: + type: string + format: uri + conditions: + type: string + export: + type: string + global: + type: object + required: + - periodicity + - months + - year + properties: + periodicity: + type: string + enum: + - day + - week + - fortnight + - month + - two_months + months: + type: string + year: + type: integer InvoiceDraftProperties: type: object properties: @@ -16624,6 +16722,7 @@ components: - accepted - rejected - expired + - verifying description: | Estado actual de la solicitud de cancelación, en caso de haberla realizado. Puedes leer más a detalle en la sección de [Cancelar Factura](#tag/invoice/operation/deleteInvoice)). example: none @@ -16633,13 +16732,15 @@ components: description: Dirección URL para verificar el estado del CFDI en el portal del SAT. Este link es el mismo que aparece en el código QR, en el PDF de la factura. example: null date: - type: string + type: + - string + - 'null' format: date-time example: null description: Fecha de timbrado del comprobante en formato ISO8601 (UTC String). Si el estado es `draft`, este campo es nulo. address: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object description: Domicilio de expedición de la factura. properties: @@ -16653,12 +16754,12 @@ components: - I - E - P - - N + - 'N' - T description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. customer: - $ref: "#/components/schemas/CustomerInfo" + $ref: '#/components/schemas/CustomerInfo' total: type: number description: Monto total facturado. @@ -16685,17 +16786,17 @@ components: payment_form: type: string description: Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). - example: 06 + example: 6 items: type: array description: Conceptos incluidos en el comprobante items: - $ref: "#/components/schemas/LineItem" + $ref: '#/components/schemas/LineItem' related_documents: type: array description: Documentos relacionados con la factura. items: - $ref: "#/components/schemas/RelatedDocument" + $ref: '#/components/schemas/RelatedDocument' currency: type: string example: MXN @@ -16709,7 +16810,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + $ref: '#/components/schemas/NominaOrCustomComplementProperties' description: Complementos a incluir en la factura. pdf_custom_section: type: string @@ -16723,7 +16824,7 @@ components: type: array description: Namespaces a insertar en el nodo raíz de la factura. Requerido en `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' is_ready_to_stamp: type: boolean description: | @@ -16736,7 +16837,7 @@ components: En una factura con status diferente a `draft`, este campo siempre será `false`. stamp: allOf: - - $ref: "#/components/schemas/Stamp" + - $ref: '#/components/schemas/Stamp' - type: object example: null @@ -16745,7 +16846,6 @@ components: properties: folio_number: type: integer - default: autoincremental description: Número de folio asignado por la empresa para control interno. Si se omite, se asignará el valor autoincremental de la organización. series: type: string @@ -16994,7 +17094,6 @@ components: date: type: string format: date-time - default: now description: Fecha de expedición del comprobante en formato ISO8601 (UTC String). No puede ser anterior a 72 horas en el pasado, ni posterior al presente. address: allOf: @@ -17070,107 +17169,135 @@ components: - $ref: "#/components/schemas/InvoiceableCommonEditInput" InvoiceCreateInput: type: object + description: Datos de la factura según su tipo y estado inicial. Omite status para timbrar; usa draft para guardar un borrador. oneOf: - - title: Ingreso - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceIngresoInput" - draft: "#/components/schemas/InvoiceIngresoEditInput" - properties: - status: - type: string - enum: - - pending - - draft - default: pending - description: | - Estado inicial de la factura. Si se envía `draft`, la factura se guardará como borrador y no se timbrará ni se - enviará al SAT. También al enviar `draft`, todos los campos requeridos se vuelven - opcionales. Si se omite, el estado por default es `pending` y una vez timbrada (en la respuesta) este - campo se actualizará a `valid`. Para facturas asíncronas, este campo se quedará en `pending` hasta que - se timbre la factura. - example: draft - - title: Egreso - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceEgresoInput" - draft: "#/components/schemas/InvoiceEgresoEditInput" - properties: - status: - type: string - enum: - - pending - - draft - default: pending - description: | - Estado inicial de la factura. Si se envía `draft`, la factura se guardará como borrador y no se timbrará ni se - enviará al SAT. También al enviar `draft`, todos los campos requeridos se vuelven - opcionales. Si se omite, el estado por default es `pending` y una vez timbrada (en la respuesta) este - campo se actualizará a `valid`. Para facturas asíncronas, este campo se quedará en `pending` hasta que - se timbre la factura. - example: draft - - title: Pago - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoicePagoInput" - draft: "#/components/schemas/InvoicePagoEditInput" - properties: - status: - type: string - enum: - - pending - - draft - default: pending - description: | - Estado inicial de la factura. Si se envía `draft`, la factura se guardará como borrador y no se timbrará ni se - enviará al SAT. También al enviar `draft`, todos los campos requeridos se vuelven - opcionales. Si se omite, el estado por default es `pending` y una vez timbrada (en la respuesta) este - campo se actualizará a `valid`. Para facturas asíncronas, este campo se quedará en `pending` hasta que - se timbre la factura. - example: draft - - title: Nómina - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceNominaInput" - draft: "#/components/schemas/InvoiceNominaEditInput" - properties: - status: - type: string - enum: - - pending - - draft - default: pending - description: | - Estado inicial de la factura. Si se envía `draft`, la factura se guardará como borrador y no se timbrará ni se - enviará al SAT. También al enviar `draft`, todos los campos requeridos se vuelven - opcionales. Si se omite, el estado por default es `pending` y una vez timbrada (en la respuesta) este - campo se actualizará a `valid`. Para facturas asíncronas, este campo se quedará en `pending` hasta que - se timbre la factura. - example: draft - - title: Traslado - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/InvoiceTrasladoInput" - draft: "#/components/schemas/InvoiceTrasladoEditInput" - properties: - status: - type: string - enum: - - pending - - draft - default: pending - description: | - Estado inicial de la factura. Si se envía `draft`, la factura se guardará como borrador y no se timbrará ni se - enviará al SAT. También al enviar `draft`, todos los campos requeridos se vuelven - opcionales. Si se omite, el estado por default es `pending` y una vez timbrada (en la respuesta) este - campo se actualizará a `valid`. Para facturas asíncronas, este campo se quedará en `pending` hasta que - se timbre la factura. - example: draft + - allOf: + - $ref: '#/components/schemas/InvoiceIngresoInput' + - type: object + properties: + type: + type: string + const: I + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceIngresoEditInput' + - type: object + required: + - status + properties: + type: + type: string + const: I + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceEgresoInput' + - type: object + required: + - type + properties: + type: + type: string + const: E + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceEgresoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: E + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoicePagoInput' + - type: object + required: + - type + properties: + type: + type: string + const: P + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoicePagoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: P + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceNominaInput' + - type: object + required: + - type + properties: + type: + type: string + const: 'N' + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceNominaEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: 'N' + status: + type: string + const: draft + - allOf: + - $ref: '#/components/schemas/InvoiceTrasladoInput' + - type: object + required: + - type + properties: + type: + type: string + const: T + status: + type: string + const: pending + default: pending + - allOf: + - $ref: '#/components/schemas/InvoiceTrasladoEditInput' + - type: object + required: + - status + - type + properties: + type: + type: string + const: T + status: + type: string + const: draft InvoiceIngresoInput: title: Ingreso required: @@ -17255,7 +17382,7 @@ components: properties: periodicity: type: string - + description: | Periodicidad que abarca la factura global. @@ -17802,8 +17929,12 @@ components: Receipt: title: Objeto Receipt allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/ReceiptProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/ReceiptProperties' + - type: object + properties: + organization: + type: string ReceiptProperties: allOf: - type: object @@ -17900,7 +18031,7 @@ components: emitir una recibo con más de 5,000 conceptos, prueba dividir la transacción en varios recibos. items: $ref: "#/components/schemas/LineItemInput" - + - $ref: "#/components/schemas/ReceiptEditableProperties" - type: object properties: @@ -17997,7 +18128,6 @@ components: from: type: string format: date - default: Inicio del último periodo example: 2022-01-01T00:00:00.000 description: | Fecha inicial de los recibos que se incluirán en la factura global. @@ -18007,7 +18137,6 @@ components: to: type: string format: date - default: Fin del último periodo example: 2022-01-31T23:59:59.999 description: | Fecha final de los recibos que se incluirán en la factura global. @@ -18016,7 +18145,6 @@ components: en la configuración de recibos de tu organización. Este valor es requerido cuando se envíe el campo `receipts`. periodicity: type: string - default: Propiedad `periodicity` de la configuración de recibos de la organización. enum: - day - week @@ -18029,14 +18157,12 @@ components: default dependerán del valor de `periodicity`. months: type: string - default: Mes contenido en el rango de fechas utilizado. description: | Clave que representa el mes o bimestre de la factura. Consulta los posibles valores en el [catálogo de Meses y Bimestres](#meses-y-bimestres). example: "01" folio_number: type: integer - default: autoincremental description: | Número de folio asignado por la empresa para control interno. Si se omite, se asignará el valor autoincremental de la organización. @@ -18047,7 +18173,6 @@ components: date: type: string format: date - default: Valor del atributo `to` example: 2022-01-01T00:00:00.000 description: | Fecha de emisión de la factura. @@ -18115,8 +18240,7 @@ components: default: false description: Si es `true`, sólo valida y regresa un resumen sin crear la factura. payment_form: - type: string - nullable: true + type: ["string","null"] minLength: 2 maxLength: 2 example: "03" @@ -18137,13 +18261,13 @@ components: description: Key del recibo. example: ticket_1001 customer: - nullable: true oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" + - $ref: '#/components/schemas/CustomerCreateInput' - type: string title: customer_id description: ID de un cliente previamente registrado en Facturapi. example: 58e93bd8e86eb318b0197456 + - type: 'null' description: | Cliente opcional para renderizar la vista previa. Si lo omites, todos los recibos deben tener asignado el mismo cliente. @@ -18157,9 +18281,13 @@ components: Retention: title: Objeto Retention allOf: - - $ref: "#/components/schemas/ResourceAutoGeneratedProps" - - $ref: "#/components/schemas/RetentionReadOnlyProperties" - - $ref: "#/components/schemas/RetentionProperties" + - $ref: '#/components/schemas/ResourceAutoGeneratedProps' + - $ref: '#/components/schemas/RetentionReadOnlyProperties' + - $ref: '#/components/schemas/RetentionProperties' + - type: object + properties: + organization: + type: string RetentionReadOnlyProperties: type: object properties: @@ -18190,9 +18318,13 @@ components: description: Folio fiscal de la retención, asignado por el SAT. example: 39c85a3f-275b-4341-b259-e8971d9f8a94 stamp: - $ref: "#/components/schemas/Stamp" + anyOf: + - $ref: '#/components/schemas/Stamp' + - type: 'null' customer: - $ref: "#/components/schemas/CustomerInfo" + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' is_ready_to_stamp: type: boolean description: | @@ -18204,12 +18336,14 @@ components: properties: cve_retenc: type: string - example: 01 + example: 1 description: Clave de la retención o información de pagos de acuerdo al catálogo del SAT. fecha_exp: - type: string + type: + - string + - 'null' format: date-time - example: "2021-09-15T06:03:23.000Z" + example: '2021-09-15T06:03:23.000Z' description: Fecha de expedición del comprobante en formato ISO8601 (UTC String). desc_retenc: type: string @@ -18278,10 +18412,10 @@ components: tipo_pago_ret: type: string enum: - - 01 - - 02 - - 03 - - 04 + - 1 + - 2 + - 3 + - 4 description: | - `01`: Pago definitivo IVA - `02`: Pago definitivo IEPS @@ -18299,7 +18433,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CustomComplementData" + $ref: '#/components/schemas/CustomComplementData' description: | Arreglo de complementos a incluir en la factura. Cada elemento contiene un `string` con el código XML del complemento. @@ -18315,7 +18449,7 @@ components: type: array description: Namespaces a insertar en el nodo raíz de la factura. Requerido en `addenda`. items: - $ref: "#/components/schemas/NamespaceProperties" + $ref: '#/components/schemas/NamespaceProperties' RetentionSearchResult: allOf: - $ref: "#/components/schemas/SearchResult" @@ -18381,16 +18515,15 @@ components: example: draft customer: description: Cliente receptor de la factura. - nullable: true oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" + - $ref: '#/components/schemas/CustomerCreateInput' - type: string title: customer_id description: ID del objeto 'customer' previamente registrado en Facturapi. example: 58e93bd8e86eb318b0197456 + - type: 'null' cve_retenc: - type: string - nullable: true + type: ["string","null"] example: 26 description: Clave de la retención o información de pagos de acuerdo al [catálogo del SAT](#clave-de-retencion). fecha_exp: @@ -18406,8 +18539,7 @@ components: example: R123 description: Identificador alfanumérico para control interno de la empresa y sin relevancia fiscal. periodo: - type: object - nullable: true + type: ["object","null"] description: Información sobre el periodo de la retención. required: - mes_ini @@ -18431,8 +18563,7 @@ components: example: 2021 description: Año o ejercicio fiscal en que se realizó la retención. totales: - type: object - nullable: true + type: ["object","null"] description: Información sobre el total de retenciones efectuadas en el periodo correspondiente. required: - monto_tot_operacion @@ -18551,21 +18682,21 @@ components: id: type: string description: ID del objeto - example: "5a2a307be93a2f00129ea035" + example: 5a2a307be93a2f00129ea035 logo_url: type: string format: uri description: URL del logotipo de la organización. - example: "https://storage.googleapis.com/cdn.facturapi.io/organization/6c100efa5c6f5d7db0379ca643476a4183526007/logo.jpg" + example: https://storage.googleapis.com/cdn.facturapi.io/organization/6c100efa5c6f5d7db0379ca643476a4183526007/logo.jpg timezone: type: string description: Zona horaria de la organización, en formato IANA. - example: "America/Mexico_City" + example: America/Mexico_City created_at: type: string format: date-time description: Fecha de registro - example: "2017-05-05T20:55:33.468Z" + example: '2017-05-05T20:55:33.468Z' is_production_ready: type: boolean description: Indica si la organización tiene información necesaria para facturar en ambiente Live. @@ -18599,7 +18730,7 @@ components: Nombre Fiscal o Razón Social de la organización, *sin* el régimen societario (ej.: S.A. de C.V.). tax_system: type: string - example: "601" + example: '601' maxLength: 3 minLength: 3 description: Código de Régimen Fiscal, del [catálogo del SAT](#régimen-fiscal). @@ -18613,7 +18744,7 @@ components: allOf: - type: object description: Domicilio fiscal de la organización. - - $ref: "#/components/schemas/OrganizationAddress" + - $ref: '#/components/schemas/OrganizationAddress' customization: type: object description: | @@ -18731,16 +18862,16 @@ components: updated_at: type: string format: date-time - example: "2023-05-05T20:55:33.468Z" + example: '2023-05-05T20:55:33.468Z' description: Fecha de la última actualización del certificado. expires_at: type: string format: date-time - example: "2025-05-05T20:55:33.468Z" + example: '2025-05-05T20:55:33.468Z' description: Fecha de expiración del certificado. serial_number: type: string - example: "30001000000300000101" + example: '30001000000300000101' description: Número de serie del certificado CSD. fiel: type: object @@ -18752,16 +18883,16 @@ components: updated_at: type: string format: date-time - example: "2023-05-05T20:55:33.468Z" + example: '2023-05-05T20:55:33.468Z' description: Fecha de la última actualización del certificado FIEL. expires_at: type: string format: date-time - example: "2025-05-05T20:55:33.468Z" + example: '2025-05-05T20:55:33.468Z' description: Fecha de expiración del certificado FIEL. serial_number: type: string - example: "30001000000300000101" + example: '30001000000300000101' description: Número de serie del certificado FIEL. receipts: type: object @@ -18839,6 +18970,49 @@ components: type: boolean description: | Indica si el correo electrónico de soporte ha sido verificado. Si es falso, el correo electrónico utilizado en el portal de autofacturación será el correo electrónico principal de la cuenta. + plan: + type: + - string + - 'null' + deprecated: true + description: Plan heredado de la organización. + add_ons: + type: array + description: Funcionalidades adicionales contratadas por la organización. + items: + type: string + pending_plan_update: + type: + - object + - 'null' + description: Cambio de plan programado, si existe. + properties: + plan: + type: string + scheduled_for: + type: string + format: date-time + pending_add_ons_update: + type: + - object + - 'null' + description: Cambio programado de funcionalidades adicionales, si existe. + properties: + add_ons: + type: array + items: + type: string + scheduled_for: + type: string + format: date-time + domain: + type: + - string + - 'null' + custom_domain: + type: + - string + - 'null' OrganizationDeleteCerts: type: object @@ -19218,12 +19392,10 @@ components: type: string description: Nombre de la organización que envió la invitación. role: - type: string - nullable: true + type: ["string","null"] description: ID del rol asignado en la invitación, si existe. role_name: - type: string - nullable: true + type: ["string","null"] description: Nombre del rol asignado en la invitación, si existe. roles: type: array @@ -19231,9 +19403,8 @@ components: items: type: string expires_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Fecha y hora en que expira la invitación. OrganizationInviteList: type: array @@ -19250,12 +19421,10 @@ components: type: string description: Nombre del rol. template_code: - type: string - nullable: true + type: ["string","null"] description: Código de plantilla base del rol, si proviene de una plantilla del sistema. organization: - type: string - nullable: true + type: ["string","null"] description: ID de la organización a la que pertenece el rol. used_by: type: integer @@ -19276,14 +19445,12 @@ components: items: type: string created_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Fecha y hora de creación del rol. updated_at: - type: string + type: ["string","null"] format: date-time - nullable: true description: Fecha y hora de la última actualización del rol. OrganizationPermissionRoleList: type: array @@ -19334,16 +19501,13 @@ components: format: email description: Correo electrónico del usuario. role: - type: string - nullable: true + type: ["string","null"] description: ID del rol asignado al usuario, si existe. Para el propietario, este valor es `null` porque su acceso es implícito. role_name: - type: string - nullable: true + type: ["string","null"] description: Nombre del rol asignado o del acceso implícito del usuario. Para el propietario, este valor es `owner`. organization: - type: string - nullable: true + type: ["string","null"] description: ID de la organización a la que pertenece el acceso. operations: type: array @@ -19393,14 +19557,14 @@ components: type: string description: Nombre del rol. template_code: - type: string - nullable: true + type: ["string","null"] enum: - org-admin - org-readonly - org-billing - org-developer - org-team-manager + - null description: Código de plantilla base para inicializar el rol, si aplica. add: type: array @@ -19419,14 +19583,14 @@ components: type: string description: Nuevo nombre del rol. template_code: - type: string - nullable: true + type: ["string","null"] enum: - org-admin - org-readonly - org-billing - org-developer - org-team-manager + - null description: Nuevo código de plantilla base del rol, si aplica. add: type: array diff --git a/website/package.json b/website/package.json index a1d1e707c..ae3390345 100644 --- a/website/package.json +++ b/website/package.json @@ -12,7 +12,8 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "typecheck": "tsc" + "typecheck": "tsc", + "test:openapi": "node scripts/check-openapi.mjs" }, "dependencies": { "@docusaurus/core": "^3.10.1", @@ -35,6 +36,8 @@ "@types/react": "^19.1.8", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", + "js-yaml": "4.2.0", + "openapi-typescript": "7.13.0", "typescript": "^5.8.3" }, "browserslist": { diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index 01dcc1050..0f3b8a71e 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -53,7 +53,7 @@ importers: version: 3.10.1 '@docusaurus/types': specifier: ^3.10.1 - version: 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/react': specifier: ^19.1.8 version: 19.2.17 @@ -63,6 +63,12 @@ importers: '@types/react-router-dom': specifier: ^5.3.3 version: 5.3.3 + js-yaml: + specifier: 4.2.0 + version: 4.2.0 + openapi-typescript: + specifier: 7.13.0 + version: 7.13.0(typescript@5.9.3) typescript: specifier: ^5.8.3 version: 5.9.3 @@ -1525,9 +1531,15 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + '@redocly/ajv@8.18.3': resolution: {integrity: sha512-l42u0of3hY98sN2A+M4qTX1O/KrpgGH32Hu9kP2GtHyD5Dfqq86PKFLe5dwaD8DEnNmlOlll2BAmeEtf0DaySg==} + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} + '@redocly/config@0.6.3': resolution: {integrity: sha512-hGWJgCsXRw0Ow4rplqRlUQifZvoSwZipkYnt11e3SeH1Eb23VUIDBcRuaQOUqy1wn0eevXkU2GzzQ8fbKdQ7Mg==} @@ -1535,6 +1547,10 @@ packages: resolution: {integrity: sha512-z06h+svyqbUcdAaePq8LPSwTPlm6Ig7j2VlL8skPBYnJvyaQ2IN7x/JkOvRL4ta+wcOCBdAex5JWnZbKaNktJg==} engines: {node: '>=14.19.0', npm: '>=7.0.0'} + '@redocly/openapi-core@1.34.20': + resolution: {integrity: sha512-ypeBZ/6BKXR9+7/TtbKhbl4UgD7raHhPS12oknlKno2A8+lnFkxIwiE/Aklu6L2cd/ioH+fCWuMxi9/p3EyAPw==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rspack/binding-darwin-arm64@1.7.11': resolution: {integrity: sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==} cpu: [arm64] @@ -2159,6 +2175,10 @@ packages: ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-html-community@0.0.8: resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} engines: {'0': node >= 0.8.0} @@ -2380,6 +2400,9 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -3401,6 +3424,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + infima@0.2.0-alpha.45: resolution: {integrity: sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==} engines: {node: '>=12'} @@ -3600,6 +3627,10 @@ packages: resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} hasBin: true + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4236,6 +4267,12 @@ packages: openapi-sampler@1.7.4: resolution: {integrity: sha512-CKS/rd5ucPCuEDbJnjGDXZTsuGWcmv53aCmQx7soZlPEONUGN4af0/dY5+THRFZraSEjeA78nlfzdFswC/N5SA==} + openapi-typescript@7.13.0: + resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -4290,6 +4327,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-numeric-range@1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -5355,6 +5396,10 @@ packages: stylis@4.3.6: resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -5501,6 +5546,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -5579,6 +5628,9 @@ packages: resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} engines: {node: '>=14.16'} + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -5965,7 +6017,7 @@ snapshots: '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -6017,7 +6069,7 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 resolve: 1.22.12 transitivePeerDependencies: @@ -6693,7 +6745,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -7072,40 +7124,6 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/babel@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.7) - '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) - '@babel/preset-env': 7.29.7(@babel/core@7.29.7) - '@babel/preset-react': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/runtime': 7.29.7 - '@babel/traverse': 7.29.7 - '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - babel-plugin-dynamic-import-node: 2.3.3 - fs-extra: 11.3.5 - tslib: 2.8.1 - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - react - - react-dom - - supports-color - - uglify-js - - webpack-cli - '@docusaurus/bundler@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@babel/core': 7.29.7 @@ -7153,12 +7171,12 @@ snapshots: '@docusaurus/core@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/babel': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/babel': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/bundler': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/logger': 3.10.1 '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) boxen: 6.2.1 @@ -7194,7 +7212,7 @@ snapshots: tinypool: 1.1.1 tslib: 2.8.1 update-notifier: 6.0.2 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) webpack-bundle-analyzer: 4.10.2 webpack-dev-server: 5.2.5(tslib@2.8.1)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) webpack-merge: 6.0.1 @@ -7231,7 +7249,7 @@ snapshots: '@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15)': dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@rspack/core': 1.7.11 '@swc/core': 1.15.41 '@swc/html': 1.15.41 @@ -7262,7 +7280,7 @@ snapshots: '@docusaurus/mdx-loader@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/mdx': 3.1.1 '@slorber/remark-comment': 1.0.0 @@ -7286,7 +7304,7 @@ snapshots: unist-util-visit: 5.1.0 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) vfile: 6.0.3 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - '@minify-html/node' - '@swc/core' @@ -7305,7 +7323,7 @@ snapshots: '@docusaurus/module-type-aliases@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/history': 4.7.11 '@types/react': 19.2.17 '@types/react-router-config': 5.0.11 @@ -7337,9 +7355,9 @@ snapshots: '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) cheerio: 1.0.0-rc.12 combine-promises: 1.2.0 @@ -7353,7 +7371,7 @@ snapshots: tslib: 2.8.1 unist-util-visit: 5.1.0 utility-types: 3.11.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7385,9 +7403,9 @@ snapshots: '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/module-type-aliases': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 @@ -7399,7 +7417,7 @@ snapshots: schema-dts: 1.1.5 tslib: 2.8.1 utility-types: 3.11.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7428,14 +7446,14 @@ snapshots: dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) tslib: 2.8.1 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7463,8 +7481,8 @@ snapshots: '@docusaurus/plugin-css-cascade-layers@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tslib: 2.8.1 transitivePeerDependencies: @@ -7496,8 +7514,8 @@ snapshots: '@docusaurus/plugin-debug@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7530,7 +7548,7 @@ snapshots: '@docusaurus/plugin-google-analytics@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7562,7 +7580,7 @@ snapshots: '@docusaurus/plugin-google-gtag@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/gtag.js': 0.0.20 react: 19.2.7 @@ -7595,7 +7613,7 @@ snapshots: '@docusaurus/plugin-google-tag-manager@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7628,9 +7646,9 @@ snapshots: dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/logger': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 @@ -7664,15 +7682,15 @@ snapshots: '@docusaurus/plugin-svgr@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/webpack': 8.1.0(typescript@5.9.3) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) tslib: 2.8.1 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7713,7 +7731,7 @@ snapshots: '@docusaurus/theme-classic': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/theme-search-algolia': 3.10.1(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) transitivePeerDependencies: @@ -7759,9 +7777,9 @@ snapshots: '@docusaurus/plugin-content-pages': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/theme-translations': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) clsx: 2.1.1 @@ -7806,8 +7824,8 @@ snapshots: '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/module-type-aliases': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/history': 4.7.11 '@types/react': 19.2.17 '@types/react-router-config': 5.0.11 @@ -7843,7 +7861,7 @@ snapshots: '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/theme-translations': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) algoliasearch: 5.54.1 algoliasearch-helper: 3.29.1(algoliasearch@5.54.1) @@ -7919,36 +7937,6 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@mdx-js/mdx': 3.1.1 - '@types/history': 4.7.11 - '@types/mdast': 4.0.4 - '@types/react': 19.2.17 - commander: 5.1.0 - joi: 17.13.4 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)' - utility-types: 3.11.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) - webpack-merge: 5.10.0 - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - supports-color - - uglify-js - - webpack-cli - '@docusaurus/utils-common@3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -7971,33 +7959,11 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - tslib: 2.8.1 - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - react - - react-dom - - supports-color - - uglify-js - - webpack-cli - '@docusaurus/utils-validation@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 joi: 17.13.4 js-yaml: 4.2.0 @@ -8062,47 +8028,6 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@docusaurus/logger': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - escape-string-regexp: 4.0.0 - execa: 5.1.1 - file-loader: 6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) - fs-extra: 11.3.5 - github-slugger: 1.5.0 - globby: 11.1.0 - gray-matter: 4.0.3 - jiti: 1.21.7 - js-yaml: 4.2.0 - lodash: 4.18.1 - micromatch: 4.0.8 - p-queue: 6.6.2 - prompts: 2.4.2 - resolve-pathname: 3.0.0 - tslib: 2.8.1 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) - utility-types: 3.11.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - react - - react-dom - - supports-color - - uglify-js - - webpack-cli - '@emnapi/core@1.11.1': dependencies: '@emnapi/wasi-threads': 1.2.2 @@ -8491,6 +8416,13 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + '@redocly/ajv@8.18.3': dependencies: fast-deep-equal: 3.1.3 @@ -8498,6 +8430,8 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + '@redocly/config@0.22.0': {} + '@redocly/config@0.6.3': {} '@redocly/openapi-core@1.16.0': @@ -8505,7 +8439,7 @@ snapshots: '@redocly/ajv': 8.18.3 '@redocly/config': 0.6.3 colorette: 1.4.0 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) js-levenshtein: 1.1.6 js-yaml: 4.2.0 lodash.isequal: 4.5.0 @@ -8517,6 +8451,20 @@ snapshots: - encoding - supports-color + '@redocly/openapi-core@1.34.20(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.3.2 + minimatch: 5.1.9 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@rspack/binding-darwin-arm64@1.7.11': optional: true @@ -9143,6 +9091,8 @@ snapshots: dependencies: string-width: 4.2.3 + ansi-colors@4.1.3: {} + ansi-html-community@0.0.8: {} ansi-regex@5.0.1: {} @@ -9198,7 +9148,7 @@ snapshots: '@babel/core': 7.29.7 find-cache-dir: 4.0.0 schema-utils: 4.3.3 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) babel-plugin-dynamic-import-node@2.3.3: dependencies: @@ -9387,6 +9337,8 @@ snapshots: chalk@5.6.2: {} + change-case@5.4.4: {} + char-regex@1.0.2: {} character-entities-html4@2.1.0: {} @@ -9553,7 +9505,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) core-js-compat@3.49.0: dependencies: @@ -9610,7 +9562,7 @@ snapshots: semver: 7.8.4 optionalDependencies: '@rspack/core': 1.7.11 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): dependencies: @@ -9620,7 +9572,7 @@ snapshots: postcss: 8.5.15 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) optionalDependencies: clean-css: 5.3.3 @@ -9727,9 +9679,11 @@ snapshots: dependencies: ms: 2.0.0 - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decko@1.2.0: {} @@ -9785,7 +9739,7 @@ snapshots: detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -9803,7 +9757,7 @@ snapshots: docusaurus-plugin-redoc@2.5.0(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)): dependencies: - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@redocly/openapi-core': 1.16.0 redoc: 2.4.0(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) transitivePeerDependencies: @@ -9827,7 +9781,7 @@ snapshots: postcss-prefix-selector: 1.16.1(postcss@8.5.15) redoc: 2.4.0(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) styled-components: 6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - core-js - css-to-react-native @@ -10138,7 +10092,7 @@ snapshots: dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) fill-range@7.1.1: dependencies: @@ -10454,7 +10408,7 @@ snapshots: tapable: 2.3.3 optionalDependencies: '@rspack/core': 1.7.11 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) htmlparser2@6.1.0: dependencies: @@ -10519,10 +10473,10 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -10553,6 +10507,8 @@ snapshots: indent-string@4.0.0: {} + index-to-position@1.2.0: {} + infima@0.2.0-alpha.45: {} inherits@2.0.4: {} @@ -10710,6 +10666,10 @@ snapshots: dependencies: argparse: 2.0.1 + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -11349,7 +11309,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.13 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -11403,7 +11363,7 @@ snapshots: dependencies: schema-utils: 4.3.3 tapable: 2.3.3 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) minimalistic-assert@1.0.1: {} @@ -11498,7 +11458,7 @@ snapshots: dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) oas-kit-common@1.0.8: dependencies: @@ -11577,6 +11537,16 @@ snapshots: fast-xml-parser: 5.9.0 json-pointer: 0.6.2 + openapi-typescript@7.13.0(typescript@5.9.3): + dependencies: + '@redocly/openapi-core': 1.34.20(supports-color@10.2.2) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.2.2 + typescript: 5.9.3 + yargs-parser: 21.1.1 + opener@1.5.2: {} p-cancelable@3.0.0: {} @@ -11643,6 +11613,12 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.7 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-numeric-range@1.3.0: {} parse5-htmlparser2-tree-adapter@7.1.0: @@ -11856,7 +11832,7 @@ snapshots: jiti: 1.21.7 postcss: 8.5.15 semver: 7.8.4 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - typescript @@ -12249,7 +12225,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.7 react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.7)' - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) react-router-config@5.1.1(react-router@5.3.4(react@19.2.7))(react@19.2.7): dependencies: @@ -12374,7 +12350,7 @@ snapshots: redocusaurus@2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): dependencies: '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) docusaurus-plugin-redoc: 2.5.0(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) docusaurus-theme-redoc: 2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) transitivePeerDependencies: @@ -12789,7 +12765,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -12800,7 +12776,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -12896,6 +12872,8 @@ snapshots: stylis@4.3.6: {} + supports-color@10.2.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -12938,7 +12916,7 @@ snapshots: dependencies: '@swc/core': 1.15.41 '@swc/counter': 0.1.3 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) tapable@2.3.3: {} @@ -12948,7 +12926,7 @@ snapshots: jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.48.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) optionalDependencies: '@swc/core': 1.15.41 '@swc/html': 1.15.41 @@ -12961,7 +12939,7 @@ snapshots: jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.48.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) optionalDependencies: '@swc/core': 1.15.41 clean-css: 5.3.3 @@ -12969,17 +12947,6 @@ snapshots: html-minifier-terser: 7.2.0 postcss: 8.5.15 - terser-webpack-plugin@5.6.1(@swc/core@1.15.41)(postcss@8.5.15)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - terser: 5.48.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) - optionalDependencies: - '@swc/core': 1.15.41 - postcss: 8.5.15 - terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -13029,6 +12996,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@4.41.0: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -13123,6 +13092,8 @@ snapshots: semver-diff: 4.0.0 xdg-basedir: 5.1.0 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -13132,7 +13103,7 @@ snapshots: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) optionalDependencies: file-loader: 6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) @@ -13210,7 +13181,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - tslib @@ -13245,7 +13216,7 @@ snapshots: webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) ws: 8.21.0 optionalDependencies: - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: - bufferutil - debug @@ -13345,45 +13316,6 @@ snapshots: - postcss - uglify-js - webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15): - dependencies: - '@types/estree': 1.0.9 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.17.0 - acorn-import-phases: 1.0.4(acorn@8.17.0) - browserslist: 4.28.2 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.0 - es-module-lexer: 2.1.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - loader-runner: 4.3.2 - mime-db: 1.54.0 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.3 - terser-webpack-plugin: 5.6.1(@swc/core@1.15.41)(postcss@8.5.15)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) - watchpack: 2.5.2 - webpack-sources: 3.5.0 - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - uglify-js - webpackbar@7.0.0(@rspack/core@1.7.11)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): dependencies: ansis: 3.17.0 @@ -13392,7 +13324,7 @@ snapshots: std-env: 3.10.0 optionalDependencies: '@rspack/core': 1.7.11 - webpack: 5.107.2(@swc/core@1.15.41)(postcss@8.5.15) + webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) websocket-driver@0.7.5: dependencies: diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs new file mode 100644 index 000000000..cdfb73215 --- /dev/null +++ b/website/scripts/check-openapi.mjs @@ -0,0 +1,134 @@ +import assert from "node:assert/strict"; +import { readFile, writeFile, mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { createRequire } from "node:module"; +import { execFileSync } from "node:child_process"; +import yaml from "js-yaml"; +import openapiTS, { astToString } from "openapi-typescript"; + +const root = new URL("../", import.meta.url); +const contracts = []; +const presentationKeys = new Set([ + "description", + "summary", + "title", + "example", + "examples", + "externalDocs", + "x-codeSamples", +]); + +function contract(value, key) { + if (Array.isArray(value)) { + const items = value.map((item) => contract(item)); + return ["required", "enum", "type"].includes(key) ? items.sort() : items; + } + if (value && typeof value === "object") { + return Object.fromEntries( + Object.entries(value) + .filter(([name]) => !presentationKeys.has(name)) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([name, nested]) => [name, contract(nested, name)]), + ); + } + return value; +} + +for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { + const spec = yaml.load(await readFile(new URL(filename, root), "utf8")); + function walk(value, path = []) { + if (!value || typeof value !== "object") return; + assert( + !("nullable" in value), + `Use OpenAPI 3.1 null unions: ${path.join(".")}`, + ); + if (value.$ref?.startsWith("#/")) { + let target = spec; + for (const part of value.$ref.slice(2).split("/")) { + target = target?.[part.replace(/~1/g, "/").replace(/~0/g, "~")]; + } + assert(target, `Unresolved reference: ${value.$ref}`); + } + for (const [key, child] of Object.entries(value)) + walk(child, [...path, key]); + } + walk(spec); + const ids = new Set(); + for (const [path, item] of Object.entries(spec.paths)) { + for (const [method, operation] of Object.entries(item)) { + if (!operation.responses) continue; + assert(operation.operationId, `Missing operationId: ${method} ${path}`); + assert( + !ids.has(operation.operationId), + `Duplicate operationId: ${operation.operationId}`, + ); + ids.add(operation.operationId); + const params = [ + ...(item.parameters || []), + ...(operation.parameters || []), + ].map((parameter) => + parameter.$ref + ? spec.components.parameters[parameter.$ref.split("/").at(-1)] + : parameter, + ); + for (const match of path.matchAll(/\{([^}]+)\}/g)) { + assert( + params.some( + (parameter) => + parameter.in === "path" && + parameter.name === match[1] && + parameter.required === true, + ), + `Missing required path parameter: ${path}`, + ); + } + } + } + contracts.push( + contract({ + paths: spec.paths, + webhooks: spec.webhooks, + components: spec.components, + }), + ); + const directory = await mkdtemp(join(tmpdir(), "facturapi-openapi-")); + try { + await writeFile( + join(directory, "schema.d.ts"), + astToString( + await openapiTS(new URL(filename, root), { defaultNonNullable: false }), + ), + ); + await writeFile( + join(directory, "fixture.ts"), + await readFile(new URL("test/openapi-types.fixture.txt", root)), + ); + execFileSync( + process.execPath, + [ + createRequire(import.meta.url).resolve("typescript/bin/tsc"), + "--noEmit", + "--strict", + "--skipLibCheck", + "--target", + "ES2022", + "--moduleResolution", + "node", + join(directory, "fixture.ts"), + ], + { stdio: "inherit" }, + ); + } finally { + await rm(directory, { recursive: true, force: true }); + } + console.log( + `${filename}: ${ids.size} operations, references and generated type contracts verified`, + ); +} +assert.deepEqual( + contracts[0], + contracts[1], + "Spanish and English must describe the same API contract", +); +console.log("Locale contracts match"); diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt new file mode 100644 index 000000000..aa68955da --- /dev/null +++ b/website/test/openapi-types.fixture.txt @@ -0,0 +1,49 @@ +import type { components, operations, webhooks } from "./schema"; +const invoice: components["schemas"]["InvoiceCreateInput"] = { + customer: "cus_example", + items: [ + { + quantity: 1, + product: { + description: "Ukelele", + product_key: "60131324", + price: 345.6, + }, + }, + ], + payment_form: "28", + use: "G01", +}; +const draft: components["schemas"]["InvoiceCreateInput"] = { status: "draft" }; +const receiptEvent: components["schemas"]["ApiEvent"] = { + id: "evt", + created_at: "2026-09-29T00:00:00Z", + livemode: false, + organization: "org", + type: "receipt.status_updated", + data: { + type: "receipt", + object: { id: "rec", created_at: "2026-09-29T00:00:00Z", livemode: false }, + }, +}; +const validation: operations["validateWebhookSignature"]["requestBody"]["content"]["application/json"] = + { + secret: "secret", + signature: "123", + payload: '{"type":"receipt.status_updated"}', + }; +const nullDate: components["schemas"]["InvoiceProperties"]["date"] = null; +const callback: keyof webhooks = "customer.edit_link_completed"; +// @ts-expect-error event discriminants must correlate with the resource +const invalid: components["schemas"]["ApiEvent"] = { + ...receiptEvent, + data: { + type: "invoice", + object: { + id: "invoice", + created_at: "2026-09-29T00:00:00Z", + livemode: false, + }, + }, +}; +void [invoice, draft, receiptEvent, validation, nullDate, callback, invalid]; diff --git a/website/tsconfig.json b/website/tsconfig.json index 314eab8a4..4dbcfa4ce 100644 --- a/website/tsconfig.json +++ b/website/tsconfig.json @@ -1,6 +1,7 @@ { // This file is not used in compilation. It is here just for a nice editor experience. "extends": "@docusaurus/tsconfig", + "exclude": ["node_modules", "build", ".docusaurus"], "compilerOptions": { "baseUrl": "." } From b71901083d32313905efad5ea81339afc8fd9170 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 13:25:43 +0200 Subject: [PATCH 02/33] docs: add public documentation contribution guidelines --- AGENTS.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..94611048c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# AGENTS.md + +## Public documentation and confidentiality + +- This is a public repository. Publish only the intended public API contract and + information authorized for public documentation. +- Private sources may be consulted to verify API behavior. Never publish their + source code, internal file paths, commit hashes, implementation details, + private data, or internal plans in files, commit messages, pull requests, + review comments, issues, or CI output. +- Keep evidence from private sources in private files or repositories. Explain + public corrections in terms of observable API behavior without citing private + implementation sources. +- Keep PR titles and descriptions focused on the documentation change. Omit + unrelated internal plans and conversational context. +- Before committing or publishing, review the full diff, commit messages, and + accompanying descriptions for confidential information. +- If confidential information was published, a later deletion commit is not + sufficient. Clean affected branch history, verify remote references, and + explicitly report any host-side references or cached copies that remain. + +## API contract changes + +- Verify changes to types, required fields, defaults, authentication, parameters, + and status codes against authoritative sources. Do not treat an SDK declaration + or a review comment alone as proof of API behavior. +- Keep the Spanish and English OpenAPI contracts structurally aligned. +- Run the relevant repository checks for specification changes. From cc0619150120e591abba9291ace58e86b669852a Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 14:27:10 +0200 Subject: [PATCH 03/33] docs: preserve SAT codes and clarify API contract details --- website/openapi_v2.en.yaml | 246 ++++++++++++------------- website/openapi_v2.yaml | 244 ++++++++++++------------ website/scripts/check-openapi.mjs | 19 +- website/test/openapi-types.fixture.txt | 7 +- 4 files changed, 270 insertions(+), 246 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 6c828cf3e..140c01d60 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -990,7 +990,7 @@ x-tagGroups: paths: /catalogs/cartaporte/3.1/air-transport-codes: get: - operationId: searchAirTransportCodes + operationId: "searchCartaPorteAirTransportCodes" tags: - carta_porte_keys summary: Search air transport codes @@ -1090,7 +1090,7 @@ paths: /catalogs/cartaporte/3.1/transport-configs: get: - operationId: searchTransportConfigs + operationId: "searchCartaPorteTransportConfigs" tags: - carta_porte_keys summary: Search auto transport configurations @@ -1190,7 +1190,7 @@ paths: /catalogs/comercioexterior/2.0/tariff-fractions: get: - operationId: searchTariffFractions + operationId: "searchComercioExteriorTariffFractions" tags: - comercio_exterior_keys summary: Search tariff fractions @@ -1289,7 +1289,7 @@ paths: /catalogs/cartaporte/3.1/rights-of-passage: get: - operationId: searchRightsOfPassage + operationId: "searchCartaPorteRightsOfPassage" tags: - carta_porte_keys summary: Search rights of passage @@ -1389,7 +1389,7 @@ paths: /catalogs/cartaporte/3.1/customs-documents: get: - operationId: searchCustomsDocuments + operationId: "searchCartaPorteCustomsDocuments" tags: - carta_porte_keys summary: Search customs documents @@ -1489,7 +1489,7 @@ paths: /catalogs/cartaporte/3.1/packaging-types: get: - operationId: searchPackagingTypes + operationId: "searchCartaPortePackagingTypes" tags: - carta_porte_keys summary: Search packaging types @@ -1589,7 +1589,7 @@ paths: /catalogs/cartaporte/3.1/trailer-types: get: - operationId: searchTrailerTypes + operationId: "searchCartaPorteTrailerTypes" tags: - carta_porte_keys summary: Search trailer types @@ -1689,7 +1689,7 @@ paths: /catalogs/cartaporte/3.1/hazardous-materials: get: - operationId: searchHazardousMaterials + operationId: "searchCartaPorteHazardousMaterials" tags: - carta_porte_keys summary: Search hazardous materials @@ -1789,7 +1789,7 @@ paths: /catalogs/cartaporte/3.1/naval-authorizations: get: - operationId: searchNavalAuthorizations + operationId: "searchCartaPorteNavalAuthorizations" tags: - carta_porte_keys summary: Search naval authorizations @@ -1899,7 +1899,7 @@ paths: /catalogs/cartaporte/3.1/port-stations: get: - operationId: searchPortStations + operationId: "searchCartaPortePortStations" tags: - carta_porte_keys summary: Search port stations @@ -1999,7 +1999,7 @@ paths: /catalogs/cartaporte/3.1/marine-containers: get: - operationId: searchMarineContainers + operationId: "searchCartaPorteMarineContainers" tags: - carta_porte_keys summary: Search marine containers @@ -3553,11 +3553,11 @@ paths: schema: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: Filter by invoice type. Exact match. - in: query name: payment_method @@ -6999,7 +6999,7 @@ paths: - valid - canceled - failed - description: Filter by one or more retention statuses. + description: "Filter by one or more retention statuses. If omitted, no status filter is applied, equivalent to `all`. Sending `all` also disables this filter." - $ref: "#/components/parameters/SearchDate" - $ref: "#/components/parameters/SearchPage" - $ref: "#/components/parameters/SearchLimit" @@ -11602,7 +11602,7 @@ paths: - type: string - type: object additionalProperties: true - description: Signed payload. Use the original JSON text to preserve the signed bytes. + description: "Signed payload. Prefer the original JSON text, preserving the exact bytes received. Objects are also accepted, but verification uses their JSON serialization." signature: type: string description: Signature from the header "Facturapi-Signature". @@ -11615,7 +11615,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Event object successfully validated + description: Original payload with a valid signature content: application/json: schema: @@ -11638,12 +11638,11 @@ paths: /check: get: - operationId: checkApiKey + operationId: "checkApiHealth" tags: - tools summary: Health check - description: | - Check the health of the Facturapi API. + description: "Checks that the API is available. This endpoint requires a secret API key." security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -13114,13 +13113,13 @@ components: type: integer example: 1 title: Página - description: Page number. Zero when no matches exist; omitted in cursor pagination. + description: "Page number. It is 0 when there are no matches. Omitted on every cursor-pagination response, including the first page." minimum: 0 total_pages: type: integer example: 1 title: Total pages - description: Total pages. Omitted in cursor pagination. + description: "Total number of pages. Omitted on every cursor-pagination response, including the first page." minimum: 0 total_results: type: integer @@ -13265,7 +13264,7 @@ components: key: type: string description: Key from the SAT catalog - example: 60131324 + example: "60131324" description: type: string description: Description @@ -13343,7 +13342,7 @@ components: description: Tax rate in decimal format. base: type: number - description: Tax base amount. + description: "Tax base. If omitted, the full subtotal of the line item is used." type: type: string description: Tax name. Free text. @@ -13375,7 +13374,7 @@ components: description: Tax rate in decimal format. base: type: number - description: Tax base amount. + description: "Tax base. If omitted, it is calculated from the line item subtotal and tax factor. For the Cuota factor, the number of units is used." type: type: string default: IVA @@ -13833,7 +13832,7 @@ components: fecha_pago: type: string format: date - description: Payment date of the payroll to the worker. + description: "Date the employee was paid. If omitted, the current date and time are used." fecha_inicial_pago: type: string format: date @@ -15530,11 +15529,11 @@ components: exterior: type: string description: Exterior number. - example: 142 + example: "142" interior: type: string description: Interior number. - example: 4 + example: "4" neighborhood: type: string description: Neighborhood @@ -15550,7 +15549,7 @@ components: zip: type: string description: Postal code - example: 86500 + example: "86500" # Main resources Webhook: title: Webhook object @@ -15682,6 +15681,7 @@ components: - type: object properties: organization: + description: "ID of the organization this resource belongs to." type: string curp: type: string @@ -15767,7 +15767,7 @@ components: phone: type: string description: Customer's phone number. - example: 6474010101 + example: "6474010101" default_invoice_use: type: string description: Default CFDI use for the customer. @@ -15824,7 +15824,7 @@ components: product_key: type: string description: Key from the SAT catalog of products/services. We provide a more convenient way to find it using our [key search tool](https://dashboard.facturapi.io/catalogs/productKey). - example: 60131324 + example: "60131324" unit_key: type: string default: H87 @@ -15892,6 +15892,7 @@ components: - type: object properties: organization: + description: "ID of the organization this resource belongs to." type: string required: - organization @@ -15917,7 +15918,7 @@ components: product_key: type: string description: Key from the SAT catalog of products/services. We provide a more convenient way to find it using our [key search tool](https://dashboard.facturapi.io/catalogs/productKey). - example: 60131324 + example: "60131324" price: type: number description: | @@ -16008,11 +16009,11 @@ components: example: Ukelele product_key: type: string - default: 84111506 + default: "84111506" description: | Key from the SAT catalog of products/services. We provide a more convenient way to find it using our [key search tool](https://dashboard.facturapi.io/catalogs/productKey). - example: 84111506 + example: "84111506" price: type: number description: | @@ -16171,14 +16172,7 @@ components: - "03" - "04" - "05" - description: | - Code representing whether the good or service is subject to tax or not. This attribute corresponds to the "ObjetoImp" field in the CFDI. - - - `01`: Not subject to tax. - - `02`: Subject to tax. - - `03`: Subject to tax, but not required to break down. - - `04`: Subject to tax, but does not cause tax. - - `05`: Subject to tax, VAT credit PODEBI. + description: "Code representing whether the good or service is subject to tax or not. This attribute corresponds to the \"ObjetoImp\" field in the CFDI.\n\n- `01`: Not subject to tax.\n- `02`: Subject to tax.\n- `03`: Subject to tax, but not required to break down.\n- `04`: Subject to tax, but does not cause tax.\n- `05`: Subject to tax, VAT credit PODEBI.\n\nIf omitted, `01` is used when `taxes` is empty and `02` when it contains at least one tax." installment: type: integer description: | @@ -16227,7 +16221,7 @@ components: date: type: string format: date-time - description: Date on which the payment was received. It is only necessary to include it if the payment was made on a date prior to the issuance of this document. Future dates are not allowed. + description: "Date the payment was received. If omitted, the current date and time are used. Include it when payment occurred before this invoice was issued. Future dates are not allowed." numOperacion: type: string description: | @@ -16250,7 +16244,7 @@ components: tipoCadPago: type: string enum: - - 01 + - "01" description: | Key of the type of payment chain generated by the receiving entity of the payment. If this field exists, it is mandatory to register the `certPago`, `cadPago`, and `selloPago` fields. @@ -16347,11 +16341,11 @@ components: InvoiceZipRequestInvoiceType: type: string enum: - - I - - E - - T - - N - - P + - "I" + - "E" + - "T" + - "N" + - "P" description: Invoice type (`I` Income, `E` Credit note/expense, `T` Transport, `N` Payroll, or `P` Payment). InvoiceZipRequestCreateInput: type: object @@ -16551,11 +16545,11 @@ components: type: type: string enum: - - I - - E - - P - - 'N' - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. customer: @@ -16588,7 +16582,7 @@ components: payment_form: type: string description: Payment form code according to the [Payment Form catalog](#payment-form). - example: 6 + example: "06" total_payment_amount: type: number description: Total amount of the Payment complement when the invoice is type P. @@ -16667,17 +16661,21 @@ components: - $ref: '#/components/schemas/Stamp' - type: 'null' cancellation: + description: "Information about the invoice cancellation request. `cancellation_status` also exposes its current status." type: object properties: requested_at: + description: "Date and time cancellation was requested." type: - string - 'null' format: date-time last_checked: + description: "Date and time the cancellation status was last checked." type: string format: date-time canceled_at: + description: "Date and time the CFDI was canceled." type: - string - 'null' @@ -16695,12 +16693,21 @@ components: Current status of the cancellation request, if it has been made. `verifying` means the SAT has received the request and is validating it; Facturapi will keep checking until it changes to a final status. You can read more in the [Cancel Invoice](#tag/invoice/operation/deleteInvoice) section. example: none motive: + description: "Cancellation reason code." type: string substitutionUUID: + description: "UUID of the replacement CFDI, when applicable." type: string cancellation_type: - type: string + description: "Indicates whether SAT allows cancellation and whether recipient authorization is required." + type: ["string", "null"] + enum: + - cancellable_without_authorization + - cancellable_with_authorization + - not_cancellable + - null organization: + description: "ID of the organization this resource belongs to." type: - string - 'null' @@ -16775,7 +16782,6 @@ components: type: string format: uri description: URL to verify the status of the CFDI on the SAT portal. This link is the same as the one that appears in the QR code on the invoice PDF. - example: null date: type: - string @@ -16797,11 +16803,11 @@ components: type: type: string enum: - - I - - E - - P - - 'N' - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. customer: @@ -16814,7 +16820,6 @@ components: type: string format: uuid description: Fiscal folio of the invoice, assigned by the SAT. If the invoice has not been stamped, this field is null. - example: 0 folio_number: type: integer description: Autoincremental folio number for internal control and without fiscal relevance. @@ -16832,7 +16837,7 @@ components: payment_form: type: string description: Payment form code according to the [Payment Form catalog](#forma-de-pago). - example: 6 + example: "06" items: type: array description: Concepts included in the document. @@ -17151,8 +17156,7 @@ components: date: type: string format: date-time - description: | - Date of issuance of the invoice in ISO8601 format (UTC String). It cannot be earlier than 72 hours in the past, nor later than the present. + description: "Invoice issuance date in ISO8601 format. If omitted, the current date and time are used. It cannot be more than 72 hours in the past or in the future." address: allOf: - $ref: "#/components/schemas/CommonAddressProperties" @@ -17613,7 +17617,7 @@ components: type: type: string enum: - - N + - "N" complements: type: array default: [] @@ -17691,11 +17695,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. items: @@ -17817,11 +17821,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. payment_form: @@ -17884,11 +17888,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. related_documents: @@ -17919,11 +17923,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. complements: @@ -17945,11 +17949,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. items: @@ -17999,6 +18003,7 @@ components: - type: object properties: organization: + description: "ID of the organization this resource belongs to." type: string ReceiptProperties: allOf: @@ -18007,13 +18012,13 @@ components: date: type: string format: date-time - example: 2021-09-10T15:21:23.456Z + example: "2021-09-10T15:21:23.456Z" description: | Date of issuance of the receipt in ISO8601 format (UTC String). expires_at: type: string format: date-time - example: 2021-09-17T15:21:23.456Z + example: "2021-09-17T15:21:23.456Z" description: | Expiration date in ISO8601 format (UTC String). @@ -18121,7 +18126,7 @@ components: date: type: string format: date-time - example: 2021-09-10T15:21:23.456Z + example: "2021-09-10T15:21:23.456Z" description: | Date of issuance of the receipt in ISO8601 format (UTC String). payment_form: @@ -18208,7 +18213,7 @@ components: from: type: string format: date - example: 2022-01-01T00:00:00.000 + example: "2022-01-01" description: | Initial date of the receipts that will be included in the global invoice. By default, this value is the start of the last period (day, week, @@ -18217,7 +18222,7 @@ components: to: type: string format: date - example: 2022-01-31T23:59:59.999 + example: "2022-01-31" description: | End date of the receipts that will be included in the global invoice. By default, this value is the end of the last period (day, week, @@ -18232,15 +18237,10 @@ components: - fortnight - month - two_months - description: | - Periodicity that corresponds to the range of dates used. - If you omit the `from` and `to` fields, the default dates will depend - on the value of `periodicity`. + description: "Periodicity that corresponds to the range of dates used.\nIf you omit the `from` and `to` fields, the default dates will depend\non the value of `periodicity`.\n\nIf omitted, the organization’s receipt periodicity setting is used." months: type: string - description: | - Key representing the month or bimester of the invoice. Consult - the possible values in the [Months and Bimesters catalog](#meses-y-bimestres). + description: "Key representing the month or bimester of the invoice. Consult\nthe possible values in the [Months and Bimesters catalog](#meses-y-bimestres).\n\nIf omitted, the month or two-month period is determined from the start date and periodicity." example: "01" folio_number: type: integer @@ -18255,9 +18255,8 @@ components: date: type: string format: date - example: 2022-01-01T00:00:00.000 - description: | - Date of issuance of the invoice. By default, it takes the value of the `to` field. + example: "2022-01-01" + description: "Invoice issuance date. If omitted, the end date (`to`) is used, capped at the current date and time." payment_form: type: string minLength: 2 @@ -18370,6 +18369,7 @@ components: - type: object properties: organization: + description: "ID of the organization this resource belongs to." type: string RetentionReadOnlyProperties: type: object @@ -18420,7 +18420,7 @@ components: properties: cve_retenc: type: string - example: 1 + example: "01" description: | Key of the retention or payment information according to the SAT catalog. fecha_exp: @@ -18502,10 +18502,10 @@ components: tipo_pago_ret: type: string enum: - - 1 - - 2 - - 3 - - 4 + - "01" + - "02" + - "03" + - "04" description: | Key of the type of payment according to the SAT catalog. @@ -18714,10 +18714,10 @@ components: tipo_pago_ret: type: string enum: - - 01 - - 02 - - 03 - - 04 + - "01" + - "02" + - "03" + - "04" description: | Key of the type of payment according to the SAT catalog. @@ -19441,11 +19441,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Invoice type. Possible values: `I` (Income), `E` (Expense), `P` (Payment), `N` (Payroll), `T` (Transfer). diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index da60449c2..e676614b6 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -961,7 +961,7 @@ x-tagGroups: paths: /catalogs/cartaporte/3.1/air-transport-codes: get: - operationId: searchAirTransportCodes + operationId: "searchCartaPorteAirTransportCodes" tags: - carta_porte_keys summary: Buscar códigos de transporte aéreo @@ -1061,7 +1061,7 @@ paths: /catalogs/comercioexterior/2.0/tariff-fractions: get: - operationId: searchTariffFractions + operationId: "searchComercioExteriorTariffFractions" tags: - comercio_exterior_keys summary: Buscar fracciones arancelarias @@ -1160,7 +1160,7 @@ paths: /catalogs/cartaporte/3.1/transport-configs: get: - operationId: searchTransportConfigs + operationId: "searchCartaPorteTransportConfigs" tags: - carta_porte_keys summary: Buscar configuraciones de autotransporte @@ -1260,7 +1260,7 @@ paths: /catalogs/cartaporte/3.1/rights-of-passage: get: - operationId: searchRightsOfPassage + operationId: "searchCartaPorteRightsOfPassage" tags: - carta_porte_keys summary: Buscar derechos de paso @@ -1360,7 +1360,7 @@ paths: /catalogs/cartaporte/3.1/customs-documents: get: - operationId: searchCustomsDocuments + operationId: "searchCartaPorteCustomsDocuments" tags: - carta_porte_keys summary: Buscar documentos aduaneros @@ -1460,7 +1460,7 @@ paths: /catalogs/cartaporte/3.1/packaging-types: get: - operationId: searchPackagingTypes + operationId: "searchCartaPortePackagingTypes" tags: - carta_porte_keys summary: Buscar tipos de empaque @@ -1560,7 +1560,7 @@ paths: /catalogs/cartaporte/3.1/trailer-types: get: - operationId: searchTrailerTypes + operationId: "searchCartaPorteTrailerTypes" tags: - carta_porte_keys summary: Buscar tipos de remolque @@ -1660,7 +1660,7 @@ paths: /catalogs/cartaporte/3.1/hazardous-materials: get: - operationId: searchHazardousMaterials + operationId: "searchCartaPorteHazardousMaterials" tags: - carta_porte_keys summary: Buscar materiales peligrosos @@ -1760,7 +1760,7 @@ paths: /catalogs/cartaporte/3.1/naval-authorizations: get: - operationId: searchNavalAuthorizations + operationId: "searchCartaPorteNavalAuthorizations" tags: - carta_porte_keys summary: Buscar autorizaciones navales @@ -1870,7 +1870,7 @@ paths: /catalogs/cartaporte/3.1/port-stations: get: - operationId: searchPortStations + operationId: "searchCartaPortePortStations" tags: - carta_porte_keys summary: Buscar estaciones/puertos @@ -1970,7 +1970,7 @@ paths: /catalogs/cartaporte/3.1/marine-containers: get: - operationId: searchMarineContainers + operationId: "searchCartaPorteMarineContainers" tags: - carta_porte_keys summary: Buscar contenedores marítimos @@ -3523,11 +3523,11 @@ paths: schema: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: Tipo de factura. Búsqueda por tipo de factura con las claves exactas. - in: query name: payment_method @@ -6959,7 +6959,7 @@ paths: - valid - canceled - failed - description: Filtrar por uno o más estados de retención. + description: "Filtrar por uno o más estados de retención. Si se omite, no se filtra por estado, equivalente a `all`. Enviar `all` también desactiva este filtro." - $ref: "#/components/parameters/SearchDate" - $ref: "#/components/parameters/SearchPage" - $ref: "#/components/parameters/SearchLimit" @@ -11552,7 +11552,7 @@ paths: - type: string - type: object additionalProperties: true - description: Payload firmado. Usa el texto JSON original para conservar los bytes que se firmaron. + description: "Payload firmado. Prefiere el texto JSON original, conservando exactamente los bytes recibidos. También se aceptan objetos, pero la verificación utiliza su serialización JSON." signature: type: string description: Firma del webhook recibida en el header `Facturapi-Signature` @@ -11565,7 +11565,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Objeto del evento validado + description: Payload original con firma válida content: application/json: schema: @@ -11587,11 +11587,11 @@ paths: /check: get: - operationId: checkApiKey + operationId: "checkApiHealth" tags: - tools summary: Health check (Pulso) - description: Indica el estatus de disponibilidad de la API. + description: "Comprueba que la API está disponible. Este endpoint requiere una llave secreta de API." security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -13080,13 +13080,13 @@ components: type: integer example: 1 title: Página - description: Número de página. Vale 0 cuando no hay coincidencias; se omite en paginación por cursor. + description: "Número de página. Vale 0 cuando no hay coincidencias. Se omite en todas las respuestas de paginación por cursor, incluida la primera página." minimum: 0 total_pages: type: integer example: 1 title: Páginas totales - description: Total de páginas. Se omite en paginación por cursor. + description: "Total de páginas. Se omite en todas las respuestas de paginación por cursor, incluida la primera página." minimum: 0 total_results: type: integer @@ -13232,7 +13232,7 @@ components: key: type: string description: Clave del catálogo - example: 60131324 + example: "60131324" description: type: string description: Descripción @@ -13293,7 +13293,7 @@ components: description: Tasa del impuesto en fracción decimal. base: type: number - description: Base del impuesto + description: "Base del impuesto. Si se omite, se utiliza el subtotal completo del concepto." type: type: string description: Nombre del impuesto. Texto libre. @@ -13325,7 +13325,7 @@ components: description: Tasa del impuesto en fracción decimal. base: type: number - description: Base del impuesto. + description: "Base del impuesto. Si se omite, se calcula a partir del subtotal del concepto y el factor del impuesto. Para el factor Cuota, se utiliza la cantidad de unidades." type: type: string default: IVA @@ -13781,7 +13781,7 @@ components: fecha_pago: type: string format: date - description: Fecha de pago de la nómina al trabajador. + description: "Fecha de pago de la nómina al trabajador. Si se omite, se utiliza la fecha y hora actuales." fecha_inicial_pago: type: string format: date @@ -15525,11 +15525,11 @@ components: exterior: type: string description: Número exterior. - example: 142 + example: "142" interior: type: string description: Número interior. - example: 4 + example: "4" neighborhood: type: string description: Colonia @@ -15545,7 +15545,7 @@ components: zip: type: string description: Código postal - example: 86500 + example: "86500" # Main resources Webhook: @@ -15678,6 +15678,7 @@ components: - type: object properties: organization: + description: "ID de la organización a la que pertenece este recurso." type: string curp: type: string @@ -15765,7 +15766,7 @@ components: phone: type: string description: Teléfono del cliente. - example: 6474010101 + example: "6474010101" default_invoice_use: type: string description: Uso de CFDI por defecto. @@ -15822,7 +15823,7 @@ components: product_key: type: string description: Clave de producto/servicio, del catálogo del SAT. Nosotros te proporcionamos una manera más conveniente de encontrarlo utilizando nuestra [herramienta de búsqueda de claves](https://dashboard.facturapi.io/catalogs/productKey). - example: 60131324 + example: "60131324" unit_key: type: string default: H87 @@ -15888,6 +15889,7 @@ components: - type: object properties: organization: + description: "ID de la organización a la que pertenece este recurso." type: string required: - organization @@ -15913,7 +15915,7 @@ components: product_key: type: string description: Clave de producto/servicio, del catálogo del SAT. Nosotros te proporcionamos una manera más conveniente de encontrarlo utilizando nuestra [herramienta de búsqueda de claves](https://dashboard.facturapi.io/catalogs/productKey). - example: 60131324 + example: "60131324" price: type: number description: Precio por unidad del bien o servicio. Este valor representará el precio con IVA incluido o sin él, dependiendo del valor de `tax_included`. @@ -15996,9 +15998,9 @@ components: example: Ukelele product_key: type: string - default: 84111506 + default: "84111506" description: Clave de producto/servicio, del catálogo del SAT. Nosotros te proporcionamos una manera más conveniente de encontrarlo utilizando nuestra [herramienta de búsqueda de claves](https://dashboard.facturapi.io/catalogs/productKey). - example: 84111506 + example: "84111506" price: type: number description: Suma total de la cantidad devuelta, descontada o bonificada. @@ -16145,14 +16147,7 @@ components: - "03" - "04" - "05" - description: | - Código que representa si el bien o servicio es objeto de impuesto o no. Este atributo corresponde al campo "ObjetoImp" en el CFDI. - - - `01`: No objeto de impuesto. - - `02`: Sí objeto de impuesto. - - `03`: Sí objeto de impuesto, pero no obligado a desglose. - - `04`: Sí objeto de impuesto, y no causa impuesto. - - `05`: Sí objeto de impuesto, IVA crédito PODEBI. + description: "Código que representa si el bien o servicio es objeto de impuesto o no. Este atributo corresponde al campo \"ObjetoImp\" en el CFDI.\n\n- `01`: No objeto de impuesto.\n- `02`: Sí objeto de impuesto.\n- `03`: Sí objeto de impuesto, pero no obligado a desglose.\n- `04`: Sí objeto de impuesto, y no causa impuesto.\n- `05`: Sí objeto de impuesto, IVA crédito PODEBI.\n\nSi se omite, se utiliza `01` cuando `taxes` está vacío y `02` cuando contiene al menos un impuesto." installment: type: integer @@ -16189,7 +16184,7 @@ components: date: type: string format: date-time - description: Fecha en que se recibió el pago. Sólo es necesario incluirla si el pago se efectuó en una fecha anterior a la emisión de este comprobante. No se permiten fechas futuras. + description: "Fecha en que se recibió el pago. Si se omite, se utiliza la fecha y hora actuales. Inclúyela cuando el pago sea anterior a la emisión del comprobante. No se permiten fechas futuras." numOperacion: type: string description: Número de cheque, de autorización, de referencia, clave de rastreo SPEI, línea de captura o algún número de referencia que permita identificar la operación correspondiente al pago efectuado. @@ -16211,7 +16206,7 @@ components: tipoCadPago: type: string enum: - - 01 + - "01" description: | Clave del tipo de cadena de pago que genera la entidad receptora del pago. Si existe este campo, es obligatorio registrar los campos `certPago`, `cadPago` y `selloPago`. @@ -16302,11 +16297,11 @@ components: InvoiceZipRequestInvoiceType: type: string enum: - - I - - E - - T - - N - - P + - "I" + - "E" + - "T" + - "N" + - "P" description: Tipo de factura (`I` Ingreso, `E` Egreso, `T` Traslado, `N` Nómina o `P` Pago). InvoiceZipRequestCreateInput: type: object @@ -16506,11 +16501,11 @@ components: type: type: string enum: - - I - - E - - P - - 'N' - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. customer: @@ -16543,7 +16538,7 @@ components: payment_form: type: string description: Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). - example: 6 + example: "06" total_payment_amount: type: number description: Total del complemento de Pago cuando la factura es tipo P. @@ -16622,17 +16617,21 @@ components: - $ref: '#/components/schemas/Stamp' - type: 'null' cancellation: + description: "Información de la solicitud de cancelación de la factura. `cancellation_status` también expone su estado actual." type: object properties: requested_at: + description: "Fecha y hora de la solicitud de cancelación." type: - string - 'null' format: date-time last_checked: + description: "Fecha y hora de la última consulta del estado de cancelación." type: string format: date-time canceled_at: + description: "Fecha y hora de cancelación del CFDI." type: - string - 'null' @@ -16650,12 +16649,21 @@ components: Estado actual de la solicitud de cancelación, en caso de haberla realizado. Puedes leer más a detalle en la sección de [Cancelar Factura](#tag/invoice/operation/deleteInvoice)). example: none motive: + description: "Clave del motivo de cancelación." type: string substitutionUUID: + description: "UUID del CFDI que sustituye a esta factura, cuando aplica." type: string cancellation_type: - type: string + description: "Indica si el SAT permite cancelar el CFDI y si se requiere aceptación del receptor." + type: ["string", "null"] + enum: + - cancellable_without_authorization + - cancellable_with_authorization + - not_cancellable + - null organization: + description: "ID de la organización a la que pertenece este recurso." type: - string - 'null' @@ -16730,7 +16738,6 @@ components: type: string format: uri description: Dirección URL para verificar el estado del CFDI en el portal del SAT. Este link es el mismo que aparece en el código QR, en el PDF de la factura. - example: null date: type: - string @@ -16751,11 +16758,11 @@ components: type: type: string enum: - - I - - E - - P - - 'N' - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. customer: @@ -16768,7 +16775,6 @@ components: type: string format: uuid description: Folio fiscal de la factura, asignado por el SAT, en caso de haber sido timbrada. - example: 0 folio_number: type: integer description: Número de folio autoincremental para control interno y sin validez fiscal. @@ -16786,7 +16792,7 @@ components: payment_form: type: string description: Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). - example: 6 + example: "06" items: type: array description: Conceptos incluidos en el comprobante @@ -17094,7 +17100,7 @@ components: date: type: string format: date-time - description: Fecha de expedición del comprobante en formato ISO8601 (UTC String). No puede ser anterior a 72 horas en el pasado, ni posterior al presente. + description: "Fecha de expedición del comprobante en formato ISO8601. Si se omite, se utiliza la fecha y hora actuales. No puede ser anterior a 72 horas en el pasado ni posterior al presente." address: allOf: - $ref: "#/components/schemas/CommonAddressProperties" @@ -17547,7 +17553,7 @@ components: type: type: string enum: - - N + - "N" complements: type: array default: [] @@ -17625,11 +17631,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. items: @@ -17753,11 +17759,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. payment_form: @@ -17817,11 +17823,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. related_documents: @@ -17852,11 +17858,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. complements: @@ -17878,11 +17884,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. items: @@ -17934,6 +17940,7 @@ components: - type: object properties: organization: + description: "ID de la organización a la que pertenece este recurso." type: string ReceiptProperties: allOf: @@ -17942,12 +17949,12 @@ components: date: type: string format: date-time - example: 2021-09-10T15:21:23.456Z + example: "2021-09-10T15:21:23.456Z" description: Fecha de emisión del recibo. expires_at: type: string format: date-time - example: 2021-09-17T15:21:23.456Z + example: "2021-09-17T15:21:23.456Z" description: | Fecha de expiración en formato ISO8601 (UTC String). Es la fecha límite para que el cliente pueda facturar su recibo en el portal de autofactura. @@ -18046,7 +18053,7 @@ components: date: type: string format: date-time - example: 2021-09-10T15:21:23.456Z + example: "2021-09-10T15:21:23.456Z" description: Fecha de emisión del recibo. Por defecto se utiliza la fecha actual. payment_form: type: string @@ -18128,7 +18135,7 @@ components: from: type: string format: date - example: 2022-01-01T00:00:00.000 + example: "2022-01-01" description: | Fecha inicial de los recibos que se incluirán en la factura global. Por default, este valor es el inicio del último periodo (día, semana, @@ -18137,7 +18144,7 @@ components: to: type: string format: date - example: 2022-01-31T23:59:59.999 + example: "2022-01-31" description: | Fecha final de los recibos que se incluirán en la factura global. Por default, este valor es el fin del último periodo (día, semana, @@ -18151,15 +18158,10 @@ components: - fortnight - month - two_months - description: | - Periodicidad que corresponde al rango de fechas utilizado. - Si omites los campos `from` y `to`, las fechas que se asignarán por - default dependerán del valor de `periodicity`. + description: "Periodicidad que corresponde al rango de fechas utilizado.\nSi omites los campos `from` y `to`, las fechas que se asignarán por\ndefault dependerán del valor de `periodicity`.\n\nSi se omite, se utiliza la periodicidad configurada en los recibos de la organización." months: type: string - description: | - Clave que representa el mes o bimestre de la factura. Consulta - los posibles valores en el [catálogo de Meses y Bimestres](#meses-y-bimestres). + description: "Clave que representa el mes o bimestre de la factura. Consulta\nlos posibles valores en el [catálogo de Meses y Bimestres](#meses-y-bimestres).\n\nSi se omite, el mes o bimestre se determina a partir de la fecha inicial y la periodicidad." example: "01" folio_number: type: integer @@ -18173,9 +18175,8 @@ components: date: type: string format: date - example: 2022-01-01T00:00:00.000 - description: | - Fecha de emisión de la factura. + example: "2022-01-01" + description: "Fecha de emisión de la factura. Si se omite, se utiliza la fecha final (`to`), limitada a la fecha y hora actuales." payment_form: type: string minLength: 2 @@ -18287,6 +18288,7 @@ components: - type: object properties: organization: + description: "ID de la organización a la que pertenece este recurso." type: string RetentionReadOnlyProperties: type: object @@ -18336,7 +18338,7 @@ components: properties: cve_retenc: type: string - example: 1 + example: "01" description: Clave de la retención o información de pagos de acuerdo al catálogo del SAT. fecha_exp: type: @@ -18412,10 +18414,10 @@ components: tipo_pago_ret: type: string enum: - - 1 - - 2 - - 3 - - 4 + - "01" + - "02" + - "03" + - "04" description: | - `01`: Pago definitivo IVA - `02`: Pago definitivo IEPS @@ -18615,10 +18617,10 @@ components: tipo_pago_ret: type: string enum: - - 01 - - 02 - - 03 - - 04 + - "01" + - "02" + - "03" + - "04" description: | - `01`: Pago definitivo IVA - `02`: Pago definitivo IEPS @@ -19337,11 +19339,11 @@ components: type: type: string enum: - - I - - E - - P - - N - - T + - "I" + - "E" + - "P" + - "N" + - "T" description: | Tipo de comprobante. Valores posibles: `I` (Ingreso), `E` (Egreso), `P` (Pago), `N` (Nómina), `T` (Traslado). diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index cdfb73215..468a24315 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -36,13 +36,30 @@ function contract(value, key) { } for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { - const spec = yaml.load(await readFile(new URL(filename, root), "utf8")); + const spec = yaml.load(await readFile(new URL(filename, root), "utf8"), { + schema: yaml.JSON_SCHEMA, + }); function walk(value, path = []) { if (!value || typeof value !== "object") return; assert( !("nullable" in value), `Use OpenAPI 3.1 null unions: ${path.join(".")}`, ); + if (value.type === "string") { + for (const item of value.enum || []) + assert.equal( + typeof item, + "string", + `String enum values must be quoted when needed: ${path.join(".")}`, + ); + for (const key of ["example", "default"]) + if (key in value) + assert.equal( + typeof value[key], + "string", + `String ${key} must remain a string: ${path.join(".")}`, + ); + } if (value.$ref?.startsWith("#/")) { let target = spec; for (const part of value.$ref.slice(2).split("/")) { diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index aa68955da..1a25ad9b8 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -34,6 +34,11 @@ const validation: operations["validateWebhookSignature"]["requestBody"]["content }; const nullDate: components["schemas"]["InvoiceProperties"]["date"] = null; const callback: keyof webhooks = "customer.edit_link_completed"; +const retainedTax: NonNullable< + NonNullable["imp_retenidos"] +>[number]["tipo_pago_ret"] = "01"; +// @ts-expect-error SAT codes retain their leading zero +const invalidRetainedTax: typeof retainedTax = "1"; // @ts-expect-error event discriminants must correlate with the resource const invalid: components["schemas"]["ApiEvent"] = { ...receiptEvent, @@ -46,4 +51,4 @@ const invalid: components["schemas"]["ApiEvent"] = { }, }, }; -void [invoice, draft, receiptEvent, validation, nullDate, callback, invalid]; +void [invoice, draft, receiptEvent, validation, nullDate, callback, retainedTax, invalidRetainedTax, invalid]; From e6f1774d88050babbc504e4fda073f71668fdfb6 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 16:37:28 +0200 Subject: [PATCH 04/33] docs: correct CommonJS installation examples --- website/docs/getting-started/install.mdx | 6 +++--- .../current/getting-started/install.mdx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/getting-started/install.mdx b/website/docs/getting-started/install.mdx index 32b787601..007acfe65 100644 --- a/website/docs/getting-started/install.mdx +++ b/website/docs/getting-started/install.mdx @@ -77,12 +77,12 @@ Importa la librería antes de usarla. -CommonJS ```javascript -import Facturapi from 'facturapi' +const Facturapi = require('facturapi'); ``` -ESM / Typescript +ESM / TypeScript + ```javascript import Facturapi from 'facturapi'; ``` diff --git a/website/i18n/en/docusaurus-plugin-content-docs/current/getting-started/install.mdx b/website/i18n/en/docusaurus-plugin-content-docs/current/getting-started/install.mdx index 148fddad0..1a9207f99 100644 --- a/website/i18n/en/docusaurus-plugin-content-docs/current/getting-started/install.mdx +++ b/website/i18n/en/docusaurus-plugin-content-docs/current/getting-started/install.mdx @@ -77,12 +77,12 @@ Import the library before using it in your code. -CommonJS ```javascript -import Facturapi from 'facturapi' +const Facturapi = require('facturapi'); ``` -ESM / Typescript +ESM / TypeScript + ```javascript import Facturapi from 'facturapi'; ``` From 8d105362aacfd58aa8d2004d09bfd1cca68f1863 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 16:44:42 +0200 Subject: [PATCH 05/33] docs: fix draft stamp nullability and validate webhook operation IDs --- website/openapi_v2.en.yaml | 14 +++---- website/openapi_v2.yaml | 14 +++---- website/scripts/check-openapi.mjs | 52 +++++++++++++------------- website/test/openapi-types.fixture.txt | 15 +++++++- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 140c01d60..016bc3515 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16887,10 +16887,10 @@ components: In an invoice with a status other than `draft`, this field will always be `false`. stamp: - allOf: + anyOf: - $ref: '#/components/schemas/Stamp' - - type: object - example: null + - type: 'null' + example: null InvoiceableCommonInput: type: object @@ -18967,12 +18967,12 @@ components: type: string format: date-time example: '2023-05-05T20:55:33.468Z' - description: Date of the last update of the certificate. + description: Date of the last update of the certificate. Omitted when no certificate is uploaded. expires_at: type: string format: date-time example: '2025-05-05T20:55:33.468Z' - description: Expiration date of the certificate. + description: Expiration date of the certificate. Omitted when no certificate is uploaded. serial_number: type: string example: '20001000000300000000' @@ -18989,12 +18989,12 @@ components: type: string format: date-time example: '2023-05-05T20:55:33.468Z' - description: Date of the last update of the FIEL certificate. + description: Date of the last update of the FIEL certificate. Omitted when no certificate is uploaded. expires_at: type: string format: date-time example: '2025-05-05T20:55:33.468Z' - description: Expiration date of the FIEL certificate. + description: Expiration date of the FIEL certificate. Omitted when no certificate is uploaded. serial_number: type: string example: '20001000000300000000' diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index e676614b6..1a42401ef 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16842,10 +16842,10 @@ components: En una factura con status diferente a `draft`, este campo siempre será `false`. stamp: - allOf: + anyOf: - $ref: '#/components/schemas/Stamp' - - type: object - example: null + - type: 'null' + example: null InvoiceableCommonInput: type: object @@ -18865,12 +18865,12 @@ components: type: string format: date-time example: '2023-05-05T20:55:33.468Z' - description: Fecha de la última actualización del certificado. + description: Fecha de la última actualización del certificado. Se omite cuando no hay un certificado cargado. expires_at: type: string format: date-time example: '2025-05-05T20:55:33.468Z' - description: Fecha de expiración del certificado. + description: Fecha de expiración del certificado. Se omite cuando no hay un certificado cargado. serial_number: type: string example: '30001000000300000101' @@ -18886,12 +18886,12 @@ components: type: string format: date-time example: '2023-05-05T20:55:33.468Z' - description: Fecha de la última actualización del certificado FIEL. + description: Fecha de la última actualización del certificado FIEL. Se omite cuando no hay un certificado cargado. expires_at: type: string format: date-time example: '2025-05-05T20:55:33.468Z' - description: Fecha de expiración del certificado FIEL. + description: Fecha de expiración del certificado FIEL. Se omite cuando no hay un certificado cargado. serial_number: type: string example: '30001000000300000101' diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index 468a24315..2e047949f 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -72,33 +72,35 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { } walk(spec); const ids = new Set(); - for (const [path, item] of Object.entries(spec.paths)) { - for (const [method, operation] of Object.entries(item)) { - if (!operation.responses) continue; - assert(operation.operationId, `Missing operationId: ${method} ${path}`); - assert( - !ids.has(operation.operationId), - `Duplicate operationId: ${operation.operationId}`, - ); - ids.add(operation.operationId); - const params = [ - ...(item.parameters || []), - ...(operation.parameters || []), - ].map((parameter) => - parameter.$ref - ? spec.components.parameters[parameter.$ref.split("/").at(-1)] - : parameter, - ); - for (const match of path.matchAll(/\{([^}]+)\}/g)) { + for (const items of [spec.paths, spec.webhooks || {}]) { + for (const [path, item] of Object.entries(items)) { + for (const [method, operation] of Object.entries(item)) { + if (!operation.responses) continue; + assert(operation.operationId, `Missing operationId: ${method} ${path}`); assert( - params.some( - (parameter) => - parameter.in === "path" && - parameter.name === match[1] && - parameter.required === true, - ), - `Missing required path parameter: ${path}`, + !ids.has(operation.operationId), + `Duplicate operationId: ${operation.operationId}`, ); + ids.add(operation.operationId); + const params = [ + ...(item.parameters || []), + ...(operation.parameters || []), + ].map((parameter) => + parameter.$ref + ? spec.components.parameters[parameter.$ref.split("/").at(-1)] + : parameter, + ); + for (const match of path.matchAll(/\{([^}]+)\}/g)) { + assert( + params.some( + (parameter) => + parameter.in === "path" && + parameter.name === match[1] && + parameter.required === true, + ), + `Missing required path parameter: ${path}`, + ); + } } } } diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index 1a25ad9b8..11fdfbb8a 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -33,6 +33,19 @@ const validation: operations["validateWebhookSignature"]["requestBody"]["content payload: '{"type":"receipt.status_updated"}', }; const nullDate: components["schemas"]["InvoiceProperties"]["date"] = null; +const draftStamp: components["schemas"]["InvoiceDraftProperties"]["stamp"] = null; +const certificate: NonNullable = { + has_certificate: false, +}; +const missingCertificateDate: typeof certificate.updated_at = undefined; +// @ts-expect-error absent certificate dates are omitted, not null +const nullCertificateDate: typeof certificate.updated_at = null; +const fiel: NonNullable = { + has_certificate: false, +}; +const missingFielDate: typeof fiel.expires_at = undefined; +// @ts-expect-error absent FIEL dates are omitted, not null +const nullFielDate: typeof fiel.expires_at = null; const callback: keyof webhooks = "customer.edit_link_completed"; const retainedTax: NonNullable< NonNullable["imp_retenidos"] @@ -51,4 +64,4 @@ const invalid: components["schemas"]["ApiEvent"] = { }, }, }; -void [invoice, draft, receiptEvent, validation, nullDate, callback, retainedTax, invalidRetainedTax, invalid]; +void [invoice, draft, receiptEvent, validation, nullDate, draftStamp, certificate, missingCertificateDate, nullCertificateDate, fiel, missingFielDate, nullFielDate, callback, retainedTax, invalidRetainedTax, invalid]; From 230dddac8184bfec0aa97c290bd69120c7929fdc Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 19:04:01 +0200 Subject: [PATCH 06/33] docs: fix payment enum and draft UUID contracts --- website/openapi_v2.en.yaml | 5 +++-- website/openapi_v2.yaml | 5 +++-- website/scripts/check-openapi.mjs | 16 +++++++++++++++- website/test/openapi-types.fixture.txt | 11 ++++++++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 016bc3515..30e93ece1 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16167,6 +16167,7 @@ components: description: Indicates if the tax is a withholding (`true`) or a transfer (`false`). taxability: type: string + enum: - "01" - "02" - "03" @@ -16817,9 +16818,9 @@ components: description: Total amount invoiced. example: 0 uuid: - type: string + type: [string, "null"] format: uuid - description: Fiscal folio of the invoice, assigned by the SAT. If the invoice has not been stamped, this field is null. + description: Fiscal folio assigned by the SAT. For an unstamped draft, this field is null or omitted. folio_number: type: integer description: Autoincremental folio number for internal control and without fiscal relevance. diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 1a42401ef..d6ed85fb0 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16142,6 +16142,7 @@ components: description: Indica si el impuesto es una retención (`true`) o un traslado (`false`). taxability: type: string + enum: - "01" - "02" - "03" @@ -16772,9 +16773,9 @@ components: description: Monto total facturado. example: 0 uuid: - type: string + type: [string, "null"] format: uuid - description: Folio fiscal de la factura, asignado por el SAT, en caso de haber sido timbrada. + description: Folio fiscal asignado por el SAT. En un borrador sin timbrar, este campo es null o se omite. folio_number: type: integer description: Número de folio autoincremental para control interno y sin validez fiscal. diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index 2e047949f..469e623b1 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -45,6 +45,19 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { !("nullable" in value), `Use OpenAPI 3.1 null unions: ${path.join(".")}`, ); + if ( + ((path[0] === "components" && path[1] === "schemas") || + path.includes("schema")) && + (typeof value.type === "string" || Array.isArray(value.type)) + ) { + for (const type of Array.isArray(value.type) ? value.type : [value.type]) + assert( + [ + "null", "boolean", "object", "array", "number", "string", "integer", + ].includes(type), + `Invalid schema type: ${path.join(".")}`, + ); + } if (value.type === "string") { for (const item of value.enum || []) assert.equal( @@ -68,7 +81,8 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { assert(target, `Unresolved reference: ${value.$ref}`); } for (const [key, child] of Object.entries(value)) - walk(child, [...path, key]); + if (!presentationKeys.has(key) && !["default", "enum", "const"].includes(key)) + walk(child, [...path, key]); } walk(spec); const ids = new Set(); diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index 11fdfbb8a..ccd8e3c7d 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -34,6 +34,15 @@ const validation: operations["validateWebhookSignature"]["requestBody"]["content }; const nullDate: components["schemas"]["InvoiceProperties"]["date"] = null; const draftStamp: components["schemas"]["InvoiceDraftProperties"]["stamp"] = null; +const draftUuid: components["schemas"]["InvoiceDraftProperties"]["uuid"] = null; +const missingDraftUuid: components["schemas"]["InvoiceDraftProperties"]["uuid"] = undefined; +const paymentTaxability: NonNullable< + components["schemas"]["PaymentInput"]["related_documents"] +>[number]["taxability"] = "01"; +// @ts-expect-error SAT codes retain their leading zero +const invalidPaymentTaxability: typeof paymentTaxability = "1"; +// @ts-expect-error taxability only accepts the documented SAT codes +const unknownPaymentTaxability: typeof paymentTaxability = "09"; const certificate: NonNullable = { has_certificate: false, }; @@ -64,4 +73,4 @@ const invalid: components["schemas"]["ApiEvent"] = { }, }, }; -void [invoice, draft, receiptEvent, validation, nullDate, draftStamp, certificate, missingCertificateDate, nullCertificateDate, fiel, missingFielDate, nullFielDate, callback, retainedTax, invalidRetainedTax, invalid]; +void [invoice, draft, receiptEvent, validation, nullDate, draftStamp, draftUuid, missingDraftUuid, paymentTaxability, invalidPaymentTaxability, unknownPaymentTaxability, certificate, missingCertificateDate, nullCertificateDate, fiel, missingFielDate, nullFielDate, callback, retainedTax, invalidRetainedTax, invalid]; From 6cf41015eafbc06603f9a7f9447e4cad9601ed58 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 19:29:39 +0200 Subject: [PATCH 07/33] docs: align complement variants and response field contracts --- website/openapi_v2.en.yaml | 268 +++++++++++++++++++------ website/openapi_v2.yaml | 268 +++++++++++++++++++------ website/scripts/check-openapi.mjs | 5 +- website/test/openapi-types.fixture.txt | 20 +- 4 files changed, 437 insertions(+), 124 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 30e93ece1..74e1d8b30 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -4928,6 +4928,15 @@ paths: application/json: schema: type: object + required: + - uuid + - series + - installment + - last_balance + - total + - currency + - amount + - taxes properties: uuid: type: string @@ -9298,6 +9307,10 @@ paths: type: array items: type: object + required: + - id + - first_12 + - created_at properties: first_12: type: string @@ -13297,6 +13310,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -13306,6 +13321,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -13443,6 +13460,11 @@ components: LineItem: type: object properties: + property_tax_account: + type: array + items: + type: string + description: Property tax accounts for this line item. quantity: type: number description: Quantity of units included in the same concept. @@ -13456,7 +13478,9 @@ components: description: | Object with information about the product or service invoiced. parts: - $ref: "#/components/schemas/Parts" + type: array + items: + $ref: "#/components/schemas/Parts" description: Object with information about the parts conforming this item or product. ThirdParty: type: object @@ -13781,6 +13805,9 @@ components: CustomComplementProperties: title: CustomComplement type: object + required: + - type + - data properties: type: type: string @@ -14385,6 +14412,10 @@ components: - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/PagoComplementProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + PagoOrCustomComplementInput: type: object title: Complement @@ -14400,23 +14431,73 @@ components: type: type: string enum: - - nomina + - pago - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/PagoComplementInput" + - $ref: "#/components/schemas/CustomComplementInput" + PagoComplementProperties: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: pago - type: object properties: data: - $ref: "#/components/schemas/NominaComplementDataProperties" + $ref: "#/components/schemas/PagoComplementDataProperties" PagoComplementInput: allOf: - - $ref: "#/components/schemas/PagoOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: pago - type: object properties: data: $ref: "#/components/schemas/PagoComplementDataInput" + InvoiceComplementProperties: + oneOf: + - $ref: '#/components/schemas/PagoComplementProperties' + - $ref: '#/components/schemas/NominaComplementProperties' + - $ref: '#/components/schemas/CartaPorteProperties' + - $ref: '#/components/schemas/ComercioExteriorProperties' + - $ref: '#/components/schemas/LeyendasFiscalesProperties' + - $ref: '#/components/schemas/CustomComplementProperties' + discriminator: + propertyName: type + mapping: + pago: '#/components/schemas/PagoComplementProperties' + nomina: '#/components/schemas/NominaComplementProperties' + carta_porte: '#/components/schemas/CartaPorteProperties' + comercio_exterior: '#/components/schemas/ComercioExteriorProperties' + leyendas_fiscales: '#/components/schemas/LeyendasFiscalesProperties' + custom: '#/components/schemas/CustomComplementProperties' + PagoComplementDataProperties: + type: array + items: + $ref: '#/components/schemas/PaymentProperties' + PaymentProperties: + allOf: + - $ref: '#/components/schemas/PaymentInput' + - type: object + required: + - date + properties: + date: + type: string + format: date-time + PagoComplementDataInput: type: array title: PagoComplementData @@ -14440,6 +14521,10 @@ components: - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/NominaComplementProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + NominaOrCustomComplementInput: type: object title: Complement @@ -14458,16 +14543,34 @@ components: - nomina - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/NominaComplementInput" + - $ref: "#/components/schemas/CustomComplementInput" + NominaComplementProperties: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: nomina - type: object properties: data: $ref: "#/components/schemas/NominaComplementDataProperties" NominaComplementInput: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: nomina - type: object properties: data: @@ -14475,42 +14578,84 @@ components: # Carta Porte Complement CartaPorteProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: carta_porte - type: object properties: data: $ref: "#/components/schemas/CartaPorteDataProperties" CartaPorteInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: carta_porte - type: object properties: data: $ref: "#/components/schemas/CartaPorteDataInput" ComercioExteriorProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: comercio_exterior - type: object properties: data: $ref: "#/components/schemas/ComercioExteriorDataProperties" ComercioExteriorInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: comercio_exterior - type: object properties: data: $ref: "#/components/schemas/ComercioExteriorDataInput" LeyendasFiscalesProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: leyendas_fiscales - type: object properties: data: $ref: "#/components/schemas/LeyendasFiscalesData" LeyendasFiscalesInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: leyendas_fiscales - type: object properties: data: @@ -14534,6 +14679,12 @@ components: - leyendas_fiscales - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/CartaPorteProperties" + - $ref: "#/components/schemas/ComercioExteriorProperties" + - $ref: "#/components/schemas/LeyendasFiscalesProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + CartaPorteOrCustomComplementInput: title: Complement type: object @@ -14556,6 +14707,12 @@ components: - leyendas_fiscales - custom description: Type of complement + oneOf: + - $ref: "#/components/schemas/CartaPorteInput" + - $ref: "#/components/schemas/ComercioExteriorInput" + - $ref: "#/components/schemas/LeyendasFiscalesInput" + - $ref: "#/components/schemas/CustomComplementInput" + LeyendasFiscalesData: type: object title: LeyendasFiscales @@ -15560,6 +15717,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -15714,6 +15873,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -15901,6 +16062,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -16479,6 +16642,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -16492,6 +16657,8 @@ components: - price InvoiceProperties: type: object + required: + - date properties: status: type: string @@ -16642,7 +16809,7 @@ components: type: array default: [] items: - $ref: '#/components/schemas/NominaOrCustomComplementProperties' + $ref: '#/components/schemas/InvoiceComplementProperties' description: Complements to include in the invoice. pdf_custom_section: type: string @@ -16661,52 +16828,6 @@ components: anyOf: - $ref: '#/components/schemas/Stamp' - type: 'null' - cancellation: - description: "Information about the invoice cancellation request. `cancellation_status` also exposes its current status." - type: object - properties: - requested_at: - description: "Date and time cancellation was requested." - type: - - string - - 'null' - format: date-time - last_checked: - description: "Date and time the cancellation status was last checked." - type: string - format: date-time - canceled_at: - description: "Date and time the CFDI was canceled." - type: - - string - - 'null' - format: date-time - status: - type: string - enum: - - none - - verifying - - pending - - accepted - - rejected - - expired - description: | - Current status of the cancellation request, if it has been made. `verifying` means the SAT has received the request and is validating it; Facturapi will keep checking until it changes to a final status. You can read more in the [Cancel Invoice](#tag/invoice/operation/deleteInvoice) section. - example: none - motive: - description: "Cancellation reason code." - type: string - substitutionUUID: - description: "UUID of the replacement CFDI, when applicable." - type: string - cancellation_type: - description: "Indicates whether SAT allows cancellation and whether recipient authorization is required." - type: ["string", "null"] - enum: - - cancellable_without_authorization - - cancellable_with_authorization - - not_cancellable - - null organization: description: "ID of the organization this resource belongs to." type: @@ -16862,7 +16983,7 @@ components: type: array default: [] items: - $ref: '#/components/schemas/NominaOrCustomComplementProperties' + $ref: '#/components/schemas/InvoiceComplementProperties' description: Complements to include in the invoice. pdf_custom_section: type: string @@ -18009,6 +18130,9 @@ components: ReceiptProperties: allOf: - type: object + required: + - date + - expires_at properties: date: type: string @@ -18174,6 +18298,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18418,6 +18544,8 @@ components: example: false RetentionProperties: type: object + required: + - fecha_exp properties: cve_retenc: type: string @@ -18549,6 +18677,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18772,6 +18902,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18780,6 +18912,11 @@ components: Organization: title: Organization object type: object + required: + - id + - created_at + - certificate + - fiel properties: id: type: string @@ -19481,6 +19618,9 @@ components: example: true OrganizationInvite: type: object + required: + - created_at + - expires_at properties: id: type: string @@ -19518,6 +19658,9 @@ components: $ref: "#/components/schemas/OrganizationInvite" OrganizationPermissionRole: type: object + required: + - created_at + - updated_at properties: id: type: string @@ -19594,6 +19737,9 @@ components: type: string OrganizationUserAccess: type: object + required: + - created_at + - updated_at properties: id: type: string diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index d6ed85fb0..5e2258c72 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -4894,6 +4894,15 @@ paths: application/json: schema: type: object + required: + - uuid + - series + - installment + - last_balance + - total + - currency + - amount + - taxes properties: uuid: type: string @@ -9256,6 +9265,10 @@ paths: type: array items: type: object + required: + - id + - first_12 + - created_at properties: first_12: type: string @@ -13265,6 +13278,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -13274,6 +13289,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -13394,6 +13411,11 @@ components: LineItem: type: object properties: + property_tax_account: + type: array + items: + type: string + description: Cuentas prediales de este concepto. quantity: type: number description: Cantidad de unidades incluidas del mismo concepto. @@ -13406,7 +13428,9 @@ components: $ref: "#/components/schemas/LineItemProduct" description: Objeto con información del producto o servicio facturado. parts: - $ref: "#/components/schemas/Parts" + type: array + items: + $ref: "#/components/schemas/Parts" description: Objeto con información de las partes de la factura. ThirdParty: type: object @@ -13731,6 +13755,9 @@ components: CustomComplementProperties: title: CustomComplement type: object + required: + - type + - data properties: type: type: string @@ -14324,6 +14351,10 @@ components: - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/PagoComplementProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + PagoOrCustomComplementInput: type: object title: Complement @@ -14339,23 +14370,73 @@ components: type: type: string enum: - - nomina + - pago - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/PagoComplementInput" + - $ref: "#/components/schemas/CustomComplementInput" + PagoComplementProperties: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: pago - type: object properties: data: - $ref: "#/components/schemas/NominaComplementDataProperties" + $ref: "#/components/schemas/PagoComplementDataProperties" PagoComplementInput: allOf: - - $ref: "#/components/schemas/PagoOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: pago - type: object properties: data: $ref: "#/components/schemas/PagoComplementDataInput" + InvoiceComplementProperties: + oneOf: + - $ref: '#/components/schemas/PagoComplementProperties' + - $ref: '#/components/schemas/NominaComplementProperties' + - $ref: '#/components/schemas/CartaPorteProperties' + - $ref: '#/components/schemas/ComercioExteriorProperties' + - $ref: '#/components/schemas/LeyendasFiscalesProperties' + - $ref: '#/components/schemas/CustomComplementProperties' + discriminator: + propertyName: type + mapping: + pago: '#/components/schemas/PagoComplementProperties' + nomina: '#/components/schemas/NominaComplementProperties' + carta_porte: '#/components/schemas/CartaPorteProperties' + comercio_exterior: '#/components/schemas/ComercioExteriorProperties' + leyendas_fiscales: '#/components/schemas/LeyendasFiscalesProperties' + custom: '#/components/schemas/CustomComplementProperties' + PagoComplementDataProperties: + type: array + items: + $ref: '#/components/schemas/PaymentProperties' + PaymentProperties: + allOf: + - $ref: '#/components/schemas/PaymentInput' + - type: object + required: + - date + properties: + date: + type: string + format: date-time + PagoComplementDataInput: type: array title: PagoComplementData @@ -14379,6 +14460,10 @@ components: - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/NominaComplementProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + NominaOrCustomComplementInput: type: object title: Complement @@ -14397,16 +14482,34 @@ components: - nomina - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/NominaComplementInput" + - $ref: "#/components/schemas/CustomComplementInput" + NominaComplementProperties: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: nomina - type: object properties: data: $ref: "#/components/schemas/NominaComplementDataProperties" NominaComplementInput: allOf: - - $ref: "#/components/schemas/NominaOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: nomina - type: object properties: data: @@ -14414,42 +14517,84 @@ components: # Carta Porte Complemento CartaPorteProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: carta_porte - type: object properties: data: $ref: "#/components/schemas/CartaPorteDataProperties" CartaPorteInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: carta_porte - type: object properties: data: $ref: "#/components/schemas/CartaPorteDataInput" ComercioExteriorProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: comercio_exterior - type: object properties: data: $ref: "#/components/schemas/ComercioExteriorDataProperties" ComercioExteriorInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: comercio_exterior - type: object properties: data: $ref: "#/components/schemas/ComercioExteriorDataInput" LeyendasFiscalesProperties: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementProperties" + - type: object + required: + - type + - data + properties: + type: + type: string + const: leyendas_fiscales - type: object properties: data: $ref: "#/components/schemas/LeyendasFiscalesData" LeyendasFiscalesInput: allOf: - - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + - type: object + required: + - type + - data + properties: + type: + type: string + const: leyendas_fiscales - type: object properties: data: @@ -14473,6 +14618,12 @@ components: - leyendas_fiscales - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/CartaPorteProperties" + - $ref: "#/components/schemas/ComercioExteriorProperties" + - $ref: "#/components/schemas/LeyendasFiscalesProperties" + - $ref: "#/components/schemas/CustomComplementProperties" + CartaPorteOrCustomComplementInput: title: Complement type: object @@ -14495,6 +14646,12 @@ components: - leyendas_fiscales - custom description: Tipo de complemento. + oneOf: + - $ref: "#/components/schemas/CartaPorteInput" + - $ref: "#/components/schemas/ComercioExteriorInput" + - $ref: "#/components/schemas/LeyendasFiscalesInput" + - $ref: "#/components/schemas/CustomComplementInput" + LeyendasFiscalesData: type: object title: LeyendasFiscales @@ -15557,6 +15714,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -15688,6 +15847,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -15898,6 +16059,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -16435,6 +16598,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -16448,6 +16613,8 @@ components: - price InvoiceProperties: type: object + required: + - date properties: status: type: string @@ -16598,7 +16765,7 @@ components: type: array default: [] items: - $ref: '#/components/schemas/NominaOrCustomComplementProperties' + $ref: '#/components/schemas/InvoiceComplementProperties' description: Complementos a incluir en la factura. pdf_custom_section: type: string @@ -16617,52 +16784,6 @@ components: anyOf: - $ref: '#/components/schemas/Stamp' - type: 'null' - cancellation: - description: "Información de la solicitud de cancelación de la factura. `cancellation_status` también expone su estado actual." - type: object - properties: - requested_at: - description: "Fecha y hora de la solicitud de cancelación." - type: - - string - - 'null' - format: date-time - last_checked: - description: "Fecha y hora de la última consulta del estado de cancelación." - type: string - format: date-time - canceled_at: - description: "Fecha y hora de cancelación del CFDI." - type: - - string - - 'null' - format: date-time - status: - type: string - enum: - - none - - pending - - accepted - - rejected - - expired - - verifying - description: | - Estado actual de la solicitud de cancelación, en caso de haberla realizado. Puedes leer más a detalle en la sección de [Cancelar Factura](#tag/invoice/operation/deleteInvoice)). - example: none - motive: - description: "Clave del motivo de cancelación." - type: string - substitutionUUID: - description: "UUID del CFDI que sustituye a esta factura, cuando aplica." - type: string - cancellation_type: - description: "Indica si el SAT permite cancelar el CFDI y si se requiere aceptación del receptor." - type: ["string", "null"] - enum: - - cancellable_without_authorization - - cancellable_with_authorization - - not_cancellable - - null organization: description: "ID de la organización a la que pertenece este recurso." type: @@ -16817,7 +16938,7 @@ components: type: array default: [] items: - $ref: '#/components/schemas/NominaOrCustomComplementProperties' + $ref: '#/components/schemas/InvoiceComplementProperties' description: Complementos a incluir en la factura. pdf_custom_section: type: string @@ -17946,6 +18067,9 @@ components: ReceiptProperties: allOf: - type: object + required: + - date + - expires_at properties: date: type: string @@ -18097,6 +18221,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18336,6 +18462,8 @@ components: example: false RetentionProperties: type: object + required: + - fecha_exp properties: cve_retenc: type: string @@ -18457,6 +18585,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18673,6 +18803,8 @@ components: allOf: - $ref: "#/components/schemas/SearchResult" - type: object + required: + - data properties: data: type: array @@ -18681,6 +18813,11 @@ components: Organization: title: Objeto Organization type: object + required: + - id + - created_at + - certificate + - fiel properties: id: type: string @@ -19379,6 +19516,9 @@ components: example: true OrganizationInvite: type: object + required: + - created_at + - expires_at properties: id: type: string @@ -19416,6 +19556,9 @@ components: $ref: "#/components/schemas/OrganizationInvite" OrganizationPermissionRole: type: object + required: + - created_at + - updated_at properties: id: type: string @@ -19492,6 +19635,9 @@ components: type: string OrganizationUserAccess: type: object + required: + - created_at + - updated_at properties: id: type: string diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index 469e623b1..dfd91d630 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -130,7 +130,10 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { await writeFile( join(directory, "schema.d.ts"), astToString( - await openapiTS(new URL(filename, root), { defaultNonNullable: false }), + await openapiTS(new URL(filename, root), { + defaultNonNullable: false, + emptyObjectsUnknown: true, + }), ), ); await writeFile( diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index ccd8e3c7d..d3d140bad 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -23,7 +23,10 @@ const receiptEvent: components["schemas"]["ApiEvent"] = { type: "receipt.status_updated", data: { type: "receipt", - object: { id: "rec", created_at: "2026-09-29T00:00:00Z", livemode: false }, + object: { + id: "rec", created_at: "2026-09-29T00:00:00Z", livemode: false, + date: "2026-09-29T00:00:00Z", expires_at: "2026-10-01T00:00:00Z", + }, }, }; const validation: operations["validateWebhookSignature"]["requestBody"]["content"]["application/json"] = @@ -70,7 +73,22 @@ const invalid: components["schemas"]["ApiEvent"] = { id: "invoice", created_at: "2026-09-29T00:00:00Z", livemode: false, + date: null, }, }, }; +const pago: components["schemas"]["PagoOrCustomComplementInput"] = { + type: "pago", + data: [{ payment_form: "28", related_documents: [{ + uuid: "39c85a3f-275b-4341-b259-e8971d9f8a94", installment: 1, + last_balance: 100, amount: 100, taxes: [], taxability: "01", + }] }], +}; +const pagoResponse: components["schemas"]["InvoiceComplementProperties"] = { + type: "pago", data: [{ date: "2026-09-29T00:00:00Z", payment_form: "28", related_documents: [] }], +}; +// @ts-expect-error a payment complement requires payment data, not payroll data +const wrongPago: components["schemas"]["PagoOrCustomComplementInput"] = { type: "pago", data: { tipo_nomina: "O" } }; +const customResponse: components["schemas"]["InvoiceComplementProperties"] = { type: "custom", data: "" }; +void [pago, pagoResponse, wrongPago, customResponse]; void [invoice, draft, receiptEvent, validation, nullDate, draftStamp, draftUuid, missingDraftUuid, paymentTaxability, invalidPaymentTaxability, unknownPaymentTaxability, certificate, missingCertificateDate, nullCertificateDate, fiel, missingFielDate, nullFielDate, callback, retainedTax, invalidRetainedTax, invalid]; From d5bdd5cebaee3b640991cddc7064e395ffe5dddb Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 19:45:50 +0200 Subject: [PATCH 08/33] docs: describe receipt invoice preview summaries --- website/openapi_v2.en.yaml | 67 +++++++++++++++++++++++++++++++++++++- website/openapi_v2.yaml | 67 +++++++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 74e1d8b30..959a5e006 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -18486,7 +18486,72 @@ components: description: CFDI Use code according to SAT catalog. ToInvoiceSummary: type: object - description: Summary object returned when `dry_run=true`. + description: Receipt amounts and taxes returned when `dry_run=true`. + required: [subtotal, discount, taxes, total, receipts, payment_form, item_count] + properties: + subtotal: + type: number + discount: + type: number + total: + type: number + receipts: + type: array + items: + type: string + payment_form: + type: string + item_count: + type: integer + taxes: + type: object + required: [totalAdded, totalWithholding, allAdded, allWithholding, localTotalAdded, localTotalWithholding, localAllAdded, localAllWithholding] + properties: + totalAdded: + type: number + totalWithholding: + type: number + localTotalAdded: + type: number + localTotalWithholding: + type: number + allAdded: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + allWithholding: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + localAllAdded: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + localAllWithholding: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + ReceiptInvoiceSummaryTax: + type: object + required: [factor, withholding, base, amount] + additionalProperties: true + properties: + type: + type: string + rate: + type: number + factor: + type: string + enum: [Tasa, Cuota, Exento] + withholding: + type: boolean + base: + type: number + amount: + type: number + name: + type: string + Retention: title: Retention object allOf: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 5e2258c72..0bc3ceec2 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -18405,7 +18405,72 @@ components: description: Código de Uso CFDI según catálogo del SAT. ToInvoiceSummary: type: object - description: Objeto resumen que regresa cuando `dry_run=true`. + description: Resumen de importes e impuestos de los recibos cuando `dry_run=true`. + required: [subtotal, discount, taxes, total, receipts, payment_form, item_count] + properties: + subtotal: + type: number + discount: + type: number + total: + type: number + receipts: + type: array + items: + type: string + payment_form: + type: string + item_count: + type: integer + taxes: + type: object + required: [totalAdded, totalWithholding, allAdded, allWithholding, localTotalAdded, localTotalWithholding, localAllAdded, localAllWithholding] + properties: + totalAdded: + type: number + totalWithholding: + type: number + localTotalAdded: + type: number + localTotalWithholding: + type: number + allAdded: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + allWithholding: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + localAllAdded: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + localAllWithholding: + type: array + items: + $ref: "#/components/schemas/ReceiptInvoiceSummaryTax" + ReceiptInvoiceSummaryTax: + type: object + required: [factor, withholding, base, amount] + additionalProperties: true + properties: + type: + type: string + rate: + type: number + factor: + type: string + enum: [Tasa, Cuota, Exento] + withholding: + type: boolean + base: + type: number + amount: + type: number + name: + type: string + Retention: title: Objeto Retention allOf: From 767c8025db942e496a9f71601171f01802f96073 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 19:55:23 +0200 Subject: [PATCH 09/33] docs: align payment taxability codes --- website/openapi_v2.en.yaml | 5 ++++- website/openapi_v2.yaml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 959a5e006..dcc466ebc 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16336,7 +16336,10 @@ components: - "03" - "04" - "05" - description: "Code representing whether the good or service is subject to tax or not. This attribute corresponds to the \"ObjetoImp\" field in the CFDI.\n\n- `01`: Not subject to tax.\n- `02`: Subject to tax.\n- `03`: Subject to tax, but not required to break down.\n- `04`: Subject to tax, but does not cause tax.\n- `05`: Subject to tax, VAT credit PODEBI.\n\nIf omitted, `01` is used when `taxes` is empty and `02` when it contains at least one tax." + - "06" + - "07" + - "08" + description: "Code representing whether the good or service is subject to tax or not. This attribute corresponds to the \"ObjetoImp\" field in the CFDI.\n\n- `01`: Not subject to tax.\n- `02`: Subject to tax.\n- `03`: Subject to tax, but not required to break down.\n- `04`: Subject to tax, but does not cause tax.\n- `05`: Subject to tax, VAT credit PODEBI.\n- `06`: Taxable, without transferred VAT.\n- `07`: No transferred VAT, with an IEPS breakdown.\n- `08`: No transferred VAT, without an IEPS breakdown.\n\nIf omitted, `01` is used when `taxes` is empty and `02` when it contains at least one tax." installment: type: integer description: | diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 0bc3ceec2..ae7716428 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16311,7 +16311,10 @@ components: - "03" - "04" - "05" - description: "Código que representa si el bien o servicio es objeto de impuesto o no. Este atributo corresponde al campo \"ObjetoImp\" en el CFDI.\n\n- `01`: No objeto de impuesto.\n- `02`: Sí objeto de impuesto.\n- `03`: Sí objeto de impuesto, pero no obligado a desglose.\n- `04`: Sí objeto de impuesto, y no causa impuesto.\n- `05`: Sí objeto de impuesto, IVA crédito PODEBI.\n\nSi se omite, se utiliza `01` cuando `taxes` está vacío y `02` cuando contiene al menos un impuesto." + - "06" + - "07" + - "08" + description: "Código que representa si el bien o servicio es objeto de impuesto o no. Este atributo corresponde al campo \"ObjetoImp\" en el CFDI.\n\n- `01`: No objeto de impuesto.\n- `02`: Sí objeto de impuesto.\n- `03`: Sí objeto de impuesto, pero no obligado a desglose.\n- `04`: Sí objeto de impuesto, y no causa impuesto.\n- `05`: Sí objeto de impuesto, IVA crédito PODEBI.\n- `06`: Sí objeto de impuesto, no IVA trasladado.\n- `07`: No traslado de IVA, pero desglose de IEPS.\n- `08`: No traslado de IVA sin desglose de IEPS.\n\nSi se omite, se utiliza `01` cuando `taxes` está vacío y `02` cuando contiene al menos un impuesto." installment: type: integer From a460e03f1d73a4a95c9cf1c47fa03a0c8909be12 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 19:59:36 +0200 Subject: [PATCH 10/33] docs: allow partial invoice preview inputs --- website/openapi_v2.en.yaml | 4 ++-- website/openapi_v2.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index dcc466ebc..6d2d297b4 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -4252,7 +4252,7 @@ paths: "series" => "F" ]); requestBody: - $ref: "#/components/requestBodies/InvoiceCreate" + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -4290,7 +4290,7 @@ paths: }); console.log(download.url, download.expires_at); requestBody: - $ref: "#/components/requestBodies/InvoiceCreate" + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] - "SecretTestKey": [] diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index ae7716428..a032968c0 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -4220,7 +4220,7 @@ paths: "series" => "F" ]); requestBody: - $ref: "#/components/requestBodies/InvoiceCreate" + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -4258,7 +4258,7 @@ paths: }); console.log(download.url, download.expires_at); requestBody: - $ref: "#/components/requestBodies/InvoiceCreate" + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] - "SecretTestKey": [] From 22b515b4f069c557d84035b78654ee043b215f1c Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 20:26:24 +0200 Subject: [PATCH 11/33] chore: update YAML parser security fixes --- website/package.json | 2 +- website/pnpm-lock.yaml | 12 ++++++++++-- website/scripts/check-openapi.mjs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/website/package.json b/website/package.json index ae3390345..2ef5e77ab 100644 --- a/website/package.json +++ b/website/package.json @@ -36,7 +36,7 @@ "@types/react": "^19.1.8", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", - "js-yaml": "4.2.0", + "js-yaml": "5.4.2", "openapi-typescript": "7.13.0", "typescript": "^5.8.3" }, diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index 0f3b8a71e..b642b01d2 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -64,8 +64,8 @@ importers: specifier: ^5.3.3 version: 5.3.3 js-yaml: - specifier: 4.2.0 - version: 4.2.0 + specifier: 5.4.2 + version: 5.4.2 openapi-typescript: specifier: 7.13.0 version: 7.13.0(typescript@5.9.3) @@ -3631,6 +3631,10 @@ packages: resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true + js-yaml@5.4.2: + resolution: {integrity: sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==} + hasBin: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -10670,6 +10674,10 @@ snapshots: dependencies: argparse: 2.0.1 + js-yaml@5.4.2: + dependencies: + argparse: 2.0.1 + jsesc@3.1.0: {} json-buffer@3.0.1: {} diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index dfd91d630..d111c66c5 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { createRequire } from "node:module"; import { execFileSync } from "node:child_process"; -import yaml from "js-yaml"; +import * as yaml from "js-yaml"; import openapiTS, { astToString } from "openapi-typescript"; const root = new URL("../", import.meta.url); From 4bcb2b67e624f939672ea52281688802ce8081f6 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 21:31:42 +0200 Subject: [PATCH 12/33] docs: refine CFDI and complement input relationships --- website/openapi_v2.en.yaml | 401 ++++++++++++++++--------- website/openapi_v2.yaml | 401 ++++++++++++++++--------- website/test/openapi-types.fixture.txt | 29 ++ 3 files changed, 537 insertions(+), 294 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 6d2d297b4..ef9a88f06 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -12488,7 +12488,7 @@ components: content: application/json: schema: - oneOf: + anyOf: - $ref: "#/components/schemas/InvoiceIngresoEditInput" - $ref: "#/components/schemas/InvoiceEgresoEditInput" - $ref: "#/components/schemas/InvoicePagoEditInput" @@ -13400,6 +13400,8 @@ components: - IVA - ISR - IEPS + ieps_mode: + $ref: "#/components/schemas/IepsMode" factor: type: string default: Tasa @@ -13412,33 +13414,40 @@ components: type: boolean default: false description: Indicates if it is a withholding tax (`true`) or a transferred tax (`false`). + IepsMode: + type: string + default: sum_before_taxes + enum: + - sum_before_taxes + - break_down + - unit + - subtract_before_break_down + description: | + Indicates in which way the tax is calculated. + + `"sum_before_taxes"`: Apply the IEPS to the subtotal first and use the result as the base for the rest of the taxes in the product. + + `"break_down"`: Charge and break down the IEPS at the same level as the rest of the taxes in the product. + + `"unit"`: Apply the IEPS before the unit price, and use the original unit price as the base for the rest of the taxes. + + `"subtract_before_break_down"`: Apply the IEPS only to calculate taxes like IVA de traslado and retentions, and use the original unit price as the base for the rest of the taxes. + + Consult with your accountant which case applies to your company and product. + IepsTax: type: object allOf: - $ref: "#/components/schemas/BaseTax" - type: object + required: + - type properties: - ieps_mode: + type: type: string - default: sum_before_taxes - enum: - - sum_before_taxes - - break_down - - unit - - subtract_before_break_down - description: | - Indicates in which way the tax is calculated. - - `"sum_before_taxes"`: Apply the IEPS to the subtotal first and use the result as the base for the rest of the taxes in the product. - - `"break_down"`: Charge and break down the IEPS at the same level as the rest of the taxes in the product. - - `"unit"`: Apply the IEPS before the unit price, and use the original unit price as the base for the rest of the taxes. - - `"subtract_before_break_down"`: Apply the IEPS only to calculate taxes like IVA de traslado and retentions, and use the original unit price as the base for the rest of the taxes. - - Consult with your accountant which case applies to your company and product. - + const: IEPS + ieps_mode: + $ref: "#/components/schemas/IepsMode" Stamp: type: object description: Information about the digital stamp added by the PAC. @@ -13817,25 +13826,23 @@ components: data: $ref: '#/components/schemas/CustomComplementData' CustomComplementInput: + required: + - type + - data title: CustomComplement allOf: - - type: object - required: - - type - - data - $ref: "#/components/schemas/CustomComplementProperties" NominaComplementDataInput: + required: + - fecha_inicial_pago + - fecha_final_pago + - num_dias_pagados + - receptor + - percepciones title: NominaComplementData description: | Object with the information of the payroll complement. allOf: - - type: object - required: - - fecha_inicial_pago - - fecha_final_pago - - num_dias_pagados - - receptor - - percepciones - $ref: "#/components/schemas/NominaComplementDataDirectProperties" - $ref: "#/components/schemas/NominaComplementDataNestedInput" NominaComplementDataProperties: @@ -13876,7 +13883,7 @@ components: type: object properties: emisor: - $ref: "#/components/schemas/NominaEmisorProperties" + $ref: "#/components/schemas/NominaEmisorInput" receptor: $ref: "#/components/schemas/NominaReceptorInput" percepciones: @@ -13933,12 +13940,11 @@ components: $ref: "#/components/schemas/NominaIncapacidadProperties" NominaIncapacidadInput: + required: + - dias_incapacidad + - tipo_incapacidad title: Incapacidad allOf: - - type: object - required: - - dias_incapacidad - - tipo_incapacidad - $ref: "#/components/schemas/NominaIncapacidadProperties" NominaIncapacidadProperties: type: object @@ -13954,13 +13960,12 @@ components: type: number description: Monetary amount of the paid incapacity. NominaOtroPagoInput: + required: + - tipo_otro_pago + - clave + - importe title: OtroPago allOf: - - type: object - required: - - tipo_otro_pago - - clave - - importe - $ref: "#/components/schemas/NominaOtroPagoDirectProperties" - type: object properties: @@ -13992,12 +13997,11 @@ components: This value will be inserted within the `SubsidioAlEmpleo` node, and is required when the value of `tipo_otro_pago` is `"002"`. NominaCompensacionInput: + required: + - saldo_a_favor + - ano + - remanente_sal_fav allOf: - - type: object - required: - - saldo_a_favor - - ano - - remanente_sal_fav - $ref: "#/components/schemas/NominaCompensacionProperties" NominaCompensacionProperties: type: object @@ -14013,13 +14017,12 @@ components: type: number description: Remaining balance in favor of the worker. NominaDeduccionInput: + required: + - tipo_deduccion + - clave + - importe title: Deduccion allOf: - - type: object - required: - - tipo_deduccion - - clave - - importe - $ref: "#/components/schemas/NominaDeduccionProperties" NominaDeduccionProperties: type: object @@ -14069,15 +14072,14 @@ components: separacion_indemnizacion: $ref: "#/components/schemas/NominaSeparacionProperties" NominaSeparacionInput: + required: + - total_pagado + - num_anos_servicio + - ultimo_sueldo_mens_ord + - ingreso_acumulable + - ingreso_no_acumulable title: Separacion allOf: - - type: object - required: - - total_pagado - - num_anos_servicio - - ultimo_sueldo_mens_ord - - ingreso_acumulable - - ingreso_no_acumulable - $ref: "#/components/schemas/NominaSeparacionProperties" NominaSeparacionProperties: type: object @@ -14100,12 +14102,11 @@ components: type: number description: Amount for non-accumulable income. NominaJubilacionInput: + required: + - ingreso_acumulable + - ingreso_no_acumulable title: Jubilacion allOf: - - type: object - required: - - ingreso_acumulable - - ingreso_no_acumulable - $ref: "#/components/schemas/NominaJubilacionProperties" NominaJubilacionProperties: type: object @@ -14132,16 +14133,79 @@ components: - $ref: "#/components/schemas/NominaPercepcionDirectProperties" - $ref: "#/components/schemas/NominaPercepcionNestedProperties" NominaPercepcionInput: + required: + - tipo_percepcion + - clave + - importe_gravado + - importe_exento + description: "Input uses the perception codes in the published catalog. Code 019 requires horas_extra." title: Percepcion allOf: - - type: object - required: - - tipo_percepcion - - clave - - importe_gravado - - importe_exento - $ref: "#/components/schemas/NominaPercepcionDirectProperties" - $ref: "#/components/schemas/NominaPercepcionNestedInput" + oneOf: + - type: object + properties: + tipo_percepcion: + type: string + const: "019" + horas_extra: + type: array + items: + $ref: "#/components/schemas/NominaHorasExtraInput" + required: + - horas_extra + - type: object + properties: + tipo_percepcion: + type: string + enum: + - "001" + - "002" + - "003" + - "004" + - "005" + - "006" + - "009" + - "010" + - "011" + - "012" + - "013" + - "014" + - "015" + - "020" + - "021" + - "022" + - "023" + - "024" + - "025" + - "026" + - "027" + - "028" + - "029" + - "030" + - "031" + - "032" + - "033" + - "034" + - "035" + - "036" + - "037" + - "038" + - "039" + - "044" + - "045" + - "046" + - "047" + - "048" + - "049" + - "050" + - "051" + - "052" + - "053" + - "054" + - "055" + - "056" NominaPercepcionDirectProperties: type: object properties: @@ -14183,14 +14247,13 @@ components: items: $ref: "#/components/schemas/NominaHorasExtraProperties" NominaHorasExtraInput: + required: + - dias + - tipo_horas + - horas_extra + - importe_pagado title: HorasExtra allOf: - - type: object - required: - - dias - - tipo_horas - - horas_extra - - importe_pagado - $ref: "#/components/schemas/NominaHorasExtraProperties" NominaHorasExtraProperties: type: object @@ -14209,12 +14272,11 @@ components: type: number description: Amount paid for extra hours. NominaAccionesInput: + required: + - valor_mercado + - precio_al_otorgarse title: Accion allOf: - - type: object - required: - - valor_mercado - - precio_al_otorgarse - $ref: "#/components/schemas/NominaAccionesProperties" NominaAccionesProperties: type: object @@ -14235,18 +14297,17 @@ components: - $ref: "#/components/schemas/NominaReceptorDirectProperties" - $ref: "#/components/schemas/NominaReceptorNestedProperties" NominaReceptorInput: + required: + - curp + - tipo_contrato + - tipo_regimen + - num_empleado + - periodicidad_pago + - clave_ent_fed type: object title: Receptor description: Worker information. allOf: - - type: object - required: - - curp - - tipo_contrato - - tipo_regimen - - num_empleado - - periodicidad_pago - - clave_ent_fed - $ref: "#/components/schemas/NominaReceptorDirectProperties" - $ref: "#/components/schemas/NominaReceptorNestedInput" NominaReceptorDirectProperties: @@ -14357,6 +14418,38 @@ components: minimum: 0.001 maximum: 100.000 description: Percentage of time the worker provided their services to the person or company that subcontracted them. + NominaEntidadSncfInput: + type: object + required: + - origen_recurso + properties: + origen_recurso: + type: string + enum: [IP, IF, IM] + monto_recurso_propio: + type: number + oneOf: + - type: object + properties: + origen_recurso: + type: string + const: IM + monto_recurso_propio: + type: number + required: + - monto_recurso_propio + - type: object + properties: + origen_recurso: + type: string + enum: [IP, IF] + NominaEmisorInput: + allOf: + - $ref: "#/components/schemas/NominaEmisorProperties" + - type: object + properties: + entidad_sncf: + $ref: "#/components/schemas/NominaEntidadSncfInput" NominaEmisorProperties: type: object title: Emisor @@ -14466,6 +14559,23 @@ components: properties: data: $ref: "#/components/schemas/PagoComplementDataInput" + InvoiceComplementInput: + oneOf: + - $ref: "#/components/schemas/PagoComplementInput" + - $ref: "#/components/schemas/NominaComplementInput" + - $ref: "#/components/schemas/CartaPorteInput" + - $ref: "#/components/schemas/ComercioExteriorInput" + - $ref: "#/components/schemas/LeyendasFiscalesInput" + - $ref: "#/components/schemas/CustomComplementInput" + discriminator: + propertyName: type + mapping: + pago: "#/components/schemas/PagoComplementInput" + nomina: "#/components/schemas/NominaComplementInput" + carta_porte: "#/components/schemas/CartaPorteInput" + comercio_exterior: "#/components/schemas/ComercioExteriorInput" + leyendas_fiscales: "#/components/schemas/LeyendasFiscalesInput" + custom: "#/components/schemas/CustomComplementInput" InvoiceComplementProperties: oneOf: - $ref: '#/components/schemas/PagoComplementProperties' @@ -15301,6 +15411,11 @@ components: $ref: "#/components/schemas/CartaPorteDetalleMercancia" CartaPorteIdentificacionVehicular: type: object + required: + - ConfigVehicular + - PesoBrutoVehicular + - PlacaVM + - AnioModeloVM properties: ConfigVehicular: type: string @@ -15316,6 +15431,9 @@ components: description: Model year of the motor vehicle. CartaPorteSeguros: type: object + required: + - AseguraRespCivil + - PolizaRespCivil properties: AseguraRespCivil: type: string @@ -15349,6 +15467,11 @@ components: description: Trailer license plate. CartaPorteAutotransporte: type: object + required: + - PermSCT + - NumPermisoSCT + - IdentificacionVehicular + - Seguros properties: PermSCT: type: string @@ -16039,11 +16162,10 @@ components: type: string description: Customs entry number (pedimento aduanal) associated with this part. PartInput: + required: + - description + - product_key allOf: - - type: object - required: - - description - - product_key - $ref: "#/components/schemas/Parts" Product: title: Product object @@ -16471,11 +16593,10 @@ components: description: ID del objeto `customer` relacionado a la factura, en caso de no haber sido eliminado example: 58e93bd8e86eb318b0197456 RelatedDocumentInput: + required: + - relationship + - related allOf: - - type: object - required: - - relationship - - related - $ref: '#/components/schemas/RelatedDocument' RelatedDocument: type: object @@ -17616,7 +17737,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the invoice. You can include any complement in the invoice if you build the XML node of the complement yourself and use the `custom` type. @@ -17688,7 +17809,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the credit note. You can include any complement in the credit note if you build the XML node of the complement yourself and use the `custom` type. @@ -17725,9 +17846,17 @@ components: - $ref: "#/components/schemas/ThirdParty" complements: type: array - default: [] + minItems: 1 + contains: + type: object + required: + - type + properties: + type: + type: string + const: pago items: - $ref: "#/components/schemas/PagoOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complements to include in the invoice. - $ref: "#/components/schemas/InvoiceCommonInputProperties" InvoiceNominaInput: @@ -17745,9 +17874,17 @@ components: - "N" complements: type: array - default: [] + minItems: 1 + contains: + type: object + required: + - type + properties: + type: + type: string + const: nomina items: - $ref: "#/components/schemas/NominaOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complements to include in the invoice. related_documents: type: array @@ -17783,7 +17920,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the invoice. You can include any complement in the invoice if you build the XML node of the complement yourself and use the `custom` type. @@ -17819,14 +17956,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. + const: "I" + description: "Document type for this input variant." items: type: array maxItems: 5000 @@ -17931,7 +18062,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the invoice. You can include any complement in the invoice if you build the XML node of the complement yourself and use the `custom` type. @@ -17945,14 +18076,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. + const: "E" + description: "Document type for this input variant." payment_form: type: string minLength: 2 @@ -17998,7 +18123,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the credit note. You can include any complement in the credit note if you build the XML node of the complement yourself and use the `custom` type. @@ -18012,14 +18137,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. + const: "P" + description: "Document type for this input variant." related_documents: type: array description: Documents related to the invoice. @@ -18037,7 +18156,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/PagoOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complements to include in the invoice. - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" InvoiceNominaEditInput: @@ -18047,18 +18166,12 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. + const: "N" + description: "Document type for this input variant." complements: type: array items: - $ref: "#/components/schemas/NominaOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complements to include in the invoice. related_documents: type: array @@ -18073,14 +18186,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. + const: "T" + description: "Document type for this input variant." items: type: array maxItems: 5000 @@ -18094,7 +18201,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complements to include in the invoice. You can include any complement in the invoice if you build the XML node of the complement yourself and use the `custom` type. diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index a032968c0..7555afbcc 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -12438,7 +12438,7 @@ components: content: application/json: schema: - oneOf: + anyOf: - $ref: "#/components/schemas/InvoiceIngresoEditInput" - $ref: "#/components/schemas/InvoiceEgresoEditInput" - $ref: "#/components/schemas/InvoicePagoEditInput" @@ -13351,6 +13351,8 @@ components: - IVA - ISR - IEPS + ieps_mode: + $ref: "#/components/schemas/IepsMode" factor: type: string default: Tasa @@ -13363,33 +13365,40 @@ components: type: boolean default: false description: Indica si se trata de un impuesto retenido (`true`), o un impuesto trasladado (`false`) + IepsMode: + type: string + default: sum_before_taxes + enum: + - sum_before_taxes + - break_down + - unit + - subtract_before_break_down + description: | + Indica la manera de cobrar el impuesto, y puede tener los valores: + + `"sum_before_taxes"`: Aplica primero el IEPS al subtotal y usa el resultado como base del resto de impuestos en el producto. + + `"break_down"`: Cobra y desglosa el IEPS al mismo nivel que el resto de los impuestos en el producto. + + `"unit"`: Aplica el IEPS antes del precio unitario, y usa el precio unitario original como base para el resto de impuestos. + + `"subtract_before_break_down"`: Aplica el IEPS solo para calcular impuestos como IVA de traslado y retenciones, y usa el precio unitario original como base para el resto de impuestos. + + Consulta con tu contador qué caso aplica para tu giro de empresa y producto. + IepsTax: type: object allOf: - $ref: "#/components/schemas/BaseTax" - type: object + required: + - type properties: - ieps_mode: + type: type: string - default: sum_before_taxes - enum: - - sum_before_taxes - - break_down - - unit - - subtract_before_break_down - description: | - Indica la manera de cobrar el impuesto, y puede tener los valores: - - `"sum_before_taxes"`: Aplica primero el IEPS al subtotal y usa el resultado como base del resto de impuestos en el producto. - - `"break_down"`: Cobra y desglosa el IEPS al mismo nivel que el resto de los impuestos en el producto. - - `"unit"`: Aplica el IEPS antes del precio unitario, y usa el precio unitario original como base para el resto de impuestos. - - `"subtract_before_break_down"`: Aplica el IEPS solo para calcular impuestos como IVA de traslado y retenciones, y usa el precio unitario original como base para el resto de impuestos. - - Consulta con tu contador qué caso aplica para tu giro de empresa y producto. - + const: IEPS + ieps_mode: + $ref: "#/components/schemas/IepsMode" Stamp: type: object description: Información sobre el timbre fiscal digital agregado por el PAC. @@ -13767,24 +13776,22 @@ components: data: $ref: '#/components/schemas/CustomComplementData' CustomComplementInput: + required: + - type + - data title: CustomComplement allOf: - - type: object - required: - - type - - data - $ref: "#/components/schemas/CustomComplementProperties" NominaComplementDataInput: + required: + - fecha_inicial_pago + - fecha_final_pago + - num_dias_pagados + - receptor + - percepciones title: NominaComplementData description: Objeto con la información del complemento de nómina. allOf: - - type: object - required: - - fecha_inicial_pago - - fecha_final_pago - - num_dias_pagados - - receptor - - percepciones - $ref: "#/components/schemas/NominaComplementDataDirectProperties" - $ref: "#/components/schemas/NominaComplementDataNestedInput" NominaComplementDataProperties: @@ -13825,7 +13832,7 @@ components: type: object properties: emisor: - $ref: "#/components/schemas/NominaEmisorProperties" + $ref: "#/components/schemas/NominaEmisorInput" receptor: $ref: "#/components/schemas/NominaReceptorInput" percepciones: @@ -13882,12 +13889,11 @@ components: $ref: "#/components/schemas/NominaIncapacidadProperties" NominaIncapacidadInput: + required: + - dias_incapacidad + - tipo_incapacidad title: Incapacidad allOf: - - type: object - required: - - dias_incapacidad - - tipo_incapacidad - $ref: "#/components/schemas/NominaIncapacidadProperties" NominaIncapacidadProperties: type: object @@ -13902,13 +13908,12 @@ components: type: number description: Monto del importe monetario de la incapacidad. NominaOtroPagoInput: + required: + - tipo_otro_pago + - clave + - importe title: OtroPago allOf: - - type: object - required: - - tipo_otro_pago - - clave - - importe - $ref: "#/components/schemas/NominaOtroPagoDirectProperties" - type: object properties: @@ -13940,12 +13945,11 @@ components: Este valor será insertado dentro del nodo `SubsidioAlEmpleo`, y es requerido cuando el valor de `tipo_otro_pago` es `"002"`. NominaCompensacionInput: + required: + - saldo_a_favor + - ano + - remanente_sal_fav allOf: - - type: object - required: - - saldo_a_favor - - ano - - remanente_sal_fav - $ref: "#/components/schemas/NominaCompensacionProperties" NominaCompensacionProperties: type: object @@ -13961,13 +13965,12 @@ components: type: number description: Remanente del saldo a favor del trabajador. NominaDeduccionInput: + required: + - tipo_deduccion + - clave + - importe title: Deduccion allOf: - - type: object - required: - - tipo_deduccion - - clave - - importe - $ref: "#/components/schemas/NominaDeduccionProperties" NominaDeduccionProperties: type: object @@ -14017,15 +14020,14 @@ components: separacion_indemnizacion: $ref: "#/components/schemas/NominaSeparacionProperties" NominaSeparacionInput: + required: + - total_pagado + - num_anos_servicio + - ultimo_sueldo_mens_ord + - ingreso_acumulable + - ingreso_no_acumulable title: Separacion allOf: - - type: object - required: - - total_pagado - - num_anos_servicio - - ultimo_sueldo_mens_ord - - ingreso_acumulable - - ingreso_no_acumulable - $ref: "#/components/schemas/NominaSeparacionProperties" NominaSeparacionProperties: type: object @@ -14048,12 +14050,11 @@ components: type: number description: Monto por ingresos no acumulables. NominaJubilacionInput: + required: + - ingreso_acumulable + - ingreso_no_acumulable title: Jubilacion allOf: - - type: object - required: - - ingreso_acumulable - - ingreso_no_acumulable - $ref: "#/components/schemas/NominaJubilacionProperties" NominaJubilacionProperties: type: object @@ -14080,16 +14081,79 @@ components: - $ref: "#/components/schemas/NominaPercepcionDirectProperties" - $ref: "#/components/schemas/NominaPercepcionNestedProperties" NominaPercepcionInput: + required: + - tipo_percepcion + - clave + - importe_gravado + - importe_exento + description: "La entrada utiliza las claves de percepción del catálogo publicado. La clave 019 requiere horas_extra." title: Percepcion allOf: - - type: object - required: - - tipo_percepcion - - clave - - importe_gravado - - importe_exento - $ref: "#/components/schemas/NominaPercepcionDirectProperties" - $ref: "#/components/schemas/NominaPercepcionNestedInput" + oneOf: + - type: object + properties: + tipo_percepcion: + type: string + const: "019" + horas_extra: + type: array + items: + $ref: "#/components/schemas/NominaHorasExtraInput" + required: + - horas_extra + - type: object + properties: + tipo_percepcion: + type: string + enum: + - "001" + - "002" + - "003" + - "004" + - "005" + - "006" + - "009" + - "010" + - "011" + - "012" + - "013" + - "014" + - "015" + - "020" + - "021" + - "022" + - "023" + - "024" + - "025" + - "026" + - "027" + - "028" + - "029" + - "030" + - "031" + - "032" + - "033" + - "034" + - "035" + - "036" + - "037" + - "038" + - "039" + - "044" + - "045" + - "046" + - "047" + - "048" + - "049" + - "050" + - "051" + - "052" + - "053" + - "054" + - "055" + - "056" NominaPercepcionDirectProperties: type: object properties: @@ -14131,14 +14195,13 @@ components: items: $ref: "#/components/schemas/NominaHorasExtraProperties" NominaHorasExtraInput: + required: + - dias + - tipo_horas + - horas_extra + - importe_pagado title: HorasExtra allOf: - - type: object - required: - - dias - - tipo_horas - - horas_extra - - importe_pagado - $ref: "#/components/schemas/NominaHorasExtraProperties" NominaHorasExtraProperties: type: object @@ -14157,12 +14220,11 @@ components: type: number description: Importe pagado por las horas extra. NominaAccionesInput: + required: + - valor_mercado + - precio_al_otorgarse title: Accion allOf: - - type: object - required: - - valor_mercado - - precio_al_otorgarse - $ref: "#/components/schemas/NominaAccionesProperties" NominaAccionesProperties: type: object @@ -14183,18 +14245,17 @@ components: - $ref: "#/components/schemas/NominaReceptorDirectProperties" - $ref: "#/components/schemas/NominaReceptorNestedProperties" NominaReceptorInput: + required: + - curp + - tipo_contrato + - tipo_regimen + - num_empleado + - periodicidad_pago + - clave_ent_fed type: object title: Receptor description: Información del trabajador. allOf: - - type: object - required: - - curp - - tipo_contrato - - tipo_regimen - - num_empleado - - periodicidad_pago - - clave_ent_fed - $ref: "#/components/schemas/NominaReceptorDirectProperties" - $ref: "#/components/schemas/NominaReceptorNestedInput" NominaReceptorDirectProperties: @@ -14296,6 +14357,38 @@ components: minimum: 0.001 maximum: 100.000 description: Porcentaje de tiempo en que el trabajador prestó sus servicios a la persona o empresa que lo subcontrató. + NominaEntidadSncfInput: + type: object + required: + - origen_recurso + properties: + origen_recurso: + type: string + enum: [IP, IF, IM] + monto_recurso_propio: + type: number + oneOf: + - type: object + properties: + origen_recurso: + type: string + const: IM + monto_recurso_propio: + type: number + required: + - monto_recurso_propio + - type: object + properties: + origen_recurso: + type: string + enum: [IP, IF] + NominaEmisorInput: + allOf: + - $ref: "#/components/schemas/NominaEmisorProperties" + - type: object + properties: + entidad_sncf: + $ref: "#/components/schemas/NominaEntidadSncfInput" NominaEmisorProperties: type: object title: Emisor @@ -14405,6 +14498,23 @@ components: properties: data: $ref: "#/components/schemas/PagoComplementDataInput" + InvoiceComplementInput: + oneOf: + - $ref: "#/components/schemas/PagoComplementInput" + - $ref: "#/components/schemas/NominaComplementInput" + - $ref: "#/components/schemas/CartaPorteInput" + - $ref: "#/components/schemas/ComercioExteriorInput" + - $ref: "#/components/schemas/LeyendasFiscalesInput" + - $ref: "#/components/schemas/CustomComplementInput" + discriminator: + propertyName: type + mapping: + pago: "#/components/schemas/PagoComplementInput" + nomina: "#/components/schemas/NominaComplementInput" + carta_porte: "#/components/schemas/CartaPorteInput" + comercio_exterior: "#/components/schemas/ComercioExteriorInput" + leyendas_fiscales: "#/components/schemas/LeyendasFiscalesInput" + custom: "#/components/schemas/CustomComplementInput" InvoiceComplementProperties: oneOf: - $ref: '#/components/schemas/PagoComplementProperties' @@ -15286,6 +15396,11 @@ components: description: Detalle de pesos y piezas de la mercancía. CartaPorteIdentificacionVehicular: type: object + required: + - ConfigVehicular + - PesoBrutoVehicular + - PlacaVM + - AnioModeloVM properties: ConfigVehicular: type: string @@ -15301,6 +15416,9 @@ components: description: Año modelo del vehículo motor. CartaPorteSeguros: type: object + required: + - AseguraRespCivil + - PolizaRespCivil properties: AseguraRespCivil: type: string @@ -15334,6 +15452,11 @@ components: description: Placa del remolque. CartaPorteAutotransporte: type: object + required: + - PermSCT + - NumPermisoSCT + - IdentificacionVehicular + - Seguros properties: PermSCT: type: string @@ -16036,11 +16159,10 @@ components: type: string description: Números de pedimento aduanal asociados a esta parte. PartInput: + required: + - description + - product_key allOf: - - type: object - required: - - description - - product_key - $ref: "#/components/schemas/Parts" Product: title: Objeto Product @@ -16428,11 +16550,10 @@ components: description: ID del objeto `customer` relacionado a la factura, en caso de no haber sido eliminado example: 58e93bd8e86eb318b0197456 RelatedDocumentInput: + required: + - relationship + - related allOf: - - type: object - required: - - relationship - - related - $ref: '#/components/schemas/RelatedDocument' RelatedDocument: type: object @@ -17557,7 +17678,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en la factura. Puedes incluir cualquier complemento en la factura si tú mismo construyes el nodo XML del complemento y usas el tipo `custom`. @@ -17624,7 +17745,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en el comprobante. Puedes incluir cualquier complemento en el comprobante si tú mismo construyes el nodo XML del @@ -17661,9 +17782,17 @@ components: - $ref: "#/components/schemas/ThirdParty" complements: type: array - default: [] + minItems: 1 + contains: + type: object + required: + - type + properties: + type: + type: string + const: pago items: - $ref: "#/components/schemas/PagoOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complementos a incluir en la factura. - $ref: "#/components/schemas/InvoiceCommonInputProperties" InvoiceNominaInput: @@ -17681,9 +17810,17 @@ components: - "N" complements: type: array - default: [] + minItems: 1 + contains: + type: object + required: + - type + properties: + type: + type: string + const: nomina items: - $ref: "#/components/schemas/NominaOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complementos a incluir en la factura. related_documents: type: array @@ -17719,7 +17856,7 @@ components: type: array default: [] items: - $ref: "#/components/schemas/CartaPorteOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en el comprobante. Puedes incluir cualquier complemento en el comprobante si tú mismo construyes el nodo XML del complemento y usas el tipo @@ -17755,14 +17892,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. + const: "I" + description: "Tipo de comprobante de esta variante de entrada." items: type: array maxItems: 5000 @@ -17869,7 +18000,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en la factura. Puedes incluir cualquier complemento en la factura si tú mismo construyes el nodo XML del complemento y usas el tipo `custom`. @@ -17883,14 +18014,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. + const: "E" + description: "Tipo de comprobante de esta variante de entrada." payment_form: type: string minLength: 2 @@ -17933,7 +18058,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en el comprobante. Puedes incluir cualquier complemento en el comprobante si tú mismo construyes el nodo XML del @@ -17947,14 +18072,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. + const: "P" + description: "Tipo de comprobante de esta variante de entrada." related_documents: type: array description: Documentos relacionados con la factura. @@ -17972,7 +18091,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/PagoOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complementos a incluir en la factura. - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" InvoiceNominaEditInput: @@ -17982,18 +18101,12 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. + const: "N" + description: "Tipo de comprobante de esta variante de entrada." complements: type: array items: - $ref: "#/components/schemas/NominaOrCustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: Complementos a incluir en la factura. related_documents: type: array @@ -18008,14 +18121,8 @@ components: properties: type: type: string - enum: - - "I" - - "E" - - "P" - - "N" - - "T" - description: | - Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. + const: "T" + description: "Tipo de comprobante de esta variante de entrada." items: type: array maxItems: 5000 @@ -18029,7 +18136,7 @@ components: complements: type: array items: - $ref: "#/components/schemas/CustomComplementInput" + $ref: "#/components/schemas/InvoiceComplementInput" description: | Complementos a incluir en el comprobante. Puedes incluir cualquier complemento en el comprobante si tú mismo construyes el nodo XML del complemento y usas el tipo diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index d3d140bad..28c7fd30e 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -92,3 +92,32 @@ const wrongPago: components["schemas"]["PagoOrCustomComplementInput"] = { type: const customResponse: components["schemas"]["InvoiceComplementProperties"] = { type: "custom", data: "" }; void [pago, pagoResponse, wrongPago, customResponse]; void [invoice, draft, receiptEvent, validation, nullDate, draftStamp, draftUuid, missingDraftUuid, paymentTaxability, invalidPaymentTaxability, unknownPaymentTaxability, certificate, missingCertificateDate, nullCertificateDate, fiel, missingFielDate, nullFielDate, callback, retainedTax, invalidRetainedTax, invalid]; + +const nominaEdit: components["schemas"]["InvoiceNominaEditInput"] = { type: "N" }; +// @ts-expect-error payroll editing has its own CFDI discriminator +const wrongNominaEdit: components["schemas"]["InvoiceNominaEditInput"] = { type: "P" }; +const paymentEdit: components["schemas"]["InvoicePagoEditInput"] = { type: "P", complements: [pago] }; +// @ts-expect-error payment editing has its own CFDI discriminator +const wrongPaymentEdit: components["schemas"]["InvoicePagoEditInput"] = { type: "N" }; +const legendsDraft: components["schemas"]["InvoiceCreateInput"] = { status: "draft", complements: [{ type: "leyendas_fiscales", data: { leyendas: [{ texto_leyenda: "Ejemplo" }] } }] }; +const plainPerception: components["schemas"]["NominaPercepcionInput"] = { tipo_percepcion: "001", clave: "ABC", importe_gravado: 1, importe_exento: 0 }; +const overtimePerception: components["schemas"]["NominaPercepcionInput"] = { ...plainPerception, tipo_percepcion: "019", horas_extra: [{ dias: 1, tipo_horas: "01", horas_extra: 1, importe_pagado: 1 }] }; +// @ts-expect-error overtime perception requires its hours-extra structure +const missingHours: components["schemas"]["NominaPercepcionInput"] = { tipo_percepcion: "019", clave: "ABC", importe_gravado: 1, importe_exento: 0 }; +const mixedFunds: components["schemas"]["NominaEntidadSncfInput"] = { origen_recurso: "IM", monto_recurso_propio: 1 }; +const federalFunds: components["schemas"]["NominaEntidadSncfInput"] = { origen_recurso: "IF" }; +// @ts-expect-error mixed funding requires its own-resource amount +const missingOwnFunds: components["schemas"]["NominaEntidadSncfInput"] = { origen_recurso: "IM" }; +const ieps: components["schemas"]["BaseTax"] = { type: "IEPS", rate: 0.08, ieps_mode: "unit" }; +// @ts-expect-error an explicitly IEPS schema cannot identify an IVA tax +const wrongIeps: components["schemas"]["IepsTax"] = { type: "IVA", rate: 0.16 }; +// @ts-expect-error selecting road transport requires its vehicle and insurance data +const incompleteRoad: components["schemas"]["CartaPorteAutotransporte"] = { PermSCT: "TPAF01", NumPermisoSCT: "Example" }; +void [nominaEdit, wrongNominaEdit, paymentEdit, wrongPaymentEdit, legendsDraft, plainPerception, overtimePerception, missingHours, mixedFunds, federalFunds, missingOwnFunds, ieps, wrongIeps, incompleteRoad]; +// @ts-expect-error composed perception input must retain its required amounts +const missingPerceptionAmounts: components["schemas"]["NominaPercepcionInput"] = { tipo_percepcion: "001", clave: "ABC" }; +// @ts-expect-error composed hours-extra input must retain its required payment amount +const missingOvertimeAmount: components["schemas"]["NominaHorasExtraInput"] = { dias: 1, tipo_horas: "01", horas_extra: 1 }; +const publicAidPerception: components["schemas"]["NominaPercepcionInput"] = { ...plainPerception, tipo_percepcion: "056" }; +const customPayroll: components["schemas"]["NominaOtroPagoInput"] = { tipo_otro_pago: "002", clave: "ABC", importe: 1 }; +void [missingPerceptionAmounts, missingOvertimeAmount, publicAidPerception, customPayroll]; From 4a6db95671492410956f861f1e02c483a827269a Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 30 Sep 2026 22:05:57 +0200 Subject: [PATCH 13/33] docs: align optional invoice fields and single payment inputs --- website/openapi_v2.en.yaml | 74 +++++++++++++++----------- website/openapi_v2.yaml | 74 +++++++++++++++----------- website/test/openapi-types.fixture.txt | 15 ++++++ 3 files changed, 103 insertions(+), 60 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index ef9a88f06..4aa72f3ce 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -14609,12 +14609,14 @@ components: format: date-time PagoComplementDataInput: - type: array title: PagoComplementData description: Payments to include in this document. The most common is to include only one payment. A case in which more than one must be added is when the payment is made with 2 different payment methods; for example, when one part is paid by card and the other in cash. - items: - $ref: "#/components/schemas/PaymentInput" - + oneOf: + - $ref: "#/components/schemas/PaymentInput" + - type: array + minItems: 1 + items: + $ref: "#/components/schemas/PaymentInput" NominaOrCustomComplementProperties: title: Complement type: object @@ -17369,18 +17371,20 @@ components: antiguedad: type: boolean default: false + InvoiceCustomerInput: + description: Customer receiving the invoice. + oneOf: + - $ref: "#/components/schemas/CustomerCreateInput" + - type: string + title: customer_id + description: ID of the `customer` object previously registered in Facturapi. + example: 58e93bd8e86eb318b0197456 InvoiceCommonInputProperties: allOf: - type: object properties: customer: - description: Customer receiving the invoice. - oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" - - type: string - title: customer_id - description: ID of the `customer` object previously registered in Facturapi. - example: 58e93bd8e86eb318b0197456 + $ref: "#/components/schemas/InvoiceCustomerInput" status: type: string enum: @@ -17432,14 +17436,6 @@ components: allOf: - type: object properties: - customer: - description: Customer receiving the invoice. - oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" - - type: string - title: customer_id - description: ID of the `Customer` object previously registered in Facturapi. - example: 58e93bd8e86eb318b0197456 status: type: string enum: @@ -17478,6 +17474,20 @@ components: If left blank, it will not be taken into account. - $ref: "#/components/schemas/InvoiceableCommonEditInput" + InvoiceDraftInputProperties: + allOf: + - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - type: object + properties: + customer: + description: Customer receiving the invoice. + oneOf: + - type: "null" + - $ref: "#/components/schemas/CustomerCreateInput" + - type: string + title: customer_id + description: ID of the `Customer` object previously registered in Facturapi. + example: 58e93bd8e86eb318b0197456 InvoiceCreateInput: type: object description: Invoice data according to its type and initial status. Omit status to stamp; use draft to save a draft. @@ -17615,7 +17625,6 @@ components: - customer - items - payment_form - - use allOf: - type: object properties: @@ -17654,9 +17663,10 @@ components: - `PUE`: Payment in One Installment (paid in full at the time of the transaction) - `PPD`: Payment in Installments or Deferred (partial or deferred payment) use: - type: string - default: G01 + type: [string, "null"] description: | + If omitted or null, the customer default is used, falling back to G03. For foreign customers or the general public, S01 is used. + Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. For global invoices you must use the code `S01`. @@ -17791,7 +17801,7 @@ components: $ref: "#/components/schemas/LineItemEgresoInput" use: type: string - default: G01 + default: G02 description: | Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. currency: @@ -17928,12 +17938,12 @@ components: `pdf_custom_section` parameter. use: type: string - default: G01 + default: S01 description: | Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. currency: type: string - default: MXN + default: XXX description: Currency code, according to the standard [ISO 4217](https://es.wikipedia.org/wiki/ISO_4217). exchange: type: number @@ -17969,7 +17979,7 @@ components: items: $ref: "#/components/schemas/LineItemInput" payment_form: - type: string + type: [string, "null"] minLength: 2 maxLength: 2 example: "03" @@ -17985,7 +17995,7 @@ components: - `PUE`: Payment in One Installment (paid in full at the time of the transaction) - `PPD`: Payment in Installments or Deferred (partial or deferred payment) use: - type: string + type: [string, "null"] example: G01 description: | Code of Use of CFDI according to the SAT catalog. You can see the codes in [this table](#uso-cfdi), or use the constants included in our libraries. @@ -18068,7 +18078,7 @@ components: invoice if you build the XML node of the complement yourself and use the `custom` type. It is necessary to add the complement information to the PDF separately using the `pdf_custom_section` parameter. - - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoiceEgresoEditInput: title: Egress allOf: @@ -18129,7 +18139,7 @@ components: credit note if you build the XML node of the complement yourself and use the `custom` type. It is necessary to add the complement information to the PDF separately using the `pdf_custom_section` parameter. - - $ref: "#/components/schemas/InvoiceCommonInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoicePagoEditInput: title: Payment allOf: @@ -18158,12 +18168,14 @@ components: items: $ref: "#/components/schemas/InvoiceComplementInput" description: Complements to include in the invoice. - - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoiceNominaEditInput: title: Payroll allOf: - type: object properties: + customer: + $ref: "#/components/schemas/InvoiceCustomerInput" type: type: string const: "N" @@ -18184,6 +18196,8 @@ components: allOf: - type: object properties: + customer: + $ref: "#/components/schemas/InvoiceCustomerInput" type: type: string const: "T" diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 7555afbcc..557cf5daf 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -14548,12 +14548,14 @@ components: format: date-time PagoComplementDataInput: - type: array title: PagoComplementData description: Pagos a incluir en este comprobante. Lo más común es incluir un sólo pago. Un caso en el que se debe de agregar más de uno es cuando el pago se realiza con 2 formas de pago distintas; por ejemplo, cuando se paga una parte con tarjeta y otra en efectivo. - items: - $ref: "#/components/schemas/PaymentInput" - + oneOf: + - $ref: "#/components/schemas/PaymentInput" + - type: array + minItems: 1 + items: + $ref: "#/components/schemas/PaymentInput" NominaOrCustomComplementProperties: title: Complement type: object @@ -17318,18 +17320,20 @@ components: antiguedad: type: boolean default: false + InvoiceCustomerInput: + description: Cliente receptor de la factura. + oneOf: + - $ref: "#/components/schemas/CustomerCreateInput" + - type: string + title: customer_id + description: ID del objeto 'customer' previamente registrado en Facturapi. + example: 58e93bd8e86eb318b0197456 InvoiceCommonInputProperties: allOf: - type: object properties: customer: - description: Cliente receptor de la factura. - oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" - - type: string - title: customer_id - description: ID del objeto 'customer' previamente registrado en Facturapi. - example: 58e93bd8e86eb318b0197456 + $ref: "#/components/schemas/InvoiceCustomerInput" status: type: string enum: @@ -17375,14 +17379,6 @@ components: allOf: - type: object properties: - customer: - description: Cliente receptor de la factura. - oneOf: - - $ref: "#/components/schemas/CustomerCreateInput" - - type: string - title: customer_id - description: ID del objeto 'customer' previamente registrado en Facturapi. - example: 58e93bd8e86eb318b0197456 status: type: string enum: @@ -17419,6 +17415,20 @@ components: Identificador único que puedes usar para evitar duplicados al reintentar una petición. Puede ser cualquier cadena de texto, mientras sea única para cada documento. Si se deja en blanco, no se tomará en cuenta. - $ref: "#/components/schemas/InvoiceableCommonEditInput" + InvoiceDraftInputProperties: + allOf: + - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - type: object + properties: + customer: + description: Cliente receptor de la factura. + oneOf: + - type: "null" + - $ref: "#/components/schemas/CustomerCreateInput" + - type: string + title: customer_id + description: ID del objeto 'customer' previamente registrado en Facturapi. + example: 58e93bd8e86eb318b0197456 InvoiceCreateInput: type: object description: Datos de la factura según su tipo y estado inicial. Omite status para timbrar; usa draft para guardar un borrador. @@ -17556,7 +17566,6 @@ components: - customer - items - payment_form - - use allOf: - type: object properties: @@ -17594,9 +17603,10 @@ components: - `PUE`: Pago en Una sola Exhibición - `PPD`: Pago en Parcialidades o Diferido use: - type: string - default: G01 + type: [string, "null"] description: | + Si se omite o es null, se utiliza el uso configurado en el cliente; si no tiene uno, se utiliza G03. Para clientes extranjeros o público en general se utiliza S01. + Código de Uso CFDI según el catálogo del SAT. Puedes ver los códigos en [esta tabla](#uso-cfdi), o utilizar las constantes incluidas en nuestras librerías. @@ -17731,7 +17741,7 @@ components: $ref: "#/components/schemas/LineItemEgresoInput" use: type: string - default: G01 + default: G02 description: Código de Uso CFDI según el catálogo del SAT. Puedes ver los códigos en [esta tabla](#uso-cfdi), o utilizar las constantes incluidas en nuestras librerías. currency: type: string @@ -17864,13 +17874,13 @@ components: usando el parámetro `pdf_custom_section`. use: type: string - default: G01 + default: S01 description: | Código de Uso CFDI según el catálogo del SAT. Puedes ver los códigos en [esta tabla](#uso-cfdi), o utilizar las constantes incluidas en nuestras librerías. currency: type: string - default: MXN + default: XXX description: Código de la moneda, acorde al estándar [ISO 4217](https://es.wikipedia.org/wiki/ISO_4217). exchange: type: number @@ -17905,7 +17915,7 @@ components: items: $ref: "#/components/schemas/LineItemInput" payment_form: - type: string + type: [string, "null"] minLength: 2 maxLength: 2 example: "03" @@ -17921,7 +17931,7 @@ components: - `PUE`: Pago en Una sola Exhibición - `PPD`: Pago en Parcialidades o Diferido use: - type: string + type: [string, "null"] example: G01 description: | Código de Uso CFDI según el catálogo del SAT. Puedes ver los códigos @@ -18006,7 +18016,7 @@ components: factura si tú mismo construyes el nodo XML del complemento y usas el tipo `custom`. Es necesario agregar la información del complemento al PDF por separado usando el parámetro `pdf_custom_section`. - - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoiceEgresoEditInput: title: Egreso allOf: @@ -18064,7 +18074,7 @@ components: complemento en el comprobante si tú mismo construyes el nodo XML del complemento y usas el tipo `custom`. Es necesario agregar la información del complemento al PDF por separado usando el parámetro `pdf_custom_section`. - - $ref: "#/components/schemas/InvoiceCommonInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoicePagoEditInput: title: Pago allOf: @@ -18093,12 +18103,14 @@ components: items: $ref: "#/components/schemas/InvoiceComplementInput" description: Complementos a incluir en la factura. - - $ref: "#/components/schemas/InvoiceCommonEditInputProperties" + - $ref: "#/components/schemas/InvoiceDraftInputProperties" InvoiceNominaEditInput: title: Nómina allOf: - type: object properties: + customer: + $ref: "#/components/schemas/InvoiceCustomerInput" type: type: string const: "N" @@ -18119,6 +18131,8 @@ components: allOf: - type: object properties: + customer: + $ref: "#/components/schemas/InvoiceCustomerInput" type: type: string const: "T" diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index 28c7fd30e..bbe891106 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -121,3 +121,18 @@ const missingOvertimeAmount: components["schemas"]["NominaHorasExtraInput"] = { const publicAidPerception: components["schemas"]["NominaPercepcionInput"] = { ...plainPerception, tipo_percepcion: "056" }; const customPayroll: components["schemas"]["NominaOtroPagoInput"] = { tipo_otro_pago: "002", clave: "ABC", importe: 1 }; void [missingPerceptionAmounts, missingOvertimeAmount, publicAidPerception, customPayroll]; +const incomeWithDefaultUse: components["schemas"]["InvoiceCreateInput"] = { customer: "cus", payment_form: "28", items: [{ quantity: 1, product: { description: "Ejemplo", product_key: "60131324", price: 1 } }] }; +const incomeWithNullUse: components["schemas"]["InvoiceCreateInput"] = { ...incomeWithDefaultUse, use: null }; +const clearedDraft: components["schemas"]["InvoiceCreateInput"] = { status: "draft", customer: null, payment_form: null, use: null }; +const clearedCreditDraft: components["schemas"]["InvoiceEgresoEditInput"] = { type: "E", customer: null }; +const clearedPaymentDraft: components["schemas"]["InvoicePagoEditInput"] = { type: "P", customer: null }; +// @ts-expect-error a payroll customer can be omitted, but cannot be cleared with null +const nullPayrollCustomer: components["schemas"]["InvoiceNominaEditInput"] = { type: "N", customer: null }; +// @ts-expect-error a transfer customer can be omitted, but cannot be cleared with null +const nullTransferCustomer: components["schemas"]["InvoiceTrasladoEditInput"] = { type: "T", customer: null }; +const singlePayment: components["schemas"]["PagoComplementInput"] = { type: "pago", data: { payment_form: "28", related_documents: [{ uuid: "39c85a3f-275b-4341-b259-e8971d9f8a94", installment: 1, last_balance: 1, amount: 1, taxes: [] }] } }; +// @ts-expect-error issued invoices still require a real customer +const nullIssuedCustomer: components["schemas"]["InvoiceCreateInput"] = { customer: null, payment_form: "28", items: incomeWithDefaultUse.items }; +// @ts-expect-error a draft edit cannot request the pending status +const pendingDraftEdit: components["schemas"]["InvoiceEgresoEditInput"] = { type: "E", status: "pending" }; +void [incomeWithDefaultUse, incomeWithNullUse, clearedDraft, clearedCreditDraft, clearedPaymentDraft, nullPayrollCustomer, nullTransferCustomer, singlePayment, nullIssuedCustomer, pendingDraftEdit]; From dc42f9d92f70af309552333390e649cdf2bebd71 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 00:43:29 +0200 Subject: [PATCH 14/33] docs: align draft customers and clarify webhook subscription values --- website/openapi_v2.en.yaml | 8 ++++++-- website/openapi_v2.yaml | 8 ++++++-- website/test/openapi-types.fixture.txt | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 4aa72f3ce..b16ee5680 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -15863,7 +15863,8 @@ components: type: array example: - receipt.status_updated - description: Events enabled for the webhook to listen to. + description: | + Subscribed webhook events. Existing responses may contain "*", but creating or updating a webhook requires explicit event names; the wildcard is not accepted in requests. items: type: string enum: @@ -17059,7 +17060,10 @@ components: description: | Type of document. It can have the values `"I"`: Income, `"P"`: Payment, `"E"`: Egress, `"N"`: Payroll, `"T"`: Transfer. customer: - $ref: '#/components/schemas/CustomerInfo' + description: Invoice customer. Null when the draft has no customer. + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' total: type: number description: Total amount invoiced. diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 557cf5daf..684a2f943 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -15860,7 +15860,8 @@ components: type: array example: - receipt.status_updated - description: Eventos dados de alta para el webhook. + description: | + Eventos a los que está suscrito el webhook. El valor "*" puede aparecer en respuestas existentes, pero no se acepta al crear o actualizar un webhook; envía los nombres de eventos explícitos. items: type: string enum: @@ -17014,7 +17015,10 @@ components: description: | Tipo de comprobante. Puede tener los valores `"I"`: Ingreso, `"P"`: Pago, `"E"`: Egreso, `"N"`: Nómina, `"T"`: Traslado. customer: - $ref: '#/components/schemas/CustomerInfo' + description: Cliente de la factura. Es null cuando el borrador no tiene cliente. + anyOf: + - $ref: '#/components/schemas/CustomerInfo' + - type: 'null' total: type: number description: Monto total facturado. diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index bbe891106..a9e8c6f9c 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -136,3 +136,11 @@ const nullIssuedCustomer: components["schemas"]["InvoiceCreateInput"] = { custom // @ts-expect-error a draft edit cannot request the pending status const pendingDraftEdit: components["schemas"]["InvoiceEgresoEditInput"] = { type: "E", status: "pending" }; void [incomeWithDefaultUse, incomeWithNullUse, clearedDraft, clearedCreditDraft, clearedPaymentDraft, nullPayrollCustomer, nullTransferCustomer, singlePayment, nullIssuedCustomer, pendingDraftEdit]; + +const draftWithoutCustomer: components["schemas"]["InvoiceDraftProperties"]["customer"] = null; +const existingWildcard: NonNullable[number] = "*"; +// @ts-expect-error webhook creation requires explicit event names +const wildcardCreate: components["schemas"]["WebhookCreateInput"] = { url: "https://example.com/hooks", enabled_events: ["*"] }; +// @ts-expect-error webhook editing requires explicit event names +const wildcardEdit: components["schemas"]["WebhookCreateEdit"] = { status: "enabled", enabled_events: ["*"] }; +void [draftWithoutCustomer, existingWildcard, wildcardCreate, wildcardEdit]; From b7063fb68f3b332e0ac58640ab10deb6baf1d86d Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 02:51:30 +0200 Subject: [PATCH 15/33] docs: track and verify OpenAPI checksums --- .gitattributes | 3 +++ .github/workflows/openapi.yml | 2 ++ AGENTS.md | 3 +++ website/openapi.sha256 | 2 ++ website/package.json | 3 ++- website/scripts/hash-openapi.mjs | 24 ++++++++++++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 website/openapi.sha256 create mode 100644 website/scripts/hash-openapi.mjs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..53423cbf5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Keep checksum inputs identical across platforms. +website/openapi_v2*.yaml text eol=lf +website/openapi.sha256 text eol=lf diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 45ef9f9f4..0a89c1e42 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -5,6 +5,8 @@ on: paths: - website/openapi_v2*.yaml - website/scripts/check-openapi.mjs + - website/scripts/hash-openapi.mjs + - website/openapi.sha256 - website/test/openapi-types.fixture.txt - website/package.json - website/pnpm-lock.yaml diff --git a/AGENTS.md b/AGENTS.md index 94611048c..745116458 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,3 +26,6 @@ or a review comment alone as proof of API behavior. - Keep the Spanish and English OpenAPI contracts structurally aligned. - Run the relevant repository checks for specification changes. +- After editing either OpenAPI v2 contract, run `pnpm --dir website hash:openapi` + and commit `website/openapi.sha256` with the contract. `test:openapi` verifies + both hashes against the exact YAML bytes, including documentation changes. diff --git a/website/openapi.sha256 b/website/openapi.sha256 new file mode 100644 index 000000000..2242f4081 --- /dev/null +++ b/website/openapi.sha256 @@ -0,0 +1,2 @@ +864fde318dd2b0fc4a19e61258121757afcae0938665c88681342caced20c643 openapi_v2.yaml +31e565b730ec80b3d9cd17bbae20b144fc8301492199aeb3ed2e77e8a2fe8cad openapi_v2.en.yaml diff --git a/website/package.json b/website/package.json index 2ef5e77ab..3f04c76cd 100644 --- a/website/package.json +++ b/website/package.json @@ -13,7 +13,8 @@ "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", "typecheck": "tsc", - "test:openapi": "node scripts/check-openapi.mjs" + "hash:openapi": "node scripts/hash-openapi.mjs", + "test:openapi": "node scripts/hash-openapi.mjs --check && node scripts/check-openapi.mjs" }, "dependencies": { "@docusaurus/core": "^3.10.1", diff --git a/website/scripts/hash-openapi.mjs b/website/scripts/hash-openapi.mjs new file mode 100644 index 000000000..38cd59c9b --- /dev/null +++ b/website/scripts/hash-openapi.mjs @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { readFile, writeFile } from "node:fs/promises"; + +const root = new URL("../", import.meta.url); +const hashes = []; +for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { + hashes.push( + `${createHash("sha256") + .update(await readFile(new URL(filename, root))) + .digest("hex")} ${filename}`, + ); +} +const content = hashes.join("\n") + "\n"; +const target = new URL("openapi.sha256", root); +if (process.argv.includes("--check")) { + assert.equal( + await readFile(target, "utf8"), + content, + "OpenAPI hashes are stale. Run pnpm hash:openapi.", + ); +} else { + await writeFile(target, content); +} From 6c23055d55c2d1915f40e913c735973522bbf601 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 03:24:20 +0200 Subject: [PATCH 16/33] docs: remove redundant OpenAPI checksum tracking --- .gitattributes | 3 --- .github/workflows/openapi.yml | 2 -- AGENTS.md | 3 --- website/openapi.sha256 | 2 -- website/package.json | 3 +-- website/scripts/hash-openapi.mjs | 24 ------------------------ 6 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 .gitattributes delete mode 100644 website/openapi.sha256 delete mode 100644 website/scripts/hash-openapi.mjs diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 53423cbf5..000000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -# Keep checksum inputs identical across platforms. -website/openapi_v2*.yaml text eol=lf -website/openapi.sha256 text eol=lf diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 0a89c1e42..45ef9f9f4 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -5,8 +5,6 @@ on: paths: - website/openapi_v2*.yaml - website/scripts/check-openapi.mjs - - website/scripts/hash-openapi.mjs - - website/openapi.sha256 - website/test/openapi-types.fixture.txt - website/package.json - website/pnpm-lock.yaml diff --git a/AGENTS.md b/AGENTS.md index 745116458..94611048c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,3 @@ or a review comment alone as proof of API behavior. - Keep the Spanish and English OpenAPI contracts structurally aligned. - Run the relevant repository checks for specification changes. -- After editing either OpenAPI v2 contract, run `pnpm --dir website hash:openapi` - and commit `website/openapi.sha256` with the contract. `test:openapi` verifies - both hashes against the exact YAML bytes, including documentation changes. diff --git a/website/openapi.sha256 b/website/openapi.sha256 deleted file mode 100644 index 2242f4081..000000000 --- a/website/openapi.sha256 +++ /dev/null @@ -1,2 +0,0 @@ -864fde318dd2b0fc4a19e61258121757afcae0938665c88681342caced20c643 openapi_v2.yaml -31e565b730ec80b3d9cd17bbae20b144fc8301492199aeb3ed2e77e8a2fe8cad openapi_v2.en.yaml diff --git a/website/package.json b/website/package.json index 3f04c76cd..2ef5e77ab 100644 --- a/website/package.json +++ b/website/package.json @@ -13,8 +13,7 @@ "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", "typecheck": "tsc", - "hash:openapi": "node scripts/hash-openapi.mjs", - "test:openapi": "node scripts/hash-openapi.mjs --check && node scripts/check-openapi.mjs" + "test:openapi": "node scripts/check-openapi.mjs" }, "dependencies": { "@docusaurus/core": "^3.10.1", diff --git a/website/scripts/hash-openapi.mjs b/website/scripts/hash-openapi.mjs deleted file mode 100644 index 38cd59c9b..000000000 --- a/website/scripts/hash-openapi.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { readFile, writeFile } from "node:fs/promises"; - -const root = new URL("../", import.meta.url); -const hashes = []; -for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { - hashes.push( - `${createHash("sha256") - .update(await readFile(new URL(filename, root))) - .digest("hex")} ${filename}`, - ); -} -const content = hashes.join("\n") + "\n"; -const target = new URL("openapi.sha256", root); -if (process.argv.includes("--check")) { - assert.equal( - await readFile(target, "utf8"), - content, - "OpenAPI hashes are stale. Run pnpm hash:openapi.", - ); -} else { - await writeFile(target, content); -} From 2aeefea3e4a0941d7d48707ef37ca4549915ec17 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 13:20:23 +0200 Subject: [PATCH 17/33] docs: define typed invoice creation responses --- website/openapi_v2.en.yaml | 9 +++------ website/openapi_v2.yaml | 9 +++------ website/test/openapi-types.fixture.txt | 7 +++++++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index b16ee5680..0fdf70515 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -3360,12 +3360,9 @@ paths: content: application/json: schema: - type: object - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/Invoice" - draft: "#/components/schemas/InvoiceDraft" + anyOf: + - $ref: "#/components/schemas/Invoice" + - $ref: "#/components/schemas/InvoiceDraft" "202": description: Request accepted; Facturapi will try to recover the CFDI up to five times, once every 10 minutes content: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 684a2f943..1cbeab9a5 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -3330,12 +3330,9 @@ paths: content: application/json: schema: - type: object - discriminator: - propertyName: status - mapping: - pending: "#/components/schemas/Invoice" - draft: "#/components/schemas/InvoiceDraft" + anyOf: + - $ref: "#/components/schemas/Invoice" + - $ref: "#/components/schemas/InvoiceDraft" "202": description: Solicitud aceptada; Facturapi intentará recuperar el CFDI hasta cinco veces, una cada 10 minutos content: diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index a9e8c6f9c..72e9adab9 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -144,3 +144,10 @@ const wildcardCreate: components["schemas"]["WebhookCreateInput"] = { url: "http // @ts-expect-error webhook editing requires explicit event names const wildcardEdit: components["schemas"]["WebhookCreateEdit"] = { status: "enabled", enabled_events: ["*"] }; void [draftWithoutCustomer, existingWildcard, wildcardCreate, wildcardEdit]; + +// Creation can return an issued invoice or a draft, with typed common fields. +declare const createdInvoiceResponse: operations["createInvoice"]["responses"][200]["content"]["application/json"]; +const createdInvoiceDate: string | null | undefined = createdInvoiceResponse.date; +const createdInvoiceStamp: components["schemas"]["Stamp"] | null | undefined = createdInvoiceResponse.stamp; +void createdInvoiceDate; +void createdInvoiceStamp; From 3e9c63ca6d494e1d45f45047430d45755f8298f2 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 13:33:49 +0200 Subject: [PATCH 18/33] docs: distinguish draft invoice creation variants --- website/openapi_v2.en.yaml | 30 ++++++++++++++++++++---------- website/openapi_v2.yaml | 30 ++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 0fdf70515..3631362c4 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -17493,7 +17493,8 @@ components: type: object description: Invoice data according to its type and initial status. Omit status to stamp; use draft to save a draft. oneOf: - - allOf: + - title: Income + allOf: - $ref: '#/components/schemas/InvoiceIngresoInput' - type: object properties: @@ -17504,7 +17505,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Income (draft) + allOf: - $ref: '#/components/schemas/InvoiceIngresoEditInput' - type: object required: @@ -17516,7 +17518,8 @@ components: status: type: string const: draft - - allOf: + - title: Egress + allOf: - $ref: '#/components/schemas/InvoiceEgresoInput' - type: object required: @@ -17529,7 +17532,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Egress (draft) + allOf: - $ref: '#/components/schemas/InvoiceEgresoEditInput' - type: object required: @@ -17542,7 +17546,8 @@ components: status: type: string const: draft - - allOf: + - title: Payment + allOf: - $ref: '#/components/schemas/InvoicePagoInput' - type: object required: @@ -17555,7 +17560,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Payment (draft) + allOf: - $ref: '#/components/schemas/InvoicePagoEditInput' - type: object required: @@ -17568,7 +17574,8 @@ components: status: type: string const: draft - - allOf: + - title: Payroll + allOf: - $ref: '#/components/schemas/InvoiceNominaInput' - type: object required: @@ -17581,7 +17588,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Payroll (draft) + allOf: - $ref: '#/components/schemas/InvoiceNominaEditInput' - type: object required: @@ -17594,7 +17602,8 @@ components: status: type: string const: draft - - allOf: + - title: Transfer + allOf: - $ref: '#/components/schemas/InvoiceTrasladoInput' - type: object required: @@ -17607,7 +17616,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Transfer (draft) + allOf: - $ref: '#/components/schemas/InvoiceTrasladoEditInput' - type: object required: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 1cbeab9a5..5c1b09819 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -17434,7 +17434,8 @@ components: type: object description: Datos de la factura según su tipo y estado inicial. Omite status para timbrar; usa draft para guardar un borrador. oneOf: - - allOf: + - title: Ingreso + allOf: - $ref: '#/components/schemas/InvoiceIngresoInput' - type: object properties: @@ -17445,7 +17446,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Ingreso (borrador) + allOf: - $ref: '#/components/schemas/InvoiceIngresoEditInput' - type: object required: @@ -17457,7 +17459,8 @@ components: status: type: string const: draft - - allOf: + - title: Egreso + allOf: - $ref: '#/components/schemas/InvoiceEgresoInput' - type: object required: @@ -17470,7 +17473,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Egreso (borrador) + allOf: - $ref: '#/components/schemas/InvoiceEgresoEditInput' - type: object required: @@ -17483,7 +17487,8 @@ components: status: type: string const: draft - - allOf: + - title: Pago + allOf: - $ref: '#/components/schemas/InvoicePagoInput' - type: object required: @@ -17496,7 +17501,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Pago (borrador) + allOf: - $ref: '#/components/schemas/InvoicePagoEditInput' - type: object required: @@ -17509,7 +17515,8 @@ components: status: type: string const: draft - - allOf: + - title: Nómina + allOf: - $ref: '#/components/schemas/InvoiceNominaInput' - type: object required: @@ -17522,7 +17529,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Nómina (borrador) + allOf: - $ref: '#/components/schemas/InvoiceNominaEditInput' - type: object required: @@ -17535,7 +17543,8 @@ components: status: type: string const: draft - - allOf: + - title: Traslado + allOf: - $ref: '#/components/schemas/InvoiceTrasladoInput' - type: object required: @@ -17548,7 +17557,8 @@ components: type: string const: pending default: pending - - allOf: + - title: Traslado (borrador) + allOf: - $ref: '#/components/schemas/InvoiceTrasladoEditInput' - type: object required: From ce658ad3a8ef244c4430e40a78f8944431d6b94a Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 14:04:24 +0200 Subject: [PATCH 19/33] docs: select invoice drafts through status --- website/openapi_v2.en.yaml | 253 +++++++++++++++++-------------------- website/openapi_v2.yaml | 253 +++++++++++++++++-------------------- website/src/pages/api.tsx | 28 +++- 3 files changed, 263 insertions(+), 271 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 3631362c4..b55c94413 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -17442,8 +17442,8 @@ components: enum: - draft description: | - Initial status of the invoice. It is only possible to edit an invoice with status `draft`, - and it is not possible to change the status when editing, so the only allowed value is `draft`. + Invoice status. The value `draft` identifies a draft that has not been stamped or sent to SAT. + Only invoices with this status can be edited; `status` cannot be changed while editing. example: draft date: type: string @@ -17494,142 +17494,127 @@ components: description: Invoice data according to its type and initial status. Omit status to stamp; use draft to save a draft. oneOf: - title: Income - allOf: - - $ref: '#/components/schemas/InvoiceIngresoInput' - - type: object - properties: - type: - type: string - const: I - status: - type: string - const: pending - default: pending - - title: Income (draft) - allOf: - - $ref: '#/components/schemas/InvoiceIngresoEditInput' - - type: object - required: - - status - properties: - type: - type: string - const: I - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceIngresoInput' + - type: object + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceIngresoEditInput' + - type: object + required: + - status + properties: + status: + type: string + const: draft - title: Egress - allOf: - - $ref: '#/components/schemas/InvoiceEgresoInput' - - type: object - required: - - type - properties: - type: - type: string - const: E - status: - type: string - const: pending - default: pending - - title: Egress (draft) - allOf: - - $ref: '#/components/schemas/InvoiceEgresoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: E - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceEgresoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceEgresoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Payment - allOf: - - $ref: '#/components/schemas/InvoicePagoInput' - - type: object - required: - - type - properties: - type: - type: string - const: P - status: - type: string - const: pending - default: pending - - title: Payment (draft) - allOf: - - $ref: '#/components/schemas/InvoicePagoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: P - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoicePagoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoicePagoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Payroll - allOf: - - $ref: '#/components/schemas/InvoiceNominaInput' - - type: object - required: - - type - properties: - type: - type: string - const: 'N' - status: - type: string - const: pending - default: pending - - title: Payroll (draft) - allOf: - - $ref: '#/components/schemas/InvoiceNominaEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: 'N' - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceNominaInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceNominaEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Transfer - allOf: - - $ref: '#/components/schemas/InvoiceTrasladoInput' - - type: object - required: - - type - properties: - type: - type: string - const: T - status: - type: string - const: pending - default: pending - - title: Transfer (draft) - allOf: - - $ref: '#/components/schemas/InvoiceTrasladoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: T - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceTrasladoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceTrasladoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft InvoiceIngresoInput: title: Income required: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 5c1b09819..27b95c50a 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -17385,8 +17385,8 @@ components: enum: - draft description: | - Estado inicial de la factura. Sólo es posible editar una factura con status `draft`, - y no es posible cambiar el status al editar, por lo que el único valor permitido es `draft`. + Estado de la factura. El valor `draft` identifica un borrador que no se ha timbrado ni enviado al SAT. + Sólo es posible editar facturas con este estado; al editarlas, no se puede cambiar `status`. example: draft date: type: string @@ -17435,142 +17435,127 @@ components: description: Datos de la factura según su tipo y estado inicial. Omite status para timbrar; usa draft para guardar un borrador. oneOf: - title: Ingreso - allOf: - - $ref: '#/components/schemas/InvoiceIngresoInput' - - type: object - properties: - type: - type: string - const: I - status: - type: string - const: pending - default: pending - - title: Ingreso (borrador) - allOf: - - $ref: '#/components/schemas/InvoiceIngresoEditInput' - - type: object - required: - - status - properties: - type: - type: string - const: I - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceIngresoInput' + - type: object + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceIngresoEditInput' + - type: object + required: + - status + properties: + status: + type: string + const: draft - title: Egreso - allOf: - - $ref: '#/components/schemas/InvoiceEgresoInput' - - type: object - required: - - type - properties: - type: - type: string - const: E - status: - type: string - const: pending - default: pending - - title: Egreso (borrador) - allOf: - - $ref: '#/components/schemas/InvoiceEgresoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: E - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceEgresoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceEgresoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Pago - allOf: - - $ref: '#/components/schemas/InvoicePagoInput' - - type: object - required: - - type - properties: - type: - type: string - const: P - status: - type: string - const: pending - default: pending - - title: Pago (borrador) - allOf: - - $ref: '#/components/schemas/InvoicePagoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: P - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoicePagoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoicePagoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Nómina - allOf: - - $ref: '#/components/schemas/InvoiceNominaInput' - - type: object - required: - - type - properties: - type: - type: string - const: 'N' - status: - type: string - const: pending - default: pending - - title: Nómina (borrador) - allOf: - - $ref: '#/components/schemas/InvoiceNominaEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: 'N' - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceNominaInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceNominaEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft - title: Traslado - allOf: - - $ref: '#/components/schemas/InvoiceTrasladoInput' - - type: object - required: - - type - properties: - type: - type: string - const: T - status: - type: string - const: pending - default: pending - - title: Traslado (borrador) - allOf: - - $ref: '#/components/schemas/InvoiceTrasladoEditInput' - - type: object - required: - - status - - type - properties: - type: - type: string - const: T - status: - type: string - const: draft + type: object + oneOf: + - title: pending + allOf: + - $ref: '#/components/schemas/InvoiceTrasladoInput' + - type: object + required: + - type + properties: + status: + type: string + const: pending + default: pending + - title: draft + allOf: + - $ref: '#/components/schemas/InvoiceTrasladoEditInput' + - type: object + required: + - status + - type + properties: + status: + type: string + const: draft InvoiceIngresoInput: title: Ingreso required: diff --git a/website/src/pages/api.tsx b/website/src/pages/api.tsx index 26712324c..d7fa890f5 100644 --- a/website/src/pages/api.tsx +++ b/website/src/pages/api.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import ApiDoc from '@theme/ApiDoc'; import useSpecData from '@theme/useSpecData'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -8,6 +8,28 @@ function CustomPage() { const {i18n} = useDocusaurusContext(); const locale = i18n.currentLocale; const specData = useSpecData(`api-${locale}`); + const displaySpecData = useMemo(() => { + const spec = structuredClone(specData.spec); + // ReDoc needs named discriminator variants to render a status selector. + // Keep this presentation hint out of the contract: status may be omitted. + spec.components.schemas.InvoiceCreateInput.oneOf = + spec.components.schemas.InvoiceCreateInput.oneOf.map( + (invoiceType: {oneOf: {title: string}[]}, typeIndex: number) => { + const mapping: Record = {}; + return { + ...invoiceType, + oneOf: invoiceType.oneOf.map((variant) => { + const name = `InvoiceCreateDisplay${typeIndex}${variant.title}`; + spec.components.schemas[name] = variant; + mapping[variant.title] = `#/components/schemas/${name}`; + return {$ref: mapping[variant.title]}; + }), + discriminator: {propertyName: 'status', mapping}, + }; + }, + ); + return {...specData, spec}; + }, [specData]); return ( ); } -export default CustomPage; \ No newline at end of file +export default CustomPage; From 2bde6968e1c1dcabeb5f56599fa1d6ffc665daf3 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 14:22:57 +0200 Subject: [PATCH 20/33] docs: place invoice status before conditional fields --- website/src/css/custom.css | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/website/src/css/custom.css b/website/src/css/custom.css index c849a4172..e7dedfb0d 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -390,6 +390,44 @@ body[data-scrolled='true'] .navbar { display: none !important; } +/* Choose the initial invoice status before reviewing its conditional fields. */ +[id='operation/createInvoice'] tbody:has(> tr > td[title='status'] + td select) { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + + > tr { + display: grid; + grid-template-columns: subgrid; + grid-column: 1 / -1; + } + + > tr > td { + width: auto; + } + + > tr > td[colspan] { + grid-column: 1 / -1; + } + + > tr:has(> td[title='status']) { + order: -1; + + > td + td > div { + display: flex; + flex-direction: column; + + > div:has(> select) { + order: -1; + margin-bottom: 0.5rem; + } + } + } + + @media (max-width: 50rem) { + grid-template-columns: minmax(0, 1fr); + } +} + html[data-theme='dark'] .redocusaurus button[aria-expanded='true'] { border-color: transparent !important; } From 572b6217e93b65991c626d78b6e42e363391ec90 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 14:32:14 +0200 Subject: [PATCH 21/33] docs: clarify accepted ISO date formats and correct descriptions --- website/openapi_v2.en.yaml | 35 +++++++++++++++++++------------- website/openapi_v2.yaml | 41 ++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index b55c94413..abb5dd6dd 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -12712,6 +12712,13 @@ components: Returns the results before the given cursor. Only with `pagination=cursor`; mutually exclusive with `after`. schemas: + DateOrDateTime: + description: Date in YYYY-MM-DD format or an ISO8601 date and time. + anyOf: + - type: string + format: date + - type: string + format: date-time InvoiceGlobalInvoiceCreatedEvent: allOf: - $ref: '#/components/schemas/EventBase' @@ -13861,16 +13868,16 @@ components: - `"O"` (Ordinary): For payments made in a regular manner, such as salaries. - `"E"` (Extraordinary): For payments outside the ordinary, such as settlements, bonuses, or Christmas bonuses. fecha_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: "Date the employee was paid. If omitted, the current date and time are used." fecha_inicial_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: Initial date of the payment period. fecha_final_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: Final date of the payment period. num_dias_pagados: type: number @@ -14317,8 +14324,8 @@ components: type: string description: Social security number. fecha_inicio_rel_laboral: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: | Start date of the employment relationship between the employer and the employee. @@ -18458,8 +18465,8 @@ components: - periodicity properties: from: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-01" description: | Initial date of the receipts that will be included in the global invoice. @@ -18467,8 +18474,8 @@ components: fortnight, or month), according to the value of "Periodicity" (`periodicity`) in the receipts configuration of your organization. This value is required when the `receipts` field is sent. to: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-31" description: | End date of the receipts that will be included in the global invoice. @@ -18500,8 +18507,8 @@ components: description: Series. Alphanumeric characters designated by the company for internal control and without fiscal validity. example: "F" date: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-01" description: "Invoice issuance date. If omitted, the end date (`to`) is used, capped at the current date and time." payment_form: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 27b95c50a..2082883a4 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -2762,7 +2762,7 @@ paths: Puedes usar el ID del producto para crear facturas sin tener que enviar todos los datos del producto cada vez. - Te en cuenta que los productos que crees en ambiente _Test_ **no se + Ten en cuenta que los productos que crees en ambiente _Test_ **no se comparten** con el ambiente _Live_. x-codeSamples: - lang: Bash @@ -7153,7 +7153,7 @@ paths: description: | Realiza una solicitud de cancelación de retención ante el SAT. - A diferencia de las facturas comúnes, la cancelación de la retención es inmediata y no requiere autorización de parte del receptor. + A diferencia de las facturas comunes, la cancelación de la retención es inmediata y no requiere autorización de parte del receptor. Si el status de la retención es `draft`, este método la eliminará de la base de datos sin llamar al SAT/PAC y sin requerir parámetros de cancelación. @@ -11423,7 +11423,7 @@ paths: tags: - webhooks summary: Eliminar Webhook - description: Elimina el webhook pertenciente a la organización. + description: Elimina el webhook perteneciente a la organización. x-codeSamples: - lang: Bash label: cURL @@ -12663,6 +12663,13 @@ components: Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. schemas: + DateOrDateTime: + description: Fecha en formato YYYY-MM-DD o fecha y hora en formato ISO8601. + anyOf: + - type: string + format: date + - type: string + format: date-time InvoiceGlobalInvoiceCreatedEvent: allOf: - $ref: '#/components/schemas/EventBase' @@ -13810,16 +13817,16 @@ components: - `“O”` (Ordinaria): Cuando corresponde a un pago que se realiza de manera habitual, como sueldos. - `“E”` (Extraordinaria): Para pagos fuera de lo habitual, como liquidaciones, aguinaldos o bonos. fecha_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: "Fecha de pago de la nómina al trabajador. Si se omite, se utiliza la fecha y hora actuales." fecha_inicial_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: Fecha inicial del periodo de pago. fecha_final_pago: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: Fecha final del periodo de pago. num_dias_pagados: type: number @@ -14265,8 +14272,8 @@ components: type: string description: Número de seguridad social. fecha_inicio_rel_laboral: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" description: Fecha de inicio de la relación laboral entre el empleador y el empleado. antiguedad: oneOf: @@ -18380,8 +18387,8 @@ components: - periodicity properties: from: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-01" description: | Fecha inicial de los recibos que se incluirán en la factura global. @@ -18389,8 +18396,8 @@ components: quincena o mes), según el valor de "Periodicidad" (`periodicity`) en la configuración de recibos de tu organización. Este valor es requerido cuando se envíe el campo `receipts`. to: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-31" description: | Fecha final de los recibos que se incluirán en la factura global. @@ -18420,8 +18427,8 @@ components: maxLength: 25 description: Serie. Caracteres designados por la empresa para control interno y sin validez fiscal. date: - type: string - format: date + allOf: + - $ref: "#/components/schemas/DateOrDateTime" example: "2022-01-01" description: "Fecha de emisión de la factura. Si se omite, se utiliza la fecha final (`to`), limitada a la fecha y hora actuales." payment_form: From 3e49b06805fcfcadcab2d968a9e627cc9243434e Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 15:12:04 +0200 Subject: [PATCH 22/33] docs: improve API reference order and update renderer --- website/docusaurus.config.js | 2 +- website/openapi_v2.en.yaml | 3870 +++++++++++++++++----------------- website/openapi_v2.yaml | 3538 +++++++++++++++---------------- website/package.json | 14 +- website/pnpm-lock.yaml | 636 +++--- website/pnpm-workspace.yaml | 4 + website/src/css/custom.css | 15 +- 7 files changed, 4058 insertions(+), 4021 deletions(-) diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index d541e9af6..709f1f74f 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -62,7 +62,7 @@ const darkCodeTheme = require("prism-react-renderer").themes.dracula; }, options: { disableSearch: true, - requiredPropsFirst: true, + sortRequiredPropsFirst: true, noAutoAuth: true, }, }, diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index abb5dd6dd..36d4b5acd 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -3651,58 +3651,30 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests: - post: - operationId: createInvoiceZipRequest + /invoices/{invoice_id}: + get: + operationId: getInvoice tags: - invoice - summary: Create or retrieve a monthly ZIP request - description: | - Creates a request to generate a ZIP file containing one month of invoices, or retrieves the existing request with the same filters. - - This operation is idempotent. Invoice types are normalized, so `["I", "E"]` and `["E", "I"]` resolve to the same request. Identical concurrent calls also return the same request. - - If an earlier request has a `failed` status, calling this method again retries it. Before retrying, the previous error and task fields, processed progress, and failed-document list are cleared. If scheduling fails, the request is saved with a `failed` status and the API returns a `5xx` error. - - This method requires a live-mode organization API key, an active subscription, and permission to read invoices. Test-mode keys return HTTP 402. + summary: Retrieve invoice by ID + description: Returns the `Invoice` object with the specified ID. If the invoice does not exist, a 404 error will be returned. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests \ - -H "Authorization: Bearer sk_live_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "year": 2025, - "month": 3, - "issuer_type": "issuing", - "invoice_types": ["I", "E"] - }' + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequest = await facturapi.invoices.createZipRequest({ - year: 2025, - month: 3, - issuer_type: 'issuing', - invoice_types: ['I', 'E'] - }); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.retrieve('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequest = await facturapi.Invoice.CreateZipRequestAsync( - new Dictionary - { - ["year"] = 2025, - ["month"] = 3, - ["issuer_type"] = "issuing", - ["invoice_types"] = new[] { "I", "E" } - } - ); + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.RetrieveAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | @@ -3710,497 +3682,448 @@ paths: import java.util.List; import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequest = facturapi.invoices().createZipRequest( - Map.of( - "year", 2025, - "month", 3, - "issuer_type", "issuing", - "invoice_types", List.of("I", "E") - ) - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().retrieve( + "inv_123" + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequest = $facturapi->Invoices->createZipRequest([ - "year" => 2025, - "month" => 3, - "issuer_type" => "issuing", - "invoice_types" => ["I", "E"] - ]); - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/InvoiceZipRequestCreateInput" + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->retrieve( "58e93bd8e86eb318b019743d" ); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: ZIP request created or retrieved successfully. + description: "`Invoice` object" content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequest" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNoInvoices" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - get: - operationId: listInvoiceZipRequests + put: + operationId: updateDraftInvoice tags: - invoice - summary: List monthly ZIP requests + summary: Edit draft invoice description: | - Returns a paginated list of ZIP requests. `year` and `month` must be provided together. `invoice_types` filters by one type or an exact normalized array. + Updates the information of a draft invoice, setting only the values for + the paramenters that are sent. Undefined values will not be modified. - This method requires a live-mode organization API key, an active subscription, and permission to read invoices. + In the `Invoice` response object, Facturapi will automatically assign the + `is_ready_to_stamp` field with the value `true` if the invoice passes the + minimum validation required to be stamped; otherwise, the + `is_ready_to_stamp` field will be `false`. x-codeSamples: - lang: Bash label: cURL source: | - curl "https://www.facturapi.io/v2/invoices/zip-requests?year=2025&month=3&status=finished&limit=20&page=1" \ - -H "Authorization: Bearer sk_live_API_KEY" + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + -X PUT \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "payment_form": "06" + }' - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequests = await facturapi.invoices.listZipRequests({ - year: 2025, - month: 3, - status: 'finished', - limit: 20, - page: 1 - }); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.updateDraft( + '58e93bd8e86eb318b019743d', + { + payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO + } + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequests = await facturapi.Invoice.ListZipRequestsAsync( + var facturapi = new Facturapi("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.UpdateDraftAsync( + "58e93bd8e86eb318b019743d", new Dictionary { - ["year"] = 2025, - ["month"] = 3, - ["status"] = "finished", - ["limit"] = 20, - ["page"] = 1 + ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO } ); - lang: Java label: Java source: | import io.facturapi.Facturapi; + import java.util.List; import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequests = facturapi.invoices().listZipRequests( - Map.of( - "year", 2025, - "month", 3, - "status", "finished", - "limit", 20, - "page", 1 - ) - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().updateDraft("inv_123", Map.of( + "items", List.of( + Map.of( + "quantity", 1, + "product", "prod_123" + ) + ) + )); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequests = $facturapi->Invoices->listZipRequests([ - "year" => 2025, - "month" => 3, - "status" => "finished", - "limit" => 20, - "page" => 1 + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->updateDraft("58e93bd8e86eb318b019743d", [ + "payment_form" => \Facturapi\PaymentForm::EFECTIVO ]); parameters: - - in: query - name: year - schema: - type: integer - minimum: 2000 - maximum: 9999 - description: Year to filter. Must be provided with `month`. - - in: query - name: month - schema: - type: integer - minimum: 1 - maximum: 12 - description: Month to filter. Must be provided with `year`. - - in: query - name: status - schema: - $ref: "#/components/schemas/InvoiceZipRequestStatus" - description: ZIP request status. - - in: query - name: issuer_type - schema: - $ref: "#/components/schemas/IssuingType" - description: Filters issued or received invoices. - - in: query - name: invoice_types - schema: - type: array - uniqueItems: true - items: - $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" - description: Filters by one invoice type or an exact normalized array. - - in: query - name: page + - in: path + name: invoice_id schema: - type: integer - minimum: 1 - default: 1 - description: Results page, starting at 1. - - $ref: "#/components/parameters/SearchLimit" + type: string + required: true + description: ID of the invoice to edit + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Paginated ZIP request results. + description: "`Invoice` object edited successfully" content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequestSearchResult" + $ref: "#/components/schemas/InvoiceDraft" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}: - get: - operationId: retrieveInvoiceZipRequest + delete: + operationId: cancelInvoice tags: - invoice - summary: Retrieve a monthly ZIP request + summary: Cancel invoice description: | - Retrieves a ZIP request. Poll this method until the status becomes `finished` or `failed`. Once it is `finished`, call the download method. + Creates a cancellation request to the SAT for the specified invoice, using the **SAT's new cancellation scheme (effective since 2022)**. - Requires a live-mode organization API key, an active subscription, and permission to read invoices. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000 \ - -H "Authorization: Bearer sk_live_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; + When using this method, the following results can occur: - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequest = await facturapi.invoices.retrieveZipRequest( - '66b0f0000000000000000000' + - The call returns an error with the explanation of why the cancellation could not be completed. + - The call is successful and returns an `invoice` object with the property `status: "canceled"` (the cancellation has already been accepted by the SAT). + - The call is successful, but the cancellation requires confirmation from your client, in which case the response will be the `invoice` object with the properties `status: "valid"` and `cancellation_status: "pending"`. + - The call is successful, but the SAT replies that the request was received and is being validated, in which case the response will be `status: "valid"` and `cancellation_status: "verifying"`. + + In the `pending` or `verifying` scenarios, the value of `cancellation_status` will be automatically updated by Facturapi when the SAT or your client accepts, rejects, or lets the request expire, so that when you query an invoice (using [Get Invoice](#tag/invoice/operation/getInvoice)), the `cancellation_status` property will reflect the most recent status of the request. + + Check the possible values of `cancellation_status` below. + + After the cancellation, the invoice will no longer be valid, the object will change its `status` to `"canceled"` and will still be available for future queries. + + If the status of the invoice is `draft`, this method will delete it from the database. + + If the status of the invoice is not `valid`, this method will return an error. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d?motive=02 \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X DELETE + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.cancel( + '58e93bd8e86eb318b019743d', + { motive: '02' } ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequest = await facturapi.Invoice.RetrieveZipRequestAsync( - "66b0f0000000000000000000" + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.CancelAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["motive"] = "02" + } ); - lang: Java label: Java source: | import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequest = facturapi.invoices().retrieveZipRequest( - "66b0f0000000000000000000" - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().cancel( + "inv_123", + Map.of( + "motive", "02" + ) + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequest = $facturapi->Invoices->retrieveZipRequest( - "66b0f0000000000000000000" + $facturapi = new Facturapi("sk_test_API_KEY"); + $canceled_invoice = $facturapi->Invoices->cancel( + "58e93bd8e86eb318b019743d", + [ + "motive" => "02" + ] ); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice to cancel + - in: query + name: motive + required: true + schema: + type: string + enum: + - "01" + - "02" + - "03" + - "04" + description: | + Key representing the motive for the cancellation of the invoice. + + Possible values: + + - `01`: **Invoice issued with errors with relation**. When the invoice contains any errors in quantities, keys, or any other data and the replacement invoice has already been issued, which should be indicated through the `substitution` attribute. + - `02`: **Invoice issued with errors without relation**. When the invoice contains any errors in quantities, keys, or any other data and it is not required to be related to another invoice. + - `03`: **Operation not carried out**. When the sale or transaction was not completed. + - `04`: **Nominative operation related to the global invoice**. When it is necessary to cancel an invoice to the general public because the customer requests their invoice. + - in: query + name: substitution + required: false + schema: + type: string + description: | + ID of the invoice that replaces the invoice being canceled. + + You can use either the ID assigned by Facturapi or the fiscal folio (UUID). security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: ZIP request retrieved successfully. + description: "`Invoice` object after cancellation" content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequest" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}/zip: - get: - operationId: downloadInvoiceZipRequest + /invoices/{invoice_id}/copy: + post: + operationId: copyToDraftInvoice tags: - invoice - summary: Download a monthly ZIP + summary: Copy to draft description: | - Downloads the ZIP for a finished request. The filename uses the `YYYY-MM.zip` format. - - Requires a live-mode organization API key, an active subscription, and permission to read invoices. + Creates a new draft invoice with the same information as the specified invoice. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/zip \ - -H "Authorization: Bearer sk_live_API_KEY" \ - --output 2025-03.zip + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/copy \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST - lang: JavaScript label: Node.js source: | - import fs from 'fs'; - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipStream = await facturapi.invoices.downloadZipRequest( - '66b0f0000000000000000000' - ); - zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.copyToDraft('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipStream = await facturapi.Invoice.DownloadZipRequestAsync( - "66b0f0000000000000000000" - ); - await using var file = File.Create("2025-03.zip"); - await zipStream.CopyToAsync(file); + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.CopyToDraftAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.io.InputStream; - import java.nio.file.Files; - import java.nio.file.Path; - import java.nio.file.StandardCopyOption; + import java.util.List; + import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - try (InputStream zipStream = facturapi.invoices().downloadZipRequest( - "66b0f0000000000000000000" - )) { - Files.copy(zipStream, Path.of("./2025-03.zip"), StandardCopyOption.REPLACE_EXISTING); - } + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var draft = facturapi.invoices().copyToDraft( + "inv_123" + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zip = $facturapi->Invoices->downloadZipRequest( - "66b0f0000000000000000000" - ); - file_put_contents("2025-03.zip", $zip); + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->copyToDraft("58e93bd8e86eb318b019743d"); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice to copy security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Generated ZIP file. - headers: - Content-Disposition: - description: Suggested filename in `attachment; filename="YYYY-MM.zip"` format. - schema: - type: string + description: "`Invoice` draft object created successfully" content: - application/zip: + application/json: schema: - type: string - format: binary + $ref: "#/components/schemas/InvoiceDraft" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" - "409": - $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}/download-url: - get: - operationId: getInvoiceZipRequestDownloadUrl + /invoices/{invoice_id}/stamp: + post: + operationId: stampDraftInvoice tags: - invoice - summary: Get monthly ZIP download URL + summary: Stamp draft invoice description: | - Returns a temporary URL for downloading the ZIP of a finished request without the file travelling through your server. + Stamps a draft invoice and sends it to the SAT for validation. - The URL grants access to that one file while it is valid: treat it as a credential and do not store it. Requires a live-mode organization API key, an active subscription, and permission to read invoices. + When using this method, the value of the `is_ready_to_stamp` field (assigned by Facturapi) + must be `true`. Otherwise, the call will return an error. To get the value of `is_ready_to_stamp`, + use the [Get Invoice](#tag/invoice/operation/getInvoice) method. + + This method does not allow editing the invoice, only stamping it. If you need to edit + information in the invoice before stamping it, use the [Edit Draft Invoice](#tag/invoice/operation/editDraftInvoice) method. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/download-url \ - -H "Authorization: Bearer sk_live_API_KEY" + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/stamp \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const stampedInvoice = await facturapi.invoices.stampDraft('58e93bd8e86eb318b019743d'); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var stampedInvoice = await facturapi.Invoice.StampDraftAsync("58e93bd8e86eb318b019743d"); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; - const facturapi = new Facturapi('sk_live_API_KEY'); - const download = await facturapi.invoices.downloadZipRequestUrl( - '66b0f0000000000000000000' - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - console.log(download.url, download.expires_at); + var invoice = facturapi.invoices().stampDraft( + "inv_123", + Map.of( + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + $stamped_invoice = $facturapi->Invoices->stampDraft("58e93bd8e86eb318b019743d"); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" - security: - - "SecretLiveKey": [] - responses: - "200": - description: Temporary download URL for the generated ZIP file. - content: - application/json: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice to stamp + - in: query + name: async + schema: + type: boolean + required: false + description: | + Useful for large invoices. If sent `false` or not sent, the call will wait for the SAT to respond by stamping the invoice. + If sent `true`, the call will return immediately with the `invoice` object in status `pending`, and its status can be checked + for a change to `valid` at a later time. + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: "`Invoice` object stamped successfully" + content: + application/json: schema: - $ref: "#/components/schemas/SignedDownloadUrl" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" "409": - $ref: "#/components/responses/InvoiceZipRequestNotReady" + $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/preview/pdf: - post: - operationId: previewInvoicePdf + + /invoices/{invoice_id}/status: + put: + operationId: updateInvoiceStatus tags: - invoice - summary: Preview invoice PDF + summary: | + Update invoice status description: | - Generates a PDF preview of an invoice **without stamping it**. The PDF will be generated with the default template of your organization. + Consults the status of a stamped invoice at the SAT and updates the invoice object with the most recent information. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/preview/pdf \ + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/status \ -H "Authorization: Bearer sk_test_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "customer": { - "legal_name": "Dunder Mifflin", - "email": "email@example.com", - "tax_id": "ABC101010111", - "tax_system": "601", - "address": { - "zip": "85900" - } - }, - "items": [{ - "quantity": 2, - "product": { - "description": "Ukelele", - "product_key": "60131324", - "price": 345.60 - } - }], - "payment_form": "06", - "folio_number": 914, - "series": "F" - }' + -X PUT - lang: JavaScript label: Node.js source: | - const Facturapi = require('facturapi'); - - const facturapi = new Facturapi('sk_live_API_KEY'); - const pdfStream = await facturapi.invoices.previewPdf({ - customer: { - legal_name: 'Dunder Mifflin', - email: 'email@example.com', - tax_id: 'ABC101010111', - tax_system: '601', - address: { - zip: '85900' - } - }, - items: [{ - quantity: 2, - product: { - description: 'Ukelele', - product_key: '60131324', - price: 345.60 - } - }], - payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO, - folio_number: 914, - series: 'F' - }); - // Save the PDF to a file - const fs = require('fs'); - const file = fs.createWriteStream('/route/to/save/invoice.pdf'); - pdfStream.pipe(file); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.updateStatus('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var pdfStream = await facturapi.Invoice.PreviewPdfAsync(new Dictionary - { - ["customer"] = new Dictionary - { - ["legal_name"] = "Dunder Mifflin", - ["email"] = "email@example.com", - ["tax_id"] = "ABC101010111", - ["tax_system"] = "601", - ["address"] = new Dictionary - { - ["zip"] = "85900" - } - }, - ["items"] = new Dictionary[] - { - new Dictionary - { - ["product"] = new Dictionary - { - ["description"] = "Ukelele", - ["product_key"] = "60131324", - ["price"] = 345.60 - } - } - }, - ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO, - ["folio_number"] = 914, - ["series"] = "F" - }); - // Save the PDF to a file - var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.pdf", FileMode.Create); - pdfStream.CopyTo(file); - file.Close(); + var facturapi = new Facturapi + var invoice = await facturapi.Invoice.UpdateStatusAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | @@ -4210,94 +4133,30 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var pdf = facturapi.invoices().previewPdf( - Map.of( - "customer", "cus_123", - "items", List.of( - Map.of( - "quantity", 1, - "product", "prod_123" - ) - ) - )); + var invoice = facturapi.invoices().updateStatus( + "inv_123" + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $pdfContent = $facturapi->Invoices->previewPdf([ - "customer" => [ - "legal_name" => "Dunder Mifflin", - "email" => "email@example.com", - "tax_id" => "ABC101010111", - "tax_system" => "601", - "address" => [ - "zip" => "85900" - ] - ], - "items" => [ - [ - "quantity" => 2, - "product" => [ - "description" => "Ukelele", - "product_key" => "60131324", - "price" => 345.60, - "sku" => "ABC4567" - ] - ] - ], - "payment_form" => \Facturapi\PaymentForm::EFECTIVO, - "folio_number" => 914, - "series" => "F" - ]); - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: PDF binary content - content: - application/pdf: - schema: - type: string - format: binary - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/preview/pdf/download-url: - post: - operationId: previewInvoicePdfUrl - tags: - - invoice - summary: Get invoice PDF preview URL - description: Returns a temporary URL for an unstamped invoice PDF preview. - x-codeSamples: - - lang: JavaScript - label: Node.js - source: | - const download = await facturapi.invoices.previewPdfUrl({ - customer: 'cus_123', - items: [{ product: 'prod_123' }], - payment_form: '06' - }); - console.log(download.url, download.expires_at); - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->updateStatus("58e93bd8e86eb318b019743d"); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice to update security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the PDF preview. + description: "`Invoice` object updated successfully" content: application/json: schema: - $ref: "#/components/schemas/SignedDownloadUrl" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": @@ -4306,117 +4165,269 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}: + + /invoices/{invoice_id}/payment-summary: get: - operationId: getInvoice + operationId: getInvoicePaymentSummary tags: - invoice - summary: Retrieve invoice by ID - description: Returns the `Invoice` object with the specified ID. If the invoice does not exist, a 404 error will be returned. + summary: Payment summary + description: | + Returns the information needed to add this invoice as a related document in a payment + complement (complemento de pago): the installment number according to the payment history, + the previous balance (`last_balance`), and the invoice tax breakdown prorated to the amount + being paid. + + The response is ready to be used as an element of `related_documents` when + [creating a Payment invoice](#tag/invoice/operation/createInvoice). + + The `amount` parameter must be expressed in the invoice currency and cannot exceed the + outstanding balance (`amount_due`). When the payment is received in a different currency, + convert the amount before calling this method. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + curl "https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/payment-summary?amount=100" \ -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.retrieve('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.RetrieveAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const summary = await facturapi.invoices.paymentSummary( + '58e93bd8e86eb318b019743d', + { amount: 100 } + ); - var invoice = facturapi.invoices().retrieve( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->retrieve( "58e93bd8e86eb318b019743d" ); + // The summary goes as-is into the complement's related documents + const invoice = await facturapi.invoices.create({ + type: 'P', + customer: 'customer_id', + complements: [ + { + type: 'pago', + data: [ + { + payment_form: '28', + related_documents: [summary] + } + ] + } + ] + }); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID of the invoice + description: ID of the income invoice (PPD payment method) being paid + - in: query + name: amount + schema: + type: number + required: true + description: Amount being paid on this invoice, expressed in the invoice currency. Cannot exceed the outstanding balance. security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: "`Invoice` object" + description: Related document summary content: application/json: schema: - $ref: "#/components/schemas/Invoice" + type: object + required: + - uuid + - series + - installment + - last_balance + - total + - currency + - amount + - taxes + properties: + uuid: + type: string + description: Invoice UUID + folio_number: + type: number + description: Invoice folio number. Omitted when the invoice has none registered. + series: + type: ["string","null"] + description: Invoice series + installment: + type: number + description: Installment number corresponding to this payment + last_balance: + type: number + description: Invoice outstanding balance before this payment + total: + type: number + description: Invoice total + currency: + type: string + description: Invoice currency + amount: + type: number + description: Amount paid in this installment + taxes: + type: array + description: Invoice taxes prorated to the paid amount + items: + type: object + properties: + base: + type: number + description: Tax base prorated to the paid amount + rate: + type: number + description: Tax rate or quota + type: + type: string + description: Tax type (VAT, income tax withholding, etc.) + factor: + type: string + description: Factor type (Rate, Exempt, etc.) + withholding: + type: boolean + description: Whether this tax is a withholding + example: + uuid: 39c85a3f-275b-4341-b259-e8971d9f8a94 + folio_number: 914 + series: F + installment: 2 + last_balance: 245.6 + total: 345.6 + currency: MXN + amount: 100 + taxes: + - base: 86.21 + rate: 0.16 + type: IVA + factor: Tasa + withholding: false "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - put: - operationId: updateDraftInvoice + + /invoices/preview/pdf: + post: + operationId: previewInvoicePdf tags: - invoice - summary: Edit draft invoice + summary: Preview invoice PDF description: | - Updates the information of a draft invoice, setting only the values for - the paramenters that are sent. Undefined values will not be modified. - - In the `Invoice` response object, Facturapi will automatically assign the - `is_ready_to_stamp` field with the value `true` if the invoice passes the - minimum validation required to be stamped; otherwise, the - `is_ready_to_stamp` field will be `false`. + Generates a PDF preview of an invoice **without stamping it**. The PDF will be generated with the default template of your organization. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ - -X PUT \ + curl https://www.facturapi.io/v2/invoices/preview/pdf \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "payment_form": "06" - }' + "customer": { + "legal_name": "Dunder Mifflin", + "email": "email@example.com", + "tax_id": "ABC101010111", + "tax_system": "601", + "address": { + "zip": "85900" + } + }, + "items": [{ + "quantity": 2, + "product": { + "description": "Ukelele", + "product_key": "60131324", + "price": 345.60 + } + }], + "payment_form": "06", + "folio_number": 914, + "series": "F" + }' - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.updateDraft( - '58e93bd8e86eb318b019743d', - { - payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO - } - ); + const Facturapi = require('facturapi'); + + const facturapi = new Facturapi('sk_live_API_KEY'); + const pdfStream = await facturapi.invoices.previewPdf({ + customer: { + legal_name: 'Dunder Mifflin', + email: 'email@example.com', + tax_id: 'ABC101010111', + tax_system: '601', + address: { + zip: '85900' + } + }, + items: [{ + quantity: 2, + product: { + description: 'Ukelele', + product_key: '60131324', + price: 345.60 + } + }], + payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO, + folio_number: 914, + series: 'F' + }); + // Save the PDF to a file + const fs = require('fs'); + const file = fs.createWriteStream('/route/to/save/invoice.pdf'); + pdfStream.pipe(file); - lang: csharp label: C# source: | - var facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.UpdateDraftAsync( - "58e93bd8e86eb318b019743d", - new Dictionary + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var pdfStream = await facturapi.Invoice.PreviewPdfAsync(new Dictionary + { + ["customer"] = new Dictionary { - ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO - } - ); + ["legal_name"] = "Dunder Mifflin", + ["email"] = "email@example.com", + ["tax_id"] = "ABC101010111", + ["tax_system"] = "601", + ["address"] = new Dictionary + { + ["zip"] = "85900" + } + }, + ["items"] = new Dictionary[] + { + new Dictionary + { + ["product"] = new Dictionary + { + ["description"] = "Ukelele", + ["product_key"] = "60131324", + ["price"] = 345.60 + } + } + }, + ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO, + ["folio_number"] = 914, + ["series"] = "F" + }); + // Save the PDF to a file + var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.pdf", FileMode.Create); + pdfStream.CopyTo(file); + file.Close(); - lang: Java label: Java source: | @@ -4426,7 +4437,9 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.invoices().updateDraft("inv_123", Map.of( + var pdf = facturapi.invoices().previewPdf( + Map.of( + "customer", "cus_123", "items", List.of( Map.of( "quantity", 1, @@ -4436,29 +4449,82 @@ paths: )); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->updateDraft("58e93bd8e86eb318b019743d", [ - "payment_form" => \Facturapi\PaymentForm::EFECTIVO - ]); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the invoice to edit - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" + $facturapi = new Facturapi("sk_live_API_KEY"); + $pdfContent = $facturapi->Invoices->previewPdf([ + "customer" => [ + "legal_name" => "Dunder Mifflin", + "email" => "email@example.com", + "tax_id" => "ABC101010111", + "tax_system" => "601", + "address" => [ + "zip" => "85900" + ] + ], + "items" => [ + [ + "quantity" => 2, + "product" => [ + "description" => "Ukelele", + "product_key" => "60131324", + "price" => 345.60, + "sku" => "ABC4567" + ] + ] + ], + "payment_form" => \Facturapi\PaymentForm::EFECTIVO, + "folio_number" => 914, + "series" => "F" + ]); + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: "`Invoice` object edited successfully" + description: PDF binary content + content: + application/pdf: + schema: + type: string + format: binary + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/preview/pdf/download-url: + post: + operationId: previewInvoicePdfUrl + tags: + - invoice + summary: Get invoice PDF preview URL + description: Returns a temporary URL for an unstamped invoice PDF preview. + x-codeSamples: + - lang: JavaScript + label: Node.js + source: | + const download = await facturapi.invoices.previewPdfUrl({ + customer: 'cus_123', + items: [{ product: 'prod_123' }], + payment_form: '06' + }); + console.log(download.url, download.expires_at); + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Temporary download URL for the PDF preview. content: application/json: schema: - $ref: "#/components/schemas/InvoiceDraft" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": @@ -4467,291 +4533,197 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - delete: - operationId: cancelInvoice + /invoices/{invoice_id}/{format}: + get: + operationId: downloadInvoice tags: - invoice - summary: Cancel invoice - description: | - Creates a cancellation request to the SAT for the specified invoice, using the **SAT's new cancellation scheme (effective since 2022)**. - - When using this method, the following results can occur: - - - The call returns an error with the explanation of why the cancellation could not be completed. - - The call is successful and returns an `invoice` object with the property `status: "canceled"` (the cancellation has already been accepted by the SAT). - - The call is successful, but the cancellation requires confirmation from your client, in which case the response will be the `invoice` object with the properties `status: "valid"` and `cancellation_status: "pending"`. - - The call is successful, but the SAT replies that the request was received and is being validated, in which case the response will be `status: "valid"` and `cancellation_status: "verifying"`. - - In the `pending` or `verifying` scenarios, the value of `cancellation_status` will be automatically updated by Facturapi when the SAT or your client accepts, rejects, or lets the request expire, so that when you query an invoice (using [Get Invoice](#tag/invoice/operation/getInvoice)), the `cancellation_status` property will reflect the most recent status of the request. - - Check the possible values of `cancellation_status` below. - - After the cancellation, the invoice will no longer be valid, the object will change its `status` to `"canceled"` and will still be available for future queries. - - If the status of the invoice is `draft`, this method will delete it from the database. - - If the status of the invoice is not `valid`, this method will return an error. + summary: Download invoice + description: Download your invoice in PDF, XML, or both in a ZIP file. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d?motive=02 \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X DELETE + ## Download PDF and XML compressed in a ZIP file + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/zip \ + -H "Authorization: Bearer sk_test_API_KEY" + + ## Download only the PDF + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + + ## Download only the XML + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/xml \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | + import fs from 'fs'; import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.cancel( - '58e93bd8e86eb318b019743d', - { motive: '02' } - ); + + // Download PDF and XML compressed in a ZIP file + const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); + const zipFile = fs.createWriteStream('./factura.zip'); + zipStream.pipe(zipFile); + + // Download only the PDF + const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); + const pdfFile = fs.createWriteStream('./factura.pdf'); + pdfStream.pipe(pdfFile); + + // Download only the XML + const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); + const xmlFile = fs.createWriteStream('./factura.xml'); + xmlStream.pipe(xmlFile); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.CancelAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["motive"] = "02" - } - ); + // Download PDF and XML compressed in a ZIP file + var zipStream = await facturapi.Invoice.DownloadZipAsync("58e93bd8e86eb318b019743d"); + // Download only the XML + var xmlStream = await facturapi.Invoice.DownloadXmlAsync("58e93bd8e86eb318b019743d"); + // Download only the PDF + var pdfStream = await facturapi.Invoice.DownloadPdfAsync("58e93bd8e86eb318b019743d"); + + // Save the streams to a file + var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.zip", FileMode.Create); + zipStream.CopyTo(file); + file.Close(); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; + import java.io.InputStream; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardCopyOption; Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.invoices().cancel( - "inv_123", - Map.of( - "motive", "02" - ) - ); + try (InputStream zipStream = facturapi.invoices().downloadZip("58e93bd8e86eb318b019743d")) { + Files.copy(zipStream, Path.of("./factura.zip"), StandardCopyOption.REPLACE_EXISTING); + } + + try (InputStream pdfStream = facturapi.invoices().downloadPdf("58e93bd8e86eb318b019743d")) { + Files.copy(pdfStream, Path.of("./factura.pdf"), StandardCopyOption.REPLACE_EXISTING); + } + + try (InputStream xmlStream = facturapi.invoices().downloadXml("58e93bd8e86eb318b019743d")) { + Files.copy(xmlStream, Path.of("./factura.xml"), StandardCopyOption.REPLACE_EXISTING); + } - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $canceled_invoice = $facturapi->Invoices->cancel( - "58e93bd8e86eb318b019743d", - [ - "motive" => "02" - ] - ); + + // Stream containing the ZIP file with the PDF and XML files + $zip = $facturapi->Invoices->downloadZip("58e93bd8e86eb318b019743d"); + // Stream containing the PDF file + $pdf = $facturapi->Invoices->downloadPdf("58e93bd8e86eb318b019743d"); + // Stream containing the XML file + $xml = $facturapi->Invoices->downloadXml("58e93bd8e86eb318b019743d"); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID of the invoice to cancel - - in: query - name: motive - required: true + description: ID of the invoice to download + - in: path + name: format schema: type: string enum: - - "01" - - "02" - - "03" - - "04" - description: | - Key representing the motive for the cancellation of the invoice. - - Possible values: - - - `01`: **Invoice issued with errors with relation**. When the invoice contains any errors in quantities, keys, or any other data and the replacement invoice has already been issued, which should be indicated through the `substitution` attribute. - - `02`: **Invoice issued with errors without relation**. When the invoice contains any errors in quantities, keys, or any other data and it is not required to be related to another invoice. - - `03`: **Operation not carried out**. When the sale or transaction was not completed. - - `04`: **Nominative operation related to the global invoice**. When it is necessary to cancel an invoice to the general public because the customer requests their invoice. - - in: query - name: substitution - required: false - schema: - type: string - description: | - ID of the invoice that replaces the invoice being canceled. - - You can use either the ID assigned by Facturapi or the fiscal folio (UUID). + - xml + - pdf + - zip + required: true + description: Format of the file to download security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: "`Invoice` object after cancellation" + description: Official CFDI file in the specified format content: - application/json: + application/octet-stream: schema: - $ref: "#/components/schemas/Invoice" + type: string + format: binary "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "409": - $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/copy: - post: - operationId: copyToDraftInvoice + /invoices/{invoice_id}/download-url/{format}: + get: + operationId: getInvoiceDownloadUrl tags: - invoice - summary: Copy to draft + summary: Get download URL description: | - Creates a new draft invoice with the same information as the specified invoice. + Returns a temporary URL to download the invoice in PDF, XML, or both in a ZIP file, without the file travelling through your server. + + The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/copy \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.copyToDraft('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.CopyToDraftAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const download = await facturapi.invoices.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); - var draft = facturapi.invoices().copyToDraft( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->copyToDraft("58e93bd8e86eb318b019743d"); + console.log(download.url, download.expires_at); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID of the invoice to copy - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: "`Invoice` draft object created successfully" - content: - application/json: - schema: - $ref: "#/components/schemas/InvoiceDraft" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/stamp: - post: - operationId: stampDraftInvoice - tags: - - invoice - summary: Stamp draft invoice - description: | - Stamps a draft invoice and sends it to the SAT for validation. - - When using this method, the value of the `is_ready_to_stamp` field (assigned by Facturapi) - must be `true`. Otherwise, the call will return an error. To get the value of `is_ready_to_stamp`, - use the [Get Invoice](#tag/invoice/operation/getInvoice) method. - - This method does not allow editing the invoice, only stamping it. If you need to edit - information in the invoice before stamping it, use the [Edit Draft Invoice](#tag/invoice/operation/editDraftInvoice) method. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/stamp \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - const stampedInvoice = await facturapi.invoices.stampDraft('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var stampedInvoice = await facturapi.Invoice.StampDraftAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var invoice = facturapi.invoices().stampDraft( - "inv_123", - Map.of( - ) - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $stamped_invoice = $facturapi->Invoices->stampDraft("58e93bd8e86eb318b019743d"); - parameters: + description: ID of the object to download - in: path - name: invoice_id + name: format schema: type: string + enum: + - pdf + - xml + - zip required: true - description: ID of the invoice to stamp - - in: query - name: async - schema: - type: boolean - required: false - description: | - Useful for large invoices. If sent `false` or not sent, the call will wait for the SAT to respond by stamping the invoice. - If sent `true`, the call will return immediately with the `invoice` object in status `pending`, and its status can be checked - for a change to `valid` at a later time. + description: Format of the file to download security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: "`Invoice` object stamped successfully" + description: Temporary download URL for the CFDI in the requested format content: application/json: schema: - $ref: "#/components/schemas/Invoice" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/cancellation_receipt/{format}: get: operationId: downloadCancellationReceiptXml @@ -4850,151 +4822,59 @@ paths: "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/payment-summary: + /invoices/{invoice_id}/cancellation_receipt/download-url/{format}: get: - operationId: getInvoicePaymentSummary + operationId: getCancellationReceiptDownloadUrl tags: - invoice - summary: Payment summary + summary: Get cancellation receipt download URL description: | - Returns the information needed to add this invoice as a related document in a payment - complement (complemento de pago): the installment number according to the payment history, - the previous balance (`last_balance`), and the invoice tax breakdown prorated to the amount - being paid. - - The response is ready to be used as an element of `related_documents` when - [creating a Payment invoice](#tag/invoice/operation/createInvoice). + Returns a temporary URL to download the XML or PDF receipt issued by SAT when a cancellation request is submitted through Facturapi, without the file travelling through your server. The receipt contains the immediate request result and does not necessarily prove that the CFDI is already canceled; check the invoice status to confirm the outcome. - The `amount` parameter must be expressed in the invoice currency and cannot exceed the - outstanding balance (`amount_due`). When the payment is received in a different currency, - convert the amount before calling this method. + The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: - lang: Bash label: cURL source: | - curl "https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/payment-summary?amount=100" \ + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/download-url/pdf \ -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); + import Facturapi from 'facturapi'; - const summary = await facturapi.invoices.paymentSummary( - '58e93bd8e86eb318b019743d', - { amount: 100 } + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.invoices.downloadCancellationReceiptPdfUrl( + '58e93bd8e86eb318b019743d' ); - // The summary goes as-is into the complement's related documents - const invoice = await facturapi.invoices.create({ - type: 'P', - customer: 'customer_id', - complements: [ - { - type: 'pago', - data: [ - { - payment_form: '28', - related_documents: [summary] - } - ] - } - ] - }); + console.log(download.url, download.expires_at); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID of the income invoice (PPD payment method) being paid - - in: query - name: amount + description: ID of the object to download + - in: path + name: format schema: - type: number + type: string + enum: + - xml + - pdf required: true - description: Amount being paid on this invoice, expressed in the invoice currency. Cannot exceed the outstanding balance. + description: Format of the cancellation receipt security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Related document summary + description: Temporary download URL for the cancellation receipt in the requested format content: application/json: schema: - type: object - required: - - uuid - - series - - installment - - last_balance - - total - - currency - - amount - - taxes - properties: - uuid: - type: string - description: Invoice UUID - folio_number: - type: number - description: Invoice folio number. Omitted when the invoice has none registered. - series: - type: ["string","null"] - description: Invoice series - installment: - type: number - description: Installment number corresponding to this payment - last_balance: - type: number - description: Invoice outstanding balance before this payment - total: - type: number - description: Invoice total - currency: - type: string - description: Invoice currency - amount: - type: number - description: Amount paid in this installment - taxes: - type: array - description: Invoice taxes prorated to the paid amount - items: - type: object - properties: - base: - type: number - description: Tax base prorated to the paid amount - rate: - type: number - description: Tax rate or quota - type: - type: string - description: Tax type (VAT, income tax withholding, etc.) - factor: - type: string - description: Factor type (Rate, Exempt, etc.) - withholding: - type: boolean - description: Whether this tax is a withholding - example: - uuid: 39c85a3f-275b-4341-b259-e8971d9f8a94 - folio_number: 914 - series: F - installment: 2 - last_balance: 245.6 - total: 345.6 - currency: MXN - amount: 100 - taxes: - - base: 86.21 - rate: 0.16 - type: IVA - factor: Tasa - withholding: false + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": @@ -5005,135 +4885,9 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - - /invoices/{invoice_id}/{format}: - get: - operationId: downloadInvoice - tags: - - invoice - summary: Download invoice - description: Download your invoice in PDF, XML, or both in a ZIP file. - x-codeSamples: - - lang: Bash - label: cURL - source: | - ## Download PDF and XML compressed in a ZIP file - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/zip \ - -H "Authorization: Bearer sk_test_API_KEY" - - ## Download only the PDF - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - ## Download only the XML - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/xml \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import fs from 'fs'; - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - // Download PDF and XML compressed in a ZIP file - const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); - const zipFile = fs.createWriteStream('./factura.zip'); - zipStream.pipe(zipFile); - - // Download only the PDF - const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); - const pdfFile = fs.createWriteStream('./factura.pdf'); - pdfStream.pipe(pdfFile); - - // Download only the XML - const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); - const xmlFile = fs.createWriteStream('./factura.xml'); - xmlStream.pipe(xmlFile); - - lang: csharp - label: C# - source: | - // Download PDF and XML compressed in a ZIP file - var zipStream = await facturapi.Invoice.DownloadZipAsync("58e93bd8e86eb318b019743d"); - // Download only the XML - var xmlStream = await facturapi.Invoice.DownloadXmlAsync("58e93bd8e86eb318b019743d"); - // Download only the PDF - var pdfStream = await facturapi.Invoice.DownloadPdfAsync("58e93bd8e86eb318b019743d"); - - // Save the streams to a file - var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.zip", FileMode.Create); - zipStream.CopyTo(file); - file.Close(); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.io.InputStream; - import java.nio.file.Files; - import java.nio.file.Path; - import java.nio.file.StandardCopyOption; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - try (InputStream zipStream = facturapi.invoices().downloadZip("58e93bd8e86eb318b019743d")) { - Files.copy(zipStream, Path.of("./factura.zip"), StandardCopyOption.REPLACE_EXISTING); - } - - try (InputStream pdfStream = facturapi.invoices().downloadPdf("58e93bd8e86eb318b019743d")) { - Files.copy(pdfStream, Path.of("./factura.pdf"), StandardCopyOption.REPLACE_EXISTING); - } - - try (InputStream xmlStream = facturapi.invoices().downloadXml("58e93bd8e86eb318b019743d")) { - Files.copy(xmlStream, Path.of("./factura.xml"), StandardCopyOption.REPLACE_EXISTING); - } - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - // Stream containing the ZIP file with the PDF and XML files - $zip = $facturapi->Invoices->downloadZip("58e93bd8e86eb318b019743d"); - // Stream containing the PDF file - $pdf = $facturapi->Invoices->downloadPdf("58e93bd8e86eb318b019743d"); - // Stream containing the XML file - $xml = $facturapi->Invoices->downloadXml("58e93bd8e86eb318b019743d"); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the invoice to download - - in: path - name: format - schema: - type: string - enum: - - xml - - pdf - - zip - required: true - description: Format of the file to download - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Official CFDI file in the specified format - content: - application/octet-stream: - schema: - type: string - format: binary - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/email: - post: - operationId: sendInvoiceByEmail + /invoices/{invoice_id}/email: + post: + operationId: sendInvoiceByEmail tags: - invoice summary: Send invoice by email @@ -5212,162 +4966,537 @@ paths: label: Java source: | import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var response = facturapi.invoices().sendByEmail( + "inv_123", + Map.of( + "to", "cliente@example.com" + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + // Send to the email registered by the client + $facturapi->Invoices->sendByEmail("58e93bd8e86eb318b019743d"); + + // Send to a different email + $facturapi->Invoices->sendByEmail( + "58e93bd8e86eb318b019743d", + "another@email.com" + ); + + // Send to more than one email (max 10) + $facturapi->Invoices->sendByEmail( + "58e93bd8e86eb318b019743d", + [ + "first@email.com", + "second@email.com" + ] + ); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID of the invoice to send + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + email: + description: | + Email address to send the invoice. If not sent, the email registered by the customer will be used. + oneOf: + - type: string + format: email + description: Email address to send the invoice. + example: another@email.com + - type: array + example: ["first@email.com", "second@email.com"] + description: | + Array of email addresses to send the invoice. The maximum number of emails is 10. + maxLength: 10 + items: + type: string + format: email + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Email sent successfully + content: + application/json: + schema: + type: object + required: + - ok + properties: + ok: + type: boolean + description: | + `true` if the email was sent successfully, `false` otherwise. + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/zip-requests: + post: + operationId: createInvoiceZipRequest + tags: + - invoice + summary: Create or retrieve a monthly ZIP request + description: | + Creates a request to generate a ZIP file containing one month of invoices, or retrieves the existing request with the same filters. + + This operation is idempotent. Invoice types are normalized, so `["I", "E"]` and `["E", "I"]` resolve to the same request. Identical concurrent calls also return the same request. + + If an earlier request has a `failed` status, calling this method again retries it. Before retrying, the previous error and task fields, processed progress, and failed-document list are cleared. If scheduling fails, the request is saved with a `failed` status and the API returns a `5xx` error. + + This method requires a live-mode organization API key, an active subscription, and permission to read invoices. Test-mode keys return HTTP 402. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/zip-requests \ + -H "Authorization: Bearer sk_live_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "year": 2025, + "month": 3, + "issuer_type": "issuing", + "invoice_types": ["I", "E"] + }' + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequest = await facturapi.invoices.createZipRequest({ + year: 2025, + month: 3, + issuer_type: 'issuing', + invoice_types: ['I', 'E'] + }); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequest = await facturapi.Invoice.CreateZipRequestAsync( + new Dictionary + { + ["year"] = 2025, + ["month"] = 3, + ["issuer_type"] = "issuing", + ["invoice_types"] = new[] { "I", "E" } + } + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequest = facturapi.invoices().createZipRequest( + Map.of( + "year", 2025, + "month", 3, + "issuer_type", "issuing", + "invoice_types", List.of("I", "E") + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequest = $facturapi->Invoices->createZipRequest([ + "year" => 2025, + "month" => 3, + "issuer_type" => "issuing", + "invoice_types" => ["I", "E"] + ]); + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequestCreateInput" + security: + - "SecretLiveKey": [] + responses: + "200": + description: ZIP request created or retrieved successfully. + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequest" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNoInvoices" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + get: + operationId: listInvoiceZipRequests + tags: + - invoice + summary: List monthly ZIP requests + description: | + Returns a paginated list of ZIP requests. `year` and `month` must be provided together. `invoice_types` filters by one type or an exact normalized array. + + This method requires a live-mode organization API key, an active subscription, and permission to read invoices. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl "https://www.facturapi.io/v2/invoices/zip-requests?year=2025&month=3&status=finished&limit=20&page=1" \ + -H "Authorization: Bearer sk_live_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequests = await facturapi.invoices.listZipRequests({ + year: 2025, + month: 3, + status: 'finished', + limit: 20, + page: 1 + }); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequests = await facturapi.Invoice.ListZipRequestsAsync( + new Dictionary + { + ["year"] = 2025, + ["month"] = 3, + ["status"] = "finished", + ["limit"] = 20, + ["page"] = 1 + } + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequests = facturapi.invoices().listZipRequests( + Map.of( + "year", 2025, + "month", 3, + "status", "finished", + "limit", 20, + "page", 1 + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequests = $facturapi->Invoices->listZipRequests([ + "year" => 2025, + "month" => 3, + "status" => "finished", + "limit" => 20, + "page" => 1 + ]); + parameters: + - in: query + name: year + schema: + type: integer + minimum: 2000 + maximum: 9999 + description: Year to filter. Must be provided with `month`. + - in: query + name: month + schema: + type: integer + minimum: 1 + maximum: 12 + description: Month to filter. Must be provided with `year`. + - in: query + name: status + schema: + $ref: "#/components/schemas/InvoiceZipRequestStatus" + description: ZIP request status. + - in: query + name: issuer_type + schema: + $ref: "#/components/schemas/IssuingType" + description: Filters issued or received invoices. + - in: query + name: invoice_types + schema: + type: array + uniqueItems: true + items: + $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" + description: Filters by one invoice type or an exact normalized array. + - in: query + name: page + schema: + type: integer + minimum: 1 + default: 1 + description: Results page, starting at 1. + - $ref: "#/components/parameters/SearchLimit" + security: + - "SecretLiveKey": [] + responses: + "200": + description: Paginated ZIP request results. + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequestSearchResult" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/zip-requests/{id}: + get: + operationId: retrieveInvoiceZipRequest + tags: + - invoice + summary: Retrieve a monthly ZIP request + description: | + Retrieves a ZIP request. Poll this method until the status becomes `finished` or `failed`. Once it is `finished`, call the download method. + + Requires a live-mode organization API key, an active subscription, and permission to read invoices. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000 \ + -H "Authorization: Bearer sk_live_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequest = await facturapi.invoices.retrieveZipRequest( + '66b0f0000000000000000000' + ); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequest = await facturapi.Invoice.RetrieveZipRequestAsync( + "66b0f0000000000000000000" + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequest = facturapi.invoices().retrieveZipRequest( + "66b0f0000000000000000000" + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequest = $facturapi->Invoices->retrieveZipRequest( + "66b0f0000000000000000000" + ); + parameters: + - $ref: "#/components/parameters/InvoiceZipRequestId" + security: + - "SecretLiveKey": [] + responses: + "200": + description: ZIP request retrieved successfully. + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequest" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/zip-requests/{id}/zip: + get: + operationId: downloadInvoiceZipRequest + tags: + - invoice + summary: Download a monthly ZIP + description: | + Downloads the ZIP for a finished request. The filename uses the `YYYY-MM.zip` format. + + Requires a live-mode organization API key, an active subscription, and permission to read invoices. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/zip \ + -H "Authorization: Bearer sk_live_API_KEY" \ + --output 2025-03.zip + - lang: JavaScript + label: Node.js + source: | + import fs from 'fs'; + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipStream = await facturapi.invoices.downloadZipRequest( + '66b0f0000000000000000000' + ); + zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipStream = await facturapi.Invoice.DownloadZipRequestAsync( + "66b0f0000000000000000000" + ); + await using var file = File.Create("2025-03.zip"); + await zipStream.CopyToAsync(file); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.io.InputStream; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardCopyOption; - var response = facturapi.invoices().sendByEmail( - "inv_123", - Map.of( - "to", "cliente@example.com" - ) - ); + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + try (InputStream zipStream = facturapi.invoices().downloadZipRequest( + "66b0f0000000000000000000" + )) { + Files.copy(zipStream, Path.of("./2025-03.zip"), StandardCopyOption.REPLACE_EXISTING); + } - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - // Send to the email registered by the client - $facturapi->Invoices->sendByEmail("58e93bd8e86eb318b019743d"); - - // Send to a different email - $facturapi->Invoices->sendByEmail( - "58e93bd8e86eb318b019743d", - "another@email.com" - ); - - // Send to more than one email (max 10) - $facturapi->Invoices->sendByEmail( - "58e93bd8e86eb318b019743d", - [ - "first@email.com", - "second@email.com" - ] + $facturapi = new Facturapi("sk_live_API_KEY"); + $zip = $facturapi->Invoices->downloadZipRequest( + "66b0f0000000000000000000" ); + file_put_contents("2025-03.zip", $zip); parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the invoice to send - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - email: - description: | - Email address to send the invoice. If not sent, the email registered by the customer will be used. - oneOf: - - type: string - format: email - description: Email address to send the invoice. - example: another@email.com - - type: array - example: ["first@email.com", "second@email.com"] - description: | - Array of email addresses to send the invoice. The maximum number of emails is 10. - maxLength: 10 - items: - type: string - format: email + - $ref: "#/components/parameters/InvoiceZipRequestId" security: - "SecretLiveKey": [] - - "SecretTestKey": [] responses: "200": - description: Email sent successfully + description: Generated ZIP file. + headers: + Content-Disposition: + description: Suggested filename in `attachment; filename="YYYY-MM.zip"` format. + schema: + type: string content: - application/json: + application/zip: schema: - type: object - required: - - ok - properties: - ok: - type: boolean - description: | - `true` if the email was sent successfully, `false` otherwise. + type: string + format: binary "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/status: - put: - operationId: updateInvoiceStatus + /invoices/zip-requests/{id}/download-url: + get: + operationId: getInvoiceZipRequestDownloadUrl tags: - invoice - summary: | - Update invoice status + summary: Get monthly ZIP download URL description: | - Consults the status of a stamped invoice at the SAT and updates the invoice object with the most recent information. + Returns a temporary URL for downloading the ZIP of a finished request without the file travelling through your server. + + The URL grants access to that one file while it is valid: treat it as a credential and do not store it. Requires a live-mode organization API key, an active subscription, and permission to read invoices. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/status \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X PUT + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/download-url \ + -H "Authorization: Bearer sk_live_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.updateStatus('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new Facturapi - var invoice = await facturapi.Invoice.UpdateStatusAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; + import Facturapi from 'facturapi'; - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const facturapi = new Facturapi('sk_live_API_KEY'); + const download = await facturapi.invoices.downloadZipRequestUrl( + '66b0f0000000000000000000' + ); - var invoice = facturapi.invoices().updateStatus( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->updateStatus("58e93bd8e86eb318b019743d"); + console.log(download.url, download.expires_at); parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the invoice to update + - $ref: "#/components/parameters/InvoiceZipRequestId" security: - "SecretLiveKey": [] - - "SecretTestKey": [] responses: "200": - description: "`Invoice` object updated successfully" + description: Temporary download URL for the generated ZIP file. content: application/json: schema: - $ref: "#/components/schemas/Invoice" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts: post: operationId: createReceipt @@ -5891,87 +6020,12 @@ paths: source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const receipt = await facturapi.receipts.cancel('5ebd8e56f5687a013ca0df46'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var receipt = await facturapi.Receipt.CancelAsync("5ebd8e56f5687a013ca0df46"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var receipt = facturapi.receipts().cancel( - "rec_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $facturapi->Receipts->cancel("5ebd8e56f5687a013ca0df46"); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID of the receipt to cancel - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Receipt object canceled successfully - content: - application/json: - schema: - $ref: "#/components/schemas/Receipt" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/pdf: - get: - operationId: downloadReceiptPdf - tags: - - receipt - summary: Download PDF - description: Download the electronic receipt in PDF format. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import fs from 'fs'; - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - // Download the electronic receipt in PDF format - const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); - const pdfFile = fs.createWriteStream('./recibo.pdf'); - pdfStream.pipe(pdfFile); - - lang: csharp - label: C# - source: | - // Download the electronic receipt in PDF format - var pdfStream = await facturapi.Receipt.DownloadPdfAsync("58e93bd8e86eb318b019743d"); - - // Save the stream to a file - var file = new System.IO.FileStream("C:\\route\\to\\save\\receipt.pdf", FileMode.Create); - pdfStream.CopyTo(file); - file.Close(); + const receipt = await facturapi.receipts.cancel('5ebd8e56f5687a013ca0df46'); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var receipt = await facturapi.Receipt.CancelAsync("5ebd8e56f5687a013ca0df46"); - lang: Java label: Java source: | @@ -5980,33 +6034,31 @@ paths: import java.util.Map; Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - byte[] pdf = facturapi.receipts().downloadPdf( + + var receipt = facturapi.receipts().cancel( "rec_123" ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - - // stream containing the PDF file - $pdf = $facturapi->Receipts->downloadPdf("58e93bd8e86eb318b019743d"); + $facturapi->Receipts->cancel("5ebd8e56f5687a013ca0df46"); parameters: - in: path name: receipt_id schema: type: string required: true - description: ID of the receipt to download + description: ID of the receipt to cancel security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: E-receipt in PDF format + description: Receipt object canceled successfully content: - application/octet-stream: + application/json: schema: - type: string - format: binary + $ref: "#/components/schemas/Receipt" "400": $ref: "#/components/responses/BadRequest" "401": @@ -6015,75 +6067,53 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/email: + /receipts/{receipt_id}/invoice: post: - operationId: sendReceiptByEmail + operationId: invoiceReceipt tags: - receipt - summary: Send e-receipt by email + summary: Convert e-receipt to invoice description: | - Send the e-receipt by email to the customer. + Creates a new invoice from a receipt. Once invoiced, the receipt's `status` will change to `"invoiced_to_customer"`. - The email sent will be customized with the logo and colors of the organization that created it, - and will include a button to invoice the receipt, as well as the receipt attached as a PDF to the message. + Only open receipts (`status = "open"`) can be invoiced. + + If you send `customer`, that customer is used as the invoice recipient + and overrides the customer assigned to the receipt. If you omit + `customer`, the receipt must already have an assigned customer. x-codeSamples: - lang: Bash label: cURL source: | - # Send to a different email than the one registered by the customer - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/email \ + curl https://www.facturapi.io/v2/receipts/5ebd8e56f5687a013ca0df46/invoice \ -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST \ -H "Content-Type: application/json" \ -d '{ - "email": "another_email@example.com" - }' + "customer": "58e93bd8e86eb318b0197456", + "folio_number": 914, + "series": "F" + }' - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - # Send to a different email than the one registered by the customer - await facturapi.receipts.sendByEmail( - '58e93bd8e86eb318b019743d', - { email: 'ejemplo@correo.com' } - ); - - # Send to multiple emails (max 10) - await facturapi.receipts.sendByEmail( - '58e93bd8e86eb318b019743d', - { - email: [ - 'primer@correo.com', - 'segundo@correo.com' - ] - } - ); + const invoice = await facturapi.receipts.invoice('5ebd8e56f5687a013ca0df46', { + customer: '58e93bd8e86eb318b0197456', + folio_number: 914, + series: 'F' + }); - lang: csharp label: C# source: | - // Send to a different email than the one registered by the customer - await facturapi.Receipt.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = "ejemplo@correo.com" - } - ); - - // Send to multiple emails (max 10) - await facturapi.Receipt.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = new String[] - { - "primer@correo.com", - "segundo@correo.com" - } - } - ); + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Receipt.InvoiceAsync("5ebd8e56f5687a013ca0df46", new Dictionary + { + ["customer"] = "58e93bd8e86eb318b0197456", + ["folio_number"] = 914, + ["series"] = "F" + }); - lang: Java label: Java source: | @@ -6093,133 +6123,127 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var response = facturapi.receipts().sendByEmail( + var invoice = facturapi.receipts().invoice( "rec_123", Map.of( - "to", "cliente@example.com" + "customer", "cus_123" ) ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - // Send to a different email than the one registered by the customer - $facturapi->Receipts->sendByEmail( - "58e93bd8e86eb318b019743d", - "ejemplo@correo.com" - ); - - // Send to multiple emails (max 10) - $facturapi->Receipts->sendByEmail( - "58e93bd8e86eb318b019743d", - [ - "primer@correo.com", - "segundo@correo.com" - ] - ); + $invoice = $facturapi->Receipts->invoice("5a3f3e35f508333611ad6b3e", [ + "customer" => "58e93bd8e86eb318b0197456", + "folio_number" => 914, + "series" => "F" + ]); parameters: - in: path name: receipt_id schema: type: string required: true - description: ID of the e-receipt to send + description: ID of the receipt to invoice requestBody: - required: false - content: - application/json: - schema: - type: object - required: - - email - properties: - email: - description: | - Email address to send the e-receipt. If not sent, the email registered by the customer will be used. - oneOf: - - type: string - format: email - description: Email address to send the e-receipt. - example: other@email.com - - type: array - example: ["first@email.com", "second@email.com"] - description: | - Array of email addresses to send the e-receipt. The maximum number of emails is 10. - maxLength: 10 - items: - type: string - format: email + $ref: "#/components/requestBodies/ReceiptInvoice" security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Generic response object + description: Nuevo `Invoice` object created content: application/json: schema: - type: object - required: - - ok - properties: - ok: - type: boolean - description: Indicates if the email was sent successfully + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - - /receipts/{receipt_id}/invoice: + /receipts/to-invoice: post: - operationId: invoiceReceipt + operationId: createToInvoiceFromReceipts tags: - receipt - summary: Convert e-receipt to invoice + summary: Create invoice from multiple receipts description: | - Creates a new invoice from a receipt. Once invoiced, the receipt's `status` will change to `"invoiced_to_customer"`. - - Only open receipts (`status = "open"`) can be invoiced. + Creates a single invoice from multiple receipts selected by their `key`. If you send `customer`, that customer is used as the invoice recipient - and overrides the customer assigned to the receipt. If you omit - `customer`, the receipt must already have an assigned customer. + and overrides the customer assigned to the included receipts. If you omit + `customer`, all receipts must already have the same assigned customer. + The `address` field of the included receipts will also be validated. + + If `dry_run` is `true`, the endpoint does not create the invoice and returns a summary preview. + The `dry_run` validates the same rules as real invoice creation, but does not persist changes. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/receipts/5ebd8e56f5687a013ca0df46/invoice \ + curl https://www.facturapi.io/v2/receipts/to-invoice \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "customer": "58e93bd8e86eb318b0197456", - "folio_number": 914, - "series": "F" - }' + "keys": ["ticket_1001", "ticket_1002"], + "customer": { + "legal_name": "Dunder Mifflin", + "tax_id": "ABC101010111", + "tax_system": "601", + "email": "email@example.com", + "address": { + "zip": "85900" + } + }, + "use": "G03", + "payment_form": "03" + }' - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.receipts.invoice('5ebd8e56f5687a013ca0df46', { - customer: '58e93bd8e86eb318b0197456', - folio_number: 914, - series: 'F' + const invoice = await facturapi.receipts.toInvoice({ + keys: ['ticket_1001', 'ticket_1002'], + customer: { + legal_name: 'Dunder Mifflin', + tax_id: 'ABC101010111', + tax_system: '601', + email: 'email@example.com', + address: { + zip: '85900' + } + }, + use: 'G03', + payment_form: Facturapi.PaymentForm.TRANSFERENCIA_ELECTRONICA_DE_FONDOS }); - lang: csharp label: C# source: | var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Receipt.InvoiceAsync("5ebd8e56f5687a013ca0df46", new Dictionary + var invoice = await facturapi.Receipt.ToInvoiceAsync(new Dictionary { - ["customer"] = "58e93bd8e86eb318b0197456", - ["folio_number"] = 914, - ["series"] = "F" + ["keys"] = new[] { "ticket_1001", "ticket_1002" }, + ["customer"] = new Dictionary + { + ["legal_name"] = "Dunder Mifflin", + ["tax_id"] = "ABC101010111", + ["tax_system"] = "601", + ["email"] = "email@example.com", + ["address"] = new Dictionary + { + ["zip"] = "85900" + } + }, + ["use"] = "G03", + ["payment_form"] = Facturapi.PaymentForm.TRANSFERENCIA_ELECTRONICA_DE_FONDOS }); - lang: Java label: Java @@ -6230,71 +6254,75 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.receipts().invoice( - "rec_123", - Map.of( - "customer", "cus_123" - ) - ); + var invoice = facturapi.receipts().toInvoice( + Map.of( + "keys", List.of("ticket_1001", "ticket_1002"), + "customer", Map.of( + "legal_name", "Dunder Mifflin", + "tax_id", "ABC101010111", + "tax_system", "601", + "address", Map.of("zip", "85900") + ), + "use", "G03", + "payment_form", "03" + ) + ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Receipts->invoice("5a3f3e35f508333611ad6b3e", [ - "customer" => "58e93bd8e86eb318b0197456", - "folio_number" => 914, - "series" => "F" + $invoice = $facturapi->Receipts->toInvoice([ + "keys" => ["ticket_1001", "ticket_1002"], + "customer" => [ + "legal_name" => "Dunder Mifflin", + "tax_id" => "ABC101010111", + "tax_system" => "601", + "email" => "email@example.com", + "address" => [ + "zip" => "85900" + ] + ], + "use" => "G03", + "payment_form" => \Facturapi\PaymentForm::TRANSFERENCIA_ELECTRONICA_DE_FONDOS ]); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID of the receipt to invoice requestBody: - $ref: "#/components/requestBodies/ReceiptInvoice" + $ref: "#/components/requestBodies/ReceiptCreateToInvoice" security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Nuevo `Invoice` object created + description: Created `Invoice` object or summary object when `dry_run=true` content: application/json: schema: - $ref: "#/components/schemas/Invoice" + oneOf: + - $ref: "#/components/schemas/Invoice" + - $ref: "#/components/schemas/ToInvoiceSummary" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" "404": $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/to-invoice: + /receipts/to-invoice/preview: post: - operationId: createToInvoiceFromReceipts + operationId: previewToInvoiceFromReceipts tags: - receipt - summary: Create invoice from multiple receipts + summary: Preview PDF for multiple receipts invoice description: | - Creates a single invoice from multiple receipts selected by their `key`. - - If you send `customer`, that customer is used as the invoice recipient - and overrides the customer assigned to the included receipts. If you omit - `customer`, all receipts must already have the same assigned customer. - The `address` field of the included receipts will also be validated. + Generates a PDF preview for an invoice built from multiple receipts selected by their `key`. - If `dry_run` is `true`, the endpoint does not create the invoice and returns a summary preview. - The `dry_run` validates the same rules as real invoice creation, but does not persist changes. + The preview validates the same customer rules as real invoice creation: + if you omit `customer`, all receipts must already have the same assigned customer. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/receipts/to-invoice \ + curl https://www.facturapi.io/v2/receipts/to-invoice/preview \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ @@ -6303,39 +6331,39 @@ paths: "legal_name": "Dunder Mifflin", "tax_id": "ABC101010111", "tax_system": "601", - "email": "email@example.com", "address": { "zip": "85900" } }, - "use": "G03", - "payment_form": "03" + "use": "G03" }' - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' + import fs from 'fs' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.receipts.toInvoice({ + const pdfStream = await facturapi.receipts.previewToInvoicePdf({ keys: ['ticket_1001', 'ticket_1002'], customer: { legal_name: 'Dunder Mifflin', tax_id: 'ABC101010111', tax_system: '601', - email: 'email@example.com', address: { zip: '85900' } }, - use: 'G03', - payment_form: Facturapi.PaymentForm.TRANSFERENCIA_ELECTRONICA_DE_FONDOS + use: 'G03' }); + + const file = fs.createWriteStream('to_invoice_preview.pdf'); + pdfStream.pipe(file); - lang: csharp label: C# source: | var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Receipt.ToInvoiceAsync(new Dictionary + var pdfStream = await facturapi.Receipt.PreviewToInvoicePdfAsync(new Dictionary { ["keys"] = new[] { "ticket_1001", "ticket_1002" }, ["customer"] = new Dictionary @@ -6343,14 +6371,12 @@ paths: ["legal_name"] = "Dunder Mifflin", ["tax_id"] = "ABC101010111", ["tax_system"] = "601", - ["email"] = "email@example.com", ["address"] = new Dictionary { ["zip"] = "85900" } }, - ["use"] = "G03", - ["payment_form"] = Facturapi.PaymentForm.TRANSFERENCIA_ELECTRONICA_DE_FONDOS + ["use"] = "G03" }); - lang: Java label: Java @@ -6361,7 +6387,7 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.receipts().toInvoice( + var pdf = facturapi.receipts().previewToInvoicePdf( Map.of( "keys", List.of("ticket_1001", "ticket_1002"), "customer", Map.of( @@ -6370,121 +6396,235 @@ paths: "tax_system", "601", "address", Map.of("zip", "85900") ), - "use", "G03", - "payment_form", "03" + "use", "G03" ) ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Receipts->toInvoice([ + $pdfBytes = $facturapi->Receipts->previewToInvoicePdf([ "keys" => ["ticket_1001", "ticket_1002"], "customer" => [ "legal_name" => "Dunder Mifflin", "tax_id" => "ABC101010111", "tax_system" => "601", - "email" => "email@example.com", "address" => [ "zip" => "85900" ] ], - "use" => "G03", - "payment_form" => \Facturapi\PaymentForm::TRANSFERENCIA_ELECTRONICA_DE_FONDOS + "use" => "G03" ]); requestBody: - $ref: "#/components/requestBodies/ReceiptCreateToInvoice" + $ref: "#/components/requestBodies/ReceiptPreviewToInvoice" security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Created `Invoice` object or summary object when `dry_run=true` + description: PDF binary content + content: + application/pdf: + schema: + type: string + format: binary + "204": + description: No eligible receipts found for the provided keys + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "500": + $ref: "#/components/responses/UnexpectedError" + /receipts/to-invoice/preview/download-url: + post: + operationId: previewToInvoiceFromReceiptsUrl + tags: + - receipt + summary: Get receipts invoice preview URL + description: Returns a temporary URL for the PDF preview of an invoice built from the selected receipts. + x-codeSamples: + - lang: JavaScript + label: Node.js + source: | + const download = await facturapi.receipts.previewToInvoicePdfUrl({ + keys: ['ticket_1001', 'ticket_1002'], + customer: 'cus_123', + use: 'G03' + }); + console.log(download.url, download.expires_at); + requestBody: + $ref: "#/components/requestBodies/ReceiptPreviewToInvoice" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Temporary download URL for the PDF preview. content: application/json: schema: - oneOf: - - $ref: "#/components/schemas/Invoice" - - $ref: "#/components/schemas/ToInvoiceSummary" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" "404": $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/to-invoice/preview: + /receipts/global-invoice: post: - operationId: previewToInvoiceFromReceipts + operationId: createGlobalInvoice tags: - receipt - summary: Preview PDF for multiple receipts invoice + summary: Create global invoice description: | - Generates a PDF preview for an invoice built from multiple receipts selected by their `key`. + Creates a global invoice that will include all receipts with `status = "open"` from a certain period. - The preview validates the same customer rules as real invoice creation: - if you omit `customer`, all receipts must already have the same assigned customer. + Global invoices are issued to the generic `PUBLICO EN GENERAL` customer. + Included receipts are associated with that customer and their `status` + changes to `"invoiced_globally"`. + + A global invoice can include up to 5,000 open receipts. If the period contains + more, send `limit_to_max_receipts: true` and repeat the request with the same + period until the response is `null`. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/receipts/to-invoice/preview \ + curl https://www.facturapi.io/v2/receipts/global-invoice \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "keys": ["ticket_1001", "ticket_1002"], - "customer": { - "legal_name": "Dunder Mifflin", - "tax_id": "ABC101010111", - "tax_system": "601", - "address": { - "zip": "85900" - } - }, - "use": "G03" - }' + "from": "2021-01-01T05:00:00.000Z", + "to": "2021-01-31T04:59:59.999Z", + "periodicity": "month", + "months": "01", + "year": 2021, + "folio_number": 1234, + "series": "G", + "limit_to_max_receipts": true + }' + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + const invoice = await facturapi.receipts.createGlobalInvoice({ + from: '2020-12-01T05:00:00.000Z', + to: '2020-12-31T04:59:59.999Z', + periodicity: 'month', + months: '01', + year: 2021, + folio_number: 1234, + series: 'G', + limit_to_max_receipts: true + }); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Receipt.CreateGlobalInvoiceAsync(new Dictionary + { + ["from"] = "2020-12-01T05:00:00.000Z", + ["to"] = "2020-12-31T04:59:59.999Z", + ["periodicity"] = "month", + ["months"] = "01", + ["year"] = 2021, + ["folio_number"] = 1234, + ["series"] = "G" + }); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.receipts().createGlobalInvoice( + Map.of( + "month", 5, + "year", 2024 + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + $invoice = $facturapi->Receipts->createGlobalInvoice([ + "from" => "2020-12-01T05:00:00.000Z", + "to" => "2020-12-31T04:59:59.999Z", + "periodicity" => "month", + "months" => "01", + "year" => 2021, + "folio_number" => 1234, + "series" => "G" + ]); + requestBody: + $ref: "#/components/requestBodies/ReceiptCreateGlobalInvoice" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Created `Invoice` object, or `null` when the period has no open receipts + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/Invoice" + - type: "null" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + + /receipts/{receipt_id}/pdf: + get: + operationId: downloadReceiptPdf + tags: + - receipt + summary: Download PDF + description: Download the electronic receipt in PDF format. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | + import fs from 'fs'; import Facturapi from 'facturapi' - import fs from 'fs' const facturapi = new Facturapi('sk_test_API_KEY'); - const pdfStream = await facturapi.receipts.previewToInvoicePdf({ - keys: ['ticket_1001', 'ticket_1002'], - customer: { - legal_name: 'Dunder Mifflin', - tax_id: 'ABC101010111', - tax_system: '601', - address: { - zip: '85900' - } - }, - use: 'G03' - }); - - const file = fs.createWriteStream('to_invoice_preview.pdf'); - pdfStream.pipe(file); + // Download the electronic receipt in PDF format + const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); + const pdfFile = fs.createWriteStream('./recibo.pdf'); + pdfStream.pipe(pdfFile); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var pdfStream = await facturapi.Receipt.PreviewToInvoicePdfAsync(new Dictionary - { - ["keys"] = new[] { "ticket_1001", "ticket_1002" }, - ["customer"] = new Dictionary - { - ["legal_name"] = "Dunder Mifflin", - ["tax_id"] = "ABC101010111", - ["tax_system"] = "601", - ["address"] = new Dictionary - { - ["zip"] = "85900" - } - }, - ["use"] = "G03" - }); + // Download the electronic receipt in PDF format + var pdfStream = await facturapi.Receipt.DownloadPdfAsync("58e93bd8e86eb318b019743d"); + + // Save the stream to a file + var file = new System.IO.FileStream("C:\\route\\to\\save\\receipt.pdf", FileMode.Create); + pdfStream.CopyTo(file); + file.Close(); - lang: Java label: Java source: | @@ -6493,81 +6633,81 @@ paths: import java.util.Map; Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var pdf = facturapi.receipts().previewToInvoicePdf( - Map.of( - "keys", List.of("ticket_1001", "ticket_1002"), - "customer", Map.of( - "legal_name", "Dunder Mifflin", - "tax_id", "ABC101010111", - "tax_system", "601", - "address", Map.of("zip", "85900") - ), - "use", "G03" - ) - ); + byte[] pdf = facturapi.receipts().downloadPdf( + "rec_123" + ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $pdfBytes = $facturapi->Receipts->previewToInvoicePdf([ - "keys" => ["ticket_1001", "ticket_1002"], - "customer" => [ - "legal_name" => "Dunder Mifflin", - "tax_id" => "ABC101010111", - "tax_system" => "601", - "address" => [ - "zip" => "85900" - ] - ], - "use" => "G03" - ]); - requestBody: - $ref: "#/components/requestBodies/ReceiptPreviewToInvoice" + // stream containing the PDF file + $pdf = $facturapi->Receipts->downloadPdf("58e93bd8e86eb318b019743d"); + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID of the receipt to download security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: PDF binary content + description: E-receipt in PDF format content: - application/pdf: + application/octet-stream: schema: type: string format: binary - "204": - description: No eligible receipts found for the provided keys "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/to-invoice/preview/download-url: - post: - operationId: previewToInvoiceFromReceiptsUrl + /receipts/{receipt_id}/download-url/pdf: + get: + operationId: getReceiptDownloadUrl tags: - receipt - summary: Get receipts invoice preview URL - description: Returns a temporary URL for the PDF preview of an invoice built from the selected receipts. + summary: Get download URL + description: | + Returns a temporary URL to download the receipt in PDF, without the file travelling through your server. + + The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | - const download = await facturapi.receipts.previewToInvoicePdfUrl({ - keys: ['ticket_1001', 'ticket_1002'], - customer: 'cus_123', - use: 'G03' - }); + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.receipts.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); + console.log(download.url, download.expires_at); - requestBody: - $ref: "#/components/requestBodies/ReceiptPreviewToInvoice" + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID of the object to download security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the PDF preview. + description: Temporary download URL for the receipt in PDF content: application/json: schema: @@ -6582,69 +6722,75 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/global-invoice: + /receipts/{receipt_id}/email: post: - operationId: createGlobalInvoice + operationId: sendReceiptByEmail tags: - receipt - summary: Create global invoice + summary: Send e-receipt by email description: | - Creates a global invoice that will include all receipts with `status = "open"` from a certain period. - - Global invoices are issued to the generic `PUBLICO EN GENERAL` customer. - Included receipts are associated with that customer and their `status` - changes to `"invoiced_globally"`. + Send the e-receipt by email to the customer. - A global invoice can include up to 5,000 open receipts. If the period contains - more, send `limit_to_max_receipts: true` and repeat the request with the same - period until the response is `null`. + The email sent will be customized with the logo and colors of the organization that created it, + and will include a button to invoice the receipt, as well as the receipt attached as a PDF to the message. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/receipts/global-invoice \ + # Send to a different email than the one registered by the customer + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/email \ -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST \ -H "Content-Type: application/json" \ -d '{ - "from": "2021-01-01T05:00:00.000Z", - "to": "2021-01-31T04:59:59.999Z", - "periodicity": "month", - "months": "01", - "year": 2021, - "folio_number": 1234, - "series": "G", - "limit_to_max_receipts": true - }' + "email": "another_email@example.com" + }' - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.receipts.createGlobalInvoice({ - from: '2020-12-01T05:00:00.000Z', - to: '2020-12-31T04:59:59.999Z', - periodicity: 'month', - months: '01', - year: 2021, - folio_number: 1234, - series: 'G', - limit_to_max_receipts: true - }); + # Send to a different email than the one registered by the customer + await facturapi.receipts.sendByEmail( + '58e93bd8e86eb318b019743d', + { email: 'ejemplo@correo.com' } + ); + + # Send to multiple emails (max 10) + await facturapi.receipts.sendByEmail( + '58e93bd8e86eb318b019743d', + { + email: [ + 'primer@correo.com', + 'segundo@correo.com' + ] + } + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Receipt.CreateGlobalInvoiceAsync(new Dictionary - { - ["from"] = "2020-12-01T05:00:00.000Z", - ["to"] = "2020-12-31T04:59:59.999Z", - ["periodicity"] = "month", - ["months"] = "01", - ["year"] = 2021, - ["folio_number"] = 1234, - ["series"] = "G" - }); + // Send to a different email than the one registered by the customer + await facturapi.Receipt.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = "ejemplo@correo.com" + } + ); + + // Send to multiple emails (max 10) + await facturapi.Receipt.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = new String[] + { + "primer@correo.com", + "segundo@correo.com" + } + } + ); - lang: Java label: Java source: | @@ -6654,45 +6800,82 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.receipts().createGlobalInvoice( + var response = facturapi.receipts().sendByEmail( + "rec_123", Map.of( - "month", 5, - "year", 2024 + "to", "cliente@example.com" ) ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Receipts->createGlobalInvoice([ - "from" => "2020-12-01T05:00:00.000Z", - "to" => "2020-12-31T04:59:59.999Z", - "periodicity" => "month", - "months" => "01", - "year" => 2021, - "folio_number" => 1234, - "series" => "G" - ]); + // Send to a different email than the one registered by the customer + $facturapi->Receipts->sendByEmail( + "58e93bd8e86eb318b019743d", + "ejemplo@correo.com" + ); + + // Send to multiple emails (max 10) + $facturapi->Receipts->sendByEmail( + "58e93bd8e86eb318b019743d", + [ + "primer@correo.com", + "segundo@correo.com" + ] + ); + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID of the e-receipt to send requestBody: - $ref: "#/components/requestBodies/ReceiptCreateGlobalInvoice" + required: false + content: + application/json: + schema: + type: object + required: + - email + properties: + email: + description: | + Email address to send the e-receipt. If not sent, the email registered by the customer will be used. + oneOf: + - type: string + format: email + description: Email address to send the e-receipt. + example: other@email.com + - type: array + example: ["first@email.com", "second@email.com"] + description: | + Array of email addresses to send the e-receipt. The maximum number of emails is 10. + maxLength: 10 + items: + type: string + format: email security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Created `Invoice` object, or `null` when the period has no open receipts + description: Generic response object content: application/json: schema: - oneOf: - - $ref: "#/components/schemas/Invoice" - - type: "null" + type: object + required: + - ok + properties: + ok: + type: boolean + description: Indicates if the email was sent successfully "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -7544,6 +7727,72 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" + /retentions/{retention_id}/download-url/{format}: + get: + operationId: getRetentionDownloadUrl + tags: + - retention + summary: Get download URL + description: | + Returns a temporary URL to download the retention in PDF, XML, or both in a ZIP file, without the file travelling through your server. + + The URL grants access to that one file while it is valid: treat it as a credential and do not store it. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/retentions/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.retentions.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); + + console.log(download.url, download.expires_at); + parameters: + - in: path + name: retention_id + schema: + type: string + required: true + description: ID of the object to download + - in: path + name: format + schema: + type: string + enum: + - pdf + - xml + - zip + required: true + description: Format of the file to download + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Temporary download URL for the retention in the requested format + content: + application/json: + schema: + $ref: "#/components/schemas/SignedDownloadUrl" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "409": + $ref: "#/components/responses/Conflict" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" /retentions/{retention_id}/email: post: operationId: sendRetentionByEmail @@ -7810,28 +8059,173 @@ paths: operationId: listOrganizations tags: - organization - summary: List organizations + summary: List organizations + description: | + Returns a paginated list of all the organizations registered under your account, or performs a search according to parameters. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/organizations \ + -H "Authorization: Bearer sk_user_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + const organizationResults = await facturapi.organizations.list(); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + + var searchResult = await facturapi.Organization.ListAsync(); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var searchResult = facturapi.organizations().list( + Map.of( + "page", 0, + "limit", 10 + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + $organizations = $facturapi->Organizations->all() + parameters: + - $ref: "#/components/parameters/SearchPagination" + - $ref: "#/components/parameters/SearchAfter" + - $ref: "#/components/parameters/SearchBefore" + + - in: query + name: q + schema: + type: string + description: Free text search. Text to search in `name` (commercial name) or `legal_name` (fiscal name) or `tax_id` (RFC). + - $ref: "#/components/parameters/SearchDate" + - $ref: "#/components/parameters/SearchPage" + - $ref: "#/components/parameters/SearchLimit" + security: + - "SecretUserKey": [] + responses: + "200": + description: Search results + content: + application/json: + schema: + $ref: "#/components/schemas/OrganizationSearchResult" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + + /organizations/me: + get: + operationId: meOrganization + tags: + - organization + summary: Organization detail + description: | + Returns the detail of a organization registered under your account. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/organizations/me \ + -H "Authorization: Bearer sk_user_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + const organizationResults = await facturapi.organizations.me(); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + + var searchResult = await facturapi.Organization.MeAsync(); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var organization = facturapi.organizations().me( + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + $organizations = $facturapi->Organizations->me() + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: The `Organization` object + content: + application/json: + schema: + $ref: "#/components/schemas/Organization" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /organizations/{organization_id}: + get: + operationId: getOrganization + tags: + - organization + summary: Retrieve organization by ID description: | - Returns a paginated list of all the organizations registered under your account, or performs a search according to parameters. + Retrieve the organization by its ID. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/organizations \ + curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ -H "Authorization: Bearer sk_user_API_KEY" - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - const organizationResults = await facturapi.organizations.list(); + const facturapi = new Facturapi('sk_user_API_KEY'); + const organization = await facturapi.organizations.retrieve( + '5a2a307be93a2f00129ea035' + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - - var searchResult = await facturapi.Organization.ListAsync(); + var facturapi = new FacturapiClient("sk_user_API_KEY"); + var organization = await facturapi.Organization.RetrieveAsync( + "5a2a307be93a2f00129ea035" + ); - lang: Java label: Java source: | @@ -7841,77 +8235,70 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var searchResult = facturapi.organizations().list( - Map.of( - "page", 0, - "limit", 10 - ) + var organization = facturapi.organizations().retrieve( + "org_123" ); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - $organizations = $facturapi->Organizations->all() + $facturapi = new Facturapi("sk_user_API_KEY"); + $organization = $facturapi->Organizations->retrieve("5a2a307be93a2f00129ea035"); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - - - in: query - name: q + - in: path + name: organization_id schema: type: string - description: Free text search. Text to search in `name` (commercial name) or `legal_name` (fiscal name) or `tax_id` (RFC). - - $ref: "#/components/parameters/SearchDate" - - $ref: "#/components/parameters/SearchPage" - - $ref: "#/components/parameters/SearchLimit" + required: true + description: ID of the organization security: + - "SecretLiveKey": [] + - "SecretTestKey": [] - "SecretUserKey": [] responses: "200": - description: Search results + description: "`Organization` object" content: application/json: schema: - $ref: "#/components/schemas/OrganizationSearchResult" + $ref: "#/components/schemas/Organization" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - - /organizations/me: - get: - operationId: meOrganization + delete: + operationId: deleteOrganization tags: - organization - summary: Organization detail + summary: Delete organization description: | - Returns the detail of a organization registered under your account. + Delete the organization from your Facturapi account. Once deleted, you + will not be able to access its resources, such as clients, products, + invoices, receipts, or retentions. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/organizations/me \ + curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ + -X DELETE \ -H "Authorization: Bearer sk_user_API_KEY" - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - const organizationResults = await facturapi.organizations.me(); + const facturapi = new Facturapi('sk_user_API_KEY'); + const organization = await facturapi.organizations.del( + '5a2a307be93a2f00129ea035' + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - - var searchResult = await facturapi.Organization.MeAsync(); + var facturapi = new FacturapiClient("sk_user_API_KEY"); + var organization = await facturapi.Organization.DeleteAsync( + "5a2a307be93a2f00129ea035" + ); - lang: Java label: Java source: | @@ -7921,19 +8308,27 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var organization = facturapi.organizations().me( + var organization = facturapi.organizations().delete( + "org_123" ); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - $organizations = $facturapi->Organizations->me() + $facturapi = new Facturapi("sk_user_API_KEY"); + $organization = $facturapi->Organizations->delete( + "5a2a307be93a2f00129ea035" + ); + parameters: + - in: path + name: organization_id + schema: + type: string + required: true + description: ID of the organization security: - - "SecretLiveKey": [] - - "SecretTestKey": [] + - "SecretUserKey": [] responses: "200": - description: The `Organization` object + description: "`Organization` object deleted" content: application/json: schema: @@ -7942,8 +8337,6 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -8926,160 +9319,14 @@ paths: type: string required: true description: ID of the organization - requestBody: - $ref: "#/components/requestBodies/OrganizationEditDomain" - security: - - "SecretLiveKey": [] - - "SecretUserKey": [] - responses: - "200": - description: Modified `Organization` object - content: - application/json: - schema: - $ref: "#/components/schemas/Organization" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /organizations/{organization_id}: - get: - operationId: getOrganization - tags: - - organization - summary: Retrieve organization by ID - description: | - Retrieve the organization by its ID. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ - -H "Authorization: Bearer sk_user_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_user_API_KEY'); - const organization = await facturapi.organizations.retrieve( - '5a2a307be93a2f00129ea035' - ); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_user_API_KEY"); - var organization = await facturapi.Organization.RetrieveAsync( - "5a2a307be93a2f00129ea035" - ); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var organization = facturapi.organizations().retrieve( - "org_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_user_API_KEY"); - $organization = $facturapi->Organizations->retrieve("5a2a307be93a2f00129ea035"); - parameters: - - in: path - name: organization_id - schema: - type: string - required: true - description: ID of the organization - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - - "SecretUserKey": [] - responses: - "200": - description: "`Organization` object" - content: - application/json: - schema: - $ref: "#/components/schemas/Organization" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - delete: - operationId: deleteOrganization - tags: - - organization - summary: Delete organization - description: | - Delete the organization from your Facturapi account. Once deleted, you - will not be able to access its resources, such as clients, products, - invoices, receipts, or retentions. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ - -X DELETE \ - -H "Authorization: Bearer sk_user_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_user_API_KEY'); - const organization = await facturapi.organizations.del( - '5a2a307be93a2f00129ea035' - ); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_user_API_KEY"); - var organization = await facturapi.Organization.DeleteAsync( - "5a2a307be93a2f00129ea035" - ); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var organization = facturapi.organizations().delete( - "org_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_user_API_KEY"); - $organization = $facturapi->Organizations->delete( - "5a2a307be93a2f00129ea035" - ); - parameters: - - in: path - name: organization_id - schema: - type: string - required: true - description: ID of the organization + requestBody: + $ref: "#/components/requestBodies/OrganizationEditDomain" security: + - "SecretLiveKey": [] - "SecretUserKey": [] responses: "200": - description: "`Organization` object deleted" + description: Modified `Organization` object content: application/json: schema: @@ -9088,6 +9335,8 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -11929,255 +12178,6 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/download-url/{format}: - get: - operationId: getInvoiceDownloadUrl - tags: - - invoice - summary: Get download URL - description: | - Returns a temporary URL to download the invoice in PDF, XML, or both in a ZIP file, without the file travelling through your server. - - The URL grants access to that one file while it is valid: treat it as a credential and do not store it. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.invoices.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the object to download - - in: path - name: format - schema: - type: string - enum: - - pdf - - xml - - zip - required: true - description: Format of the file to download - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Temporary download URL for the CFDI in the requested format - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "409": - $ref: "#/components/responses/Conflict" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/cancellation_receipt/download-url/{format}: - get: - operationId: getCancellationReceiptDownloadUrl - tags: - - invoice - summary: Get cancellation receipt download URL - description: | - Returns a temporary URL to download the XML or PDF receipt issued by SAT when a cancellation request is submitted through Facturapi, without the file travelling through your server. The receipt contains the immediate request result and does not necessarily prove that the CFDI is already canceled; check the invoice status to confirm the outcome. - - The URL grants access to that one file while it is valid: treat it as a credential and do not store it. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.invoices.downloadCancellationReceiptPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID of the object to download - - in: path - name: format - schema: - type: string - enum: - - xml - - pdf - required: true - description: Format of the cancellation receipt - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Temporary download URL for the cancellation receipt in the requested format - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/download-url/pdf: - get: - operationId: getReceiptDownloadUrl - tags: - - receipt - summary: Get download URL - description: | - Returns a temporary URL to download the receipt in PDF, without the file travelling through your server. - - The URL grants access to that one file while it is valid: treat it as a credential and do not store it. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.receipts.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID of the object to download - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Temporary download URL for the receipt in PDF - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /retentions/{retention_id}/download-url/{format}: - get: - operationId: getRetentionDownloadUrl - tags: - - retention - summary: Get download URL - description: | - Returns a temporary URL to download the retention in PDF, XML, or both in a ZIP file, without the file travelling through your server. - - The URL grants access to that one file while it is valid: treat it as a credential and do not store it. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/retentions/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.retentions.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: retention_id - schema: - type: string - required: true - description: ID of the object to download - - in: path - name: format - schema: - type: string - enum: - - pdf - - xml - - zip - required: true - description: Format of the file to download - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Temporary download URL for the retention in the requested format - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "409": - $ref: "#/components/responses/Conflict" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" webhooks: invoice.global_invoice_created: post: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 2082883a4..544e60267 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -3621,58 +3621,30 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests: - post: - operationId: createInvoiceZipRequest + /invoices/{invoice_id}: + get: + operationId: getInvoice tags: - invoice - summary: Crear o recuperar solicitud de ZIP mensual - description: | - Crea una solicitud para generar un archivo ZIP con las facturas de un mes, o recupera la solicitud existente con los mismos filtros. - - La operación es idempotente. Los tipos de factura se normalizan, por lo que `["I", "E"]` y `["E", "I"]` corresponden a la misma solicitud. Las llamadas concurrentes idénticas también regresan la misma solicitud. - - Si una solicitud anterior tiene status `failed`, volver a llamar este método reintentará su procesamiento. Antes del nuevo intento se limpian el error, la tarea anterior, el progreso procesado y la lista de documentos fallidos. Si no es posible programar la generación, la solicitud se guarda con status `failed` y la API regresa un error `5xx`. - - Este método requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. Las llaves de ambiente Test regresan HTTP 402. + summary: Obtener factura por ID + description: Regresa el objeto 'Invoice' relacionado al `id` especificado. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests \ - -H "Authorization: Bearer sk_live_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "year": 2025, - "month": 3, - "issuer_type": "issuing", - "invoice_types": ["I", "E"] - }' + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequest = await facturapi.invoices.createZipRequest({ - year: 2025, - month: 3, - issuer_type: 'issuing', - invoice_types: ['I', 'E'] - }); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.retrieve('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequest = await facturapi.Invoice.CreateZipRequestAsync( - new Dictionary - { - ["year"] = 2025, - ["month"] = 3, - ["issuer_type"] = "issuing", - ["invoice_types"] = new[] { "I", "E" } - } - ); + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.RetrieveAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | @@ -3680,495 +3652,452 @@ paths: import java.util.List; import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequest = facturapi.invoices().createZipRequest( - Map.of( - "year", 2025, - "month", 3, - "issuer_type", "issuing", - "invoice_types", List.of("I", "E") - ) - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().retrieve( + "inv_123" + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequest = $facturapi->Invoices->createZipRequest([ - "year" => 2025, - "month" => 3, - "issuer_type" => "issuing", - "invoice_types" => ["I", "E"] - ]); - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/InvoiceZipRequestCreateInput" + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->retrieve( "58e93bd8e86eb318b019743d" ); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID del objeto a obtener security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Solicitud de ZIP creada o recuperada correctamente. + description: Objeto `Invoice` content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequest" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNoInvoices" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - get: - operationId: listInvoiceZipRequests + put: + operationId: updateDraftInvoice tags: - invoice - summary: Listar solicitudes de ZIP mensual + summary: Editar borrador de factura description: | - Regresa una lista paginada de solicitudes de ZIP. `year` y `month` deben enviarse juntos. `invoice_types` filtra por un tipo o por un arreglo normalizado exacto. + Actualiza la información de una factura con status `draft`, asignando + los valores de los parámetros enviados. Los parámetros que no se envíen + en la petición no se modificarán. - Este método requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. + En el objeto `invoice` de respuesta, Facturapi asignará automáticamente + el campo `is_ready_to_stamp` con el valor `true` si la factura pasa la + validación mínima requerida para ser timbrada; de lo contrario, el campo + `is_ready_to_stamp` será `false`. x-codeSamples: - lang: Bash label: cURL source: | - curl "https://www.facturapi.io/v2/invoices/zip-requests?year=2025&month=3&status=finished&limit=20&page=1" \ - -H "Authorization: Bearer sk_live_API_KEY" + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + -X PUT \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "payment_form": "06" + }' - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequests = await facturapi.invoices.listZipRequests({ - year: 2025, - month: 3, - status: 'finished', - limit: 20, - page: 1 - }); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.updateDraft( + '58e93bd8e86eb318b019743d', + { + payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO + } + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequests = await facturapi.Invoice.ListZipRequestsAsync( + var facturapi = new Facturapi("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.UpdateDraftAsync( + "58e93bd8e86eb318b019743d", new Dictionary { - ["year"] = 2025, - ["month"] = 3, - ["status"] = "finished", - ["limit"] = 20, - ["page"] = 1 + ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO } ); - lang: Java label: Java source: | import io.facturapi.Facturapi; + import java.util.List; import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequests = facturapi.invoices().listZipRequests( - Map.of( - "year", 2025, - "month", 3, - "status", "finished", - "limit", 20, - "page", 1 - ) - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().updateDraft("inv_123", Map.of( + "items", List.of( + Map.of( + "quantity", 1, + "product", "prod_123" + ) + ) + )); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequests = $facturapi->Invoices->listZipRequests([ - "year" => 2025, - "month" => 3, - "status" => "finished", - "limit" => 20, - "page" => 1 + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->updateDraft("58e93bd8e86eb318b019743d", [ + "payment_form" => \Facturapi\PaymentForm::EFECTIVO ]); parameters: - - in: query - name: year - schema: - type: integer - minimum: 2000 - maximum: 9999 - description: Año a filtrar. Debe enviarse junto con `month`. - - in: query - name: month - schema: - type: integer - minimum: 1 - maximum: 12 - description: Mes a filtrar. Debe enviarse junto con `year`. - - in: query - name: status - schema: - $ref: "#/components/schemas/InvoiceZipRequestStatus" - description: Status de la solicitud. - - in: query - name: issuer_type - schema: - $ref: "#/components/schemas/IssuingType" - description: Filtra facturas emitidas o recibidas. - - in: query - name: invoice_types - schema: - type: array - uniqueItems: true - items: - $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" - description: Filtra por un tipo de factura o por un arreglo normalizado exacto. - - in: query - name: page + - in: path + name: invoice_id schema: - type: integer - minimum: 1 - default: 1 - description: Página de resultados, empezando en 1. - - $ref: "#/components/parameters/SearchLimit" + type: string + required: true + description: ID del objeto a editar + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Resultado paginado de solicitudes de ZIP. + description: Objeto `Invoice` editado correctamente content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequestSearchResult" + $ref: "#/components/schemas/InvoiceDraft" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}: - get: - operationId: retrieveInvoiceZipRequest + delete: + operationId: cancelInvoice tags: - invoice - summary: Recuperar solicitud de ZIP mensual + summary: Cancelar factura description: | - Recupera una solicitud de ZIP. Consulta este método hasta que el status sea `finished` o `failed`. Cuando sea `finished`, descarga el archivo con el método de descarga. + Realiza una solicitud de cancelación de factura ante el SAT, soportando el esquema de cancelación 2022. - Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000 \ - -H "Authorization: Bearer sk_live_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; + Al usar este método pueden ocurrir 3 posibles resultados: - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipRequest = await facturapi.invoices.retrieveZipRequest( - '66b0f0000000000000000000' + - Que la llamada regrese un error con la explicación de por qué no se pudo cancelar. + - Que la llamada sea satisfactoria y regrese un objeto `invoice` con la propiedad `status: "canceled"`. + - Que la llamada sea satisfactoria, pero que la cancelación requiera de confirmación de parte de tu cliente, en cuyo caso se obtendrá como respuesta el objeto `invoice` con las propiedades `status: "valid"` y `cancellation_status: "pending"`. + + En el tercer escenario, el valor de `cancellation_status` será actualizado automáticamente por Facturapi cuando tu cliente acepte, rechace o deje expirar la solicitud, de tal manera que al consultar una factura (usando [Obtener Factura](#tag/invoice/operation/getInvoice)), la propiedad `cancellation_status` reflejará el estado más reciente de la solicitud. + + Consulta los valores posibles de `cancellation_status` más abajo. + + Después de la cancelación la factura ya no tendrá validez, el objeto cambiará su `status` a `"canceled"` y seguirá estando disponible para futuras consultas. + + Si el status de la factura es `draft`, este método la eliminará de la base de datos. + + Si el status de la factura es `canceled`, este método regresará un error. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d?motive=02 \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X DELETE + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.cancel( + '58e93bd8e86eb318b019743d', + { motive: '02' } ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipRequest = await facturapi.Invoice.RetrieveZipRequestAsync( - "66b0f0000000000000000000" + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.CancelAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["motive"] = "02" + } ); - lang: Java label: Java source: | import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - var zipRequest = facturapi.invoices().retrieveZipRequest( - "66b0f0000000000000000000" - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var invoice = facturapi.invoices().cancel( + "inv_123", + Map.of( + "motive", "02" + ) + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zipRequest = $facturapi->Invoices->retrieveZipRequest( - "66b0f0000000000000000000" + $facturapi = new Facturapi("sk_test_API_KEY"); + $canceled_invoice = $facturapi->Invoices->cancel( + "58e93bd8e86eb318b019743d", + [ + "motive" => "02" + ] ); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID de la factura a cancelar + - in: query + name: motive + required: true + schema: + type: string + enum: + - "01" + - "02" + - "03" + - "04" + description: | + Clave que representa el motivo de la cancelación de la factura. + + - `01`: **Comprobante emitido con errores con relación**. Cuando la + factura contiene algún error en las cantidades, claves o cualquier otro dato y ya + se ha emitido el comprobante que la sustituye, el cual deberá indicarse por medio + del atributo `substitution`. + - `02`: **Comprobante emitido con errores sin relación**. Cuando la + factura contiene algún error en las cantidades, claves o cualquier otro dato y no + se requiere relacionar con otra factura. + - `03`: **No se llevó a cabo la operación**. Cuando la venta o transacción no se concretó. + - `04`: **Operación nominativa relacionada en la factura global**. Cuando se requiere cancelar + una factura al público en general porque el cliente solicita su comprobante. + - in: query + name: substitution + required: false + schema: + type: string + description: | + ID de la factura que sustituye a la factura que se está cancelando. + + Puedes usar el ID de Facturapi o el folio fiscal (UUID). security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Solicitud de ZIP recuperada correctamente. + description: Solicitud de cancelación exitosa content: application/json: schema: - $ref: "#/components/schemas/InvoiceZipRequest" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}/zip: - get: - operationId: downloadInvoiceZipRequest + /invoices/{invoice_id}/copy: + post: + operationId: copyToDraftInvoice tags: - invoice - summary: Descargar ZIP mensual + summary: Copiar a borrador description: | - Descarga el ZIP de una solicitud terminada. El nombre del archivo usa el formato `YYYY-MM.zip`. - - Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. + Crea una copia en borrador de la factura especificada. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/zip \ - -H "Authorization: Bearer sk_live_API_KEY" \ - --output 2025-03.zip + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/copy \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST - lang: JavaScript label: Node.js source: | - import fs from 'fs'; - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_live_API_KEY'); - const zipStream = await facturapi.invoices.downloadZipRequest( - '66b0f0000000000000000000' - ); - zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const invoice = await facturapi.invoices.copyToDraft('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_live_API_KEY"); - var zipStream = await facturapi.Invoice.DownloadZipRequestAsync( - "66b0f0000000000000000000" - ); - await using var file = File.Create("2025-03.zip"); - await zipStream.CopyToAsync(file); + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var invoice = await facturapi.Invoice.CopyToDraftAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.io.InputStream; - import java.nio.file.Files; - import java.nio.file.Path; - import java.nio.file.StandardCopyOption; + import java.util.List; + import java.util.Map; - Facturapi facturapi = new Facturapi("sk_live_API_KEY"); - try (InputStream zipStream = facturapi.invoices().downloadZipRequest( - "66b0f0000000000000000000" - )) { - Files.copy(zipStream, Path.of("./2025-03.zip"), StandardCopyOption.REPLACE_EXISTING); - } + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var draft = facturapi.invoices().copyToDraft( + "inv_123" + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_live_API_KEY"); - $zip = $facturapi->Invoices->downloadZipRequest( - "66b0f0000000000000000000" - ); - file_put_contents("2025-03.zip", $zip); + $facturapi = new Facturapi("sk_test_API_KEY"); + $invoice = $facturapi->Invoices->copyToDraft("58e93bd8e86eb318b019743d"); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID de la factura a copiar security: - "SecretLiveKey": [] + - "SecretTestKey": [] responses: "200": - description: Archivo ZIP generado. - headers: - Content-Disposition: - description: Nombre sugerido con formato `attachment; filename="YYYY-MM.zip"`. - schema: - type: string + description: Nuevo objeto `Invoice` con status `draft`. content: - application/zip: + application/json: schema: - type: string - format: binary + $ref: "#/components/schemas/InvoiceDraft" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" - "409": - $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/zip-requests/{id}/download-url: - get: - operationId: getInvoiceZipRequestDownloadUrl + /invoices/{invoice_id}/stamp: + post: + operationId: stampDraftInvoice tags: - invoice - summary: Obtener URL de descarga del ZIP mensual + summary: Timbrar borrador de factura description: | - Devuelve una URL temporal para descargar el ZIP de una solicitud terminada sin que el archivo viaje a través de tu servidor. + Timbra una factura con status `draft` y la envía al SAT para su validación. - La URL permite acceder únicamente a ese archivo mientras sea válida: trátala como una credencial y no la almacenes. Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. + Al usar este método, el valor del campo `is_ready_to_stamp` (asignado por Facturapi) + deberá ser `true`. De otra forma, la llamada regresará un error. + + Este método no permite editar la factura, sólo timbrarla. Si necesitas editar información + en la factura antes de timbrarla, usa el método [Editar Borrador de Factura](#tag/invoice/operation/editDraftInvoice). x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/download-url \ - -H "Authorization: Bearer sk_live_API_KEY" + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/stamp \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi'; + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + const stampedInvoice = await facturapi.invoices.stampDraft('58e93bd8e86eb318b019743d'); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var stampedInvoice = await facturapi.Invoice.StampDraftAsync("58e93bd8e86eb318b019743d"); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; - const facturapi = new Facturapi('sk_live_API_KEY'); - const download = await facturapi.invoices.downloadZipRequestUrl( - '66b0f0000000000000000000' - ); + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - console.log(download.url, download.expires_at); + var invoice = facturapi.invoices().stampDraft( + "inv_123", + Map.of( + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + $stamped_invoice = $facturapi->Invoices->stampDraft("58e93bd8e86eb318b019743d"); parameters: - - $ref: "#/components/parameters/InvoiceZipRequestId" - security: - - "SecretLiveKey": [] - responses: - "200": - description: URL temporal de descarga para el archivo ZIP generado. + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID del objeto a timbrar + - in: query + name: async + schema: + type: boolean + required: false + description: | + Útil para facturas de gran tamaño. Si se envía `false` o no se envía, la llamada esperará a que el SAT responda timbrando la factura. + Si se envía `true`, la llamada regresará inmediatamente con el objeto `invoice` en status `pending`, y podrá consultarse su cambio de status + a `valid` en un momento posterior. + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Objeto `Invoice` timbrado correctamente content: application/json: schema: - $ref: "#/components/schemas/SignedDownloadUrl" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "402": - $ref: "#/components/responses/InvoiceZipRequestAccessRequired" - "404": - $ref: "#/components/responses/InvoiceZipRequestNotFound" "409": - $ref: "#/components/responses/InvoiceZipRequestNotReady" + $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/preview/pdf: - post: - operationId: previewInvoicePdf + + /invoices/{invoice_id}/status: + put: + operationId: updateInvoiceStatus tags: - invoice - summary: Vista previa de factura en PDF - description: Genera una vista previa en PDF de una factura sin timbrar ni guardar en la organización. + summary: | + Actualizar status de factura + description: | + Consulta el status de una factura timbrada en el SAT y actualiza el objeto invoice + con La información más reciente. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/preview/pdf \ + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/status \ -H "Authorization: Bearer sk_test_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "customer": { - "legal_name": "Dunder Mifflin", - "email": "email@example.com", - "tax_id": "ABC101010111", - "tax_system": "601", - "address": { - "zip": "85900" - } - }, - "items": [{ - "quantity": 2, - "product": { - "description": "Ukelele", - "product_key": "60131324", - "price": 345.60 - } - }], - "payment_form": "06", - "folio_number": 914, - "series": "F" - }' + -X PUT - lang: JavaScript label: Node.js source: | - const Facturapi = require('facturapi'); + import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const pdfStream = await facturapi.invoices.previewPdf({ - customer: { - legal_name: 'Dunder Mifflin', - email: 'email@example.com', - tax_id: 'ABC101010111', - tax_system: '601', - address: { - zip: '85900' - } - }, - items: [{ - quantity: 2, - product: { - description: 'Ukelele', - product_key: '60131324', - price: 345.60 - } - }], - payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO, - folio_number: 914, - series: 'F' - }); - // Save PDF stream to a file - const fs = require('fs'); - const file = fs.createWriteStream('invoice_preview.pdf'); - pdfStream.pipe(file); + const invoice = await facturapi.invoices.updateStatus('58e93bd8e86eb318b019743d'); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var pdfStream = await facturapi.Invoice.PreviewPdfAsync(new Dictionary - { - ["customer"] = new Dictionary - { - ["legal_name"] = "Dunder Mifflin", - ["email"] = "email@example.com", - ["tax_id"] = "ABC101010111", - ["tax_system"] = "601", - ["address"] = new Dictionary - { - ["zip"] = "85900" - } - }, - ["items"] = new Dictionary[] - { - new Dictionary - { - ["product"] = new Dictionary - { - ["description"] = "Ukelele", - ["product_key"] = "60131324", - ["price"] = 345.60 - } - } - }, - ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO, - ["folio_number"] = 914, - ["series"] = "F" - }); - // Save PDF stream to a file - var file = new System.IO.FileStream("invoice_preview.pdf", System.IO.FileMode.Create, System.IO.FileAccess.Write); - pdfStream.CopyTo(file); - file.Close(); + var facturapi = new Facturapi + var invoice = await facturapi.Invoice.UpdateStatusAsync("58e93bd8e86eb318b019743d"); - lang: Java label: Java source: | @@ -4178,94 +4107,30 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var pdf = facturapi.invoices().previewPdf( - Map.of( - "customer", "cus_123", - "items", List.of( - Map.of( - "quantity", 1, - "product", "prod_123" - ) - ) - )); + var invoice = facturapi.invoices().updateStatus( + "inv_123" + ); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $pdfBytes = $facturapi->Invoices->previewPdf([ - "customer" => [ - "legal_name" => "Dunder Mifflin", - "email" => "email@example.com", - "tax_id" => "ABC101010111", - "tax_system" => "601", - "address" => [ - "zip" => "85900" - ] - ], - "items" => [ - [ - "quantity" => 2, - "product" => [ - "description" => "Ukelele", - "product_key" => "60131324", - "price" => 345.60, - "sku" => "ABC4567" - ] - ] - ], - "payment_form" => \Facturapi\PaymentForm::EFECTIVO, - "folio_number" => 914, - "series" => "F" - ]); - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: El archivo PDF de la factura - content: - application/pdf: - schema: - type: string - format: binary - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/preview/pdf/download-url: - post: - operationId: previewInvoicePdfUrl - tags: - - invoice - summary: Obtener URL del preview PDF de factura - description: Devuelve una URL temporal para el preview PDF de una factura sin timbrar. - x-codeSamples: - - lang: JavaScript - label: Node.js - source: | - const download = await facturapi.invoices.previewPdfUrl({ - customer: 'cus_123', - items: [{ product: 'prod_123' }], - payment_form: '06' - }); - console.log(download.url, download.expires_at); - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" + $invoice = $facturapi->Invoices->updateStatus("58e93bd8e86eb318b019743d"); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID del objeto invoice a actualizar security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: URL temporal de descarga para el preview PDF. + description: Objeto `Invoice` actualizado content: application/json: schema: - $ref: "#/components/schemas/SignedDownloadUrl" + $ref: "#/components/schemas/Invoice" "400": $ref: "#/components/responses/BadRequest" "401": @@ -4274,118 +4139,267 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}: + + /invoices/{invoice_id}/payment-summary: get: - operationId: getInvoice + operationId: getInvoicePaymentSummary tags: - invoice - summary: Obtener factura por ID - description: Regresa el objeto 'Invoice' relacionado al `id` especificado. + summary: Resumen de pago + description: | + Devuelve la información necesaria para agregar esta factura como documento relacionado en un + Comprobante de Pago (complemento de pago): el número de parcialidad que corresponde según el + historial de pagos, el saldo anterior (`last_balance`) y el desglose de impuestos de la factura + prorrateado al monto que se pretende pagar. + + El valor de retorno está listo para usarse como elemento de `related_documents` al + [crear una factura de tipo Pago](#tag/invoice/operation/createInvoice). + + El parámetro `amount` debe expresarse en la divisa de la factura y no puede exceder el saldo + pendiente (`amount_due`). Cuando el pago se recibe en otra divisa, convierte el monto antes de + llamar este método. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ + curl "https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/payment-summary?amount=100" \ -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.retrieve('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.RetrieveAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const summary = await facturapi.invoices.paymentSummary( + '58e93bd8e86eb318b019743d', + { amount: 100 } + ); - var invoice = facturapi.invoices().retrieve( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->retrieve( "58e93bd8e86eb318b019743d" ); + // El resumen va completo como related_document del complemento + const invoice = await facturapi.invoices.create({ + type: 'P', + customer: 'customer_id', + complements: [ + { + type: 'pago', + data: [ + { + payment_form: '28', + related_documents: [summary] + } + ] + } + ] + }); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID del objeto a obtener + description: ID de la factura de ingreso (método de pago PPD) que se desea pagar + - in: query + name: amount + schema: + type: number + required: true + description: Monto que se paga de esta factura, expresado en la divisa de la factura. No puede exceder el saldo pendiente. security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Objeto `Invoice` + description: Resumen del documento relacionado content: application/json: schema: - $ref: "#/components/schemas/Invoice" + type: object + required: + - uuid + - series + - installment + - last_balance + - total + - currency + - amount + - taxes + properties: + uuid: + type: string + description: UUID de la factura + folio_number: + type: number + description: Folio de la factura. Se omite si la factura no lo tiene registrado. + series: + type: ["string","null"] + description: Serie de la factura + installment: + type: number + description: Número de parcialidad que corresponde a este pago + last_balance: + type: number + description: Saldo pendiente de la factura antes de aplicar este pago + total: + type: number + description: Total de la factura + currency: + type: string + description: Divisa de la factura + amount: + type: number + description: Monto que se paga en esta parcialidad + taxes: + type: array + description: Impuestos de la factura prorrateados al monto pagado + items: + type: object + properties: + base: + type: number + description: Base del impuesto prorrateada al monto pagado + rate: + type: number + description: Tasa o cuota del impuesto + type: + type: string + description: Tipo de impuesto (IVA, ISR, etc.) + factor: + type: string + description: Tipo de factor (Tasa, Exento, etc.) + withholding: + type: boolean + description: Indica si se trata de una retención + example: + uuid: 39c85a3f-275b-4341-b259-e8971d9f8a94 + folio_number: 914 + series: F + installment: 2 + last_balance: 245.6 + total: 345.6 + currency: MXN + amount: 100 + taxes: + - base: 86.21 + rate: 0.16 + type: IVA + factor: Tasa + withholding: false "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - put: - operationId: updateDraftInvoice + + /invoices/preview/pdf: + post: + operationId: previewInvoicePdf tags: - invoice - summary: Editar borrador de factura - description: | - Actualiza la información de una factura con status `draft`, asignando - los valores de los parámetros enviados. Los parámetros que no se envíen - en la petición no se modificarán. - - En el objeto `invoice` de respuesta, Facturapi asignará automáticamente - el campo `is_ready_to_stamp` con el valor `true` si la factura pasa la - validación mínima requerida para ser timbrada; de lo contrario, el campo - `is_ready_to_stamp` será `false`. + summary: Vista previa de factura en PDF + description: Genera una vista previa en PDF de una factura sin timbrar ni guardar en la organización. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d \ - -X PUT \ + curl https://www.facturapi.io/v2/invoices/preview/pdf \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "payment_form": "06" - }' + "customer": { + "legal_name": "Dunder Mifflin", + "email": "email@example.com", + "tax_id": "ABC101010111", + "tax_system": "601", + "address": { + "zip": "85900" + } + }, + "items": [{ + "quantity": 2, + "product": { + "description": "Ukelele", + "product_key": "60131324", + "price": 345.60 + } + }], + "payment_form": "06", + "folio_number": 914, + "series": "F" + }' - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' + const Facturapi = require('facturapi'); const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.updateDraft( - '58e93bd8e86eb318b019743d', - { - payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO - } - ); + const pdfStream = await facturapi.invoices.previewPdf({ + customer: { + legal_name: 'Dunder Mifflin', + email: 'email@example.com', + tax_id: 'ABC101010111', + tax_system: '601', + address: { + zip: '85900' + } + }, + items: [{ + quantity: 2, + product: { + description: 'Ukelele', + product_key: '60131324', + price: 345.60 + } + }], + payment_form: Facturapi.PaymentForm.DINERO_ELECTRONICO, + folio_number: 914, + series: 'F' + }); + // Save PDF stream to a file + const fs = require('fs'); + const file = fs.createWriteStream('invoice_preview.pdf'); + pdfStream.pipe(file); - lang: csharp label: C# source: | - var facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.UpdateDraftAsync( - "58e93bd8e86eb318b019743d", - new Dictionary + var facturapi = new FacturapiClient("sk_test_API_KEY"); + var pdfStream = await facturapi.Invoice.PreviewPdfAsync(new Dictionary + { + ["customer"] = new Dictionary { - ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO - } - ); + ["legal_name"] = "Dunder Mifflin", + ["email"] = "email@example.com", + ["tax_id"] = "ABC101010111", + ["tax_system"] = "601", + ["address"] = new Dictionary + { + ["zip"] = "85900" + } + }, + ["items"] = new Dictionary[] + { + new Dictionary + { + ["product"] = new Dictionary + { + ["description"] = "Ukelele", + ["product_key"] = "60131324", + ["price"] = 345.60 + } + } + }, + ["payment_form"] = Facturapi.PaymentForm.DINERO_ELECTRONICO, + ["folio_number"] = 914, + ["series"] = "F" + }); + // Save PDF stream to a file + var file = new System.IO.FileStream("invoice_preview.pdf", System.IO.FileMode.Create, System.IO.FileAccess.Write); + pdfStream.CopyTo(file); + file.Close(); - lang: Java label: Java source: | @@ -4395,7 +4409,9 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.invoices().updateDraft("inv_123", Map.of( + var pdf = facturapi.invoices().previewPdf( + Map.of( + "customer", "cus_123", "items", List.of( Map.of( "quantity", 1, @@ -4406,28 +4422,81 @@ paths: - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->updateDraft("58e93bd8e86eb318b019743d", [ - "payment_form" => \Facturapi\PaymentForm::EFECTIVO - ]); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto a editar - requestBody: - $ref: "#/components/requestBodies/InvoiceEdit" - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Objeto `Invoice` editado correctamente + $pdfBytes = $facturapi->Invoices->previewPdf([ + "customer" => [ + "legal_name" => "Dunder Mifflin", + "email" => "email@example.com", + "tax_id" => "ABC101010111", + "tax_system" => "601", + "address" => [ + "zip" => "85900" + ] + ], + "items" => [ + [ + "quantity" => 2, + "product" => [ + "description" => "Ukelele", + "product_key" => "60131324", + "price" => 345.60, + "sku" => "ABC4567" + ] + ] + ], + "payment_form" => \Facturapi\PaymentForm::EFECTIVO, + "folio_number" => 914, + "series" => "F" + ]); + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: El archivo PDF de la factura + content: + application/pdf: + schema: + type: string + format: binary + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/preview/pdf/download-url: + post: + operationId: previewInvoicePdfUrl + tags: + - invoice + summary: Obtener URL del preview PDF de factura + description: Devuelve una URL temporal para el preview PDF de una factura sin timbrar. + x-codeSamples: + - lang: JavaScript + label: Node.js + source: | + const download = await facturapi.invoices.previewPdfUrl({ + customer: 'cus_123', + items: [{ product: 'prod_123' }], + payment_form: '06' + }); + console.log(download.url, download.expires_at); + requestBody: + $ref: "#/components/requestBodies/InvoiceEdit" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: URL temporal de descarga para el preview PDF. content: application/json: schema: - $ref: "#/components/schemas/InvoiceDraft" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": @@ -4436,293 +4505,197 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - delete: - operationId: cancelInvoice + /invoices/{invoice_id}/{format}: + get: + operationId: downloadInvoice tags: - invoice - summary: Cancelar factura - description: | - Realiza una solicitud de cancelación de factura ante el SAT, soportando el esquema de cancelación 2022. - - Al usar este método pueden ocurrir 3 posibles resultados: - - - Que la llamada regrese un error con la explicación de por qué no se pudo cancelar. - - Que la llamada sea satisfactoria y regrese un objeto `invoice` con la propiedad `status: "canceled"`. - - Que la llamada sea satisfactoria, pero que la cancelación requiera de confirmación de parte de tu cliente, en cuyo caso se obtendrá como respuesta el objeto `invoice` con las propiedades `status: "valid"` y `cancellation_status: "pending"`. - - En el tercer escenario, el valor de `cancellation_status` será actualizado automáticamente por Facturapi cuando tu cliente acepte, rechace o deje expirar la solicitud, de tal manera que al consultar una factura (usando [Obtener Factura](#tag/invoice/operation/getInvoice)), la propiedad `cancellation_status` reflejará el estado más reciente de la solicitud. - - Consulta los valores posibles de `cancellation_status` más abajo. - - Después de la cancelación la factura ya no tendrá validez, el objeto cambiará su `status` a `"canceled"` y seguirá estando disponible para futuras consultas. - - Si el status de la factura es `draft`, este método la eliminará de la base de datos. - - Si el status de la factura es `canceled`, este método regresará un error. + summary: Descargar factura + description: Descarga tu Factura en PDF, XML o ambos en un archivo comprimido ZIP. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d?motive=02 \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X DELETE + ## Descargar PDF y XML comprimidos en archivo ZIP + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/zip \ + -H "Authorization: Bearer sk_test_API_KEY" + + ## Descargar sólo el PDF + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + + ## Descargar sólo el XML + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/xml \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | + import fs from 'fs'; import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.cancel( - '58e93bd8e86eb318b019743d', - { motive: '02' } - ); + + // Descargar PDF y XML comprimidos en archivo ZIP + const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); + const zipFile = fs.createWriteStream('./factura.zip'); + zipStream.pipe(zipFile); + + // Descargar sólo el PDF + const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); + const pdfFile = fs.createWriteStream('./factura.pdf'); + pdfStream.pipe(pdfFile); + + // Descargar sólo el XML + const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); + const xmlFile = fs.createWriteStream('./factura.xml'); + xmlStream.pipe(xmlFile); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.CancelAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["motive"] = "02" - } - ); + // Descargar PDF y XML comprimidos en archivo ZIP + var zipStream = await facturapi.Invoice.DownloadZipAsync("58e93bd8e86eb318b019743d"); + // Descargar sólo el XML + var xmlStream = await facturapi.Invoice.DownloadXmlAsync("58e93bd8e86eb318b019743d"); + // Descargar sólo el PDF + var pdfStream = await facturapi.Invoice.DownloadPdfAsync("58e93bd8e86eb318b019743d"); + + // Para guardar la descarga en un archivo + var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.zip", FileMode.Create); + zipStream.CopyTo(file); + file.Close(); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; + import java.io.InputStream; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardCopyOption; Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var invoice = facturapi.invoices().cancel( - "inv_123", - Map.of( - "motive", "02" - ) - ); + try (InputStream zipStream = facturapi.invoices().downloadZip("58e93bd8e86eb318b019743d")) { + Files.copy(zipStream, Path.of("./factura.zip"), StandardCopyOption.REPLACE_EXISTING); + } + + try (InputStream pdfStream = facturapi.invoices().downloadPdf("58e93bd8e86eb318b019743d")) { + Files.copy(pdfStream, Path.of("./factura.pdf"), StandardCopyOption.REPLACE_EXISTING); + } + + try (InputStream xmlStream = facturapi.invoices().downloadXml("58e93bd8e86eb318b019743d")) { + Files.copy(xmlStream, Path.of("./factura.xml"), StandardCopyOption.REPLACE_EXISTING); + } - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); - $canceled_invoice = $facturapi->Invoices->cancel( - "58e93bd8e86eb318b019743d", - [ - "motive" => "02" - ] - ); + + // stream containing the PDF and XML as a ZIP file + $zip = $facturapi->Invoices->downloadZip("58e93bd8e86eb318b019743d"); + // stream containing the PDF file + $pdf = $facturapi->Invoices->downloadPdf("58e93bd8e86eb318b019743d"); + // stream containing the XML file + $xml = $facturapi->Invoices->downloadXml("58e93bd8e86eb318b019743d"); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID de la factura a cancelar - - in: query - name: motive - required: true + description: ID del objeto a descargar + - in: path + name: format schema: type: string enum: - - "01" - - "02" - - "03" - - "04" - description: | - Clave que representa el motivo de la cancelación de la factura. - - - `01`: **Comprobante emitido con errores con relación**. Cuando la - factura contiene algún error en las cantidades, claves o cualquier otro dato y ya - se ha emitido el comprobante que la sustituye, el cual deberá indicarse por medio - del atributo `substitution`. - - `02`: **Comprobante emitido con errores sin relación**. Cuando la - factura contiene algún error en las cantidades, claves o cualquier otro dato y no - se requiere relacionar con otra factura. - - `03`: **No se llevó a cabo la operación**. Cuando la venta o transacción no se concretó. - - `04`: **Operación nominativa relacionada en la factura global**. Cuando se requiere cancelar - una factura al público en general porque el cliente solicita su comprobante. - - in: query - name: substitution - required: false - schema: - type: string - description: | - ID de la factura que sustituye a la factura que se está cancelando. - - Puedes usar el ID de Facturapi o el folio fiscal (UUID). + - xml + - pdf + - zip + required: true + description: Formato del archivo de descarga security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Solicitud de cancelación exitosa + description: Archivo del comprobante CFDI en el formato solicitado content: - application/json: + application/octet-stream: schema: - $ref: "#/components/schemas/Invoice" + type: string + format: binary "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "409": - $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/copy: - post: - operationId: copyToDraftInvoice + /invoices/{invoice_id}/download-url/{format}: + get: + operationId: getInvoiceDownloadUrl tags: - invoice - summary: Copiar a borrador + summary: Obtener enlace de descarga description: | - Crea una copia en borrador de la factura especificada. + Devuelve un enlace temporal para descargar la factura en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. + + El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/copy \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.copyToDraft('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var invoice = await facturapi.Invoice.CopyToDraftAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const download = await facturapi.invoices.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); - var draft = facturapi.invoices().copyToDraft( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->copyToDraft("58e93bd8e86eb318b019743d"); + console.log(download.url, download.expires_at); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID de la factura a copiar - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Nuevo objeto `Invoice` con status `draft`. - content: - application/json: - schema: - $ref: "#/components/schemas/InvoiceDraft" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/stamp: - post: - operationId: stampDraftInvoice - tags: - - invoice - summary: Timbrar borrador de factura - description: | - Timbra una factura con status `draft` y la envía al SAT para su validación. - - Al usar este método, el valor del campo `is_ready_to_stamp` (asignado por Facturapi) - deberá ser `true`. De otra forma, la llamada regresará un error. - - Este método no permite editar la factura, sólo timbrarla. Si necesitas editar información - en la factura antes de timbrarla, usa el método [Editar Borrador de Factura](#tag/invoice/operation/editDraftInvoice). - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/stamp \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - const stampedInvoice = await facturapi.invoices.stampDraft('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - var stampedInvoice = await facturapi.Invoice.StampDraftAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var invoice = facturapi.invoices().stampDraft( - "inv_123", - Map.of( - ) - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $stamped_invoice = $facturapi->Invoices->stampDraft("58e93bd8e86eb318b019743d"); - parameters: + description: ID del objeto a descargar - in: path - name: invoice_id + name: format schema: type: string + enum: + - pdf + - xml + - zip required: true - description: ID del objeto a timbrar - - in: query - name: async - schema: - type: boolean - required: false - description: | - Útil para facturas de gran tamaño. Si se envía `false` o no se envía, la llamada esperará a que el SAT responda timbrando la factura. - Si se envía `true`, la llamada regresará inmediatamente con el objeto `invoice` en status `pending`, y podrá consultarse su cambio de status - a `valid` en un momento posterior. + description: Formato del archivo de descarga security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Objeto `Invoice` timbrado correctamente + description: Enlace temporal de descarga del comprobante CFDI en el formato solicitado content: application/json: schema: - $ref: "#/components/schemas/Invoice" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/cancellation_receipt/{format}: get: operationId: downloadCancellationReceiptXml @@ -4816,151 +4789,59 @@ paths: "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/payment-summary: + /invoices/{invoice_id}/cancellation_receipt/download-url/{format}: get: - operationId: getInvoicePaymentSummary + operationId: getCancellationReceiptDownloadUrl tags: - invoice - summary: Resumen de pago + summary: Obtener enlace del acuse de cancelación description: | - Devuelve la información necesaria para agregar esta factura como documento relacionado en un - Comprobante de Pago (complemento de pago): el número de parcialidad que corresponde según el - historial de pagos, el saldo anterior (`last_balance`) y el desglose de impuestos de la factura - prorrateado al monto que se pretende pagar. - - El valor de retorno está listo para usarse como elemento de `related_documents` al - [crear una factura de tipo Pago](#tag/invoice/operation/createInvoice). + Devuelve un enlace temporal para descargar en XML o PDF el acuse emitido por el SAT al solicitar la cancelación mediante Facturapi. El acuse contiene el resultado inmediato de la solicitud y no necesariamente acredita que el CFDI ya esté cancelado; consulta el estado de la factura para confirmar el desenlace. - El parámetro `amount` debe expresarse en la divisa de la factura y no puede exceder el saldo - pendiente (`amount_due`). Cuando el pago se recibe en otra divisa, convierte el monto antes de - llamar este método. + El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: - lang: Bash label: cURL source: | - curl "https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/payment-summary?amount=100" \ + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/download-url/pdf \ -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); + import Facturapi from 'facturapi'; - const summary = await facturapi.invoices.paymentSummary( - '58e93bd8e86eb318b019743d', - { amount: 100 } + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.invoices.downloadCancellationReceiptPdfUrl( + '58e93bd8e86eb318b019743d' ); - // El resumen va completo como related_document del complemento - const invoice = await facturapi.invoices.create({ - type: 'P', - customer: 'customer_id', - complements: [ - { - type: 'pago', - data: [ - { - payment_form: '28', - related_documents: [summary] - } - ] - } - ] - }); + console.log(download.url, download.expires_at); parameters: - in: path name: invoice_id schema: type: string required: true - description: ID de la factura de ingreso (método de pago PPD) que se desea pagar - - in: query - name: amount + description: ID del objeto a descargar + - in: path + name: format schema: - type: number + type: string + enum: + - xml + - pdf required: true - description: Monto que se paga de esta factura, expresado en la divisa de la factura. No puede exceder el saldo pendiente. + description: Formato del acuse de cancelación security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Resumen del documento relacionado + description: Enlace temporal de descarga del acuse de cancelación en el formato solicitado content: application/json: schema: - type: object - required: - - uuid - - series - - installment - - last_balance - - total - - currency - - amount - - taxes - properties: - uuid: - type: string - description: UUID de la factura - folio_number: - type: number - description: Folio de la factura. Se omite si la factura no lo tiene registrado. - series: - type: ["string","null"] - description: Serie de la factura - installment: - type: number - description: Número de parcialidad que corresponde a este pago - last_balance: - type: number - description: Saldo pendiente de la factura antes de aplicar este pago - total: - type: number - description: Total de la factura - currency: - type: string - description: Divisa de la factura - amount: - type: number - description: Monto que se paga en esta parcialidad - taxes: - type: array - description: Impuestos de la factura prorrateados al monto pagado - items: - type: object - properties: - base: - type: number - description: Base del impuesto prorrateada al monto pagado - rate: - type: number - description: Tasa o cuota del impuesto - type: - type: string - description: Tipo de impuesto (IVA, ISR, etc.) - factor: - type: string - description: Tipo de factor (Tasa, Exento, etc.) - withholding: - type: boolean - description: Indica si se trata de una retención - example: - uuid: 39c85a3f-275b-4341-b259-e8971d9f8a94 - folio_number: 914 - series: F - installment: 2 - last_balance: 245.6 - total: 345.6 - currency: MXN - amount: 100 - taxes: - - base: 86.21 - rate: 0.16 - type: IVA - factor: Tasa - withholding: false + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": @@ -4971,366 +4852,614 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - - /invoices/{invoice_id}/{format}: - get: - operationId: downloadInvoice + /invoices/{invoice_id}/email: + post: + operationId: sendInvoiceByEmail tags: - invoice - summary: Descargar factura - description: Descarga tu Factura en PDF, XML o ambos en un archivo comprimido ZIP. + summary: Enviar factura por correo electrónico + description: Envía un correo electrónico a la dirección de tu cliente, con los archivos XML y PDF adjuntos al mensaje. x-codeSamples: - lang: Bash label: cURL source: | - ## Descargar PDF y XML comprimidos en archivo ZIP - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/zip \ - -H "Authorization: Bearer sk_test_API_KEY" - - ## Descargar sólo el PDF - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" + # Enviar al correo del cliente + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/email \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST - ## Descargar sólo el XML - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/xml \ - -H "Authorization: Bearer sk_test_API_KEY" + # Enviar a otro correo + curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/email \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{ + "email": "another_email@example.com" + }' - lang: JavaScript label: Node.js source: | - import fs from 'fs'; import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - // Descargar PDF y XML comprimidos en archivo ZIP - const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); - const zipFile = fs.createWriteStream('./factura.zip'); - zipStream.pipe(zipFile); + // Enviar al correo del cliente + await facturapi.invoices.sendByEmail('58e93bd8e86eb318b019743d'); - // Descargar sólo el PDF - const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); - const pdfFile = fs.createWriteStream('./factura.pdf'); - pdfStream.pipe(pdfFile); + // Enviar a otro correo + await facturapi.invoices.sendByEmail( + '58e93bd8e86eb318b019743d', + { email: 'otro@correo.com' } + ); - // Descargar sólo el XML - const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); - const xmlFile = fs.createWriteStream('./factura.xml'); - xmlStream.pipe(xmlFile); + // Enviar a más de un correo (máx. 10) + await facturapi.invoices.sendByEmail( + '58e93bd8e86eb318b019743d', + { + email: [ + 'primer@correo.com', + 'segundo@correo.com' + ] + } + ); - lang: csharp label: C# source: | - // Descargar PDF y XML comprimidos en archivo ZIP - var zipStream = await facturapi.Invoice.DownloadZipAsync("58e93bd8e86eb318b019743d"); - // Descargar sólo el XML - var xmlStream = await facturapi.Invoice.DownloadXmlAsync("58e93bd8e86eb318b019743d"); - // Descargar sólo el PDF - var pdfStream = await facturapi.Invoice.DownloadPdfAsync("58e93bd8e86eb318b019743d"); + // Enviar al correo del cliente + await facturapi.Invoice.SendByEmailAsync("58e93bd8e86eb318b019743d"); - // Para guardar la descarga en un archivo - var file = new System.IO.FileStream("C:\\route\\to\\save\\invoice.zip", FileMode.Create); - zipStream.CopyTo(file); - file.Close(); + // Enviar a otro correo + await facturapi.Invoice.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = "otro@correo.com" + } + ); + + // Enviar a más de un correo + await facturapi.Invoice.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = new String[] + { + "primer@correo.com", + "segundo@correo.com" + } + } + ); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.io.InputStream; - import java.nio.file.Files; - import java.nio.file.Path; - import java.nio.file.StandardCopyOption; + import java.util.List; + import java.util.Map; Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - try (InputStream zipStream = facturapi.invoices().downloadZip("58e93bd8e86eb318b019743d")) { - Files.copy(zipStream, Path.of("./factura.zip"), StandardCopyOption.REPLACE_EXISTING); - } + var response = facturapi.invoices().sendByEmail( + "inv_123", + Map.of( + "to", "cliente@example.com" + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); - try (InputStream pdfStream = facturapi.invoices().downloadPdf("58e93bd8e86eb318b019743d")) { - Files.copy(pdfStream, Path.of("./factura.pdf"), StandardCopyOption.REPLACE_EXISTING); - } + // Enviar al correo del cliente + $facturapi->Invoices->sendByEmail("58e93bd8e86eb318b019743d"); - try (InputStream xmlStream = facturapi.invoices().downloadXml("58e93bd8e86eb318b019743d")) { - Files.copy(xmlStream, Path.of("./factura.xml"), StandardCopyOption.REPLACE_EXISTING); - } + // Enviar a otro correo + $facturapi->Invoices->sendByEmail( + "58e93bd8e86eb318b019743d", + "otro@correo.com" + ); + + // Enviar a más de un correo (máx 10) + $facturapi->Invoices->sendByEmail( + "58e93bd8e86eb318b019743d", + [ + "primer@correo.com", + "segundo@correo.com" + ] + ); + parameters: + - in: path + name: invoice_id + schema: + type: string + required: true + description: ID del objeto a obtener + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + email: + description: Dirección de correo electrónico a enviar la factura. Si no se envía este parámetro, la factura será enviada al correo que el cliente tenga registrado. + oneOf: + - type: string + format: email + description: Dirección de correo electrónico + example: otro@correo.com + - type: array + example: ["primer@correo.com", "segundo@correo.com"] + description: Lista de direcciones de correo que recibirán la factura. + maxLength: 10 + items: + type: string + format: email + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Objeto genérico de respuesta + content: + application/json: + schema: + type: object + required: + - ok + properties: + ok: + type: boolean + description: Indica si el correo fue enviado exitosamente + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/zip-requests: + post: + operationId: createInvoiceZipRequest + tags: + - invoice + summary: Crear o recuperar solicitud de ZIP mensual + description: | + Crea una solicitud para generar un archivo ZIP con las facturas de un mes, o recupera la solicitud existente con los mismos filtros. + + La operación es idempotente. Los tipos de factura se normalizan, por lo que `["I", "E"]` y `["E", "I"]` corresponden a la misma solicitud. Las llamadas concurrentes idénticas también regresan la misma solicitud. + + Si una solicitud anterior tiene status `failed`, volver a llamar este método reintentará su procesamiento. Antes del nuevo intento se limpian el error, la tarea anterior, el progreso procesado y la lista de documentos fallidos. Si no es posible programar la generación, la solicitud se guarda con status `failed` y la API regresa un error `5xx`. + + Este método requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. Las llaves de ambiente Test regresan HTTP 402. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/zip-requests \ + -H "Authorization: Bearer sk_live_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "year": 2025, + "month": 3, + "issuer_type": "issuing", + "invoice_types": ["I", "E"] + }' + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequest = await facturapi.invoices.createZipRequest({ + year: 2025, + month: 3, + issuer_type: 'issuing', + invoice_types: ['I', 'E'] + }); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequest = await facturapi.Invoice.CreateZipRequestAsync( + new Dictionary + { + ["year"] = 2025, + ["month"] = 3, + ["issuer_type"] = "issuing", + ["invoice_types"] = new[] { "I", "E" } + } + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequest = facturapi.invoices().createZipRequest( + Map.of( + "year", 2025, + "month", 3, + "issuer_type", "issuing", + "invoice_types", List.of("I", "E") + ) + ); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequest = $facturapi->Invoices->createZipRequest([ + "year" => 2025, + "month" => 3, + "issuer_type" => "issuing", + "invoice_types" => ["I", "E"] + ]); + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequestCreateInput" + security: + - "SecretLiveKey": [] + responses: + "200": + description: Solicitud de ZIP creada o recuperada correctamente. + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequest" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNoInvoices" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + get: + operationId: listInvoiceZipRequests + tags: + - invoice + summary: Listar solicitudes de ZIP mensual + description: | + Regresa una lista paginada de solicitudes de ZIP. `year` y `month` deben enviarse juntos. `invoice_types` filtra por un tipo o por un arreglo normalizado exacto. - // stream containing the PDF and XML as a ZIP file - $zip = $facturapi->Invoices->downloadZip("58e93bd8e86eb318b019743d"); - // stream containing the PDF file - $pdf = $facturapi->Invoices->downloadPdf("58e93bd8e86eb318b019743d"); - // stream containing the XML file - $xml = $facturapi->Invoices->downloadXml("58e93bd8e86eb318b019743d"); + Este método requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl "https://www.facturapi.io/v2/invoices/zip-requests?year=2025&month=3&status=finished&limit=20&page=1" \ + -H "Authorization: Bearer sk_live_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequests = await facturapi.invoices.listZipRequests({ + year: 2025, + month: 3, + status: 'finished', + limit: 20, + page: 1 + }); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequests = await facturapi.Invoice.ListZipRequestsAsync( + new Dictionary + { + ["year"] = 2025, + ["month"] = 3, + ["status"] = "finished", + ["limit"] = 20, + ["page"] = 1 + } + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequests = facturapi.invoices().listZipRequests( + Map.of( + "year", 2025, + "month", 3, + "status", "finished", + "limit", 20, + "page", 1 + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequests = $facturapi->Invoices->listZipRequests([ + "year" => 2025, + "month" => 3, + "status" => "finished", + "limit" => 20, + "page" => 1 + ]); + parameters: + - in: query + name: year + schema: + type: integer + minimum: 2000 + maximum: 9999 + description: Año a filtrar. Debe enviarse junto con `month`. + - in: query + name: month + schema: + type: integer + minimum: 1 + maximum: 12 + description: Mes a filtrar. Debe enviarse junto con `year`. + - in: query + name: status + schema: + $ref: "#/components/schemas/InvoiceZipRequestStatus" + description: Status de la solicitud. + - in: query + name: issuer_type + schema: + $ref: "#/components/schemas/IssuingType" + description: Filtra facturas emitidas o recibidas. + - in: query + name: invoice_types + schema: + type: array + uniqueItems: true + items: + $ref: "#/components/schemas/InvoiceZipRequestInvoiceType" + description: Filtra por un tipo de factura o por un arreglo normalizado exacto. + - in: query + name: page + schema: + type: integer + minimum: 1 + default: 1 + description: Página de resultados, empezando en 1. + - $ref: "#/components/parameters/SearchLimit" + security: + - "SecretLiveKey": [] + responses: + "200": + description: Resultado paginado de solicitudes de ZIP. + content: + application/json: + schema: + $ref: "#/components/schemas/InvoiceZipRequestSearchResult" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /invoices/zip-requests/{id}: + get: + operationId: retrieveInvoiceZipRequest + tags: + - invoice + summary: Recuperar solicitud de ZIP mensual + description: | + Recupera una solicitud de ZIP. Consulta este método hasta que el status sea `finished` o `failed`. Cuando sea `finished`, descarga el archivo con el método de descarga. + + Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000 \ + -H "Authorization: Bearer sk_live_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipRequest = await facturapi.invoices.retrieveZipRequest( + '66b0f0000000000000000000' + ); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipRequest = await facturapi.Invoice.RetrieveZipRequestAsync( + "66b0f0000000000000000000" + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + var zipRequest = facturapi.invoices().retrieveZipRequest( + "66b0f0000000000000000000" + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_live_API_KEY"); + $zipRequest = $facturapi->Invoices->retrieveZipRequest( + "66b0f0000000000000000000" + ); parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto a descargar - - in: path - name: format - schema: - type: string - enum: - - xml - - pdf - - zip - required: true - description: Formato del archivo de descarga + - $ref: "#/components/parameters/InvoiceZipRequestId" security: - "SecretLiveKey": [] - - "SecretTestKey": [] responses: "200": - description: Archivo del comprobante CFDI en el formato solicitado + description: Solicitud de ZIP recuperada correctamente. content: - application/octet-stream: + application/json: schema: - type: string - format: binary + $ref: "#/components/schemas/InvoiceZipRequest" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/email: - post: - operationId: sendInvoiceByEmail + /invoices/zip-requests/{id}/zip: + get: + operationId: downloadInvoiceZipRequest tags: - invoice - summary: Enviar factura por correo electrónico - description: Envía un correo electrónico a la dirección de tu cliente, con los archivos XML y PDF adjuntos al mensaje. + summary: Descargar ZIP mensual + description: | + Descarga el ZIP de una solicitud terminada. El nombre del archivo usa el formato `YYYY-MM.zip`. + + Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. x-codeSamples: - lang: Bash label: cURL source: | - # Enviar al correo del cliente - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/email \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST - - # Enviar a otro correo - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/email \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST \ - -H "Content-Type: application/json" \ - -d '{ - "email": "another_email@example.com" - }' + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/zip \ + -H "Authorization: Bearer sk_live_API_KEY" \ + --output 2025-03.zip - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - // Enviar al correo del cliente - await facturapi.invoices.sendByEmail('58e93bd8e86eb318b019743d'); - - // Enviar a otro correo - await facturapi.invoices.sendByEmail( - '58e93bd8e86eb318b019743d', - { email: 'otro@correo.com' } - ); + import fs from 'fs'; + import Facturapi from 'facturapi'; - // Enviar a más de un correo (máx. 10) - await facturapi.invoices.sendByEmail( - '58e93bd8e86eb318b019743d', - { - email: [ - 'primer@correo.com', - 'segundo@correo.com' - ] - } + const facturapi = new Facturapi('sk_live_API_KEY'); + const zipStream = await facturapi.invoices.downloadZipRequest( + '66b0f0000000000000000000' ); + zipStream.pipe(fs.createWriteStream('./2025-03.zip')); - lang: csharp label: C# source: | - // Enviar al correo del cliente - await facturapi.Invoice.SendByEmailAsync("58e93bd8e86eb318b019743d"); - - // Enviar a otro correo - await facturapi.Invoice.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = "otro@correo.com" - } - ); - - // Enviar a más de un correo - await facturapi.Invoice.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = new String[] - { - "primer@correo.com", - "segundo@correo.com" - } - } + var facturapi = new FacturapiClient("sk_live_API_KEY"); + var zipStream = await facturapi.Invoice.DownloadZipRequestAsync( + "66b0f0000000000000000000" ); + await using var file = File.Create("2025-03.zip"); + await zipStream.CopyToAsync(file); - lang: Java label: Java source: | import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + import java.io.InputStream; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardCopyOption; - var response = facturapi.invoices().sendByEmail( - "inv_123", - Map.of( - "to", "cliente@example.com" - ) - ); + Facturapi facturapi = new Facturapi("sk_live_API_KEY"); + try (InputStream zipStream = facturapi.invoices().downloadZipRequest( + "66b0f0000000000000000000" + )) { + Files.copy(zipStream, Path.of("./2025-03.zip"), StandardCopyOption.REPLACE_EXISTING); + } - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - // Enviar al correo del cliente - $facturapi->Invoices->sendByEmail("58e93bd8e86eb318b019743d"); - - // Enviar a otro correo - $facturapi->Invoices->sendByEmail( - "58e93bd8e86eb318b019743d", - "otro@correo.com" - ); - - // Enviar a más de un correo (máx 10) - $facturapi->Invoices->sendByEmail( - "58e93bd8e86eb318b019743d", - [ - "primer@correo.com", - "segundo@correo.com" - ] + $facturapi = new Facturapi("sk_live_API_KEY"); + $zip = $facturapi->Invoices->downloadZipRequest( + "66b0f0000000000000000000" ); + file_put_contents("2025-03.zip", $zip); parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto a obtener - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - email: - description: Dirección de correo electrónico a enviar la factura. Si no se envía este parámetro, la factura será enviada al correo que el cliente tenga registrado. - oneOf: - - type: string - format: email - description: Dirección de correo electrónico - example: otro@correo.com - - type: array - example: ["primer@correo.com", "segundo@correo.com"] - description: Lista de direcciones de correo que recibirán la factura. - maxLength: 10 - items: - type: string - format: email + - $ref: "#/components/parameters/InvoiceZipRequestId" security: - "SecretLiveKey": [] - - "SecretTestKey": [] responses: "200": - description: Objeto genérico de respuesta + description: Archivo ZIP generado. + headers: + Content-Disposition: + description: Nombre sugerido con formato `attachment; filename="YYYY-MM.zip"`. + schema: + type: string content: - application/json: + application/zip: schema: - type: object - required: - - ok - properties: - ok: - type: boolean - description: Indica si el correo fue enviado exitosamente + type: string + format: binary "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/status: - put: - operationId: updateInvoiceStatus + /invoices/zip-requests/{id}/download-url: + get: + operationId: getInvoiceZipRequestDownloadUrl tags: - invoice - summary: | - Actualizar status de factura + summary: Obtener URL de descarga del ZIP mensual description: | - Consulta el status de una factura timbrada en el SAT y actualiza el objeto invoice - con La información más reciente. + Devuelve una URL temporal para descargar el ZIP de una solicitud terminada sin que el archivo viaje a través de tu servidor. + + La URL permite acceder únicamente a ese archivo mientras sea válida: trátala como una credencial y no la almacenes. Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/status \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X PUT + curl https://www.facturapi.io/v2/invoices/zip-requests/66b0f0000000000000000000/download-url \ + -H "Authorization: Bearer sk_live_API_KEY" - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - const invoice = await facturapi.invoices.updateStatus('58e93bd8e86eb318b019743d'); - - lang: csharp - label: C# - source: | - var facturapi = new Facturapi - var invoice = await facturapi.Invoice.UpdateStatusAsync("58e93bd8e86eb318b019743d"); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; + import Facturapi from 'facturapi'; - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + const facturapi = new Facturapi('sk_live_API_KEY'); + const download = await facturapi.invoices.downloadZipRequestUrl( + '66b0f0000000000000000000' + ); - var invoice = facturapi.invoices().updateStatus( - "inv_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - $invoice = $facturapi->Invoices->updateStatus("58e93bd8e86eb318b019743d"); + console.log(download.url, download.expires_at); parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto invoice a actualizar + - $ref: "#/components/parameters/InvoiceZipRequestId" security: - "SecretLiveKey": [] - - "SecretTestKey": [] responses: "200": - description: Objeto `Invoice` actualizado + description: URL temporal de descarga para el archivo ZIP generado. content: application/json: schema: - $ref: "#/components/schemas/Invoice" + $ref: "#/components/schemas/SignedDownloadUrl" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "402": + $ref: "#/components/responses/InvoiceZipRequestAccessRequired" + "404": + $ref: "#/components/responses/InvoiceZipRequestNotFound" + "409": + $ref: "#/components/responses/InvoiceZipRequestNotReady" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts: post: operationId: createReceipt @@ -5888,242 +6017,9 @@ paths: "200": description: Objeto 'Receipt' cancelado exitosamente content: - application/json: - schema: - $ref: "#/components/schemas/Receipt" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/pdf: - get: - operationId: downloadReceiptPdf - tags: - - receipt - summary: Descargar PDF - description: Descarga el recibo digital en formato PDF. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import fs from 'fs'; - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - // Descargar recibo en formato PDF - const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); - const pdfFile = fs.createWriteStream('./recibo.pdf'); - pdfStream.pipe(pdfFile); - - lang: csharp - label: C# - source: | - // Descargar recibo en formato PDF - var pdfStream = await facturapi.Receipt.DownloadPdfAsync("58e93bd8e86eb318b019743d"); - - // Para guardar la descarga en un archivo - var file = new System.IO.FileStream("C:\\route\\to\\save\\receipt.pdf", FileMode.Create); - pdfStream.CopyTo(file); - file.Close(); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - byte[] pdf = facturapi.receipts().downloadPdf( - "rec_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - // stream containing the PDF file - $pdf = $facturapi->Receipts->downloadPdf("58e93bd8e86eb318b019743d"); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID del objeto a descargar - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Archivo del recibo digital en formato PDF - content: - application/octet-stream: - schema: - type: string - format: binary - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/email: - post: - operationId: sendReceiptByEmail - tags: - - receipt - summary: Enviar recibo por correo electrónico - description: | - Envía un correo electrónico a la dirección de tu cliente. - - El correo enviado estará personalizado con el logotipo y los colores de la organización que lo creó, - e incluirá un botón para facturar el recibo, así con el recibo en formato PDF adjunto al mensaje. - x-codeSamples: - - lang: Bash - label: cURL - source: | - # Enviar recibo por correo electrónico - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/email \ - -H "Authorization: Bearer sk_test_API_KEY" \ - -X POST \ - -H "Content-Type: application/json" \ - -d '{ - "email": "another_email@example.com" - }' - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - // Enviar recibo por correo electrónico - await facturapi.receipts.sendByEmail( - '58e93bd8e86eb318b019743d', - { email: 'ejemplo@correo.com' } - ); - - // Enviar a más de un correo (máx. 10) - await facturapi.receipts.sendByEmail( - '58e93bd8e86eb318b019743d', - { - email: [ - 'primer@correo.com', - 'segundo@correo.com' - ] - } - ); - - lang: csharp - label: C# - source: | - // Enviar recibo por correo electrónico - await facturapi.Receipt.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = "ejemplo@correo.com" - } - ); - - // Enviar a más de un correo - await facturapi.Receipt.SendByEmailAsync( - "58e93bd8e86eb318b019743d", - new Dictionary - { - ["email"] = new String[] - { - "primer@correo.com", - "segundo@correo.com" - } - } - ); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var response = facturapi.receipts().sendByEmail( - "rec_123", - Map.of( - "to", "cliente@example.com" - ) - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - // Enviar recibo por correo electrónico - $facturapi->Receipts->sendByEmail( - "58e93bd8e86eb318b019743d", - "ejemplo@correo.com" - ); - - // Enviar a más de un correo (máx 10) - $facturapi->Receipts->sendByEmail( - "58e93bd8e86eb318b019743d", - [ - "primer@correo.com", - "segundo@correo.com" - ] - ); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID del objeto a obtener - requestBody: - required: false - content: - application/json: - schema: - type: object - required: - - email - properties: - email: - description: Dirección de correo electrónico a enviar el recibo digital. - oneOf: - - type: string - format: email - description: Dirección de correo electrónico - example: otro@correo.com - - type: array - example: ["primer@correo.com", "segundo@correo.com"] - description: Lista de direcciones de correo que recibirán el recibo digital. - maxLength: 10 - items: - type: string - format: email - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Objeto genérico de respuesta - content: - application/json: - schema: - type: object - required: - - ok - properties: - ok: - type: boolean - description: Indica si el correo fue enviado exitosamente + application/json: + schema: + $ref: "#/components/schemas/Receipt" "400": $ref: "#/components/responses/BadRequest" "401": @@ -6132,7 +6028,6 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/invoice: post: operationId: invoiceReceipt @@ -6635,25 +6530,313 @@ paths: "series" => "G" ]); requestBody: - $ref: "#/components/requestBodies/ReceiptCreateGlobalInvoice" + $ref: "#/components/requestBodies/ReceiptCreateGlobalInvoice" + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Nuevo objeto `Invoice` creado, o `null` si no hay recibos abiertos en el periodo + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/Invoice" + - type: "null" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + + /receipts/{receipt_id}/pdf: + get: + operationId: downloadReceiptPdf + tags: + - receipt + summary: Descargar PDF + description: Descarga el recibo digital en formato PDF. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import fs from 'fs'; + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + // Descargar recibo en formato PDF + const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); + const pdfFile = fs.createWriteStream('./recibo.pdf'); + pdfStream.pipe(pdfFile); + - lang: csharp + label: C# + source: | + // Descargar recibo en formato PDF + var pdfStream = await facturapi.Receipt.DownloadPdfAsync("58e93bd8e86eb318b019743d"); + + // Para guardar la descarga en un archivo + var file = new System.IO.FileStream("C:\\route\\to\\save\\receipt.pdf", FileMode.Create); + pdfStream.CopyTo(file); + file.Close(); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + byte[] pdf = facturapi.receipts().downloadPdf( + "rec_123" + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + // stream containing the PDF file + $pdf = $facturapi->Receipts->downloadPdf("58e93bd8e86eb318b019743d"); + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID del objeto a descargar + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Archivo del recibo digital en formato PDF + content: + application/octet-stream: + schema: + type: string + format: binary + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /receipts/{receipt_id}/download-url/pdf: + get: + operationId: getReceiptDownloadUrl + tags: + - receipt + summary: Obtener enlace de descarga + description: | + Devuelve un enlace temporal para descargar el recibo digital en PDF, sin que el archivo pase por tu servidor. + + El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.receipts.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); + + console.log(download.url, download.expires_at); + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID del objeto a descargar + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Enlace temporal de descarga del recibo digital en formato PDF + content: + application/json: + schema: + $ref: "#/components/schemas/SignedDownloadUrl" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /receipts/{receipt_id}/email: + post: + operationId: sendReceiptByEmail + tags: + - receipt + summary: Enviar recibo por correo electrónico + description: | + Envía un correo electrónico a la dirección de tu cliente. + + El correo enviado estará personalizado con el logotipo y los colores de la organización que lo creó, + e incluirá un botón para facturar el recibo, así con el recibo en formato PDF adjunto al mensaje. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # Enviar recibo por correo electrónico + curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/email \ + -H "Authorization: Bearer sk_test_API_KEY" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{ + "email": "another_email@example.com" + }' + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + // Enviar recibo por correo electrónico + await facturapi.receipts.sendByEmail( + '58e93bd8e86eb318b019743d', + { email: 'ejemplo@correo.com' } + ); + + // Enviar a más de un correo (máx. 10) + await facturapi.receipts.sendByEmail( + '58e93bd8e86eb318b019743d', + { + email: [ + 'primer@correo.com', + 'segundo@correo.com' + ] + } + ); + - lang: csharp + label: C# + source: | + // Enviar recibo por correo electrónico + await facturapi.Receipt.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = "ejemplo@correo.com" + } + ); + + // Enviar a más de un correo + await facturapi.Receipt.SendByEmailAsync( + "58e93bd8e86eb318b019743d", + new Dictionary + { + ["email"] = new String[] + { + "primer@correo.com", + "segundo@correo.com" + } + } + ); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var response = facturapi.receipts().sendByEmail( + "rec_123", + Map.of( + "to", "cliente@example.com" + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + // Enviar recibo por correo electrónico + $facturapi->Receipts->sendByEmail( + "58e93bd8e86eb318b019743d", + "ejemplo@correo.com" + ); + + // Enviar a más de un correo (máx 10) + $facturapi->Receipts->sendByEmail( + "58e93bd8e86eb318b019743d", + [ + "primer@correo.com", + "segundo@correo.com" + ] + ); + parameters: + - in: path + name: receipt_id + schema: + type: string + required: true + description: ID del objeto a obtener + requestBody: + required: false + content: + application/json: + schema: + type: object + required: + - email + properties: + email: + description: Dirección de correo electrónico a enviar el recibo digital. + oneOf: + - type: string + format: email + description: Dirección de correo electrónico + example: otro@correo.com + - type: array + example: ["primer@correo.com", "segundo@correo.com"] + description: Lista de direcciones de correo que recibirán el recibo digital. + maxLength: 10 + items: + type: string + format: email security: - "SecretLiveKey": [] - "SecretTestKey": [] responses: "200": - description: Nuevo objeto `Invoice` creado, o `null` si no hay recibos abiertos en el periodo + description: Objeto genérico de respuesta content: application/json: schema: - oneOf: - - $ref: "#/components/schemas/Invoice" - - type: "null" + type: object + required: + - ok + properties: + ok: + type: boolean + description: Indica si el correo fue enviado exitosamente "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -7507,6 +7690,72 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" + /retentions/{retention_id}/download-url/{format}: + get: + operationId: getRetentionDownloadUrl + tags: + - retention + summary: Obtener enlace de descarga + description: | + Devuelve un enlace temporal para descargar la retención en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. + + El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/retentions/58e93bd8e86eb318b019743d/download-url/pdf \ + -H "Authorization: Bearer sk_test_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi'; + + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.retentions.downloadPdfUrl( + '58e93bd8e86eb318b019743d' + ); + + console.log(download.url, download.expires_at); + parameters: + - in: path + name: retention_id + schema: + type: string + required: true + description: ID del objeto a descargar + - in: path + name: format + schema: + type: string + enum: + - pdf + - xml + - zip + required: true + description: Formato del archivo de descarga + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Enlace temporal de descarga de la retención en el formato solicitado + content: + application/json: + schema: + $ref: "#/components/schemas/SignedDownloadUrl" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "409": + $ref: "#/components/responses/Conflict" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" /retentions/{retention_id}/email: post: operationId: sendRetentionByEmail @@ -7769,30 +8018,173 @@ paths: "500": $ref: "#/components/responses/UnexpectedError" get: - operationId: listOrganizations + operationId: listOrganizations + tags: + - organization + summary: Listar organizaciones + description: Regresa una lista paginada de todas las organizationes registradas bajo tu cuenta, o realiza una búsqueda de acuerdo a parámetros. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/organizations \ + -H "Authorization: Bearer sk_user_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + const organizationResults = await facturapi.organizations.list(); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + + var searchResult = await facturapi.Organization.ListAsync(); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var searchResult = facturapi.organizations().list( + Map.of( + "page", 0, + "limit", 10 + ) + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + $organizations = $facturapi->Organizations->all() + parameters: + - $ref: "#/components/parameters/SearchPagination" + - $ref: "#/components/parameters/SearchAfter" + - $ref: "#/components/parameters/SearchBefore" + + - in: query + name: q + schema: + type: string + description: Consulta. Texto a buscar en `name` (nombre comercial), `legal_name` (nombre fiscal) o en `tax_id` (RFC). + - $ref: "#/components/parameters/SearchDate" + - $ref: "#/components/parameters/SearchPage" + - $ref: "#/components/parameters/SearchLimit" + security: + - "SecretUserKey": [] + responses: + "200": + description: Resultado de la búsqueda + content: + application/json: + schema: + $ref: "#/components/schemas/OrganizationSearchResult" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /organizations/me: + get: + operationId: meOrganization + tags: + - organization + summary: Detalle de organización + description: | + Retorna el detalle de la organización actualmente autenticada. + x-codeSamples: + - lang: Bash + label: cURL + source: | + curl https://www.facturapi.io/v2/organizations/me \ + -H "Authorization: Bearer sk_user_API_KEY" + - lang: JavaScript + label: Node.js + source: | + import Facturapi from 'facturapi' + const facturapi = new Facturapi('sk_test_API_KEY'); + + const organizationResults = await facturapi.organizations.me(); + - lang: csharp + label: C# + source: | + var facturapi = new FacturapiClient("sk_test_API_KEY"); + + var searchResult = await facturapi.Organization.MeAsync(); + - lang: Java + label: Java + source: | + import io.facturapi.Facturapi; + import java.util.List; + import java.util.Map; + + Facturapi facturapi = new Facturapi("sk_test_API_KEY"); + + var organization = facturapi.organizations().me( + ); + - lang: PHP + source: | + $facturapi = new Facturapi("sk_test_API_KEY"); + + $organizations = $facturapi->Organizations->me() + security: + - "SecretLiveKey": [] + - "SecretTestKey": [] + responses: + "200": + description: Objeto `Organization` + content: + application/json: + schema: + $ref: "#/components/schemas/Organization" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" + "429": + $ref: "#/components/responses/RateLimited" + "500": + $ref: "#/components/responses/UnexpectedError" + /organizations/{organization_id}: + get: + operationId: getOrganization tags: - organization - summary: Listar organizaciones - description: Regresa una lista paginada de todas las organizationes registradas bajo tu cuenta, o realiza una búsqueda de acuerdo a parámetros. + summary: Obtener organización por ID + description: Regresa el objeto 'Organization' relacionado al `id` especificado. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/organizations \ + curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ -H "Authorization: Bearer sk_user_API_KEY" - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - const organizationResults = await facturapi.organizations.list(); + const facturapi = new Facturapi('sk_user_API_KEY'); + const organization = await facturapi.organizations.retrieve( + '5a2a307be93a2f00129ea035' + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - - var searchResult = await facturapi.Organization.ListAsync(); + var facturapi = new FacturapiClient("sk_user_API_KEY"); + var organization = await facturapi.Organization.RetrieveAsync( + "5a2a307be93a2f00129ea035" + ); - lang: Java label: Java source: | @@ -7802,76 +8194,70 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var searchResult = facturapi.organizations().list( - Map.of( - "page", 0, - "limit", 10 - ) + var organization = facturapi.organizations().retrieve( + "org_123" ); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - $organizations = $facturapi->Organizations->all() + $facturapi = new Facturapi("sk_user_API_KEY"); + $organization = $facturapi->Organizations->retrieve("5a2a307be93a2f00129ea035"); parameters: - - $ref: "#/components/parameters/SearchPagination" - - $ref: "#/components/parameters/SearchAfter" - - $ref: "#/components/parameters/SearchBefore" - - - in: query - name: q + - in: path + name: organization_id schema: type: string - description: Consulta. Texto a buscar en `name` (nombre comercial), `legal_name` (nombre fiscal) o en `tax_id` (RFC). - - $ref: "#/components/parameters/SearchDate" - - $ref: "#/components/parameters/SearchPage" - - $ref: "#/components/parameters/SearchLimit" + required: true + description: ID de la organización security: + - "SecretLiveKey": [] + - "SecretTestKey": [] - "SecretUserKey": [] responses: "200": - description: Resultado de la búsqueda + description: Objeto `Organization` content: application/json: schema: - $ref: "#/components/schemas/OrganizationSearchResult" + $ref: "#/components/schemas/Organization" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /organizations/me: - get: - operationId: meOrganization + delete: + operationId: deleteOrganization tags: - organization - summary: Detalle de organización + summary: Eliminar organización description: | - Retorna el detalle de la organización actualmente autenticada. + Elimina la organización de tu cuenta de Facturapi. Una vez eliminada, + ya no podrás acceder a sus recursos, tales como clientes, productos, + facturas, recibos o retenciones. x-codeSamples: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/organizations/me \ + curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ + -X DELETE \ -H "Authorization: Bearer sk_user_API_KEY" - lang: JavaScript label: Node.js source: | import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_test_API_KEY'); - - const organizationResults = await facturapi.organizations.me(); + const facturapi = new Facturapi('sk_user_API_KEY'); + const organization = await facturapi.organizations.del( + '5a2a307be93a2f00129ea035' + ); - lang: csharp label: C# source: | - var facturapi = new FacturapiClient("sk_test_API_KEY"); - - var searchResult = await facturapi.Organization.MeAsync(); + var facturapi = new FacturapiClient("sk_user_API_KEY"); + var organization = await facturapi.Organization.DeleteAsync( + "5a2a307be93a2f00129ea035" + ); - lang: Java label: Java source: | @@ -7881,19 +8267,27 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - var organization = facturapi.organizations().me( + var organization = facturapi.organizations().delete( + "org_123" ); - lang: PHP source: | - $facturapi = new Facturapi("sk_test_API_KEY"); - - $organizations = $facturapi->Organizations->me() + $facturapi = new Facturapi("sk_user_API_KEY"); + $organization = $facturapi->Organizations->delete( + "5a2a307be93a2f00129ea035" + ); + parameters: + - in: path + name: organization_id + schema: + type: string + required: true + description: ID del objeto a eliminar security: - - "SecretLiveKey": [] - - "SecretTestKey": [] + - "SecretUserKey": [] responses: "200": - description: Objeto `Organization` + description: Objeto `Organization` eliminado correctamente content: application/json: schema: @@ -7902,8 +8296,6 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -8886,159 +9278,14 @@ paths: type: string required: true description: ID de la organización - requestBody: - $ref: "#/components/requestBodies/OrganizationEditDomain" - security: - - "SecretLiveKey": [] - - "SecretUserKey": [] - responses: - "200": - description: Objeto `Organization` modificado - content: - application/json: - schema: - $ref: "#/components/schemas/Organization" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /organizations/{organization_id}: - get: - operationId: getOrganization - tags: - - organization - summary: Obtener organización por ID - description: Regresa el objeto 'Organization' relacionado al `id` especificado. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ - -H "Authorization: Bearer sk_user_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_user_API_KEY'); - const organization = await facturapi.organizations.retrieve( - '5a2a307be93a2f00129ea035' - ); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_user_API_KEY"); - var organization = await facturapi.Organization.RetrieveAsync( - "5a2a307be93a2f00129ea035" - ); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var organization = facturapi.organizations().retrieve( - "org_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_user_API_KEY"); - $organization = $facturapi->Organizations->retrieve("5a2a307be93a2f00129ea035"); - parameters: - - in: path - name: organization_id - schema: - type: string - required: true - description: ID de la organización - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - - "SecretUserKey": [] - responses: - "200": - description: Objeto `Organization` - content: - application/json: - schema: - $ref: "#/components/schemas/Organization" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - delete: - operationId: deleteOrganization - tags: - - organization - summary: Eliminar organización - description: | - Elimina la organización de tu cuenta de Facturapi. Una vez eliminada, - ya no podrás acceder a sus recursos, tales como clientes, productos, - facturas, recibos o retenciones. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/organizations/5a2a307be93a2f00129ea035 \ - -X DELETE \ - -H "Authorization: Bearer sk_user_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi' - const facturapi = new Facturapi('sk_user_API_KEY'); - const organization = await facturapi.organizations.del( - '5a2a307be93a2f00129ea035' - ); - - lang: csharp - label: C# - source: | - var facturapi = new FacturapiClient("sk_user_API_KEY"); - var organization = await facturapi.Organization.DeleteAsync( - "5a2a307be93a2f00129ea035" - ); - - lang: Java - label: Java - source: | - import io.facturapi.Facturapi; - import java.util.List; - import java.util.Map; - - Facturapi facturapi = new Facturapi("sk_test_API_KEY"); - - var organization = facturapi.organizations().delete( - "org_123" - ); - - lang: PHP - source: | - $facturapi = new Facturapi("sk_user_API_KEY"); - $organization = $facturapi->Organizations->delete( - "5a2a307be93a2f00129ea035" - ); - parameters: - - in: path - name: organization_id - schema: - type: string - required: true - description: ID del objeto a eliminar + requestBody: + $ref: "#/components/requestBodies/OrganizationEditDomain" security: + - "SecretLiveKey": [] - "SecretUserKey": [] responses: "200": - description: Objeto `Organization` eliminado correctamente + description: Objeto `Organization` modificado content: application/json: schema: @@ -9047,6 +9294,8 @@ paths: $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthenticated" + "404": + $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/RateLimited" "500": @@ -11879,255 +12128,6 @@ paths: $ref: "#/components/responses/RateLimited" "500": $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/download-url/{format}: - get: - operationId: getInvoiceDownloadUrl - tags: - - invoice - summary: Obtener enlace de descarga - description: | - Devuelve un enlace temporal para descargar la factura en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. - - El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.invoices.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto a descargar - - in: path - name: format - schema: - type: string - enum: - - pdf - - xml - - zip - required: true - description: Formato del archivo de descarga - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Enlace temporal de descarga del comprobante CFDI en el formato solicitado - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "409": - $ref: "#/components/responses/Conflict" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /invoices/{invoice_id}/cancellation_receipt/download-url/{format}: - get: - operationId: getCancellationReceiptDownloadUrl - tags: - - invoice - summary: Obtener enlace del acuse de cancelación - description: | - Devuelve un enlace temporal para descargar en XML o PDF el acuse emitido por el SAT al solicitar la cancelación mediante Facturapi. El acuse contiene el resultado inmediato de la solicitud y no necesariamente acredita que el CFDI ya esté cancelado; consulta el estado de la factura para confirmar el desenlace. - - El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/invoices/58e93bd8e86eb318b019743d/cancellation_receipt/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.invoices.downloadCancellationReceiptPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: invoice_id - schema: - type: string - required: true - description: ID del objeto a descargar - - in: path - name: format - schema: - type: string - enum: - - xml - - pdf - required: true - description: Formato del acuse de cancelación - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Enlace temporal de descarga del acuse de cancelación en el formato solicitado - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /receipts/{receipt_id}/download-url/pdf: - get: - operationId: getReceiptDownloadUrl - tags: - - receipt - summary: Obtener enlace de descarga - description: | - Devuelve un enlace temporal para descargar el recibo digital en PDF, sin que el archivo pase por tu servidor. - - El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.receipts.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: receipt_id - schema: - type: string - required: true - description: ID del objeto a descargar - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Enlace temporal de descarga del recibo digital en formato PDF - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" - /retentions/{retention_id}/download-url/{format}: - get: - operationId: getRetentionDownloadUrl - tags: - - retention - summary: Obtener enlace de descarga - description: | - Devuelve un enlace temporal para descargar la retención en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. - - El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. - x-codeSamples: - - lang: Bash - label: cURL - source: | - curl https://www.facturapi.io/v2/retentions/58e93bd8e86eb318b019743d/download-url/pdf \ - -H "Authorization: Bearer sk_test_API_KEY" - - lang: JavaScript - label: Node.js - source: | - import Facturapi from 'facturapi'; - - const facturapi = new Facturapi('sk_test_API_KEY'); - const download = await facturapi.retentions.downloadPdfUrl( - '58e93bd8e86eb318b019743d' - ); - - console.log(download.url, download.expires_at); - parameters: - - in: path - name: retention_id - schema: - type: string - required: true - description: ID del objeto a descargar - - in: path - name: format - schema: - type: string - enum: - - pdf - - xml - - zip - required: true - description: Formato del archivo de descarga - security: - - "SecretLiveKey": [] - - "SecretTestKey": [] - responses: - "200": - description: Enlace temporal de descarga de la retención en el formato solicitado - content: - application/json: - schema: - $ref: "#/components/schemas/SignedDownloadUrl" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthenticated" - "404": - $ref: "#/components/responses/NotFound" - "409": - $ref: "#/components/responses/Conflict" - "429": - $ref: "#/components/responses/RateLimited" - "500": - $ref: "#/components/responses/UnexpectedError" webhooks: invoice.global_invoice_created: post: diff --git a/website/package.json b/website/package.json index 2ef5e77ab..17ed999b3 100644 --- a/website/package.json +++ b/website/package.json @@ -16,9 +16,9 @@ "test:openapi": "node scripts/check-openapi.mjs" }, "dependencies": { - "@docusaurus/core": "^3.10.1", - "@docusaurus/faster": "^3.10.1", - "@docusaurus/preset-classic": "^3.10.1", + "@docusaurus/core": "^3.10.2", + "@docusaurus/faster": "^3.10.2", + "@docusaurus/preset-classic": "^3.10.2", "@mdx-js/react": "^3.1.0", "clsx": "^2.1.1", "file-loader": "^6.2.0", @@ -26,13 +26,13 @@ "prismjs": "^1.30.0", "react": "^19.1.0", "react-dom": "^19.1.0", - "redocusaurus": "^2.5.0", + "redocusaurus": "^2.5.2", "url-loader": "^4.1.1" }, "devDependencies": { - "@docusaurus/module-type-aliases": "^3.10.1", - "@docusaurus/tsconfig": "^3.10.1", - "@docusaurus/types": "^3.10.1", + "@docusaurus/module-type-aliases": "^3.10.2", + "@docusaurus/tsconfig": "^3.10.2", + "@docusaurus/types": "^3.10.2", "@types/react": "^19.1.8", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index b642b01d2..34b9c04de 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -4,19 +4,22 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + docusaurus-theme-redoc>redoc: 2.5.4 + importers: .: dependencies: '@docusaurus/core': - specifier: ^3.10.1 - version: 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + specifier: ^3.10.2 + version: 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) '@docusaurus/faster': - specifier: ^3.10.1 - version: 3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) + specifier: ^3.10.2 + version: 3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) '@docusaurus/preset-classic': - specifier: ^3.10.1 - version: 3.10.1(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3) + specifier: ^3.10.2 + version: 3.10.2(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3) '@mdx-js/react': specifier: ^3.1.0 version: 3.1.1(@types/react@19.2.17)(react@19.2.7) @@ -39,21 +42,21 @@ importers: specifier: ^19.1.0 version: 19.2.7(react@19.2.7) redocusaurus: - specifier: ^2.5.0 - version: 2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) + specifier: ^2.5.2 + version: 2.5.2(@docusaurus/theme-common@3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@docusaurus/utils@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) url-loader: specifier: ^4.1.1 version: 4.1.1(file-loader@6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) devDependencies: '@docusaurus/module-type-aliases': - specifier: ^3.10.1 - version: 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^3.10.2 + version: 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@docusaurus/tsconfig': - specifier: ^3.10.1 - version: 3.10.1 + specifier: ^3.10.2 + version: 3.10.2 '@docusaurus/types': - specifier: ^3.10.1 - version: 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^3.10.2 + version: 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/react': specifier: ^19.1.8 version: 19.2.17 @@ -75,6 +78,10 @@ importers: packages: + '@11ty/gray-matter@1.0.0': + resolution: {integrity: sha512-7mJJl+wf1AByoT0PknQiQfOPnVNT4fevGrUBVWO4HXsnYn1aQPyRyrELYrNUFleUBM++KzMKN6QaxHPk0t/6/g==} + engines: {node: '>=11'} + '@algolia/abtesting@1.20.1': resolution: {integrity: sha512-ZXOLrNfmAAhBrIPp+9LH9CDRHUqIx2Uf17YRN6GJ2D0wVPHhCwvMgegCUKQz3W78xVdmzEzjawqf93pPBZVMOg==} engines: {node: '>= 14.0.0'} @@ -1076,12 +1083,12 @@ packages: search-insights: optional: true - '@docusaurus/babel@3.10.1': - resolution: {integrity: sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg==} + '@docusaurus/babel@3.10.2': + resolution: {integrity: sha512-aJ1hpGyvfkte3dDAfNbWM4biW4yWZBVz7TIGLZP+v+tWOBgxX3e0N5ZIXHIvmfNNXTI77pcHUx3KmtOk05Ze3Q==} engines: {node: '>=20.0'} - '@docusaurus/bundler@3.10.1': - resolution: {integrity: sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw==} + '@docusaurus/bundler@3.10.2': + resolution: {integrity: sha512-i0ZNcy0f0WhaOlYVgzLsWhIoEXO9kS3HRoKPtgE6vQtZUq7arKZaYdNBudr3mqCmd+TyOkwtwfHgs1ENj07r5g==} engines: {node: '>=20.0'} peerDependencies: '@docusaurus/faster': '*' @@ -1089,8 +1096,8 @@ packages: '@docusaurus/faster': optional: true - '@docusaurus/core@3.10.1': - resolution: {integrity: sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w==} + '@docusaurus/core@3.10.2': + resolution: {integrity: sha512-EYByj6nk+aD9KeVxV6Hmo2/nAAT79P21Y82ycTBOBtrmqilloIbIEhgL2/8Xpt2Jz/pgNqHAwyusOGwmbKeJmA==} engines: {node: '>=20.0'} hasBin: true peerDependencies: @@ -1102,103 +1109,103 @@ packages: '@docusaurus/faster': optional: true - '@docusaurus/cssnano-preset@3.10.1': - resolution: {integrity: sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ==} + '@docusaurus/cssnano-preset@3.10.2': + resolution: {integrity: sha512-4gCnHRbJLTloiwfvFAa92tgb2gI4KYhvjfQVYnEaiMO/EgvWfCo1LwytHXen+1oZAN0VAlS0JAPxp3MsvKDa3A==} engines: {node: '>=20.0'} - '@docusaurus/faster@3.10.1': - resolution: {integrity: sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ==} + '@docusaurus/faster@3.10.2': + resolution: {integrity: sha512-p/5E5/RyHv+QWusJMPN5i3OMJTqTgkhuwzVbB1AReDWTUHXQCmf5mlTFzGiDrWeQWIDOKsuOPn1jJh0s9LUOHA==} engines: {node: '>=20.0'} peerDependencies: '@docusaurus/types': '*' - '@docusaurus/logger@3.10.1': - resolution: {integrity: sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw==} + '@docusaurus/logger@3.10.2': + resolution: {integrity: sha512-gSEwqtPfCAnC3ZSJY6xL7tcIfgg0vFD39jbv93eakuweyvO2864xR0K+kmKwBhkTCtWRNjuGGnb5rdmkD/ndqw==} engines: {node: '>=20.0'} - '@docusaurus/mdx-loader@3.10.1': - resolution: {integrity: sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ==} + '@docusaurus/mdx-loader@3.10.2': + resolution: {integrity: sha512-9Fd4V/SFjfrVQ0JH5EN0+iPWyFunvTeQE3gfyFeetqPaXMP0OylIjOw16dCuXG4NZJrYdBqwzjh18/h3gRi47w==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/module-type-aliases@3.10.1': - resolution: {integrity: sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w==} + '@docusaurus/module-type-aliases@3.10.2': + resolution: {integrity: sha512-h/I5e4jaAhDHW4vaLENi1i2hnOEnXY1t9R+nnRTbgUl7ymVRzN/HF7dDfj8rKYGj8gfIge+Ef+iYRAMtbGvsrQ==} peerDependencies: react: '*' react-dom: '*' - '@docusaurus/plugin-content-blog@3.10.1': - resolution: {integrity: sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==} + '@docusaurus/plugin-content-blog@3.10.2': + resolution: {integrity: sha512-0cbEnNKf0InmLkhj/+nVRmqEnWEoOE8Mh+2x1qOXI0qYpCnphq4RXknVJ8BvybKRXqYVvbmdMfiJSup+k4tm5w==} engines: {node: '>=20.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-content-docs@3.10.1': - resolution: {integrity: sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ==} + '@docusaurus/plugin-content-docs@3.10.2': + resolution: {integrity: sha512-Sqwl4FPoZBDrlY8I2VU2H8O0M91CHp9T8ToMSkTZmjvHCif+1laqfXi6sTk8IfyVS/trN5yNjcWd1bFsGB6W5Q==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-content-pages@3.10.1': - resolution: {integrity: sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw==} + '@docusaurus/plugin-content-pages@3.10.2': + resolution: {integrity: sha512-h5R12sZ/vV9EPiVjvIl9YFCOwkpwXes7dQMYt3EvP6Pphu4amHxxTqWxf08Fl5DR8h+oZMbWpFTNw5vKEYfvzQ==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-css-cascade-layers@3.10.1': - resolution: {integrity: sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw==} + '@docusaurus/plugin-css-cascade-layers@3.10.2': + resolution: {integrity: sha512-UkdvQby5OQUKWrw3lLnSTJXQ6VETaUVTuPQX9AABtmFm5h+ifEBx1OQ+LN726Q4byuwBf2ElHkf4qU4hTxdvRg==} engines: {node: '>=20.0'} - '@docusaurus/plugin-debug@3.10.1': - resolution: {integrity: sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA==} + '@docusaurus/plugin-debug@3.10.2': + resolution: {integrity: sha512-8vbZNOSCpnsT57EY6CgN7sgRVmx3KTYwO8Uvo2pbxOyb8tbqAwtT9SslqaQ41HbA1v1hpn5RP7u5s2KvRwAFpQ==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-google-analytics@3.10.1': - resolution: {integrity: sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA==} + '@docusaurus/plugin-google-analytics@3.10.2': + resolution: {integrity: sha512-kMHMBK9j4VAtgd5owwrRLRIi0EjkrpXlX7ePj1+y68XfVZV9I1T4S+koPDm+Hfw2TtnyHvh0uNrDvjz+DjQGVA==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-google-gtag@3.10.1': - resolution: {integrity: sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw==} + '@docusaurus/plugin-google-gtag@3.10.2': + resolution: {integrity: sha512-Vt90nNFhtAChRe9+it1hcHFgFvETdSnOkL5Bma+p6E/yU2tAYrvvyk+gv+LJGM2ZUkyKuKXLRsZ2Lb0bO7+Vog==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-google-tag-manager@3.10.1': - resolution: {integrity: sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw==} + '@docusaurus/plugin-google-tag-manager@3.10.2': + resolution: {integrity: sha512-MLCffCldysi/R0nzJQP7ZWd0xAoGNnSTiVOo6TTR6mKVGFhE+/XArGe67ZcaZv1uytgQXoXs92VJrgVDrz80rQ==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-sitemap@3.10.1': - resolution: {integrity: sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg==} + '@docusaurus/plugin-sitemap@3.10.2': + resolution: {integrity: sha512-PODkwg5XetLML3hU/3xpCKJUZ9cqExLaBnD/Fzzwj2VHogLeqnDisLIujae87zuze7T4mCm2A6KEqZkyiz07EQ==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/plugin-svgr@3.10.1': - resolution: {integrity: sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q==} + '@docusaurus/plugin-svgr@3.10.2': + resolution: {integrity: sha512-JgfT3jWM0TJ8Uw0cEcqxHpybngQY1vlBYpuuNO+gEh5iPh5Ar+vxq/u9CFrYsWeXy48BN7Db76Pzp2edNXUQ8A==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/preset-classic@3.10.1': - resolution: {integrity: sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg==} + '@docusaurus/preset-classic@3.10.2': + resolution: {integrity: sha512-a4B3VczmDl99zK0EufDQYomdJ186WDingjmDXxhN2PNPS9Ty/Y2M5CLFX1KQMRKqRTLiRDKfutzG5IY1FC/ceg==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 @@ -1209,51 +1216,51 @@ packages: peerDependencies: react: '*' - '@docusaurus/theme-classic@3.10.1': - resolution: {integrity: sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A==} + '@docusaurus/theme-classic@3.10.2': + resolution: {integrity: sha512-JqTSLQmqmA9uKWZsD5iwBGJ4JyKB4/yTw6PsSXVPRJG/6GAm/u+add9Iip+hvwP12/AnPNztrdxsI14NJW4KeA==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/theme-common@3.10.1': - resolution: {integrity: sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA==} + '@docusaurus/theme-common@3.10.2': + resolution: {integrity: sha512-R9b/vMpK1yye6hNZTA6x/ivRv+at6GhxnXcxkpzCGzO1R1RwiquqiFg2wMFh6aqlJTpWRFKpFD2TzCDQcyOU0A==} engines: {node: '>=20.0'} peerDependencies: '@docusaurus/plugin-content-docs': '*' react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/theme-search-algolia@3.10.1': - resolution: {integrity: sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug==} + '@docusaurus/theme-search-algolia@3.10.2': + resolution: {integrity: sha512-1msxllyhi/5m77JukXtp5UFnUAriwZIC1oJ7MTnpQpCwLTbclJi5BK5n28CTZuSXpQN2ewbbnqRgAhMM6c6ihg==} engines: {node: '>=20.0'} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/theme-translations@3.10.1': - resolution: {integrity: sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw==} + '@docusaurus/theme-translations@3.10.2': + resolution: {integrity: sha512-iv20wrxnyXkY89LM3TzRlzGlt5fIGO5UnaR6UL1ZVfB9RRFjxQFQ6awDrwAc6Km8Y5gD8pInuwYPF+6/TiCxXA==} engines: {node: '>=20.0'} - '@docusaurus/tsconfig@3.10.1': - resolution: {integrity: sha512-rYvB7yqkdqWIpAbDzQljGfM4cDBkLTbhmagZBEcsyj6oPUsz47lmW2pYdN1j+7sGFgltbAmQH62xfbrij4Eh6Q==} + '@docusaurus/tsconfig@3.10.2': + resolution: {integrity: sha512-5GiB7h/nFsMFPO9mCqcRNE1yA5TSXXNCshNIgHPL6fCPOjcTDixs6qjQBu8ddkgPcicwCvOA7n3jeK2rGdJk6g==} - '@docusaurus/types@3.10.1': - resolution: {integrity: sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw==} + '@docusaurus/types@3.10.2': + resolution: {integrity: sha512-B6rvfwIFSapUqUJjMriZswX13K8l5Z7AcmVE6uTEJpYddQieSTR12DsGaFtcZAIDsQd4p+0WTl0Vc6jmZK0Trw==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - '@docusaurus/utils-common@3.10.1': - resolution: {integrity: sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA==} + '@docusaurus/utils-common@3.10.2': + resolution: {integrity: sha512-x3Dz6jv6iQKBNjBmVTu8p57abMp/VNTUgKBMgRVXJc5444orBTsArv0+cdfrXTiz/VMmHfDRVkPbL7GH2B7T7w==} engines: {node: '>=20.0'} - '@docusaurus/utils-validation@3.10.1': - resolution: {integrity: sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg==} + '@docusaurus/utils-validation@3.10.2': + resolution: {integrity: sha512-sn8unbDfUL585NtR3cwHefPicOyaHvPaX7VD0aOg/siIxUBoKyKKaGEqzJZDS64mM43TnxurkYDtmB1wsJlZsw==} engines: {node: '>=20.0'} - '@docusaurus/utils@3.10.1': - resolution: {integrity: sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw==} + '@docusaurus/utils@3.10.2': + resolution: {integrity: sha512-xx0W3eav2uW1NRIpuHJWNwLTC15xPNjU4Uxi9NSnd3swYC96BE3vFiT93SD8s24kmAAWNwgZwfZ2fghGZ01Lcw==} engines: {node: '>=20.0'} '@emnapi/core@1.11.1': @@ -1935,9 +1942,6 @@ packages: '@types/express@4.17.25': resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} - '@types/gtag.js@0.0.20': - resolution: {integrity: sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==} - '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2127,9 +2131,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - address@1.2.2: - resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} - engines: {node: '>= 10.0.0'} + address@2.0.3: + resolution: {integrity: sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA==} + engines: {node: '>= 16.0.0'} agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} @@ -2214,9 +2218,6 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2812,9 +2813,9 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - detect-port@1.6.1: - resolution: {integrity: sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==} - engines: {node: '>= 4.0.0'} + detect-port@2.1.0: + resolution: {integrity: sha512-epZuWb/6Q62L+nDHJc/hQAqf8pylsqgk3BpZXVBx1CDnr3nkrVNn73Uu1rXcFzkNcc+hkP3whuOg7JZYaQB65Q==} + engines: {node: '>= 16.0.0'} hasBin: true devlop@1.1.0: @@ -2834,8 +2835,8 @@ packages: peerDependencies: '@docusaurus/utils': ^3.6.0 - docusaurus-theme-redoc@2.5.0: - resolution: {integrity: sha512-ykLmnnvE20Im3eABlIpUnXnT2gSHVAjgyy2fU2G8yecu7zqIE+G/SiBpBg/hrWMUycL31a8VSG7Ehkf3pg1u+A==} + docusaurus-theme-redoc@2.5.1: + resolution: {integrity: sha512-BGbDv748peVQwttDQbhGCnA5eXtcBa76WP+nmc7Vz0bwEJv5Dh9et/WHJBRlFu97ScMS38+WpBnexCvYv3HYww==} engines: {node: '>=18'} peerDependencies: '@docusaurus/theme-common': ^3.6.0 @@ -2978,11 +2979,6 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -3235,10 +3231,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} - gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -3619,14 +3611,6 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} - hasBin: true - - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} - hasBin: true - js-yaml@4.3.2: resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true @@ -4116,6 +4100,19 @@ packages: react-native: optional: true + mobx-react@9.2.0: + resolution: {integrity: sha512-dkGWCx+S0/1mfiuFfHRH8D9cplmwhxOV5CkXMp38u6rQGG2Pv3FWYztS0M7ncR6TyPRQKaTG/pnitInoYE9Vrw==} + peerDependencies: + mobx: ^6.9.0 + react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + mobx-react@9.2.2: resolution: {integrity: sha512-ShszmQzR/VrhU3M0cQ7DA/s8qNcLcF2emSuudJ/TnDILS3C1Im48mdaG6CpyjZHy8+WqgXUCC9mPqSRIwPPMuQ==} peerDependencies: @@ -4972,8 +4969,18 @@ packages: react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 styled-components: ^4.1.1 || ^5.1.1 || ^6.0.5 - redocusaurus@2.5.0: - resolution: {integrity: sha512-QWJX2hgnEfSDb7fZzS4iZe6aqdAvm/XLCsNv6RkgDw6Pl/lsTZKipP2n1r5QS1CC5hY8eAwsjVXeF7B03vkz2g==} + redoc@2.5.4: + resolution: {integrity: sha512-M6jWhG1qoBnH6TFmzJnstyCZ87HmOY/UzDm78mHiYihEdlV/YcS9ogOo1NlElnJMeLsyxHFe2yFc4sNjHTrABQ==} + engines: {node: '>=6.9', npm: '>=3.0.0'} + peerDependencies: + core-js: ^3.1.4 + mobx: ^6.0.4 + react: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 + styled-components: ^4.1.1 || ^5.1.1 || ^6.0.5 + + redocusaurus@2.5.2: + resolution: {integrity: sha512-81xELtq+yRW1p+407yroPRvmIDjK5QNldYi5hRAJC1vVPKWm6lzBQ9HihE+51520MuAbZWmNNVa1ml5DhlDd1A==} engines: {node: '>=14'} peerDependencies: '@docusaurus/theme-common': ^3.6.0 @@ -5300,9 +5307,6 @@ packages: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} engines: {node: '>=6.0.0'} - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - srcset@4.0.0: resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} engines: {node: '>=12'} @@ -5870,6 +5874,13 @@ packages: snapshots: + '@11ty/gray-matter@1.0.0': + dependencies: + js-yaml: 4.3.2 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + '@algolia/abtesting@1.20.1': dependencies: '@algolia/client-common': 5.54.1 @@ -7094,7 +7105,7 @@ snapshots: - '@algolia/client-search' - algoliasearch - '@docusaurus/babel@3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/babel@3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 @@ -7105,8 +7116,8 @@ snapshots: '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) '@babel/runtime': 7.29.7 '@babel/traverse': 7.29.7 - '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/logger': 3.10.2 + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) babel-plugin-dynamic-import-node: 2.3.3 fs-extra: 11.3.5 tslib: 2.8.1 @@ -7128,14 +7139,14 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/bundler@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/bundler@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: '@babel/core': 7.29.7 - '@docusaurus/babel': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/cssnano-preset': 3.10.1 - '@docusaurus/logger': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/babel': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/cssnano-preset': 3.10.2 + '@docusaurus/logger': 3.10.2 + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) babel-loader: 9.2.1(@babel/core@7.29.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) clean-css: 5.3.3 copy-webpack-plugin: 11.0.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) @@ -7155,7 +7166,7 @@ snapshots: webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) webpackbar: 7.0.0(@rspack/core@1.7.11)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) optionalDependencies: - '@docusaurus/faster': 3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) + '@docusaurus/faster': 3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) transitivePeerDependencies: - '@minify-html/node' - '@parcel/css' @@ -7173,15 +7184,15 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/core@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/core@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/babel': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/bundler': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/babel': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/bundler': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) boxen: 6.2.1 chalk: 4.1.2 @@ -7190,7 +7201,7 @@ snapshots: combine-promises: 1.2.0 commander: 5.1.0 core-js: 3.49.0 - detect-port: 1.6.1 + detect-port: 2.1.0 escape-html: 1.0.3 eta: 2.2.0 eval: 0.1.8 @@ -7221,7 +7232,7 @@ snapshots: webpack-dev-server: 5.2.5(tslib@2.8.1)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) webpack-merge: 6.0.1 optionalDependencies: - '@docusaurus/faster': 3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) + '@docusaurus/faster': 3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15) transitivePeerDependencies: - '@minify-html/node' - '@parcel/css' @@ -7244,16 +7255,16 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/cssnano-preset@3.10.1': + '@docusaurus/cssnano-preset@3.10.2': dependencies: cssnano-preset-advanced: 6.1.2(postcss@8.5.15) postcss: 8.5.15 postcss-sort-media-queries: 5.2.0(postcss@8.5.15) tslib: 2.8.1 - '@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15)': + '@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15)': dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@rspack/core': 1.7.11 '@swc/core': 1.15.41 '@swc/html': 1.15.41 @@ -7276,16 +7287,16 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/logger@3.10.1': + '@docusaurus/logger@3.10.2': dependencies: chalk: 4.1.2 tslib: 2.8.1 - '@docusaurus/mdx-loader@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/mdx-loader@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/logger': 3.10.2 + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/mdx': 3.1.1 '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 @@ -7325,9 +7336,9 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/module-type-aliases@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/history': 4.7.11 '@types/react': 19.2.17 '@types/react-router-config': 5.0.11 @@ -7352,17 +7363,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': - dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/plugin-content-blog@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + dependencies: + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/plugin-content-docs': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) cheerio: 1.0.0-rc.12 combine-promises: 1.2.0 feed: 4.2.2 @@ -7400,21 +7411,21 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': - dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/module-type-aliases': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + dependencies: + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/module-type-aliases': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.3.5 - js-yaml: 4.2.0 + js-yaml: 4.3.2 lodash: 4.18.1 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7446,13 +7457,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-pages@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-content-pages@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7482,12 +7493,12 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-css-cascade-layers@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-css-cascade-layers@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7515,11 +7526,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-debug@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-debug@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7549,11 +7560,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-analytics@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-google-analytics@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) tslib: 2.8.1 @@ -7581,12 +7592,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-gtag@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-google-gtag@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@types/gtag.js': 0.0.20 + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) tslib: 2.8.1 @@ -7614,11 +7624,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-google-tag-manager@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) tslib: 2.8.1 @@ -7646,14 +7656,14 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-sitemap@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-sitemap@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -7683,12 +7693,12 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-svgr@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + '@docusaurus/plugin-svgr@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/webpack': 8.1.0(typescript@5.9.3) react: 19.2.7 @@ -7719,23 +7729,23 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/preset-classic@3.10.1(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3)': - dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-content-blog': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-content-pages': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-css-cascade-layers': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-debug': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-google-analytics': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-google-gtag': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-google-tag-manager': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-sitemap': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-svgr': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/theme-classic': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/theme-search-algolia': 3.10.1(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3) - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/preset-classic@3.10.2(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3)': + dependencies: + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-content-blog': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-content-docs': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-content-pages': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-css-cascade-layers': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-debug': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-google-analytics': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-google-gtag': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-google-tag-manager': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-sitemap': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-svgr': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/theme-classic': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-search-algolia': 3.10.2(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) transitivePeerDependencies: @@ -7770,21 +7780,21 @@ snapshots: '@types/react': 19.2.17 react: 19.2.7 - '@docusaurus/theme-classic@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': - dependencies: - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/module-type-aliases': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/plugin-content-blog': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/plugin-content-pages': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/theme-translations': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-classic@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + dependencies: + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/module-type-aliases': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/plugin-content-blog': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-content-docs': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/plugin-content-pages': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-translations': 3.10.2 + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) clsx: 2.1.1 copy-text-to-clipboard: 3.2.2 @@ -7823,13 +7833,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/theme-common@3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/mdx-loader': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/module-type-aliases': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/mdx-loader': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/module-type-aliases': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/plugin-content-docs': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@types/history': 4.7.11 '@types/react': 19.2.17 '@types/react-router-config': 5.0.11 @@ -7856,17 +7866,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-search-algolia@3.10.1(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3)': + '@docusaurus/theme-search-algolia@3.10.2(@algolia/client-search@5.54.1)(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(@types/react@19.2.17)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3)(typescript@5.9.3)': dependencies: '@algolia/autocomplete-core': 1.19.8(@algolia/client-search@5.54.1)(algoliasearch@5.54.1)(search-insights@2.17.3) '@docsearch/react': 4.6.3(@algolia/client-search@5.54.1)(@types/react@19.2.17)(algoliasearch@5.54.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(search-insights@2.17.3) - '@docusaurus/core': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/logger': 3.10.1 - '@docusaurus/plugin-content-docs': 3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/theme-translations': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-validation': 3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/core': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/logger': 3.10.2 + '@docusaurus/plugin-content-docs': 3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-translations': 3.10.2 + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-validation': 3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) algoliasearch: 5.54.1 algoliasearch-helper: 3.29.1(algoliasearch@5.54.1) clsx: 2.1.1 @@ -7904,14 +7914,14 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-translations@3.10.1': + '@docusaurus/theme-translations@3.10.2': dependencies: fs-extra: 11.3.5 tslib: 2.8.1 - '@docusaurus/tsconfig@3.10.1': {} + '@docusaurus/tsconfig@3.10.2': {} - '@docusaurus/types@3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/types@3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@mdx-js/mdx': 3.1.1 '@types/history': 4.7.11 @@ -7941,9 +7951,9 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/utils-common@3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tslib: 2.8.1 transitivePeerDependencies: - '@minify-html/node' @@ -7963,14 +7973,14 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-validation@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/utils-validation@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/logger': 3.10.1 - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/logger': 3.10.2 + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) fs-extra: 11.3.5 joi: 17.13.4 - js-yaml: 4.2.0 + js-yaml: 4.3.2 lodash: 4.18.1 tslib: 2.8.1 transitivePeerDependencies: @@ -7991,20 +8001,20 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@docusaurus/utils@3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@docusaurus/logger': 3.10.1 - '@docusaurus/types': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils-common': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@11ty/gray-matter': 1.0.0 + '@docusaurus/logger': 3.10.2 + '@docusaurus/types': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils-common': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) escape-string-regexp: 4.0.0 execa: 5.1.1 file-loader: 6.2.0(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) fs-extra: 11.3.5 github-slugger: 1.5.0 globby: 11.1.0 - gray-matter: 4.0.3 jiti: 1.21.7 - js-yaml: 4.2.0 + js-yaml: 4.3.2 lodash: 4.18.1 micromatch: 4.0.8 p-queue: 6.6.2 @@ -8445,7 +8455,7 @@ snapshots: colorette: 1.4.0 https-proxy-agent: 7.0.6(supports-color@10.2.2) js-levenshtein: 1.1.6 - js-yaml: 4.2.0 + js-yaml: 4.3.2 lodash.isequal: 4.5.0 minimatch: 5.1.9 node-fetch: 2.7.0 @@ -8809,8 +8819,6 @@ snapshots: '@types/qs': 6.15.1 '@types/serve-static': 1.15.10 - '@types/gtag.js@0.0.20': {} - '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -8890,7 +8898,7 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 17.0.45 + '@types/node': 25.9.3 '@types/send@0.17.6': dependencies: @@ -9033,7 +9041,7 @@ snapshots: acorn@8.17.0: {} - address@1.2.2: {} + address@2.0.3: {} agent-base@7.1.4: {} @@ -9120,10 +9128,6 @@ snapshots: arg@5.0.2: {} - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} array-flatten@1.1.1: {} @@ -9522,7 +9526,7 @@ snapshots: cosmiconfig@8.3.6(typescript@5.9.3): dependencies: import-fresh: 3.3.1 - js-yaml: 4.2.0 + js-yaml: 4.3.2 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: @@ -9740,12 +9744,9 @@ snapshots: detect-node@2.1.0: {} - detect-port@1.6.1: + detect-port@2.1.0: dependencies: - address: 1.2.2 - debug: 4.4.3(supports-color@10.2.2) - transitivePeerDependencies: - - supports-color + address: 2.0.3 devlop@1.1.0: dependencies: @@ -9759,9 +9760,9 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 - docusaurus-plugin-redoc@2.5.0(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)): + docusaurus-plugin-redoc@2.5.0(@docusaurus/utils@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)): dependencies: - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@redocly/openapi-core': 1.16.0 redoc: 2.4.0(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) transitivePeerDependencies: @@ -9774,16 +9775,16 @@ snapshots: - styled-components - supports-color - docusaurus-theme-redoc@2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): + docusaurus-theme-redoc@2.5.1(@docusaurus/theme-common@3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): dependencies: - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@redocly/openapi-core': 1.16.0 clsx: 1.2.1 lodash: 4.18.1 mobx: 6.16.1 postcss: 8.5.15 postcss-prefix-selector: 1.16.1(postcss@8.5.15) - redoc: 2.4.0(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + redoc: 2.5.4(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) styled-components: 6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) webpack: 5.107.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15) transitivePeerDependencies: @@ -9928,8 +9929,6 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - esprima@4.0.1: {} - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -10234,13 +10233,6 @@ snapshots: graceful-fs@4.2.11: {} - gray-matter@4.0.3: - dependencies: - js-yaml: 3.14.2 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 - gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -10661,15 +10653,6 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@3.14.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.2.0: - dependencies: - argparse: 2.0.1 - js-yaml@4.3.2: dependencies: argparse: 2.0.1 @@ -11393,6 +11376,14 @@ snapshots: optionalDependencies: react-dom: 19.2.7(react@19.2.7) + mobx-react@9.2.0(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + mobx: 6.16.1 + mobx-react-lite: 4.1.1(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + optionalDependencies: + react-dom: 19.2.7(react@19.2.7) + mobx-react@9.2.2(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: mobx: 6.16.1 @@ -12324,7 +12315,7 @@ snapshots: redoc@2.4.0(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)): dependencies: - '@redocly/openapi-core': 1.16.0 + '@redocly/openapi-core': 1.34.20(supports-color@10.2.2) classnames: 2.5.1 core-js: 3.49.0 decko: 1.2.0 @@ -12355,12 +12346,45 @@ snapshots: - react-native - supports-color - redocusaurus@2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): + redoc@2.5.4(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)): dependencies: - '@docusaurus/theme-common': 3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@docusaurus/utils': 3.10.1(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - docusaurus-plugin-redoc: 2.5.0(@docusaurus/utils@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) - docusaurus-theme-redoc: 2.5.0(@docusaurus/theme-common@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) + '@redocly/openapi-core': 1.34.20(supports-color@10.2.2) + classnames: 2.5.1 + core-js: 3.49.0 + decko: 1.2.0 + dompurify: 3.4.10 + eventemitter3: 5.0.4 + json-pointer: 0.6.2 + lunr: 2.3.9 + mark.js: 8.11.1 + marked: 4.3.0 + mobx: 6.16.1 + mobx-react: 9.2.0(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + openapi-sampler: 1.7.4 + path-browserify: 1.0.1 + perfect-scrollbar: 1.5.6 + polished: 4.3.1 + prismjs: 1.30.0 + prop-types: 15.8.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-tabs: 6.1.1(react@19.2.7) + slugify: 1.4.7 + stickyfill: 1.1.1 + styled-components: 6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + swagger2openapi: 7.0.8 + url-template: 2.0.8 + transitivePeerDependencies: + - encoding + - react-native + - supports-color + + redocusaurus@2.5.2(@docusaurus/theme-common@3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@docusaurus/utils@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)): + dependencies: + '@docusaurus/theme-common': 3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@docusaurus/utils': 3.10.2(@swc/core@1.15.41)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.15))(html-minifier-terser@7.2.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + docusaurus-plugin-redoc: 2.5.0(@docusaurus/utils@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(mobx@6.16.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(styled-components@6.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)) + docusaurus-theme-redoc: 2.5.1(@docusaurus/theme-common@3.10.2(@docusaurus/plugin-content-docs@3.10.2(@docusaurus/faster@3.10.2(@docusaurus/types@3.10.2(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11)(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3))(@swc/core@1.15.41)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(core-js@3.49.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.107.2(@swc/core@1.15.41)(postcss@8.5.15)) transitivePeerDependencies: - core-js - css-to-react-native @@ -12792,8 +12816,6 @@ snapshots: transitivePeerDependencies: - supports-color - sprintf-js@1.0.3: {} - srcset@4.0.0: {} statuses@1.5.0: {} diff --git a/website/pnpm-workspace.yaml b/website/pnpm-workspace.yaml index ad5f2453e..b033fc8b4 100644 --- a/website/pnpm-workspace.yaml +++ b/website/pnpm-workspace.yaml @@ -4,3 +4,7 @@ packages: allowBuilds: '@swc/core': true core-js: true + +# Redocusaurus pins an older renderer; use the current compatible ReDoc release. +overrides: + "docusaurus-theme-redoc>redoc": 2.5.4 diff --git a/website/src/css/custom.css b/website/src/css/custom.css index e7dedfb0d..4d0ff1ea8 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -390,7 +390,7 @@ body[data-scrolled='true'] .navbar { display: none !important; } -/* Choose the initial invoice status before reviewing its conditional fields. */ +/* Keep invoice mode and related fields together when requirements change. */ [id='operation/createInvoice'] tbody:has(> tr > td[title='status'] + td select) { display: grid; grid-template-columns: max-content minmax(0, 1fr); @@ -410,7 +410,7 @@ body[data-scrolled='true'] .navbar { } > tr:has(> td[title='status']) { - order: -1; + order: -11; > td + td > div { display: flex; @@ -423,6 +423,17 @@ body[data-scrolled='true'] .navbar { } } + > tr:has(> td[title='type']) { order: -10; } + > tr:has(> td[title='customer']) { order: -9; } + > tr:has(> td[title='third_party']) { order: -8; } + > tr:has(> td:is([title='items'], [title='complements'])) { order: -7; } + > tr:has(> td[title='use']) { order: -6; } + > tr:has(> td:is([title='payment_form'], [title='payment_method'], [title='conditions'])) { order: -5; } + > tr:has(> td:is([title='currency'], [title='exchange'])) { order: -4; } + > tr:has(> td:is([title='date'], [title='folio_number'], [title='series'])) { order: -3; } + > tr:has(> td:is([title='related_documents'], [title='global'], [title='export'])) { order: 1; } + > tr:has(> td:is([title='pdf_custom_section'], [title='addenda'], [title='namespaces'], [title='pdf_options'])) { order: 2; } + @media (max-width: 50rem) { grid-template-columns: minmax(0, 1fr); } From 7817b430894914536437a320779dc9d962092bfa Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 16:41:16 +0200 Subject: [PATCH 23/33] fix: align payment summaries and webhook contracts --- .github/workflows/openapi.yml | 3 ++ website/openapi_v2.en.yaml | 64 ++++++++++++++----------- website/openapi_v2.yaml | 66 ++++++++++++++------------ website/scripts/check-openapi.mjs | 15 ++++-- website/src/pages/api.tsx | 9 ++-- website/test/openapi-types.fixture.txt | 9 ++++ 6 files changed, 99 insertions(+), 67 deletions(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 45ef9f9f4..f93e68258 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -8,7 +8,10 @@ on: - website/test/openapi-types.fixture.txt - website/package.json - website/pnpm-lock.yaml + - website/pnpm-workspace.yaml - .github/workflows/openapi.yml + push: + branches: [main] workflow_dispatch: jobs: diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 36d4b5acd..fe0f43914 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -4280,6 +4280,12 @@ paths: description: Invoice taxes prorated to the paid amount items: type: object + required: + - base + - rate + - type + - factor + - withholding properties: base: type: number @@ -4289,9 +4295,17 @@ paths: description: Tax rate or quota type: type: string + enum: + - IVA + - ISR + - IEPS description: Tax type (VAT, income tax withholding, etc.) factor: type: string + enum: + - Tasa + - Cuota + - Exento description: Factor type (Rate, Exempt, etc.) withholding: type: boolean @@ -5888,13 +5902,13 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Assign an existing customer by ID - const receipt = await facturapi.receipts.assignCustomer( + const receipt = await facturapi.receipts.updateCustomer( '58e93bd8e86eb318b019743d', { customer: '58e93bd8e86eb318b0197456' } ); // Or create the customer from payload and assign it to the receipt - const receiptWithNewCustomer = await facturapi.receipts.assignCustomer( + const receiptWithNewCustomer = await facturapi.receipts.updateCustomer( '58e93bd8e86eb318b019743d', { customer: { @@ -11431,7 +11445,7 @@ paths: var facturapi = new FacturapiClient("sk_test_API_KEY"); var customer = await facturapi.Webhook.CreateAsync(new Dictionary { - ["enabled_events"] = new Dictionary["receipt.self_invoice_complete"], + ["enabled_events"] = new string[] { "receipt.self_invoice_complete" }, ["url"] = "http://webhook_api.com" }); - lang: Java @@ -11446,7 +11460,7 @@ paths: var webhook = facturapi.webhooks().create( Map.of( "url", "https://example.com/webhooks", - "triggers", List.of("invoice.created") + "enabled_events", List.of("receipt.self_invoice_complete") )); - lang: PHP source: | @@ -11664,7 +11678,7 @@ paths: new Dictionary { ["status"] = "disabled", - ["address"] = new Dictionary["receipt.self_invoice_complete"] + ["enabled_events"] = new string[] { "receipt.self_invoice_complete" } } ); - lang: Java @@ -11677,16 +11691,15 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); var webhook = facturapi.webhooks().update("whk_123", Map.of( - "url", "https://example.com/webhooks", - "triggers", List.of("invoice.created") + "status", "disabled", + "enabled_events", List.of("receipt.self_invoice_complete") )); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); $customer = $facturapi->Webhooks->update("590ce6c56d04f840aa8438af", [ "status" => "disabled", - "address" => ["receipt.self_invoice_complete"] - ] + "enabled_events" => ["receipt.self_invoice_complete"] ]); parameters: - in: path @@ -12681,7 +12694,7 @@ components: schema: type: integer minimum: 1 - default: 50 + default: 100 maximum: 100 description: Number from 1 to 100 representing the maximum amount of results to return for pagination purposes. @@ -12770,11 +12783,6 @@ components: required: - type - object - related_resource_messages: - type: array - description: Messages related to the resource associated with the event. - items: - $ref: '#/components/schemas/RelatedResourceMessage' required: - type - data @@ -12929,7 +12937,7 @@ components: customer.edit_link_completed: '#/components/schemas/CustomerEditLinkCompletedEvent' SignedDownloadUrl: type: object - description: Temporary download URL for a file. + description: Object containing a temporary download link and file metadata. required: - url - expires_at @@ -12938,6 +12946,7 @@ components: properties: url: type: string + format: uri description: Download URL. It grants access to the file while it is valid. expires_at: type: string @@ -13003,6 +13012,11 @@ components: type: string description: ID of the organization this event is related to example: 61f81a7fbd4661b11b9b3f27 + related_resource_messages: + type: array + description: Messages related to the resource associated with the event. + items: + $ref: '#/components/schemas/RelatedResourceMessage' required: - id - created_at @@ -15986,16 +16000,12 @@ components: description: Link to a hosted page where the customer can edit their information once. example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: - - string - - 'null' + type: string format: date-time description: Expiration date of the edit link. example: '2022-12-31T23:59:59Z' sat_validated_at: - type: - - string - - 'null' + type: string format: date-time description: Date when the customer's tax information was validated by the SAT. example: '2022-12-31T23:59:59Z' @@ -16497,7 +16507,7 @@ components: description: | Optional. You can include the folio number of the related document. series: - type: string + type: [string, "null"] description: | Optional. You can include the series of the related document. currency: @@ -19435,13 +19445,9 @@ components: type: string format: date-time domain: - type: - - string - - 'null' + type: string custom_domain: - type: - - string - - 'null' + type: string OrganizationDeleteCerts: type: object diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 544e60267..982a26cf3 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -4254,6 +4254,12 @@ paths: description: Impuestos de la factura prorrateados al monto pagado items: type: object + required: + - base + - rate + - type + - factor + - withholding properties: base: type: number @@ -4263,9 +4269,17 @@ paths: description: Tasa o cuota del impuesto type: type: string + enum: + - IVA + - ISR + - IEPS description: Tipo de impuesto (IVA, ISR, etc.) factor: type: string + enum: + - Tasa + - Cuota + - Exento description: Tipo de factor (Tasa, Exento, etc.) withholding: type: boolean @@ -5849,13 +5863,13 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Asignar un cliente existente por ID - const receipt = await facturapi.receipts.assignCustomer( + const receipt = await facturapi.receipts.updateCustomer( '58e93bd8e86eb318b019743d', { customer: '58e93bd8e86eb318b0197456' } ); // O crear el cliente desde payload y asignarlo al recibo - const receiptWithNewCustomer = await facturapi.receipts.assignCustomer( + const receiptWithNewCustomer = await facturapi.receipts.updateCustomer( '58e93bd8e86eb318b019743d', { customer: { @@ -11386,7 +11400,7 @@ paths: var facturapi = new FacturapiClient("sk_test_API_KEY"); var customer = await facturapi.Webhook.CreateAsync(new Dictionary { - ["enabled_events"] = new Dictionary["receipt.self_invoice_complete"], + ["enabled_events"] = new string[] { "receipt.self_invoice_complete" }, ["url"] = "http://my-website.com/my/webhook" }); - lang: Java @@ -11401,7 +11415,7 @@ paths: var webhook = facturapi.webhooks().create( Map.of( "url", "https://example.com/webhooks", - "triggers", List.of("invoice.created") + "enabled_events", List.of("receipt.self_invoice_complete") )); - lang: PHP source: | @@ -11616,7 +11630,7 @@ paths: new Dictionary { ["status"] = "disabled", - ["address"] = new Dictionary["receipt.self_invoice_complete"] + ["enabled_events"] = new string[] { "receipt.self_invoice_complete" } } ); - lang: Java @@ -11629,16 +11643,15 @@ paths: Facturapi facturapi = new Facturapi("sk_test_API_KEY"); var webhook = facturapi.webhooks().update("whk_123", Map.of( - "url", "https://example.com/webhooks", - "triggers", List.of("invoice.created") + "status", "disabled", + "enabled_events", List.of("receipt.self_invoice_complete") )); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); $customer = $facturapi->Webhooks->update("590ce6c56d04f840aa8438af", [ "status" => "disabled", - "address" => ["receipt.self_invoice_complete"] - ] + "enabled_events" => ["receipt.self_invoice_complete"] ]); parameters: - in: path @@ -11746,7 +11759,7 @@ paths: - lang: Bash label: cURL source: | - curl https://www.facturapi.io/v2/webhooks/valdate-signature \ + curl https://www.facturapi.io/v2/webhooks/validate-signature \ -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ @@ -12632,7 +12645,7 @@ components: schema: type: integer minimum: 1 - default: 50 + default: 100 maximum: 100 description: Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. @@ -12721,11 +12734,6 @@ components: required: - type - object - related_resource_messages: - type: array - description: Mensajes relacionados con el recurso asociado al evento. - items: - $ref: '#/components/schemas/RelatedResourceMessage' required: - type - data @@ -12880,7 +12888,7 @@ components: customer.edit_link_completed: '#/components/schemas/CustomerEditLinkCompletedEvent' SignedDownloadUrl: type: object - description: Enlace temporal de descarga de un archivo. + description: Objeto con un enlace temporal de descarga y los metadatos del archivo. required: - url - expires_at @@ -12889,6 +12897,7 @@ components: properties: url: type: string + format: uri description: Enlace de descarga. Da acceso al archivo mientras siga vigente. expires_at: type: string @@ -12970,6 +12979,11 @@ components: type: string description: ID de la organización a la que pertenece el evento example: 61f81a7fbd4661b11b9b3f27 + related_resource_messages: + type: array + description: Mensajes relacionados con el recurso asociado al evento. + items: + $ref: '#/components/schemas/RelatedResourceMessage' required: - id - created_at @@ -15996,17 +16010,13 @@ components: Ejemplo: https://auto.facturapi.io/tax-info/abcdWXYZ1234 example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: - - string - - 'null' + type: string format: date-time description: | Fecha de expiración del enlace de edición. example: '2022-12-31T23:59:59Z' sat_validated_at: - type: - - string - - 'null' + type: string format: date-time description: | Fecha en la que la información fiscal fue validado por el SAT. @@ -16465,7 +16475,7 @@ components: type: integer description: Opcionalmente se puede incluir el número de folio del documento relacionado. series: - type: string + type: [string, "null"] description: Opcionalmente se puede incluir la serie del documento relacionado. currency: type: string @@ -19338,13 +19348,9 @@ components: type: string format: date-time domain: - type: - - string - - 'null' + type: string custom_domain: - type: - - string - - 'null' + type: string OrganizationDeleteCerts: type: object diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index d111c66c5..0e069326d 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -36,9 +36,8 @@ function contract(value, key) { } for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { - const spec = yaml.load(await readFile(new URL(filename, root), "utf8"), { - schema: yaml.JSON_SCHEMA, - }); + // Match the generator parser so unquoted numeric SAT codes fail validation. + const spec = yaml.load(await readFile(new URL(filename, root), "utf8")); function walk(value, path = []) { if (!value || typeof value !== "object") return; assert( @@ -65,7 +64,7 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { "string", `String enum values must be quoted when needed: ${path.join(".")}`, ); - for (const key of ["example", "default"]) + for (const key of ["example", "default", "const"]) if (key in value) assert.equal( typeof value[key], @@ -85,6 +84,14 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { walk(child, [...path, key]); } walk(spec); + for (const invoiceType of spec.components.schemas.InvoiceCreateInput.oneOf) { + assert.equal(invoiceType.oneOf.length, 2, "Expected emission and draft variants"); + assert.deepEqual( + invoiceType.oneOf.map((variant) => variant.allOf.at(-1).properties.status.const), + ["pending", "draft"], + "Invoice display variants must match their contractual status", + ); + } const ids = new Set(); for (const items of [spec.paths, spec.webhooks || {}]) { for (const [path, item] of Object.entries(items)) { diff --git a/website/src/pages/api.tsx b/website/src/pages/api.tsx index d7fa890f5..a5c9eec96 100644 --- a/website/src/pages/api.tsx +++ b/website/src/pages/api.tsx @@ -14,15 +14,16 @@ function CustomPage() { // Keep this presentation hint out of the contract: status may be omitted. spec.components.schemas.InvoiceCreateInput.oneOf = spec.components.schemas.InvoiceCreateInput.oneOf.map( - (invoiceType: {oneOf: {title: string}[]}, typeIndex: number) => { + (invoiceType: {oneOf: {allOf: {properties: {status: {const: string}}}[]}[]}, typeIndex: number) => { const mapping: Record = {}; return { ...invoiceType, oneOf: invoiceType.oneOf.map((variant) => { - const name = `InvoiceCreateDisplay${typeIndex}${variant.title}`; + const status = variant.allOf.at(-1)!.properties.status.const; + const name = `InvoiceCreateDisplay${typeIndex}${status}`; spec.components.schemas[name] = variant; - mapping[variant.title] = `#/components/schemas/${name}`; - return {$ref: mapping[variant.title]}; + mapping[status] = `#/components/schemas/${name}`; + return {$ref: mapping[status]}; }), discriminator: {propertyName: 'status', mapping}, }; diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index 72e9adab9..da942aabc 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -21,6 +21,7 @@ const receiptEvent: components["schemas"]["ApiEvent"] = { livemode: false, organization: "org", type: "receipt.status_updated", + related_resource_messages: [], data: { type: "receipt", object: { @@ -151,3 +152,11 @@ const createdInvoiceDate: string | null | undefined = createdInvoiceResponse.dat const createdInvoiceStamp: components["schemas"]["Stamp"] | null | undefined = createdInvoiceResponse.stamp; void createdInvoiceDate; void createdInvoiceStamp; + +// A payment summary can be reused directly in a payment complement. +declare const paymentSummary: operations["getInvoicePaymentSummary"]["responses"][200]["content"]["application/json"]; +const summaryRelatedDocument: components["schemas"]["PaymentInput"]["related_documents"][number] = paymentSummary; +// Catalog codes are strings: their leading zeros are part of their identity. +// @ts-expect-error a numeric catalog code is not a valid string code +const numericPaymentTaxability: typeof paymentTaxability = 1; +void [summaryRelatedDocument, numericPaymentTaxability]; From d1bf2baee4313ac41b769f49bf371fb9d7f532a6 Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 22:47:05 +0200 Subject: [PATCH 24/33] docs: clarify download response objects and correct SDK examples --- website/openapi_v2.en.yaml | 50 +++++++++++++++---------------- website/openapi_v2.yaml | 44 +++++++++++++-------------- website/scripts/check-openapi.mjs | 23 ++++++++++++++ 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index fe0f43914..ed1cdf11c 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -4516,7 +4516,7 @@ paths: tags: - invoice summary: Get invoice PDF preview URL - description: Returns a temporary URL for an unstamped invoice PDF preview. + description: Returns an object containing file metadata and a temporary URL for an unstamped invoice PDF preview. x-codeSamples: - lang: JavaScript label: Node.js @@ -4534,7 +4534,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the PDF preview. + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -4679,7 +4679,7 @@ paths: - invoice summary: Get download URL description: | - Returns a temporary URL to download the invoice in PDF, XML, or both in a ZIP file, without the file travelling through your server. + Returns an object containing file metadata and a temporary URL to download the invoice in PDF, XML, or both in a ZIP file, without the file travelling through your server. The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: @@ -4721,7 +4721,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the CFDI in the requested format + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -4843,7 +4843,7 @@ paths: - invoice summary: Get cancellation receipt download URL description: | - Returns a temporary URL to download the XML or PDF receipt issued by SAT when a cancellation request is submitted through Facturapi, without the file travelling through your server. The receipt contains the immediate request result and does not necessarily prove that the CFDI is already canceled; check the invoice status to confirm the outcome. + Returns an object containing file metadata and a temporary URL to download the XML or PDF receipt issued by SAT when a cancellation request is submitted through Facturapi, without the file travelling through your server. The receipt contains the immediate request result and does not necessarily prove that the CFDI is already canceled; check the invoice status to confirm the outcome. The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: @@ -4884,7 +4884,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the cancellation receipt in the requested format + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -5466,7 +5466,7 @@ paths: - invoice summary: Get monthly ZIP download URL description: | - Returns a temporary URL for downloading the ZIP of a finished request without the file travelling through your server. + Returns an object containing file metadata and a temporary URL for downloading the ZIP of a finished request without the file travelling through your server. The URL grants access to that one file while it is valid: treat it as a credential and do not store it. Requires a live-mode organization API key, an active subscription, and permission to read invoices. x-codeSamples: @@ -5492,7 +5492,7 @@ paths: - "SecretLiveKey": [] responses: "200": - description: Temporary download URL for the generated ZIP file. + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -6456,7 +6456,7 @@ paths: tags: - receipt summary: Get receipts invoice preview URL - description: Returns a temporary URL for the PDF preview of an invoice built from the selected receipts. + description: Returns an object containing file metadata and a temporary URL for the PDF preview of an invoice built from the selected receipts. x-codeSamples: - lang: JavaScript label: Node.js @@ -6474,7 +6474,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the PDF preview. + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -6689,7 +6689,7 @@ paths: - receipt summary: Get download URL description: | - Returns a temporary URL to download the receipt in PDF, without the file travelling through your server. + Returns an object containing file metadata and a temporary URL to download the receipt in PDF, without the file travelling through your server. The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: @@ -6721,7 +6721,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the receipt in PDF + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -6751,7 +6751,7 @@ paths: - lang: Bash label: cURL source: | - # Send to a different email than the one registered by the customer + // Send to a different email than the one registered by the customer curl https://www.facturapi.io/v2/receipts/58e93bd8e86eb318b019743d/email \ -H "Authorization: Bearer sk_test_API_KEY" \ -X POST \ @@ -6765,13 +6765,13 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_test_API_KEY'); - # Send to a different email than the one registered by the customer + // Send to a different email than the one registered by the customer await facturapi.receipts.sendByEmail( '58e93bd8e86eb318b019743d', { email: 'ejemplo@correo.com' } ); - # Send to multiple emails (max 10) + // Send to multiple emails (max 10) await facturapi.receipts.sendByEmail( '58e93bd8e86eb318b019743d', { @@ -7748,7 +7748,7 @@ paths: - retention summary: Get download URL description: | - Returns a temporary URL to download the retention in PDF, XML, or both in a ZIP file, without the file travelling through your server. + Returns an object containing file metadata and a temporary URL to download the retention in PDF, XML, or both in a ZIP file, without the file travelling through your server. The URL grants access to that one file while it is valid: treat it as a credential and do not store it. x-codeSamples: @@ -7790,7 +7790,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Temporary download URL for the retention in the requested format + description: Object containing a temporary download URL, its expiration date, the content type, and the filename. content: application/json: schema: @@ -9784,7 +9784,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const seriesList = await facturapi.organizations.getSeries( + const seriesList = await facturapi.organizations.listSeriesGroup( '5a2a307be93a2f00129ea035' ); - lang: csharp @@ -9871,7 +9871,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const newSeries = await facturapi.organizations.createSeries( + const newSeries = await facturapi.organizations.createSeriesGroup( '5a2a307be93a2f00129ea035', { series: 'New', @@ -10070,13 +10070,13 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const updatedSeries = await facturapi.organizations.updateSeries( + const updatedSeries = await facturapi.organizations.updateSeriesGroup( '5a2a307be93a2f00129ea035', 'New', - [ - "next_folio" => 1, - "next_folio_test" => 1 - ] + { + next_folio: 1, + next_folio_test: 1 + } ); - lang: csharp label: C# @@ -10166,7 +10166,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const deletedSeries = await facturapi.organizations.deleteSeries( + const deletedSeries = await facturapi.organizations.deleteSeriesGroup( '5a2a307be93a2f00129ea035', 'New' ); diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 982a26cf3..48c07c4e2 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -4488,7 +4488,7 @@ paths: tags: - invoice summary: Obtener URL del preview PDF de factura - description: Devuelve una URL temporal para el preview PDF de una factura sin timbrar. + description: Devuelve un objeto con los metadatos del archivo y una URL temporal para el preview PDF de una factura sin timbrar. x-codeSamples: - lang: JavaScript label: Node.js @@ -4506,7 +4506,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: URL temporal de descarga para el preview PDF. + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -4651,7 +4651,7 @@ paths: - invoice summary: Obtener enlace de descarga description: | - Devuelve un enlace temporal para descargar la factura en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. + Devuelve un objeto con los metadatos del archivo y un enlace temporal para descargar la factura en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: @@ -4693,7 +4693,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Enlace temporal de descarga del comprobante CFDI en el formato solicitado + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -4810,7 +4810,7 @@ paths: - invoice summary: Obtener enlace del acuse de cancelación description: | - Devuelve un enlace temporal para descargar en XML o PDF el acuse emitido por el SAT al solicitar la cancelación mediante Facturapi. El acuse contiene el resultado inmediato de la solicitud y no necesariamente acredita que el CFDI ya esté cancelado; consulta el estado de la factura para confirmar el desenlace. + Devuelve un objeto con los metadatos del archivo y un enlace temporal para descargar en XML o PDF el acuse emitido por el SAT al solicitar la cancelación mediante Facturapi. El acuse contiene el resultado inmediato de la solicitud y no necesariamente acredita que el CFDI ya esté cancelado; consulta el estado de la factura para confirmar el desenlace. El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: @@ -4851,7 +4851,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Enlace temporal de descarga del acuse de cancelación en el formato solicitado + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -5429,7 +5429,7 @@ paths: - invoice summary: Obtener URL de descarga del ZIP mensual description: | - Devuelve una URL temporal para descargar el ZIP de una solicitud terminada sin que el archivo viaje a través de tu servidor. + Devuelve un objeto con los metadatos del archivo y una URL temporal para descargar el ZIP de una solicitud terminada sin que el archivo viaje a través de tu servidor. La URL permite acceder únicamente a ese archivo mientras sea válida: trátala como una credencial y no la almacenes. Requiere una llave de API de organización en ambiente Live, una suscripción activa y permiso para leer facturas. x-codeSamples: @@ -5455,7 +5455,7 @@ paths: - "SecretLiveKey": [] responses: "200": - description: URL temporal de descarga para el archivo ZIP generado. + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -6419,7 +6419,7 @@ paths: tags: - receipt summary: Obtener URL del preview de factura de recibos - description: Devuelve una URL temporal para el preview PDF de una factura construida con los recibos seleccionados. + description: Devuelve un objeto con los metadatos del archivo y una URL temporal para el preview PDF de una factura construida con los recibos seleccionados. x-codeSamples: - lang: JavaScript label: Node.js @@ -6437,7 +6437,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: URL temporal de descarga para el preview PDF. + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -6652,7 +6652,7 @@ paths: - receipt summary: Obtener enlace de descarga description: | - Devuelve un enlace temporal para descargar el recibo digital en PDF, sin que el archivo pase por tu servidor. + Devuelve un objeto con los metadatos del archivo y un enlace temporal para descargar el recibo digital en PDF, sin que el archivo pase por tu servidor. El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: @@ -6684,7 +6684,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Enlace temporal de descarga del recibo digital en formato PDF + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -7711,7 +7711,7 @@ paths: - retention summary: Obtener enlace de descarga description: | - Devuelve un enlace temporal para descargar la retención en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. + Devuelve un objeto con los metadatos del archivo y un enlace temporal para descargar la retención en PDF, XML o ambos en un archivo comprimido ZIP, sin que el archivo pase por tu servidor. El enlace da acceso a ese archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. x-codeSamples: @@ -7753,7 +7753,7 @@ paths: - "SecretTestKey": [] responses: "200": - description: Enlace temporal de descarga de la retención en el formato solicitado + description: Objeto con una URL temporal de descarga, su fecha de expiración, el tipo de contenido y el nombre del archivo. content: application/json: schema: @@ -9741,7 +9741,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const seriesList = await facturapi.organizations.getSeries( + const seriesList = await facturapi.organizations.listSeriesGroup( '5a2a307be93a2f00129ea035' ); - lang: csharp @@ -9828,7 +9828,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const newSeries = await facturapi.organizations.createSeries( + const newSeries = await facturapi.organizations.createSeriesGroup( '5a2a307be93a2f00129ea035', { series: 'New', @@ -10027,13 +10027,13 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const updatedSeries = await facturapi.organizations.updateSeries( + const updatedSeries = await facturapi.organizations.updateSeriesGroup( '5a2a307be93a2f00129ea035', 'New', - [ - "next_folio" => 1, - "next_folio_test" => 1 - ] + { + next_folio: 1, + next_folio_test: 1 + } ); - lang: csharp label: C# @@ -10123,7 +10123,7 @@ paths: import Facturapi from 'facturapi' const facturapi = new Facturapi('sk_user_API_KEY'); - const deletedSeries = await facturapi.organizations.deleteSeries( + const deletedSeries = await facturapi.organizations.deleteSeriesGroup( '5a2a307be93a2f00129ea035', 'New' ); diff --git a/website/scripts/check-openapi.mjs b/website/scripts/check-openapi.mjs index 0e069326d..06556739b 100644 --- a/website/scripts/check-openapi.mjs +++ b/website/scripts/check-openapi.mjs @@ -6,6 +6,7 @@ import { createRequire } from "node:module"; import { execFileSync } from "node:child_process"; import * as yaml from "js-yaml"; import openapiTS, { astToString } from "openapi-typescript"; +import ts from "typescript"; const root = new URL("../", import.meta.url); const contracts = []; @@ -84,6 +85,11 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { walk(child, [...path, key]); } walk(spec); + assert.equal( + spec.components.schemas.SignedDownloadUrl.properties.url.format, + "uri", + "Download links must be declared as URI strings", + ); for (const invoiceType of spec.components.schemas.InvoiceCreateInput.oneOf) { assert.equal(invoiceType.oneOf.length, 2, "Expected emission and draft variants"); assert.deepEqual( @@ -103,6 +109,23 @@ for (const filename of ["openapi_v2.yaml", "openapi_v2.en.yaml"]) { `Duplicate operationId: ${operation.operationId}`, ); ids.add(operation.operationId); + for (const sample of operation["x-codeSamples"] || []) { + if (!["JavaScript", "TypeScript"].includes(sample.lang)) continue; + const result = ts.transpileModule(sample.source, { + compilerOptions: { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + }, + fileName: sample.lang === "JavaScript" ? "sample.js" : "sample.ts", + reportDiagnostics: true, + }); + assert.equal( + result.diagnostics.length, + 0, + `Invalid ${sample.lang} sample: ${operation.operationId}`, + ); + } + const params = [ ...(item.parameters || []), ...(operation.parameters || []), From 2c1330be7e7c093a2174221643dcd2be54b3495c Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 23:17:32 +0200 Subject: [PATCH 25/33] docs: describe incomplete customer input with edit links --- website/openapi_v2.en.yaml | 8 ++++++++ website/openapi_v2.yaml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index ed1cdf11c..96fd19f93 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -2204,6 +2204,7 @@ paths: will be valid for 7 days and can only be used once. Additionally, setting this parameter to `true` will skip the validation of the customer's fiscal data, allowing you to create customers with incomplete information. + With `true`, the request body follows `CustomerCreateWithEditLinkInput`; otherwise it follows `CustomerCreateInput`. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -16073,6 +16074,11 @@ components: type: string description: Default CFDI use for the customer. example: G01 + CustomerCreateWithEditLinkInput: + title: Customer with edit link + description: Customer information may be incomplete when createEditLink=true. Supplied fields must still have valid formats. + allOf: + - $ref: "#/components/schemas/CustomerProperties" CustomerCreateInput: title: Customer allOf: @@ -16084,6 +16090,8 @@ components: - tax_system - address properties: + legal_name: + $ref: "#/components/schemas/CustomerCommonProperties/properties/legal_name" address: allOf: - $ref: "#/components/schemas/CommonAddressProperties" diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 48c07c4e2..56ca02087 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -2176,6 +2176,7 @@ paths: válido por 7 días y sólo se podrá usar una vez. Además, pasar el valor `true` desactivará la validación de información fiscal con el SAT, permitiendo crear clientes con información incompleta. + Con `true`, el body sigue `CustomerCreateWithEditLinkInput`; en otro caso sigue `CustomerCreateInput`. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -16072,6 +16073,11 @@ components: type: string description: Uso de CFDI por defecto. example: G01 + CustomerCreateWithEditLinkInput: + title: Customer with edit link + description: La información del cliente puede estar incompleta cuando createEditLink=true. Los campos enviados deben conservar formatos válidos. + allOf: + - $ref: "#/components/schemas/CustomerProperties" CustomerCreateInput: title: Customer allOf: @@ -16083,6 +16089,8 @@ components: - tax_system - address properties: + legal_name: + $ref: "#/components/schemas/CustomerCommonProperties/properties/legal_name" address: allOf: - $ref: "#/components/schemas/CommonAddressProperties" From 8e7017193954e09101a3a09a62a72fc73382dc9f Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 23:34:06 +0200 Subject: [PATCH 26/33] docs: align conditional customer, cancellation and global invoice inputs --- website/openapi_v2.en.yaml | 291 ++++++++++++++++++++----- website/openapi_v2.yaml | 288 ++++++++++++++++++++---- website/test/openapi-types.fixture.txt | 35 +++ 3 files changed, 516 insertions(+), 98 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 96fd19f93..b31ba4f9b 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -3897,15 +3897,16 @@ paths: description: ID of the invoice to cancel - in: query name: motive - required: true + required: false schema: type: string enum: - - "01" - - "02" - - "03" - - "04" + - '01' + - '02' + - '03' + - '04' description: | + Required for issued documents; omit query parameters to delete a draft. Key representing the motive for the cancellation of the invoice. Possible values: @@ -3923,6 +3924,7 @@ paths: ID of the invoice that replaces the invoice being canceled. You can use either the ID assigned by Facturapi or the fiscal folio (UUID). + Required for motives 01 and 04. Draft deletion does not require query parameters. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -7455,10 +7457,10 @@ paths: schema: type: string enum: - - "01" - - "02" - - "03" - - "04" + - '01' + - '02' + - '03' + - '04' description: | Code representing the reason for the retention cancellation. Required for retentions that are not drafts. @@ -7474,7 +7476,7 @@ paths: description: | ID of the retention that replaces the one being canceled. You can use the Facturapi ID or the fiscal folio (UUID). - + Required for motives 01 and 04. Draft deletion does not require query parameters. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -16074,41 +16076,172 @@ components: type: string description: Default CFDI use for the customer. example: G01 + CancellationQueryInput: + description: Omit query parameters to delete a draft. Issued documents require a motive; motives 01 and 04 also require substitution. + anyOf: + - title: Replacement required + type: object + required: + - motive + - substitution + properties: + motive: + type: string + enum: + - '01' + - '04' + substitution: + type: string + description: Facturapi ID or UUID of the replacement document. + - title: Other cancellation motives + type: object + required: + - motive + properties: + motive: + type: string + enum: + - '02' + - '03' + substitution: + type: string + - title: Delete draft + type: object + properties: + motive: false + substitution: false CustomerCreateWithEditLinkInput: title: Customer with edit link description: Customer information may be incomplete when createEditLink=true. Supplied fields must still have valid formats. allOf: - $ref: "#/components/schemas/CustomerProperties" - CustomerCreateInput: - title: Customer + CustomerCreateCommonInput: + type: object + required: + - legal_name + properties: + legal_name: + $ref: '#/components/schemas/CustomerCommonProperties/properties/legal_name' + email: + $ref: '#/components/schemas/CustomerCommonProperties/properties/email' + phone: + $ref: '#/components/schemas/CustomerCommonProperties/properties/phone' + default_invoice_use: + $ref: '#/components/schemas/CustomerCommonProperties/properties/default_invoice_use' + CustomerNationalAddressInput: allOf: - - $ref: "#/components/schemas/CustomerCommonProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object required: - - legal_name - - tax_id - - tax_system - - address + - zip properties: - legal_name: - $ref: "#/components/schemas/CustomerCommonProperties/properties/legal_name" - address: + zip: + $ref: '#/components/schemas/CommonAddressProperties/properties/zip' + state: + type: string + country: + type: string + const: MEX + default: MEX + CustomerForeignAddressInput: + allOf: + - $ref: '#/components/schemas/CommonAddressProperties' + - type: object + required: + - country + properties: + country: + type: string + not: + const: MEX + minLength: 3 + maxLength: 3 + description: ISO 3166-1 alpha-3 country code other than MEX. Required to select foreign customer rules. + state: + type: string + CustomerNationalCreateInput: + title: Mexican customer + description: Country MEX, or omitted. Fiscal name, RFC, fiscal regime and postal code are required. Generic RFCs use CustomerGenericCreateInput. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - tax_id + - tax_system + - address + properties: + tax_id: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" - - type: object - description: Fiscal address. - required: - - zip - properties: - state: - type: string - description: If the country is Mexico ("MEX"), it contains the name of the State or Federative Entity. For foreigners, it contains the State code according to the standard [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2), which you can consult in our [State Catalog](https://dashboard.facturapi.io/catalogs/state). - example: Sonora - country: - type: string - description: Country code according to the standard [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3), from the [Country Catalog](https://dashboard.facturapi.io/catalogs/country). - example: MEX - default: MEX + - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_id' + not: + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_system' + address: + $ref: '#/components/schemas/CustomerNationalAddressInput' + CustomerForeignCreateInput: + title: Foreign customer + description: Requires fiscal name and an address with an explicit country other than MEX. Tax ID and postal code are optional; the fiscal regime defaults to 616. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - address + properties: + tax_id: + type: + - string + - 'null' + description: | + In Mexican clients, it contains the customer's RFC. For foreigners, it is optional and represents the tax identification number, that is, the equivalent to the RFC in the customer's country. + not: + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + type: + - string + - 'null' + enum: + - '616' + - null + - '' + default: '616' + description: Foreign customers use 616. Omission, null or an empty string use the default. + address: + $ref: '#/components/schemas/CustomerForeignAddressInput' + CustomerGenericCreateInput: + title: Generic RFC + description: Public general RFC XAXX010101000 or generic foreign RFC XEXX010101000. Fiscal name and RFC are required. The fiscal regime defaults to 616. If a Mexican address is supplied, a postal code is required. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - tax_id + properties: + tax_id: + type: string + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + type: string + enum: + - '616' + default: '616' + address: + anyOf: + - $ref: '#/components/schemas/CustomerNationalAddressInput' + - $ref: '#/components/schemas/CustomerForeignAddressInput' + CustomerCreateInput: + title: Customer + description: Required fields depend on country and RFC. Omitted country means Mexico. With createEditLink=true, use CustomerCreateWithEditLinkInput instead. + anyOf: + - $ref: '#/components/schemas/CustomerNationalCreateInput' + - $ref: '#/components/schemas/CustomerForeignCreateInput' + - $ref: '#/components/schemas/CustomerGenericCreateInput' LineItemProductInput: title: Product @@ -18478,14 +18611,64 @@ components: description: Payment conditions. Free text field usually used to specify payment terms, such as the due date. - $ref: "#/components/schemas/InvoiceableCommonInput" GlobalInvoiceInput: + description: Dates are optional when selecting a period. Explicit receipts require both from and to. Periodicity defaults to the organization configuration. + anyOf: + - title: Select by period + type: object + properties: + from: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' + to: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' + periodicity: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' + months: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' + folio_number: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' + series: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' + date: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' + payment_form: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' + receipts: false + limit_to_max_receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + - title: Select explicit receipts + type: object + required: + - receipts + - from + - to + properties: + from: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' + to: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' + periodicity: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' + months: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' + folio_number: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' + series: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' + date: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' + payment_form: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' + receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/receipts' + limit_to_max_receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + GlobalInvoiceInputProperties: type: object - required: - - periodicity properties: from: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-01" + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-01' description: | Initial date of the receipts that will be included in the global invoice. By default, this value is the start of the last period (day, week, @@ -18493,8 +18676,8 @@ components: in the receipts configuration of your organization. This value is required when the `receipts` field is sent. to: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-31" + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-31' description: | End date of the receipts that will be included in the global invoice. By default, this value is the end of the last period (day, week, @@ -18502,18 +18685,26 @@ components: in the receipts configuration of your organization. This value is required when the `receipts` field is sent. periodicity: type: string - # default: Propiedad `periodicity` de la configuración de recibos de la organización. enum: - day - week - fortnight - month - two_months - description: "Periodicity that corresponds to the range of dates used.\nIf you omit the `from` and `to` fields, the default dates will depend\non the value of `periodicity`.\n\nIf omitted, the organization’s receipt periodicity setting is used." + description: |- + Periodicity that corresponds to the range of dates used. + If you omit the `from` and `to` fields, the default dates will depend + on the value of `periodicity`. + + If omitted, the organization’s receipt periodicity setting is used. months: type: string - description: "Key representing the month or bimester of the invoice. Consult\nthe possible values in the [Months and Bimesters catalog](#meses-y-bimestres).\n\nIf omitted, the month or two-month period is determined from the start date and periodicity." - example: "01" + description: |- + Key representing the month or bimester of the invoice. Consult + the possible values in the [Months and Bimesters catalog](#meses-y-bimestres). + + If omitted, the month or two-month period is determined from the start date and periodicity. + example: '01' folio_number: type: integer description: | @@ -18523,17 +18714,17 @@ components: type: string maxLength: 25 description: Series. Alphanumeric characters designated by the company for internal control and without fiscal validity. - example: "F" + example: F date: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-01" - description: "Invoice issuance date. If omitted, the end date (`to`) is used, capped at the current date and time." + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-01' + description: Invoice issuance date. If omitted, the end date (`to`) is used, capped at the current date and time. payment_form: type: string minLength: 2 maxLength: 2 - example: "02" + example: '02' description: | Payment form code according to the [Payment Form catalog](#forma-de-pago). diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 56ca02087..c917ca039 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -3867,15 +3867,16 @@ paths: description: ID de la factura a cancelar - in: query name: motive - required: true + required: false schema: type: string enum: - - "01" - - "02" - - "03" - - "04" + - '01' + - '02' + - '03' + - '04' description: | + Requerido para documentos emitidos; omite los parámetros para eliminar un borrador. Clave que representa el motivo de la cancelación de la factura. - `01`: **Comprobante emitido con errores con relación**. Cuando la @@ -3897,6 +3898,7 @@ paths: ID de la factura que sustituye a la factura que se está cancelando. Puedes usar el ID de Facturapi o el folio fiscal (UUID). + Requerido para los motivos 01 y 04. Eliminar un borrador no requiere parámetros de consulta. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -7414,10 +7416,10 @@ paths: schema: type: string enum: - - "01" - - "02" - - "03" - - "04" + - '01' + - '02' + - '03' + - '04' description: | Clave que representa el motivo de la cancelación de la retención. Requerido para retenciones que no son borrador. @@ -7439,6 +7441,7 @@ paths: description: | ID de la retención que sustituye a la retención que se está cancelando Puedes usar el ID de Facturapi o el folio fiscal (UUID). + Requerido para los motivos 01 y 04. Eliminar un borrador no requiere parámetros de consulta. security: - "SecretLiveKey": [] - "SecretTestKey": [] @@ -16073,41 +16076,171 @@ components: type: string description: Uso de CFDI por defecto. example: G01 + CancellationQueryInput: + description: Omite los parámetros para eliminar un borrador. Los documentos emitidos requieren motivo; los motivos 01 y 04 también requieren substitution. + anyOf: + - title: Sustitución requerida + type: object + required: + - motive + - substitution + properties: + motive: + type: string + enum: + - '01' + - '04' + substitution: + type: string + description: ID de Facturapi o UUID del documento sustituto. + - title: Otros motivos de cancelación + type: object + required: + - motive + properties: + motive: + type: string + enum: + - '02' + - '03' + substitution: + type: string + - title: Eliminar borrador + type: object + properties: + motive: false + substitution: false CustomerCreateWithEditLinkInput: title: Customer with edit link description: La información del cliente puede estar incompleta cuando createEditLink=true. Los campos enviados deben conservar formatos válidos. allOf: - $ref: "#/components/schemas/CustomerProperties" - CustomerCreateInput: - title: Customer + CustomerCreateCommonInput: + type: object + required: + - legal_name + properties: + legal_name: + $ref: '#/components/schemas/CustomerCommonProperties/properties/legal_name' + email: + $ref: '#/components/schemas/CustomerCommonProperties/properties/email' + phone: + $ref: '#/components/schemas/CustomerCommonProperties/properties/phone' + default_invoice_use: + $ref: '#/components/schemas/CustomerCommonProperties/properties/default_invoice_use' + CustomerNationalAddressInput: allOf: - - $ref: "#/components/schemas/CustomerCommonProperties" + - $ref: '#/components/schemas/CommonAddressProperties' - type: object required: - - legal_name - - tax_id - - tax_system - - address + - zip properties: - legal_name: - $ref: "#/components/schemas/CustomerCommonProperties/properties/legal_name" - address: + zip: + $ref: '#/components/schemas/CommonAddressProperties/properties/zip' + state: + type: string + country: + type: string + const: MEX + default: MEX + CustomerForeignAddressInput: + allOf: + - $ref: '#/components/schemas/CommonAddressProperties' + - type: object + required: + - country + properties: + country: + type: string + not: + const: MEX + minLength: 3 + maxLength: 3 + description: Código ISO 3166-1 alpha-3 distinto de MEX. Es necesario para aplicar las reglas de cliente extranjero. + state: + type: string + CustomerNationalCreateInput: + title: Cliente nacional + description: País MEX, u omitido. Requiere razón social, RFC, régimen fiscal y código postal. Los RFC genéricos usan CustomerGenericCreateInput. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - tax_id + - tax_system + - address + properties: + tax_id: allOf: - - $ref: "#/components/schemas/CommonAddressProperties" - - type: object - description: Domicilio fiscal. - required: - - zip - properties: - state: - type: string - description: Si el país es México ("MEX"), contiene el nombre del Estado o Entidad Federativa. Para extranjeros contiene el código de Estado de acuerdo al estándar [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2), que puedes consultar en nuestro [Catálogo de Estados](https://dashboard.facturapi.io/catalogs/state). - example: Sonora - country: - type: string - description: Código de país acorde al estándar [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3), del [Catálogo de Países](https://dashboard.facturapi.io/catalogs/country). - example: MEX - default: MEX + - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_id' + not: + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_system' + address: + $ref: '#/components/schemas/CustomerNationalAddressInput' + CustomerForeignCreateInput: + title: Cliente extranjero + description: Requiere razón social y domicilio con un país explícito distinto de MEX. El identificador fiscal y el código postal son opcionales; el régimen fiscal predeterminado es 616. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - address + properties: + tax_id: + type: + - string + - 'null' + description: En clientes de México contiene el RFC del cliente. Para extranjeros es opcional y representa el número de registro de identificación tributaria, es decir, el equivalente al RFC en el país del cliente. + not: + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + type: + - string + - 'null' + enum: + - '616' + - null + - '' + default: '616' + description: Los clientes extranjeros usan 616. Omitirlo, enviar null o una cadena vacía usa el valor predeterminado. + address: + $ref: '#/components/schemas/CustomerForeignAddressInput' + CustomerGenericCreateInput: + title: RFC genérico + description: RFC de público en general XAXX010101000 o RFC genérico extranjero XEXX010101000. Requiere razón social y RFC. El régimen fiscal predeterminado es 616. Si se envía domicilio mexicano, requiere código postal. + allOf: + - $ref: '#/components/schemas/CustomerCreateCommonInput' + - type: object + required: + - tax_id + properties: + tax_id: + type: string + enum: + - XAXX010101000 + - XEXX010101000 + tax_system: + type: string + enum: + - '616' + default: '616' + address: + anyOf: + - $ref: '#/components/schemas/CustomerNationalAddressInput' + - $ref: '#/components/schemas/CustomerForeignAddressInput' + CustomerCreateInput: + title: Customer + description: Los campos requeridos dependen del país y del RFC. Omitir el país equivale a México. Con createEditLink=true se usa CustomerCreateWithEditLinkInput. + anyOf: + - $ref: '#/components/schemas/CustomerNationalCreateInput' + - $ref: '#/components/schemas/CustomerForeignCreateInput' + - $ref: '#/components/schemas/CustomerGenericCreateInput' LineItemProductInput: title: Product @@ -18400,14 +18533,64 @@ components: description: Condiciones de pago - $ref: "#/components/schemas/InvoiceableCommonInput" GlobalInvoiceInput: + description: Las fechas son opcionales al seleccionar por periodo. Al enviar receipts se requieren from y to. La periodicidad predeterminada viene de la configuración de la organización. + anyOf: + - title: Seleccionar por periodo + type: object + properties: + from: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' + to: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' + periodicity: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' + months: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' + folio_number: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' + series: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' + date: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' + payment_form: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' + receipts: false + limit_to_max_receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + - title: Seleccionar recibos explícitos + type: object + required: + - receipts + - from + - to + properties: + from: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' + to: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' + periodicity: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' + months: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' + folio_number: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' + series: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' + date: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' + payment_form: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' + receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/receipts' + limit_to_max_receipts: + $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + GlobalInvoiceInputProperties: type: object - required: - - periodicity properties: from: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-01" + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-01' description: | Fecha inicial de los recibos que se incluirán en la factura global. Por default, este valor es el inicio del último periodo (día, semana, @@ -18415,8 +18598,8 @@ components: en la configuración de recibos de tu organización. Este valor es requerido cuando se envíe el campo `receipts`. to: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-31" + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-31' description: | Fecha final de los recibos que se incluirán en la factura global. Por default, este valor es el fin del último periodo (día, semana, @@ -18430,11 +18613,20 @@ components: - fortnight - month - two_months - description: "Periodicidad que corresponde al rango de fechas utilizado.\nSi omites los campos `from` y `to`, las fechas que se asignarán por\ndefault dependerán del valor de `periodicity`.\n\nSi se omite, se utiliza la periodicidad configurada en los recibos de la organización." + description: |- + Periodicidad que corresponde al rango de fechas utilizado. + Si omites los campos `from` y `to`, las fechas que se asignarán por + default dependerán del valor de `periodicity`. + + Si se omite, se utiliza la periodicidad configurada en los recibos de la organización. months: type: string - description: "Clave que representa el mes o bimestre de la factura. Consulta\nlos posibles valores en el [catálogo de Meses y Bimestres](#meses-y-bimestres).\n\nSi se omite, el mes o bimestre se determina a partir de la fecha inicial y la periodicidad." - example: "01" + description: |- + Clave que representa el mes o bimestre de la factura. Consulta + los posibles valores en el [catálogo de Meses y Bimestres](#meses-y-bimestres). + + Si se omite, el mes o bimestre se determina a partir de la fecha inicial y la periodicidad. + example: '01' folio_number: type: integer description: | @@ -18446,16 +18638,16 @@ components: description: Serie. Caracteres designados por la empresa para control interno y sin validez fiscal. date: allOf: - - $ref: "#/components/schemas/DateOrDateTime" - example: "2022-01-01" - description: "Fecha de emisión de la factura. Si se omite, se utiliza la fecha final (`to`), limitada a la fecha y hora actuales." + - $ref: '#/components/schemas/DateOrDateTime' + example: '2022-01-01' + description: Fecha de emisión de la factura. Si se omite, se utiliza la fecha final (`to`), limitada a la fecha y hora actuales. payment_form: type: string minLength: 2 maxLength: 2 - example: "02" + example: '02' description: | - description: Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). Si se incluye, los recibos se agruparán y se crearán la factura global por la forma de pago. + Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). Si se incluye, los recibos se agruparán y se crearán la factura global por la forma de pago. receipts: type: array description: | diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index da942aabc..e217ad65f 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -160,3 +160,38 @@ const summaryRelatedDocument: components["schemas"]["PaymentInput"]["related_doc // @ts-expect-error a numeric catalog code is not a valid string code const numericPaymentTaxability: typeof paymentTaxability = 1; void [summaryRelatedDocument, numericPaymentTaxability]; + +// Customer creation requirements depend on country and generic RFCs. +const nationalCustomer: components['schemas']['CustomerCreateInput'] = { + legal_name: 'Cliente nacional', tax_id: 'ABC101010111', tax_system: '601', address: { zip: '83200' }, +}; +const foreignCustomer: components['schemas']['CustomerCreateInput'] = { + legal_name: 'Foreign customer', address: { country: 'USA' }, +}; +const genericCustomer: components['schemas']['CustomerCreateInput'] = { + legal_name: 'PUBLICO EN GENERAL', tax_id: 'XAXX010101000', +}; +// @ts-expect-error country is needed to select foreign rules +const foreignWithoutCountry: components['schemas']['CustomerCreateInput'] = { legal_name: 'Foreign customer', address: {} }; +// @ts-expect-error national customers require an RFC +const nationalWithoutRfc: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_system: '601', address: { zip: '83200' } }; +// @ts-expect-error national customers require a tax regime +const nationalWithoutRegime: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_id: 'ABC101010111', address: { zip: '83200' } }; +// @ts-expect-error explicit national address needs a postal code +const nationalWithoutZip: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_id: 'ABC101010111', tax_system: '601', address: {} }; +// @ts-expect-error foreign customers use the regime 616 +const foreignWithWrongRegime: components['schemas']['CustomerForeignCreateInput'] = { legal_name: 'Foreign', tax_system: '601', address: { country: 'USA' } }; +// @ts-expect-error generic RFCs use 616 +const genericWithWrongRegime: components['schemas']['CustomerGenericCreateInput'] = { legal_name: 'Cliente', tax_id: 'XAXX010101000', tax_system: '601' }; +const defaultGlobal: components['schemas']['GlobalInvoiceInput'] = {}; +const explicitGlobal: components['schemas']['GlobalInvoiceInput'] = { receipts: ['rec_ejemplo'], from: '2026-01-01', to: '2026-01-31' }; +// @ts-expect-error explicit receipts require both dates +const explicitGlobalWithoutDates: components['schemas']['GlobalInvoiceInput'] = { receipts: ['rec_ejemplo'] }; +const cancelReplacement: components['schemas']['CancellationQueryInput'] = { motive: '04', substitution: 'inv_ejemplo' }; +const cancelWithoutReplacement: components['schemas']['CancellationQueryInput'] = { motive: '02' }; +const deleteDraft: components['schemas']['CancellationQueryInput'] = {}; +// @ts-expect-error replacement motives require the substitution +const cancelMissingReplacement: components['schemas']['CancellationQueryInput'] = { motive: '01' }; +// @ts-expect-error a replacement without a motive is not a cancellation request +const cancelMissingMotive: components['schemas']['CancellationQueryInput'] = { substitution: 'inv_ejemplo' }; +void [nationalCustomer, foreignCustomer, genericCustomer, foreignWithoutCountry, nationalWithoutRfc, nationalWithoutRegime, nationalWithoutZip, foreignWithWrongRegime, genericWithWrongRegime, defaultGlobal, explicitGlobal, explicitGlobalWithoutDates, cancelReplacement, cancelWithoutReplacement, deleteDraft, cancelMissingReplacement, cancelMissingMotive]; From d36d6e386e04f380ce54db91eb4e73debbba375b Mon Sep 17 00:00:00 2001 From: javorosas Date: Thu, 1 Oct 2026 23:40:33 +0200 Subject: [PATCH 27/33] docs: preserve required values and field descriptions in input variants --- website/openapi_v2.en.yaml | 87 ++++++++++---------------- website/openapi_v2.yaml | 85 +++++++++---------------- website/test/openapi-types.fixture.txt | 10 +++ 3 files changed, 74 insertions(+), 108 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index b31ba4f9b..b70ac2b6d 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16121,28 +16121,36 @@ components: - legal_name properties: legal_name: - $ref: '#/components/schemas/CustomerCommonProperties/properties/legal_name' + type: string + description: | + Legal name or business name of the customer. *without* the corporate regime (e.g.: S.A. de C.V.). + example: Dunder Mifflin email: - $ref: '#/components/schemas/CustomerCommonProperties/properties/email' + type: string + format: email + description: Email address to which to send the generated invoices. + example: email@example.com phone: - $ref: '#/components/schemas/CustomerCommonProperties/properties/phone' + type: string + description: Customer's phone number. + example: '6474010101' default_invoice_use: - $ref: '#/components/schemas/CustomerCommonProperties/properties/default_invoice_use' + type: string + description: Default CFDI use for the customer. + example: G01 CustomerNationalAddressInput: allOf: - $ref: '#/components/schemas/CommonAddressProperties' - type: object - required: - - zip properties: - zip: - $ref: '#/components/schemas/CommonAddressProperties/properties/zip' state: type: string country: type: string const: MEX default: MEX + required: + - zip CustomerForeignAddressInput: allOf: - $ref: '#/components/schemas/CommonAddressProperties' @@ -16171,14 +16179,21 @@ components: - address properties: tax_id: - allOf: - - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_id' + type: string + example: ABC101010111 + description: | + In Mexican clients, it contains the customer's RFC. For foreigners, it is optional and represents the tax identification number, that is, the equivalent to the RFC in the customer's country. not: enum: - XAXX010101000 - XEXX010101000 tax_system: - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_system' + type: string + example: '601' + maxLength: 3 + minLength: 3 + description: | + Required for national clients. Key of the customer's tax regime, from the [Tax Regime Catalog](#tax-regime). address: $ref: '#/components/schemas/CustomerNationalAddressInput' CustomerForeignCreateInput: @@ -18614,54 +18629,18 @@ components: description: Dates are optional when selecting a period. Explicit receipts require both from and to. Periodicity defaults to the organization configuration. anyOf: - title: Select by period - type: object - properties: - from: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' - to: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' - periodicity: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' - months: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' - folio_number: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' - series: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' - date: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' - payment_form: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' - receipts: false - limit_to_max_receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + allOf: + - $ref: '#/components/schemas/GlobalInvoiceInputProperties' + - type: object + properties: + receipts: false - title: Select explicit receipts - type: object required: - receipts - from - to - properties: - from: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' - to: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' - periodicity: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' - months: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' - folio_number: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' - series: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' - date: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' - payment_form: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' - receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/receipts' - limit_to_max_receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + allOf: + - $ref: '#/components/schemas/GlobalInvoiceInputProperties' GlobalInvoiceInputProperties: type: object properties: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index c917ca039..f366074af 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16121,28 +16121,36 @@ components: - legal_name properties: legal_name: - $ref: '#/components/schemas/CustomerCommonProperties/properties/legal_name' + type: string + description: | + Nombre Fiscal o Razón Social del cliente. *sin* el régimen societario (ej.: S.A. de C.V.). + example: Dunder Mifflin email: - $ref: '#/components/schemas/CustomerCommonProperties/properties/email' + type: string + format: email + description: Dirección de correo electrónico al cual enviar las facturas generadas. + example: email@example.com phone: - $ref: '#/components/schemas/CustomerCommonProperties/properties/phone' + type: string + description: Teléfono del cliente. + example: '6474010101' default_invoice_use: - $ref: '#/components/schemas/CustomerCommonProperties/properties/default_invoice_use' + type: string + description: Uso de CFDI por defecto. + example: G01 CustomerNationalAddressInput: allOf: - $ref: '#/components/schemas/CommonAddressProperties' - type: object - required: - - zip properties: - zip: - $ref: '#/components/schemas/CommonAddressProperties/properties/zip' state: type: string country: type: string const: MEX default: MEX + required: + - zip CustomerForeignAddressInput: allOf: - $ref: '#/components/schemas/CommonAddressProperties' @@ -16171,14 +16179,19 @@ components: - address properties: tax_id: - allOf: - - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_id' + type: string + example: ABC101010111 + description: En clientes de México contiene el RFC del cliente. Para extranjeros es opcional y representa el número de registro de identificación tributaria, es decir, el equivalente al RFC en el país del cliente. not: enum: - XAXX010101000 - XEXX010101000 tax_system: - $ref: '#/components/schemas/CustomerCommonProperties/properties/tax_system' + type: string + example: '601' + maxLength: 3 + minLength: 3 + description: Requerido para clientes nacionales. Clave del régimen fiscal del cliente, del catálogo de [Regímenes Fiscales](#r%C3%A9gimen-fiscal). address: $ref: '#/components/schemas/CustomerNationalAddressInput' CustomerForeignCreateInput: @@ -18536,54 +18549,18 @@ components: description: Las fechas son opcionales al seleccionar por periodo. Al enviar receipts se requieren from y to. La periodicidad predeterminada viene de la configuración de la organización. anyOf: - title: Seleccionar por periodo - type: object - properties: - from: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' - to: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' - periodicity: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' - months: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' - folio_number: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' - series: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' - date: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' - payment_form: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' - receipts: false - limit_to_max_receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + allOf: + - $ref: '#/components/schemas/GlobalInvoiceInputProperties' + - type: object + properties: + receipts: false - title: Seleccionar recibos explícitos - type: object required: - receipts - from - to - properties: - from: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/from' - to: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/to' - periodicity: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/periodicity' - months: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/months' - folio_number: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/folio_number' - series: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/series' - date: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/date' - payment_form: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/payment_form' - receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/receipts' - limit_to_max_receipts: - $ref: '#/components/schemas/GlobalInvoiceInputProperties/properties/limit_to_max_receipts' + allOf: + - $ref: '#/components/schemas/GlobalInvoiceInputProperties' GlobalInvoiceInputProperties: type: object properties: diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index e217ad65f..7c1c551d8 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -195,3 +195,13 @@ const cancelMissingReplacement: components['schemas']['CancellationQueryInput'] // @ts-expect-error a replacement without a motive is not a cancellation request const cancelMissingMotive: components['schemas']['CancellationQueryInput'] = { substitution: 'inv_ejemplo' }; void [nationalCustomer, foreignCustomer, genericCustomer, foreignWithoutCountry, nationalWithoutRfc, nationalWithoutRegime, nationalWithoutZip, foreignWithWrongRegime, genericWithWrongRegime, defaultGlobal, explicitGlobal, explicitGlobalWithoutDates, cancelReplacement, cancelWithoutReplacement, deleteDraft, cancelMissingReplacement, cancelMissingMotive]; +// Required fields cannot be supplied as undefined. +// @ts-expect-error undefined fiscal name is not a customer name +const undefinedCustomerName: components['schemas']['CustomerCreateInput'] = { legal_name: undefined, address: { country: 'USA' } }; +// @ts-expect-error undefined tax regime does not complete a national customer +const undefinedNationalRegime: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_id: 'ABC101010111', tax_system: undefined, address: { zip: '83200' } }; +// @ts-expect-error undefined zip does not complete a national address +const undefinedNationalZip: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_id: 'ABC101010111', tax_system: '601', address: { zip: undefined } }; +// @ts-expect-error explicit receipt selection needs actual dates +const undefinedGlobalDates: components['schemas']['GlobalInvoiceInput'] = { receipts: ['rec_ejemplo'], from: undefined, to: undefined }; +void [undefinedCustomerName, undefinedNationalRegime, undefinedNationalZip, undefinedGlobalDates]; From 469af3ee19397d89a63769b7a9a29a2735cab268 Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 00:59:46 +0200 Subject: [PATCH 28/33] docs: correct nullable customer fields and edit link expiry --- website/openapi_v2.en.yaml | 37 ++++++++++++++++++-------- website/openapi_v2.yaml | 37 ++++++++++++++++++-------- website/test/openapi-types.fixture.txt | 13 +++++++++ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index b70ac2b6d..f096a1e84 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -2201,7 +2201,7 @@ paths: description: | If set to `true`, the response will include a link you can share with the customer to allow them to edit their information. This link will be available from the `edit_link` field, - will be valid for 7 days and can only be used once. + will be valid for 3 days and can only be used once. Additionally, setting this parameter to `true` will skip the validation of the customer's fiscal data, allowing you to create customers with incomplete information. With `true`, the request body follows `CustomerCreateWithEditLinkInput`; otherwise it follows `CustomerCreateInput`. @@ -2490,7 +2490,7 @@ paths: description: | If set to `true`, the response will include a link you can share with the customer to allow them to edit their information. This link will be available from the `edit_link` field, - will be valid for 7 days and can only be used once. + will be valid for 3 days and can only be used once. Setting this parameter to `true` while editing a customer will **not** skip the validation of the customer's fiscal data. requestBody: @@ -2587,7 +2587,7 @@ paths: description: | Sends a link for the customer to edit their fiscal information. - This link will be available in the `edit_link` field, valid for 7 days and can only be used once. + This link will be available in the `edit_link` field, valid for 3 days and can only be used once. x-codeSamples: - lang: Bash label: cURL @@ -16003,7 +16003,9 @@ components: description: Link to a hosted page where the customer can edit their information once. example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: string + type: + - string + - 'null' format: date-time description: Expiration date of the edit link. example: '2022-12-31T23:59:59Z' @@ -16052,13 +16054,17 @@ components: Legal name or business name of the customer. *without* the corporate regime (e.g.: S.A. de C.V.). example: Dunder Mifflin tax_id: - type: string + type: + - string + - 'null' example: ABC101010111 description: | In Mexican clients, it contains the customer's RFC. For foreigners, it is optional and represents the tax identification number, that is, the equivalent to the RFC in the customer's country. tax_system: - type: string - example: "601" + type: + - string + - 'null' + example: '601' maxLength: 3 minLength: 3 description: | @@ -16069,9 +16075,11 @@ components: description: Email address to which to send the generated invoices. example: email@example.com phone: - type: string + type: + - string + - 'null' description: Customer's phone number. - example: "6474010101" + example: '6474010101' default_invoice_use: type: string description: Default CFDI use for the customer. @@ -16114,7 +16122,12 @@ components: title: Customer with edit link description: Customer information may be incomplete when createEditLink=true. Supplied fields must still have valid formats. allOf: - - $ref: "#/components/schemas/CustomerProperties" + - $ref: '#/components/schemas/CustomerProperties' + - type: object + properties: + tax_system: + type: string + description: If supplied, use a valid fiscal regime. Omission permits incomplete fiscal information. CustomerCreateCommonInput: type: object required: @@ -16131,7 +16144,9 @@ components: description: Email address to which to send the generated invoices. example: email@example.com phone: - type: string + type: + - string + - 'null' description: Customer's phone number. example: '6474010101' default_invoice_use: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index f366074af..4afcbbd30 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -2173,7 +2173,7 @@ paths: description: | Si pasas el valor `true`, se generará un enlace para que el cliente pueda editar su información fiscal. Este enlace estará disponible en el campo "edit_link", será - válido por 7 días y sólo se podrá usar una vez. + válido por 3 días y sólo se podrá usar una vez. Además, pasar el valor `true` desactivará la validación de información fiscal con el SAT, permitiendo crear clientes con información incompleta. Con `true`, el body sigue `CustomerCreateWithEditLinkInput`; en otro caso sigue `CustomerCreateInput`. @@ -2462,7 +2462,7 @@ paths: description: | Si pasas el valor `true`, se generará un enlace para que el cliente pueda editar su información fiscal. Este enlace estará disponible en el campo "edit_link", será - válido por 7 días y sólo se podrá usar una vez. Pasar el valor `true` al editar + válido por 3 días y sólo se podrá usar una vez. Pasar el valor `true` al editar **no** desactivará la validación de información fiscal con el SAT. requestBody: $ref: "#/components/requestBodies/CustomerEdit" @@ -2558,7 +2558,7 @@ paths: description: | Envía un enlace para que el cliente pueda editar su información fiscal. - Este enlace estará disponible en el campo `edit_link`, será válido por 7 días y sólo se podrá usar una vez. + Este enlace estará disponible en el campo `edit_link`, será válido por 3 días y sólo se podrá usar una vez. x-codeSamples: - lang: Bash label: cURL @@ -16014,7 +16014,9 @@ components: Ejemplo: https://auto.facturapi.io/tax-info/abcdWXYZ1234 example: https://auto.facturapi.io/tax-info/abcdWXYZ1234 edit_link_expires_at: - type: string + type: + - string + - 'null' format: date-time description: | Fecha de expiración del enlace de edición. @@ -16054,12 +16056,16 @@ components: Nombre Fiscal o Razón Social del cliente. *sin* el régimen societario (ej.: S.A. de C.V.). example: Dunder Mifflin tax_id: - type: string + type: + - string + - 'null' example: ABC101010111 description: En clientes de México contiene el RFC del cliente. Para extranjeros es opcional y representa el número de registro de identificación tributaria, es decir, el equivalente al RFC en el país del cliente. tax_system: - type: string - example: "601" + type: + - string + - 'null' + example: '601' maxLength: 3 minLength: 3 description: Requerido para clientes nacionales. Clave del régimen fiscal del cliente, del catálogo de [Regímenes Fiscales](#r%C3%A9gimen-fiscal). @@ -16069,9 +16075,11 @@ components: description: Dirección de correo electrónico al cual enviar las facturas generadas. example: email@example.com phone: - type: string + type: + - string + - 'null' description: Teléfono del cliente. - example: "6474010101" + example: '6474010101' default_invoice_use: type: string description: Uso de CFDI por defecto. @@ -16114,7 +16122,12 @@ components: title: Customer with edit link description: La información del cliente puede estar incompleta cuando createEditLink=true. Los campos enviados deben conservar formatos válidos. allOf: - - $ref: "#/components/schemas/CustomerProperties" + - $ref: '#/components/schemas/CustomerProperties' + - type: object + properties: + tax_system: + type: string + description: Si se envía, debe ser un régimen fiscal válido. Omitirlo permite guardar información fiscal incompleta. CustomerCreateCommonInput: type: object required: @@ -16131,7 +16144,9 @@ components: description: Dirección de correo electrónico al cual enviar las facturas generadas. example: email@example.com phone: - type: string + type: + - string + - 'null' description: Teléfono del cliente. example: '6474010101' default_invoice_use: diff --git a/website/test/openapi-types.fixture.txt b/website/test/openapi-types.fixture.txt index 7c1c551d8..427bc6d87 100644 --- a/website/test/openapi-types.fixture.txt +++ b/website/test/openapi-types.fixture.txt @@ -205,3 +205,16 @@ const undefinedNationalZip: components['schemas']['CustomerNationalCreateInput'] // @ts-expect-error explicit receipt selection needs actual dates const undefinedGlobalDates: components['schemas']['GlobalInvoiceInput'] = { receipts: ['rec_ejemplo'], from: undefined, to: undefined }; void [undefinedCustomerName, undefinedNationalRegime, undefinedNationalZip, undefinedGlobalDates]; +// Incomplete and foreign customer responses may have null fiscal fields. +declare const incompleteCustomerResponse: components['schemas']['Customer']; +const responseTaxId: string | null | undefined = incompleteCustomerResponse.tax_id; +const responseTaxSystem: string | null | undefined = incompleteCustomerResponse.tax_system; +const incompleteCustomerWithEmptyRfc: components['schemas']['CustomerCreateWithEditLinkInput'] = { tax_id: null }; +// @ts-expect-error edit-link creation still validates a supplied fiscal regime +const incompleteCustomerWithNullRegime: components['schemas']['CustomerCreateWithEditLinkInput'] = { tax_system: null }; +// @ts-expect-error national customer creation requires a non-null fiscal regime +const nationalCustomerWithNullRegime: components['schemas']['CustomerNationalCreateInput'] = { legal_name: 'Cliente', tax_id: 'ABC101010111', tax_system: null, address: { zip: '83200' } }; +void [responseTaxId, responseTaxSystem, incompleteCustomerWithEmptyRfc, incompleteCustomerWithNullRegime, nationalCustomerWithNullRegime]; +const expiredCustomerEditLink: components['schemas']['CustomerNonEditableProperties'] = { edit_link: null, edit_link_expires_at: null }; +const clearedCustomerPhone: components['schemas']['CustomerProperties'] = { phone: null }; +void [expiredCustomerEditLink, clearedCustomerPhone]; From 8674c3aaec61fc778e0b8c56802e441db86a8100 Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 12:29:42 +0200 Subject: [PATCH 29/33] docs: correct partial product updates and SDK examples --- website/openapi_v2.en.yaml | 159 ++++++++++++++++++++++--------------- website/openapi_v2.yaml | 159 ++++++++++++++++++++++--------------- 2 files changed, 194 insertions(+), 124 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index f096a1e84..b70aa0cd2 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -3063,10 +3063,7 @@ paths: const product = await facturapi.products.update( '590e22c26d04f840aa8438b2', { - email: 'jdoe@example.com', - address: { - street: 'Santa Monica Ave.' - } + price: 456.70 } ); - lang: csharp @@ -3427,16 +3424,16 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // All invoices from the organization - const invoiceSearch = await facturapi.invoices.list(); + const invoiceSearch1 = await facturapi.invoices.list(); // All invoices issued to a certain customer - const invoiceSearch = await facturapi.invoices.list({ + const invoiceSearch2 = await facturapi.invoices.list({ customer: '590ce6c56d04f840aa8438af' }); // Page 3 of the search results for free text // of invoices issued to a certain customer between 2017 and 2019 - const invoiceSearch = await facturapi.invoices.list({ + const invoiceSearch3 = await facturapi.invoices.list({ q: 'Aspiradora Robot', customer: '590ce6c56d04f840aa8438af', date: { @@ -4379,7 +4376,7 @@ paths: - lang: JavaScript label: Node.js source: | - const Facturapi = require('facturapi'); + import Facturapi from 'facturapi'; const facturapi = new Facturapi('sk_live_API_KEY'); const pdfStream = await facturapi.invoices.previewPdf({ @@ -4405,9 +4402,11 @@ paths: series: 'F' }); // Save the PDF to a file - const fs = require('fs'); + import fs from 'node:fs'; const file = fs.createWriteStream('/route/to/save/invoice.pdf'); - pdfStream.pipe(file); + if ('pipe' in pdfStream) { + pdfStream.pipe(file); + } - lang: csharp label: C# source: | @@ -4524,6 +4523,9 @@ paths: - lang: JavaScript label: Node.js source: | + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.invoices.previewPdfUrl({ customer: 'cus_123', items: [{ product: 'prod_123' }], @@ -4582,17 +4584,23 @@ paths: // Download PDF and XML compressed in a ZIP file const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./factura.zip'); - zipStream.pipe(zipFile); + if ('pipe' in zipStream) { + zipStream.pipe(zipFile); + } // Download only the PDF const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./factura.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } // Download only the XML const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./factura.xml'); - xmlStream.pipe(xmlFile); + if ('pipe' in xmlStream) { + xmlStream.pipe(xmlFile); + } - lang: csharp label: C# source: | @@ -5399,7 +5407,9 @@ paths: const zipStream = await facturapi.invoices.downloadZipRequest( '66b0f0000000000000000000' ); - zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + if ('pipe' in zipStream) { + zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + } - lang: csharp label: C# source: | @@ -5670,11 +5680,11 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // All receipts of the organization - const receiptSearch = await facturapi.receipts.list(); + const receiptSearch1 = await facturapi.receipts.list(); // Page 3 of search results for free text search // of receipts created between 2017 and 2019 - const receiptSearch = await facturapi.receipts.list({ + const receiptSearch2 = await facturapi.receipts.list({ q: 'Aspiradora Robot', date: { gte: new Date('2017-01-01T00:00:00.000Z'), @@ -6375,7 +6385,9 @@ paths: }); const file = fs.createWriteStream('to_invoice_preview.pdf'); - pdfStream.pipe(file); + if ('pipe' in pdfStream) { + pdfStream.pipe(file); + } - lang: csharp label: C# source: | @@ -6464,6 +6476,9 @@ paths: - lang: JavaScript label: Node.js source: | + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.receipts.previewToInvoicePdfUrl({ keys: ['ticket_1001', 'ticket_1002'], customer: 'cus_123', @@ -6516,11 +6531,10 @@ paths: -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "from": "2021-01-01T05:00:00.000Z", - "to": "2021-01-31T04:59:59.999Z", + "from": "2021-01-01T00:00:00.000Z", + "to": "2021-01-31T23:59:59.999Z", "periodicity": "month", "months": "01", - "year": 2021, "folio_number": 1234, "series": "G", "limit_to_max_receipts": true @@ -6532,11 +6546,10 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); const invoice = await facturapi.receipts.createGlobalInvoice({ - from: '2020-12-01T05:00:00.000Z', - to: '2020-12-31T04:59:59.999Z', + from: '2021-01-01T00:00:00.000Z', + to: '2021-01-31T23:59:59.999Z', periodicity: 'month', months: '01', - year: 2021, folio_number: 1234, series: 'G', limit_to_max_receipts: true @@ -6547,11 +6560,10 @@ paths: var facturapi = new FacturapiClient("sk_test_API_KEY"); var invoice = await facturapi.Receipt.CreateGlobalInvoiceAsync(new Dictionary { - ["from"] = "2020-12-01T05:00:00.000Z", - ["to"] = "2020-12-31T04:59:59.999Z", + ["from"] = "2021-01-01T00:00:00.000Z", + ["to"] = "2021-01-31T23:59:59.999Z", ["periodicity"] = "month", ["months"] = "01", - ["year"] = 2021, ["folio_number"] = 1234, ["series"] = "G" }); @@ -6566,8 +6578,10 @@ paths: var invoice = facturapi.receipts().createGlobalInvoice( Map.of( - "month", 5, - "year", 2024 + "from", "2021-01-01T00:00:00.000Z", + "to", "2021-01-31T23:59:59.999Z", + "periodicity", "month", + "months", "01" ) ); - lang: PHP @@ -6575,11 +6589,10 @@ paths: $facturapi = new Facturapi("sk_test_API_KEY"); $invoice = $facturapi->Receipts->createGlobalInvoice([ - "from" => "2020-12-01T05:00:00.000Z", - "to" => "2020-12-31T04:59:59.999Z", + "from" => "2021-01-01T00:00:00.000Z", + "to" => "2021-01-31T23:59:59.999Z", "periodicity" => "month", "months" => "01", - "year" => 2021, "folio_number" => 1234, "series" => "G" ]); @@ -6631,7 +6644,9 @@ paths: // Download the electronic receipt in PDF format const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./recibo.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } - lang: csharp label: C# source: | @@ -6932,7 +6947,8 @@ paths: "imp_retenidos": [ { "monto_ret": 40, - "base_ret": 250 + "base_ret": 250, + "tipo_pago_ret": "04" } ] } @@ -6956,7 +6972,8 @@ paths: imp_retenidos: [ { monto_ret: 40, - base_ret: 250 + base_ret: 250, + tipo_pago_ret: "04" } ] } @@ -6983,9 +7000,9 @@ paths: { new Dictionary { - ["] ["monto_ret"] = 40, - ["base_ret"] = 250 + ["base_ret"] = 250, + ["tipo_pago_ret"] = "04" } } } @@ -7001,16 +7018,19 @@ paths: var retention = facturapi.retentions().create( Map.of( - "receiver", Map.of( - "name", "Cliente ejemplo" - ), - "items", List.of( - Map.of( - "quantity", 1, - "product", "prod_123" - ) - ) - )); + "customer", "58e93bd8e86eb318b0197456", + "cve_retenc", "26", + "periodo", Map.of("mes_ini", 1, "mes_fin", 12, "ejerc", 2020), + "totales", Map.of( + "monto_tot_operacion", 244.654321, + "monto_tot_exent", 145.123456, + "imp_retenidos", List.of(Map.of( + "monto_ret", 40, + "base_ret", 250, + "tipo_pago_ret", "04" + )) + ) + )); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); @@ -7029,7 +7049,8 @@ paths: [ "impuesto" => "ISR", "monto_ret" => 40, - "base_ret" => 250 + "base_ret" => 250, + "tipo_pago_ret" => "04" ] ] ] @@ -7090,16 +7111,16 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // All retentions of the organization - const retentionSearch = await facturapi.retentions.list(); + const retentionSearch1 = await facturapi.retentions.list(); // All retentions issued for a certain customer - const retentionSearch = await facturapi.retentions.list({ + const retentionSearch2 = await facturapi.retentions.list({ customer: '590ce6c56d04f840aa8438af' }); // Page 3 of search results for free text search // of retentions issued between 2017 and 2019 - const retentionSearch = await facturapi.retentions.list({ + const retentionSearch3 = await facturapi.retentions.list({ q: 'John Doe', date: { gte: new Date('2017-01-01T00:00:00.000Z'), @@ -7662,17 +7683,23 @@ paths: // Download PDF and XML compressed in a ZIP file const zipStream = await facturapi.retentions.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./retencion.zip'); - zipStream.pipe(zipFile); + if ('pipe' in zipStream) { + zipStream.pipe(zipFile); + } // Download only the PDF const pdfStream = await facturapi.retentions.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./retencion.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } // Download only the XML const xmlStream = await facturapi.retentions.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./retencion.xml'); - xmlStream.pipe(xmlFile); + if ('pipe' in xmlStream) { + xmlStream.pipe(xmlFile); + } - lang: csharp label: C# source: | @@ -11823,13 +11850,18 @@ paths: - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' + import Facturapi from 'facturapi'; const facturapi = new Facturapi('sk_test_API_KEY'); - const customer = await facturapi.webhooks.validateSignature({ - secret: "wh_sec...", - payload: "Object Response", - signature: "Signature_FROM_HEADER" - }); + + // Pass the original, unparsed body and the signature from the Facturapi-Signature header. + export async function verifyWebhook(rawBody, signature, secret) { + const event = await facturapi.webhooks.validateSignature({ + secret, + signature, + payload: rawBody + }); + return event; + } - lang: csharp label: C# source: | @@ -12478,7 +12510,7 @@ components: application/json: schema: allOf: - - $ref: "#/components/schemas/ProductProperties" + - $ref: "#/components/schemas/ProductEditableProperties" InvoiceCreate: required: true content: @@ -16380,9 +16412,12 @@ components: items: $ref: "#/components/schemas/Product" ProductProperties: + allOf: + - $ref: "#/components/schemas/ProductEditableProperties" + - type: object + required: [description, product_key, price] + ProductEditableProperties: type: object - required: - ["description","product_key","price"] properties: description: type: string diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 4afcbbd30..b094aa500 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -3034,10 +3034,7 @@ paths: const product = await facturapi.products.update( '590e22c26d04f840aa8438b2', { - email: 'jdoe@example.com', - address: { - street: 'Santa Monica Ave.' - } + price: 456.70 } ); - lang: csharp @@ -3397,16 +3394,16 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Todas las facturas de la organización - const invoiceSearch = await facturapi.invoices.list(); + const invoiceSearch1 = await facturapi.invoices.list(); // Todas las facturas emitidas para cierto cliente - const invoiceSearch = await facturapi.invoices.list({ + const invoiceSearch2 = await facturapi.invoices.list({ customer: '590ce6c56d04f840aa8438af' }); // Página 3 de los resultados de búsqueda de texto libre // de facturas emitidas por cierto cliente entre 2017 y 2019 - const invoiceSearch = await facturapi.invoices.list({ + const invoiceSearch3 = await facturapi.invoices.list({ q: 'Aspiradora Robot', customer: '590ce6c56d04f840aa8438af', date: { @@ -4352,7 +4349,7 @@ paths: - lang: JavaScript label: Node.js source: | - const Facturapi = require('facturapi'); + import Facturapi from 'facturapi'; const facturapi = new Facturapi('sk_test_API_KEY'); const pdfStream = await facturapi.invoices.previewPdf({ customer: { @@ -4377,9 +4374,11 @@ paths: series: 'F' }); // Save PDF stream to a file - const fs = require('fs'); + import fs from 'node:fs'; const file = fs.createWriteStream('invoice_preview.pdf'); - pdfStream.pipe(file); + if ('pipe' in pdfStream) { + pdfStream.pipe(file); + } - lang: csharp label: C# source: | @@ -4496,6 +4495,9 @@ paths: - lang: JavaScript label: Node.js source: | + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.invoices.previewPdfUrl({ customer: 'cus_123', items: [{ product: 'prod_123' }], @@ -4554,17 +4556,23 @@ paths: // Descargar PDF y XML comprimidos en archivo ZIP const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./factura.zip'); - zipStream.pipe(zipFile); + if ('pipe' in zipStream) { + zipStream.pipe(zipFile); + } // Descargar sólo el PDF const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./factura.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } // Descargar sólo el XML const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./factura.xml'); - xmlStream.pipe(xmlFile); + if ('pipe' in xmlStream) { + xmlStream.pipe(xmlFile); + } - lang: csharp label: C# source: | @@ -5362,7 +5370,9 @@ paths: const zipStream = await facturapi.invoices.downloadZipRequest( '66b0f0000000000000000000' ); - zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + if ('pipe' in zipStream) { + zipStream.pipe(fs.createWriteStream('./2025-03.zip')); + } - lang: csharp label: C# source: | @@ -5634,11 +5644,11 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Todos los recibos de la organización - const receiptSearch = await facturapi.receipts.list(); + const receiptSearch1 = await facturapi.receipts.list(); // Página 3 de los resultados de búsqueda de texto libre // de recibos creados entre 2017 y 2019 - const receiptSearch = await facturapi.receipts.list({ + const receiptSearch2 = await facturapi.receipts.list({ q: 'Aspiradora Robot', date: { gte: new Date('2017-01-01T00:00:00.000Z'), @@ -6338,7 +6348,9 @@ paths: }); const file = fs.createWriteStream('to_invoice_preview.pdf'); - pdfStream.pipe(file); + if ('pipe' in pdfStream) { + pdfStream.pipe(file); + } - lang: csharp label: C# source: | @@ -6427,6 +6439,9 @@ paths: - lang: JavaScript label: Node.js source: | + import Facturapi from 'facturapi'; + const facturapi = new Facturapi('sk_test_API_KEY'); + const download = await facturapi.receipts.previewToInvoicePdfUrl({ keys: ['ticket_1001', 'ticket_1002'], customer: 'cus_123', @@ -6479,11 +6494,10 @@ paths: -H "Authorization: Bearer sk_test_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "from": "2021-01-01T05:00:00.000Z", - "to": "2021-01-31T04:59:59.999Z", + "from": "2021-01-01T00:00:00.000Z", + "to": "2021-01-31T23:59:59.999Z", "periodicity": "month", "months": "01", - "year": 2021, "folio_number": 1234, "series": "G", "limit_to_max_receipts": true @@ -6495,11 +6509,10 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); const invoice = await facturapi.receipts.createGlobalInvoice({ - from: '2020-12-01T05:00:00.000Z', - to: '2020-12-31T04:59:59.999Z', + from: '2021-01-01T00:00:00.000Z', + to: '2021-01-31T23:59:59.999Z', periodicity: 'month', months: '01', - year: 2021, folio_number: 1234, series: 'G', limit_to_max_receipts: true @@ -6510,11 +6523,10 @@ paths: var facturapi = new FacturapiClient("sk_test_API_KEY"); var invoice = await facturapi.Receipt.CreateGlobalInvoiceAsync(new Dictionary { - ["from"] = "2020-12-01T05:00:00.000Z", - ["to"] = "2020-12-31T04:59:59.999Z", + ["from"] = "2021-01-01T00:00:00.000Z", + ["to"] = "2021-01-31T23:59:59.999Z", ["periodicity"] = "month", ["months"] = "01", - ["year"] = 2021, ["folio_number"] = 1234, ["series"] = "G" }); @@ -6529,8 +6541,10 @@ paths: var invoice = facturapi.receipts().createGlobalInvoice( Map.of( - "month", 5, - "year", 2024 + "from", "2021-01-01T00:00:00.000Z", + "to", "2021-01-31T23:59:59.999Z", + "periodicity", "month", + "months", "01" ) ); - lang: PHP @@ -6538,11 +6552,10 @@ paths: $facturapi = new Facturapi("sk_test_API_KEY"); $invoice = $facturapi->Receipts->createGlobalInvoice([ - "from" => "2020-12-01T05:00:00.000Z", - "to" => "2020-12-31T04:59:59.999Z", + "from" => "2021-01-01T00:00:00.000Z", + "to" => "2021-01-31T23:59:59.999Z", "periodicity" => "month", "months" => "01", - "year" => 2021, "folio_number" => 1234, "series" => "G" ]); @@ -6594,7 +6607,9 @@ paths: // Descargar recibo en formato PDF const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./recibo.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } - lang: csharp label: C# source: | @@ -6893,7 +6908,8 @@ paths: "imp_retenidos": [ { "monto_ret": 40, - "base_ret": 250 + "base_ret": 250, + "tipo_pago_ret": "04" } ] } @@ -6917,7 +6933,8 @@ paths: imp_retenidos: [ { monto_ret: 40, - base_ret: 250 + base_ret: 250, + tipo_pago_ret: "04" } ] } @@ -6944,9 +6961,9 @@ paths: { new Dictionary { - ["] ["monto_ret"] = 40, - ["base_ret"] = 250 + ["base_ret"] = 250, + ["tipo_pago_ret"] = "04" } } } @@ -6962,16 +6979,19 @@ paths: var retention = facturapi.retentions().create( Map.of( - "receiver", Map.of( - "name", "Cliente ejemplo" - ), - "items", List.of( - Map.of( - "quantity", 1, - "product", "prod_123" - ) - ) - )); + "customer", "58e93bd8e86eb318b0197456", + "cve_retenc", "26", + "periodo", Map.of("mes_ini", 1, "mes_fin", 12, "ejerc", 2020), + "totales", Map.of( + "monto_tot_operacion", 244.654321, + "monto_tot_exent", 145.123456, + "imp_retenidos", List.of(Map.of( + "monto_ret", 40, + "base_ret", 250, + "tipo_pago_ret", "04" + )) + ) + )); - lang: PHP source: | $facturapi = new Facturapi("sk_test_API_KEY"); @@ -6990,7 +7010,8 @@ paths: [ "impuesto" => "ISR", "monto_ret" => 40, - "base_ret" => 250 + "base_ret" => 250, + "tipo_pago_ret" => "04" ] ] ] @@ -7050,16 +7071,16 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Todas las retenciones de la organización - const retentionSearch = await facturapi.retentions.list(); + const retentionSearch1 = await facturapi.retentions.list(); // Todas las retenciones emitidas para cierto cliente - const retentionSearch = await facturapi.retentions.list({ + const retentionSearch2 = await facturapi.retentions.list({ customer: '590ce6c56d04f840aa8438af' }); // Página 3 de los resultados de búsqueda de texto libre // de retenciones emitidas entre 2017 y 2019 - const retentionSearch = await facturapi.retentions.list({ + const retentionSearch3 = await facturapi.retentions.list({ q: 'John Doe', date: { gte: new Date('2017-01-01T00:00:00.000Z'), @@ -7626,17 +7647,23 @@ paths: // Descargar PDF y XML comprimidos en archivo ZIP const zipStream = await facturapi.retentions.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./retencion.zip'); - zipStream.pipe(zipFile); + if ('pipe' in zipStream) { + zipStream.pipe(zipFile); + } // Descargar sólo el PDF const pdfStream = await facturapi.retentions.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./retencion.pdf'); - pdfStream.pipe(pdfFile); + if ('pipe' in pdfStream) { + pdfStream.pipe(pdfFile); + } // Descargar sólo el XML const xmlStream = await facturapi.retentions.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./retencion.xml'); - xmlStream.pipe(xmlFile); + if ('pipe' in xmlStream) { + xmlStream.pipe(xmlFile); + } - lang: csharp label: C# source: | @@ -11774,13 +11801,18 @@ paths: - lang: JavaScript label: Node.js source: | - import Facturapi from 'facturapi' + import Facturapi from 'facturapi'; const facturapi = new Facturapi('sk_test_API_KEY'); - const customer = await facturapi.webhooks.validateSignature({ - secret: "wh_sec...", - payload: "Object Response", - signature: "Signature_FROM_HEADER" - }); + + // Pasa el body original sin parsearlo y la firma del encabezado Facturapi-Signature. + export async function verifyWebhook(rawBody, signature, secret) { + const event = await facturapi.webhooks.validateSignature({ + secret, + signature, + payload: rawBody + }); + return event; + } - lang: csharp label: C# source: | @@ -12429,7 +12461,7 @@ components: application/json: schema: allOf: - - $ref: "#/components/schemas/ProductProperties" + - $ref: "#/components/schemas/ProductEditableProperties" InvoiceCreate: required: true content: @@ -16375,9 +16407,12 @@ components: items: $ref: "#/components/schemas/Product" ProductProperties: + allOf: + - $ref: "#/components/schemas/ProductEditableProperties" + - type: object + required: [description, product_key, price] + ProductEditableProperties: type: object - required: - ["description","product_key","price"] properties: description: type: string From 8d2ac5f35cb03b63c1e21da37aa355f3e6797454 Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 12:30:16 +0200 Subject: [PATCH 30/33] docs: narrow binary downloads in Node examples --- website/docs/guides/invoices/cancelaciones.mdx | 8 ++++++-- website/docs/quickstart.mdx | 8 ++++++-- .../current/guides/invoices/cancelaciones.mdx | 8 ++++++-- .../docusaurus-plugin-content-docs/current/quickstart.mdx | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/website/docs/guides/invoices/cancelaciones.mdx b/website/docs/guides/invoices/cancelaciones.mdx index 856aa1a68..2a7db9016 100644 --- a/website/docs/guides/invoices/cancelaciones.mdx +++ b/website/docs/guides/invoices/cancelaciones.mdx @@ -188,10 +188,14 @@ import fs from 'node:fs'; const facturapi = new Facturapi('sk_test_API_KEY'); const xmlStream = await facturapi.invoices.downloadCancellationReceiptXml('58e93bd8e86eb318b019743d'); -xmlStream.pipe(fs.createWriteStream('acuse_cancelacion.xml')); +if ('pipe' in xmlStream) { + xmlStream.pipe(fs.createWriteStream('acuse_cancelacion.xml')); +} const pdfStream = await facturapi.invoices.downloadCancellationReceiptPdf('58e93bd8e86eb318b019743d'); -pdfStream.pipe(fs.createWriteStream('acuse_cancelacion.pdf')); +if ('pipe' in pdfStream) { + pdfStream.pipe(fs.createWriteStream('acuse_cancelacion.pdf')); +} ``` diff --git a/website/docs/quickstart.mdx b/website/docs/quickstart.mdx index 314520577..bb21d920b 100644 --- a/website/docs/quickstart.mdx +++ b/website/docs/quickstart.mdx @@ -373,9 +373,13 @@ import fs from 'fs'; const zipStream = await facturapi.invoices.downloadZip(invoice.id); // Guarda la descarga en un archivo const file = fs.createWriteStream('./factura.zip'); -zipStream.pipe(file); +if ('pipe' in zipStream) { + zipStream.pipe(file); +} // O envíalo como respuesta a tu cliente (en ExpressJS) -zipStream.pipe(res); +if ('pipe' in zipStream) { + zipStream.pipe(res); +} ``` diff --git a/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx b/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx index d279076ea..27ddfcbeb 100644 --- a/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx +++ b/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx @@ -174,10 +174,14 @@ import fs from 'node:fs'; const facturapi = new Facturapi('sk_test_API_KEY'); const xmlStream = await facturapi.invoices.downloadCancellationReceiptXml('58e93bd8e86eb318b019743d'); -xmlStream.pipe(fs.createWriteStream('cancellation_receipt.xml')); +if ('pipe' in xmlStream) { + xmlStream.pipe(fs.createWriteStream('cancellation_receipt.xml')); +} const pdfStream = await facturapi.invoices.downloadCancellationReceiptPdf('58e93bd8e86eb318b019743d'); -pdfStream.pipe(fs.createWriteStream('cancellation_receipt.pdf')); +if ('pipe' in pdfStream) { + pdfStream.pipe(fs.createWriteStream('cancellation_receipt.pdf')); +} ``` diff --git a/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx b/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx index 70aea933f..bcdc34ef6 100644 --- a/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx +++ b/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx @@ -332,9 +332,13 @@ import fs from 'fs'; const zipStream = await facturapi.invoices.downloadZip(invoice.id); // Save the downloaded file to disk const file = fs.createWriteStream('./factura.zip'); -zipStream.pipe(file); +if ('pipe' in zipStream) { + zipStream.pipe(file); +} // Or send it as a response to your customer (ExpressJS syntax) -zipStream.pipe(res); +if ('pipe' in zipStream) { + zipStream.pipe(res); +} ``` From 60c067a7c6d398679e4e22dd5994759a27a4f2b8 Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 12:33:37 +0200 Subject: [PATCH 31/33] docs: make binary and webhook examples type safe --- .../docs/guides/invoices/cancelaciones.mdx | 4 +-- website/docs/quickstart.mdx | 4 +-- .../current/guides/invoices/cancelaciones.mdx | 4 +-- .../current/quickstart.mdx | 4 +-- website/openapi_v2.en.yaml | 25 +++++++++++-------- website/openapi_v2.yaml | 25 +++++++++++-------- 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/website/docs/guides/invoices/cancelaciones.mdx b/website/docs/guides/invoices/cancelaciones.mdx index 2a7db9016..5da3717bb 100644 --- a/website/docs/guides/invoices/cancelaciones.mdx +++ b/website/docs/guides/invoices/cancelaciones.mdx @@ -188,12 +188,12 @@ import fs from 'node:fs'; const facturapi = new Facturapi('sk_test_API_KEY'); const xmlStream = await facturapi.invoices.downloadCancellationReceiptXml('58e93bd8e86eb318b019743d'); -if ('pipe' in xmlStream) { +if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(fs.createWriteStream('acuse_cancelacion.xml')); } const pdfStream = await facturapi.invoices.downloadCancellationReceiptPdf('58e93bd8e86eb318b019743d'); -if ('pipe' in pdfStream) { +if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(fs.createWriteStream('acuse_cancelacion.pdf')); } ``` diff --git a/website/docs/quickstart.mdx b/website/docs/quickstart.mdx index bb21d920b..4771488ec 100644 --- a/website/docs/quickstart.mdx +++ b/website/docs/quickstart.mdx @@ -373,11 +373,11 @@ import fs from 'fs'; const zipStream = await facturapi.invoices.downloadZip(invoice.id); // Guarda la descarga en un archivo const file = fs.createWriteStream('./factura.zip'); -if ('pipe' in zipStream) { +if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(file); } // O envíalo como respuesta a tu cliente (en ExpressJS) -if ('pipe' in zipStream) { +if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(res); } ``` diff --git a/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx b/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx index 27ddfcbeb..53cf66e3f 100644 --- a/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx +++ b/website/i18n/en/docusaurus-plugin-content-docs/current/guides/invoices/cancelaciones.mdx @@ -174,12 +174,12 @@ import fs from 'node:fs'; const facturapi = new Facturapi('sk_test_API_KEY'); const xmlStream = await facturapi.invoices.downloadCancellationReceiptXml('58e93bd8e86eb318b019743d'); -if ('pipe' in xmlStream) { +if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(fs.createWriteStream('cancellation_receipt.xml')); } const pdfStream = await facturapi.invoices.downloadCancellationReceiptPdf('58e93bd8e86eb318b019743d'); -if ('pipe' in pdfStream) { +if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(fs.createWriteStream('cancellation_receipt.pdf')); } ``` diff --git a/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx b/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx index bcdc34ef6..4a05096b6 100644 --- a/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx +++ b/website/i18n/en/docusaurus-plugin-content-docs/current/quickstart.mdx @@ -332,11 +332,11 @@ import fs from 'fs'; const zipStream = await facturapi.invoices.downloadZip(invoice.id); // Save the downloaded file to disk const file = fs.createWriteStream('./factura.zip'); -if ('pipe' in zipStream) { +if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(file); } // Or send it as a response to your customer (ExpressJS syntax) -if ('pipe' in zipStream) { +if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(res); } ``` diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index b70aa0cd2..9452e391d 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -4404,7 +4404,7 @@ paths: // Save the PDF to a file import fs from 'node:fs'; const file = fs.createWriteStream('/route/to/save/invoice.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(file); } - lang: csharp @@ -4584,21 +4584,21 @@ paths: // Download PDF and XML compressed in a ZIP file const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./factura.zip'); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(zipFile); } // Download only the PDF const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./factura.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } // Download only the XML const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./factura.xml'); - if ('pipe' in xmlStream) { + if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(xmlFile); } - lang: csharp @@ -5407,7 +5407,7 @@ paths: const zipStream = await facturapi.invoices.downloadZipRequest( '66b0f0000000000000000000' ); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(fs.createWriteStream('./2025-03.zip')); } - lang: csharp @@ -6385,7 +6385,7 @@ paths: }); const file = fs.createWriteStream('to_invoice_preview.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(file); } - lang: csharp @@ -6644,7 +6644,7 @@ paths: // Download the electronic receipt in PDF format const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./recibo.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } - lang: csharp @@ -7683,21 +7683,21 @@ paths: // Download PDF and XML compressed in a ZIP file const zipStream = await facturapi.retentions.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./retencion.zip'); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(zipFile); } // Download only the PDF const pdfStream = await facturapi.retentions.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./retencion.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } // Download only the XML const xmlStream = await facturapi.retentions.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./retencion.xml'); - if ('pipe' in xmlStream) { + if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(xmlFile); } - lang: csharp @@ -11854,6 +11854,11 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Pass the original, unparsed body and the signature from the Facturapi-Signature header. + /** + * @param {string | Uint8Array | ArrayBuffer} rawBody + * @param {string} signature + * @param {string} secret + */ export async function verifyWebhook(rawBody, signature, secret) { const event = await facturapi.webhooks.validateSignature({ secret, diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index b094aa500..d2331ae41 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -4376,7 +4376,7 @@ paths: // Save PDF stream to a file import fs from 'node:fs'; const file = fs.createWriteStream('invoice_preview.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(file); } - lang: csharp @@ -4556,21 +4556,21 @@ paths: // Descargar PDF y XML comprimidos en archivo ZIP const zipStream = await facturapi.invoices.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./factura.zip'); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(zipFile); } // Descargar sólo el PDF const pdfStream = await facturapi.invoices.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./factura.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } // Descargar sólo el XML const xmlStream = await facturapi.invoices.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./factura.xml'); - if ('pipe' in xmlStream) { + if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(xmlFile); } - lang: csharp @@ -5370,7 +5370,7 @@ paths: const zipStream = await facturapi.invoices.downloadZipRequest( '66b0f0000000000000000000' ); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(fs.createWriteStream('./2025-03.zip')); } - lang: csharp @@ -6348,7 +6348,7 @@ paths: }); const file = fs.createWriteStream('to_invoice_preview.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(file); } - lang: csharp @@ -6607,7 +6607,7 @@ paths: // Descargar recibo en formato PDF const pdfStream = await facturapi.receipts.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./recibo.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } - lang: csharp @@ -7647,21 +7647,21 @@ paths: // Descargar PDF y XML comprimidos en archivo ZIP const zipStream = await facturapi.retentions.downloadZip('58e93bd8e86eb318b019743d'); const zipFile = fs.createWriteStream('./retencion.zip'); - if ('pipe' in zipStream) { + if ('pipe' in zipStream && typeof zipStream.pipe === 'function') { zipStream.pipe(zipFile); } // Descargar sólo el PDF const pdfStream = await facturapi.retentions.downloadPdf('58e93bd8e86eb318b019743d'); const pdfFile = fs.createWriteStream('./retencion.pdf'); - if ('pipe' in pdfStream) { + if ('pipe' in pdfStream && typeof pdfStream.pipe === 'function') { pdfStream.pipe(pdfFile); } // Descargar sólo el XML const xmlStream = await facturapi.retentions.downloadXml('58e93bd8e86eb318b019743d'); const xmlFile = fs.createWriteStream('./retencion.xml'); - if ('pipe' in xmlStream) { + if ('pipe' in xmlStream && typeof xmlStream.pipe === 'function') { xmlStream.pipe(xmlFile); } - lang: csharp @@ -11805,6 +11805,11 @@ paths: const facturapi = new Facturapi('sk_test_API_KEY'); // Pasa el body original sin parsearlo y la firma del encabezado Facturapi-Signature. + /** + * @param {string | Uint8Array | ArrayBuffer} rawBody + * @param {string} signature + * @param {string} secret + */ export async function verifyWebhook(rawBody, signature, secret) { const event = await facturapi.webhooks.validateSignature({ secret, From 1badb5a6f3606ff1e1aa044c578ff84687167cfc Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 12:35:50 +0200 Subject: [PATCH 32/33] docs: preserve required product creation fields --- website/openapi_v2.en.yaml | 3 +-- website/openapi_v2.yaml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index 9452e391d..e8165aa34 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16419,8 +16419,7 @@ components: ProductProperties: allOf: - $ref: "#/components/schemas/ProductEditableProperties" - - type: object - required: [description, product_key, price] + required: [description, product_key, price] ProductEditableProperties: type: object properties: diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index d2331ae41..7f81756fe 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16414,8 +16414,7 @@ components: ProductProperties: allOf: - $ref: "#/components/schemas/ProductEditableProperties" - - type: object - required: [description, product_key, price] + required: [description, product_key, price] ProductEditableProperties: type: object properties: From fa739524c4d72c4aae9a1253188f166c228a9db0 Mon Sep 17 00:00:00 2001 From: javorosas Date: Fri, 2 Oct 2026 12:38:44 +0200 Subject: [PATCH 33/33] docs: allow unvalidated customer timestamps to be null --- website/openapi_v2.en.yaml | 2 +- website/openapi_v2.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/openapi_v2.en.yaml b/website/openapi_v2.en.yaml index e8165aa34..bccc5a428 100644 --- a/website/openapi_v2.en.yaml +++ b/website/openapi_v2.en.yaml @@ -16047,7 +16047,7 @@ components: description: Expiration date of the edit link. example: '2022-12-31T23:59:59Z' sat_validated_at: - type: string + type: [string, "null"] format: date-time description: Date when the customer's tax information was validated by the SAT. example: '2022-12-31T23:59:59Z' diff --git a/website/openapi_v2.yaml b/website/openapi_v2.yaml index 7f81756fe..1351317e5 100644 --- a/website/openapi_v2.yaml +++ b/website/openapi_v2.yaml @@ -16059,7 +16059,7 @@ components: Fecha de expiración del enlace de edición. example: '2022-12-31T23:59:59Z' sat_validated_at: - type: string + type: [string, "null"] format: date-time description: | Fecha en la que la información fiscal fue validado por el SAT.