From 4f25aa5fd27b3e10567675641154872fc5f7874f Mon Sep 17 00:00:00 2001 From: "raul@facturapi.io" Date: Thu, 5 Nov 2026 11:22:43 -0600 Subject: [PATCH 1/2] feat(organizations): add manifiesto ZIP download URL --- CHANGELOG.md | 1 + openapi/source.json | 2 +- scripts/sdk/resources.json | 6 +++ src/generated/dates.ts | 1 + src/generated/input.ts | 51 +++++++++++++++++++++ src/generated/output.ts | 51 +++++++++++++++++++++ src/resources/organizations.ts | 23 ++++++++++ test/node/signed-download-urls.node.test.ts | 29 ++++++++++++ 8 files changed, 163 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 061d410..76f4047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added +- `organizations.downloadManifiestoZipUrl(id)` to obtain a temporary URL for downloading the signed Carta Manifiesto ZIP associated with the organization's certificate RFC. - Autocompletion and editor documentation for request fields, method arguments, and responses across SDK operations. - More precise input types for CFDI variants, drafts, structured complements, and customer creation. Related fields are checked by TypeScript in supported cases, helping catch incomplete or incompatible inputs before sending a request. - Invoice responses distinguish draft, pending, failed, and stamped states; checking the status exposes the guaranteed UUID and stamp fields. diff --git a/openapi/source.json b/openapi/source.json index 75aa6e2..1d6a842 100644 --- a/openapi/source.json +++ b/openapi/source.json @@ -1,5 +1,5 @@ { "repository": "FacturAPI/facturapi-docs", - "revision": "6e89062add592bad94b0afd1086627b0d9c0d2cf", + "revision": "6a81247386e6e9036c618e99c2e91c2b7e74ab77", "path": "website/openapi_v2.yaml" } diff --git a/scripts/sdk/resources.json b/scripts/sdk/resources.json index 3697750..a08b6ef 100644 --- a/scripts/sdk/resources.json +++ b/scripts/sdk/resources.json @@ -211,6 +211,12 @@ ] }, "deleteCertificate": "deleteOrganizationCertificate", + "downloadManifiestoZipUrl": { + "operation": "getOrganizationManifiestoDownloadUrl", + "argumentNames": { + "organization_id": "id" + } + }, "del": "deleteOrganization", "getTestApiKey": "getTestApiKey", "renewTestApiKey": "renewTestApiKey", diff --git a/src/generated/dates.ts b/src/generated/dates.ts index 47a6499..123ff8b 100644 --- a/src/generated/dates.ts +++ b/src/generated/dates.ts @@ -761,6 +761,7 @@ export const operationDatePlans = { meOrganization: 122, getOrganization: 122, deleteOrganization: 122, + getOrganizationManifiestoDownloadUrl: 37, editOrganizationLegal: 122, uploadOrganizationCertificate: 122, deleteOrganizationCertificate: 127, diff --git a/src/generated/input.ts b/src/generated/input.ts index 9d64911..45c9b8b 100644 --- a/src/generated/input.ts +++ b/src/generated/input.ts @@ -1362,6 +1362,28 @@ export interface paths { patch?: never; trace?: never; }; + '/organizations/{organization_id}/manifiesto/download-url': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Obtener enlace de descarga de Carta Manifiesto + * Devuelve un enlace temporal para descargar en ZIP la Carta Manifiesto firmada que corresponde al RFC del CSD cargado en la organización. + * + * La organización debe tener un CSD cargado y debe existir una Carta Manifiesto firmada para el RFC extraído de ese certificado. El enlace da acceso al archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. + */ + get: operations['getOrganizationManifiestoDownloadUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/organizations/{organization_id}/legal': { parameters: { query?: never; @@ -10148,6 +10170,35 @@ export interface operations { 500: components['responses']['UnexpectedError']; }; }; + getOrganizationManifiestoDownloadUrl: { + parameters: { + query?: never; + header?: never; + path: { + /** ID de la organización. También puedes usar `me` con una Secret Key de la organización. */ + organization_id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Objeto con una URL temporal para descargar la Carta Manifiesto en ZIP, su fecha de expiración, el tipo de contenido y el nombre del archivo. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SignedDownloadUrl']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 404: components['responses']['NotFound']; + 409: components['responses']['Conflict']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; editOrganizationLegal: { parameters: { query?: never; diff --git a/src/generated/output.ts b/src/generated/output.ts index 6fec991..93e8a47 100644 --- a/src/generated/output.ts +++ b/src/generated/output.ts @@ -1374,6 +1374,28 @@ export interface paths { patch?: never; trace?: never; }; + '/organizations/{organization_id}/manifiesto/download-url': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Obtener enlace de descarga de Carta Manifiesto + * Devuelve un enlace temporal para descargar en ZIP la Carta Manifiesto firmada que corresponde al RFC del CSD cargado en la organización. + * + * La organización debe tener un CSD cargado y debe existir una Carta Manifiesto firmada para el RFC extraído de ese certificado. El enlace da acceso al archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. + */ + get: operations['getOrganizationManifiestoDownloadUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/organizations/{organization_id}/legal': { parameters: { query?: never; @@ -10164,6 +10186,35 @@ export interface operations { 500: components['responses']['UnexpectedError']; }; }; + getOrganizationManifiestoDownloadUrl: { + parameters: { + query?: never; + header?: never; + path: { + /** ID de la organización. También puedes usar `me` con una Secret Key de la organización. */ + organization_id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Objeto con una URL temporal para descargar la Carta Manifiesto en ZIP, su fecha de expiración, el tipo de contenido y el nombre del archivo. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SignedDownloadUrl']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 404: components['responses']['NotFound']; + 409: components['responses']['Conflict']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; editOrganizationLegal: { parameters: { query?: never; diff --git a/src/resources/organizations.ts b/src/resources/organizations.ts index b421953..8965664 100644 --- a/src/resources/organizations.ts +++ b/src/resources/organizations.ts @@ -335,6 +335,29 @@ export default class Organizations { }); } + /** + * Obtener enlace de descarga de Carta Manifiesto + * + * Devuelve un enlace temporal para descargar en ZIP la Carta Manifiesto firmada que corresponde al RFC del CSD cargado en la organización. + * + * La organización debe tener un CSD cargado y debe existir una Carta Manifiesto firmada para el RFC extraído de ese certificado. El enlace da acceso al archivo mientras siga vigente: trátalo como una credencial y no lo almacenes. + * + * @param id - ID de la organización. También puedes usar `me` con una Secret Key de la organización. + * @returns Objeto SignedDownloadUrl con url, expires_at, content_type y filename. + */ + downloadManifiestoZipUrl( + id: string, + ): Promise> { + if (!id) return Promise.reject(new Error('id is required')); + + return this.client.request< + OperationResponse<'getOrganizationManifiestoDownloadUrl'> + >(`/organizations/${encodeURIComponent(id)}/manifiesto/download-url`, { + method: 'GET', + datePlan: operationDatePlans.getOrganizationManifiestoDownloadUrl, + }); + } + /** * Eliminar organización * diff --git a/test/node/signed-download-urls.node.test.ts b/test/node/signed-download-urls.node.test.ts index 30f945a..8a80228 100644 --- a/test/node/signed-download-urls.node.test.ts +++ b/test/node/signed-download-urls.node.test.ts @@ -116,6 +116,32 @@ describe('signed download URLs', () => { expect(result.filename).toBe('receipt.pdf'); }); + it('requests a signed URL for the organization manifiesto ZIP', async () => { + const client = new Facturapi('sk_test_123'); + client.BASE_URL = 'https://api.test.local/v2'; + globalThis.fetch = vi.fn(async (url, options) => { + expect(url).toBe( + 'https://api.test.local/v2/organizations/org_123/manifiesto/download-url', + ); + expect(options?.method).toBe('GET'); + return signedUrlResponse( + 'application/zip', + 'manifiesto_AAA010101AAA.zip', + ); + }) as typeof fetch; + + const result = + await client.organizations.downloadManifiestoZipUrl('org_123'); + + expect(result).toEqual( + expect.objectContaining({ + content_type: 'application/zip', + filename: 'manifiesto_AAA010101AAA.zip', + expires_at: new Date('2030-01-01T00:00:00.000Z'), + }), + ); + }); + it.each([ [ 'PDF', @@ -189,6 +215,9 @@ describe('signed download URLs', () => { await expect(client.retentions.downloadZipUrl('')).rejects.toThrow( 'id is required', ); + await expect( + client.organizations.downloadManifiestoZipUrl(''), + ).rejects.toThrow('id is required'); expect(fetchMock).not.toHaveBeenCalled(); }); }); From d4bda16cc8bf67b0890dda3eb0a51354a1987b34 Mon Sep 17 00:00:00 2001 From: javorosas Date: Wed, 11 Nov 2026 21:41:51 +0100 Subject: [PATCH 2/2] chore: sync public contract and correct release notes --- CHANGELOG.md | 5 +++-- openapi/source.json | 2 +- src/generated/input.ts | 40 +++++++++++++++++++++++++++++----------- src/generated/output.ts | 40 +++++++++++++++++++++++++++++----------- 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76f4047..6ed490c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,15 +9,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- Editor documentation now describes HTTP 409 responses for reused or concurrently processing idempotency keys. - Allow omitting search text for Carta Porte, Comercio Exterior, and payroll catalogs, matching the API contract. Empty queries return no matches. ### Added +- `organizations.downloadManifiestoZipUrl(id)` to obtain a temporary URL for downloading the signed Carta Manifiesto ZIP associated with the organization's certificate RFC. - Explore product/service categories and resolve category paths from full product keys. Product searches can filter by category prefix. - Search Mexican postal codes, countries, tax regimes, and CFDI uses through `catalogs`, and retrieve postal-code details including neighborhoods. Postal-code searches accept numeric prefixes or neighborhood, locality/city, municipality, and state names, ignore case and diacritics, and support page and cursor pagination. Every postal-code result includes all its neighborhoods. -## [6.0.0] Unreleased +## [6.0.0] - 2026-11-02 ### Breaking @@ -34,7 +36,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added -- `organizations.downloadManifiestoZipUrl(id)` to obtain a temporary URL for downloading the signed Carta Manifiesto ZIP associated with the organization's certificate RFC. - Autocompletion and editor documentation for request fields, method arguments, and responses across SDK operations. - More precise input types for CFDI variants, drafts, structured complements, and customer creation. Related fields are checked by TypeScript in supported cases, helping catch incomplete or incompatible inputs before sending a request. - Invoice responses distinguish draft, pending, failed, and stamped states; checking the status exposes the guaranteed UUID and stamp fields. diff --git a/openapi/source.json b/openapi/source.json index 1d6a842..18a92f8 100644 --- a/openapi/source.json +++ b/openapi/source.json @@ -1,5 +1,5 @@ { "repository": "FacturAPI/facturapi-docs", - "revision": "6a81247386e6e9036c618e99c2e91c2b7e74ab77", + "revision": "57b2bd16f8b0f02e31f01631a3a50d41868a6a93", "path": "website/openapi_v2.yaml" } diff --git a/src/generated/input.ts b/src/generated/input.ts index 45c9b8b..edc906c 100644 --- a/src/generated/input.ts +++ b/src/generated/input.ts @@ -5401,7 +5401,7 @@ export interface components { series?: string; /** Identificador que puedes usar para relacionar esta factura con tus registros para después buscar por este número. */ external_id?: string; - /** 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. */ + /** Clave que identifica una operación para evitar recursos duplicados. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; /** Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). */ payment_form?: string | null; @@ -5742,8 +5742,9 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta factura con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['InvoiceableCommonInput']; @@ -5766,8 +5767,9 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta factura con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['InvoiceableCommonEditInput']; @@ -6282,7 +6284,7 @@ export interface components { items: components['schemas']['InvoiceItem'][]; /** Identificador que puedes usar para relacionar este recibo con tus registros para después buscar por este número. */ external_id?: string; - /** 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. */ + /** Clave que identifica una operación para evitar recursos duplicados. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['ReceiptCommonProperties']; ReceiptInput: { @@ -6301,8 +6303,9 @@ export interface components { items: components['schemas']['InvoiceItemInput'][]; } & components['schemas']['ReceiptCommonProperties'] & { /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; }; @@ -6571,8 +6574,8 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta retención con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string | null; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados. Si se deja en blanco, no se toma en cuenta. + * Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string | null; /** @@ -6663,7 +6666,10 @@ export interface components { } | null; /** Identificador opcional que puedes usar para relacionar esta retención con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; - /** 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. */ + /** + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. Consulta [Idempotencia](/docs/getting-started/idempotency). + */ idempotency_key?: string; /** * Arreglo de complementos a incluir en la factura. Cada elemento del arreglo deberá contener @@ -7418,6 +7424,15 @@ export interface components { 'application/json': components['schemas']['GenericError']; }; }; + /** La `idempotency_key` está siendo procesada por otra solicitud o ya está asociada a un recurso. Facturapi no reproduce la respuesta original. */ + IdempotencyKeyInUse: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GenericError']; + }; + }; /** No se encontró el recurso especificado. */ NotFound: { headers: { @@ -8686,6 +8701,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; }; @@ -9392,6 +9408,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; }; @@ -9765,6 +9782,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; }; diff --git a/src/generated/output.ts b/src/generated/output.ts index 93e8a47..4ec4d25 100644 --- a/src/generated/output.ts +++ b/src/generated/output.ts @@ -5415,7 +5415,7 @@ export interface components { series?: string; /** Identificador que puedes usar para relacionar esta factura con tus registros para después buscar por este número. */ external_id?: string; - /** 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. */ + /** Clave que identifica una operación para evitar recursos duplicados. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; /** Código que representa la forma de pago, de acuerdo al [catálogo del SAT](#forma-de-pago). */ payment_form?: string | null; @@ -5756,8 +5756,9 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta factura con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['InvoiceableCommonInput']; @@ -5780,8 +5781,9 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta factura con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['InvoiceableCommonEditInput']; @@ -6297,7 +6299,7 @@ export interface components { items: components['schemas']['InvoiceItem'][]; /** Identificador que puedes usar para relacionar este recibo con tus registros para después buscar por este número. */ external_id?: string; - /** 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. */ + /** Clave que identifica una operación para evitar recursos duplicados. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; } & components['schemas']['ReceiptCommonProperties']; ReceiptInput: { @@ -6316,8 +6318,9 @@ export interface components { items: components['schemas']['InvoiceItemInput'][]; } & components['schemas']['ReceiptCommonProperties'] & { /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. + * Si se deja en blanco, no se toma en cuenta. Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string; }; @@ -6587,8 +6590,8 @@ export interface components { /** Identificador opcional que puedes usar para relacionar esta retención con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string | null; /** - * 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. + * Clave que identifica una operación para evitar recursos duplicados. Si se deja en blanco, no se toma en cuenta. + * Consulta [Idempotencia](/docs/getting-started/idempotency). */ idempotency_key?: string | null; /** @@ -6679,7 +6682,10 @@ export interface components { } | null; /** Identificador opcional que puedes usar para relacionar esta retención con tus registros y poder hacer búsquedas usando este identificador. Facturapi no valida que este campo sea único. */ external_id?: string; - /** 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. */ + /** + * Clave que identifica una operación para evitar recursos duplicados al repetir o enviar solicitudes en paralelo. Debe ser única dentro de la misma organización, ambiente y tipo de recurso. + * Si otra solicitud está procesando la clave o si ya está asociada a un recurso, la API responde HTTP `409` con `code: idempotency_key_in_use`; no reproduce la respuesta original. Consulta [Idempotencia](/docs/getting-started/idempotency). + */ idempotency_key?: string; /** * Arreglo de complementos a incluir en la factura. Cada elemento del arreglo deberá contener @@ -7434,6 +7440,15 @@ export interface components { 'application/json': components['schemas']['GenericError']; }; }; + /** La `idempotency_key` está siendo procesada por otra solicitud o ya está asociada a un recurso. Facturapi no reproduce la respuesta original. */ + IdempotencyKeyInUse: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GenericError']; + }; + }; /** No se encontró el recurso especificado. */ NotFound: { headers: { @@ -8702,6 +8717,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; }; @@ -9408,6 +9424,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; }; @@ -9781,6 +9798,7 @@ export interface operations { 400: components['responses']['BadRequest']; 401: components['responses']['Unauthenticated']; 404: components['responses']['NotFound']; + 409: components['responses']['IdempotencyKeyInUse']; 429: components['responses']['RateLimited']; 500: components['responses']['UnexpectedError']; };