Amounts
Every financial event carries one principal amount in amount. Invoices and settlements also say how that amount is made up — subtotal and tax, gross and fees — in amountBreakdown. This guide explains how to choose the principal amount, how to build the breakdown, and which amount types each financial type accepts.
The principal amount: amount
Section titled “The principal amount: amount”amount, together with currencyCode and isNegative, is the event’s principal amount:
- It is the amount that reconciles. Reconciliation compares the principal amount of each event and nothing else. The breakdown is never used for matching.
- You decide which figure it is. TreasuryHub does not derive it from the breakdown, and does not check that the components add up to it. Choose one convention per financial type and keep it: every match, report and later process uses the figure you send.
- It is always greater than 0. The direction goes in
isNegative.amount: 0returns400 ERR-3005(onlyACCOUNT_BALANCEaccepts zero).
Which figure to choose
Section titled “Which figure to choose”| Type | Suggested amount | Why |
|---|---|---|
SALE_INVOICE, SALE_INVOICE_LINE | Total: what the customer has to pay (subtotal + tax − discount − withholding) | The customer’s payment carries the total, so it is the figure the payment matches against. |
PSP_SETTLEMENT | Net: what the PSP deposits (gross − fees and their tax − holds − refunds + released holds) | The deposit on the bank statement carries the net, so it is the figure the BANK_MOVEMENT matches against. |
The choice matters most for invoices. If you later use them to drive payments — for example, in a payment dispersion — the amount that moves is the principal amount, so it must be what is actually paid: the total. With the subtotal as principal, every invoice would fall short by its tax. Changing the convention later means sending the events already loaded again.
The breakdown: amountBreakdown
Section titled “The breakdown: amountBreakdown”amountBreakdown lists the components that make up amount, for reporting. It is required for SALE_INVOICE, SALE_INVOICE_LINE and PSP_SETTLEMENT.
| Field | Type | Description |
|---|---|---|
amountType | string | Code of the component. Must be allowed for the event’s type (see the table below). |
currencyCode | string | ISO 4217 currency code of the component. Usually the event’s currencyCode. |
amount | number | Amount of the component. Always greater than 0. |
isNegative | boolean | true when the component subtracts from the principal (a deduction), false when it adds to it. |
Never include the principal itself. The net (or the total) is amount; there is no NET amount type. The breakdown only carries the parts the principal is made of.
The breakdown is not the same as multiCurrencyAmounts: that list is the same amount expressed in other currencies, while the breakdown is the parts the amount is made of.
Validation rules
Section titled “Validation rules”| Rule | Error |
|---|---|
amountType is allowed for the event’s type | ERR-3047 AmountTypeNotAllowed |
Each amountType + currencyCode pair appears at most once | ERR-3048 AmountBreakdownDuplicate |
Each component’s amount is greater than 0 (the sign goes in isNegative) | ERR-3049 AmountBreakdownAmountMustBePositive |
Each component’s currencyCode is a valid ISO 4217 code | ERR-3050 InvalidAmountBreakdownCurrencyCode |
Each failure names the offending item in errors[].field: AmountBreakdown[<index>].AmountType, .Amount or .CurrencyCode, and AmountBreakdown[<index>] for a duplicate. See Error Handling.
TreasuryHub does not check that the components add up to amount, nor that their currency matches multiCurrencyAmounts. Keeping the breakdown consistent with the principal is your responsibility: reports read the components exactly as you send them.
Allowed amount types
Section titled “Allowed amount types”Each financial type accepts its own amount types. A deduction subtracts from the principal and is sent with isNegative: true.
| Type | amountType | Meaning | Deduction |
|---|---|---|---|
PSP_SETTLEMENT | GROSS | Total of the payments the settlement covers, before any deduction | — |
FEE | Commission the PSP kept | ✓ | |
FEE_TAX | Tax on the PSP’s commission (for example, VAT on the fee) | ✓ | |
DISPUTE_HOLD | Amount the PSP held back for disputes or chargebacks | ✓ | |
REFUND_DISCOUNT | Refunds the PSP deducted from the settlement | ✓ | |
RELEASED_HOLD | Amount held in an earlier settlement and released in this one | — | |
SALE_INVOICE, SALE_INVOICE_LINE | SUBTOTAL | Amount before taxes and discounts | — |
TAX | Taxes charged on the invoice (for example, VAT) | — | |
DISCOUNT | Discount granted to the customer | ✓ | |
WITHHOLDING | Taxes the customer withholds (for example, withheld income tax or VAT) | ✓ |
FEE_TAX is kept apart from TAX on purpose: the tax a PSP charges on its fee and the tax on an invoice are different concepts, and reports keep them apart.
Every other financial type has no amount type enabled yet: any breakdown item sent for it returns ERR-3047, so omit the field. New amount types can be enabled for a type without an API change — when you read events, treat an unknown amountType as valid.
Sign convention
Section titled “Sign convention”amountis always positive, in the event and in every component. The direction goes inisNegative.- Deductions (✓ in the table) are sent with
isNegative: true; the other components withisNegative: false. A fee travels as"amount": 387.93, "isNegative": true— never as-387.93. - If a component goes against its usual direction (for example, a fee the PSP gives back), flip
isNegativefor that item. - The components then add up to the principal:
amount= sum of the items withisNegative: false− sum of the items withisNegative: true.
Examples
Section titled “Examples”PSP settlement
Section titled “PSP settlement”The PSP collected 10,500.00 MXN, kept a 387.93 fee plus 62.07 of tax on it, and deposited the rest. The principal amount is the net deposited:
GROSS − FEE − FEE_TAX = 10500.00 − 387.93 − 62.07 = 10050.00 = amount
{ "externalId": "STL-2026-10-15-0001", "type": "PSP_SETTLEMENT", "countryCode": "MX", "currencyCode": "MXN", "amount": 10050.00, "isNegative": false, "status": "BOOKED", "amountBreakdown": [ { "amountType": "GROSS", "currencyCode": "MXN", "amount": 10500.00, "isNegative": false }, { "amountType": "FEE", "currencyCode": "MXN", "amount": 387.93, "isNegative": true }, { "amountType": "FEE_TAX", "currencyCode": "MXN", "amount": 62.07, "isNegative": true } ], "payload": { "partnerIdentifier": "PSP-001", "partnerName": "Pasarela de Pagos MX", "settlementDate": "2026-10-15", "periodFrom": "2026-10-08", "periodTo": "2026-10-14", "payoutReference": "PO-20261015-8841", "transactionCount": 42 }}The settlement’s own id is the event’s externalId. The PSP_PAYIN events it pays out reference it in their relatedIds.
Invoice line
Section titled “Invoice line”Two units at 500.00, a 50.00 discount, and 16% VAT on the discounted subtotal. The principal amount is the line total:
SUBTOTAL + TAX − DISCOUNT = 1000.00 + 152.00 − 50.00 = 1102.00 = amount
{ "externalId": "INV-A-10234-L1", "type": "SALE_INVOICE_LINE", "countryCode": "MX", "currencyCode": "MXN", "amount": 1102.00, "isNegative": false, "status": "BOOKED", "amountBreakdown": [ { "amountType": "SUBTOTAL", "currencyCode": "MXN", "amount": 1000.00, "isNegative": false }, { "amountType": "TAX", "currencyCode": "MXN", "amount": 152.00, "isNegative": false }, { "amountType": "DISCOUNT", "currencyCode": "MXN", "amount": 50.00, "isNegative": true } ], "payload": { "invoiceNumber": "A-10234", "customerIdentifier": "CUST-0042", "customerName": "Comercializadora del Norte SA de CV", "customerTaxId": "CNO010101AB1", "lineNumber": 1, "productCode": "SKU-7781", "description": "Licencia anual de software", "quantity": 2, "unitPrice": 500.00, "taxRate": 16 }}quantity, unitPrice and taxRate describe the line; they are not amounts. The amounts that make up the line go in amountBreakdown.
Updating the breakdown
Section titled “Updating the breakdown”On PUT /api/h2h/ingestion/financial-events/{id}, amountBreakdown is updated as a whole:
- Present: it replaces every component the event had. Send all of them, not only the ones that changed. An empty array (
[]) clears the breakdown. - Omitted or
null: the breakdown is left untouched.
When you read the event back (GET), amountBreakdown is null if the event never carried a breakdown, and [] if a PUT cleared it.
The new breakdown is validated against the stored event’s type, with the same rules as on create. An amountType not allowed for that type returns ERR-3047 as a single error, without an errors array; the other breakdown errors come inside errors, as on create. TreasuryHub does not recompute amount: if the components change the principal, send the new amount in the same request. Each successful PUT creates a new version of the event.
For example, the PSP later held 500.00 of the settlement above for a dispute:
{ "amount": 9550.00, "amountBreakdown": [ { "amountType": "GROSS", "currencyCode": "MXN", "amount": 10500.00, "isNegative": false }, { "amountType": "FEE", "currencyCode": "MXN", "amount": 387.93, "isNegative": true }, { "amountType": "FEE_TAX", "currencyCode": "MXN", "amount": 62.07, "isNegative": true }, { "amountType": "DISPUTE_HOLD", "currencyCode": "MXN", "amount": 500.00, "isNegative": true } ]}See Error Handling for the error codes, and the Financial Events API reference for the full schemas.
Todo evento financiero lleva un único monto principal en amount. Las facturas y los settlements además indican cómo se compone ese monto —subtotal e impuestos, bruto y comisiones— en amountBreakdown. Esta guía explica cómo elegir el monto principal, cómo armar el desglose y qué tipos de monto acepta cada tipo financiero.
El monto principal: amount
Section titled “El monto principal: amount”amount, junto con currencyCode e isNegative, es el monto principal del evento:
- Es el monto que concilia. La conciliación compara el monto principal de cada evento y nada más. El desglose nunca se usa para el matching.
- Tú decides qué cifra es. TreasuryHub no lo deriva del desglose ni verifica que los componentes sumen ese monto. Elige una convención por tipo financiero y mantenla: cada match, reporte y proceso posterior usa la cifra que envías.
- Siempre es mayor que 0. El sentido va en
isNegative.amount: 0devuelve400 ERR-3005(soloACCOUNT_BALANCEacepta cero).
Qué cifra elegir
Section titled “Qué cifra elegir”| Tipo | amount sugerido | Por qué |
|---|---|---|
SALE_INVOICE, SALE_INVOICE_LINE | Total: lo que el cliente tiene que pagar (subtotal + impuestos − descuento − retenciones) | El pago del cliente llega por el total, así que es la cifra contra la que concilia el pago. |
PSP_SETTLEMENT | Neto: lo que deposita el PSP (bruto − comisiones y su impuesto − retenciones por disputas − reembolsos + liberaciones) | El depósito en el extracto bancario llega por el neto, así que es la cifra contra la que concilia el BANK_MOVEMENT. |
La elección importa sobre todo en las facturas. Si más adelante las usas para mover pagos —por ejemplo, en una dispersión de pagos—, el monto que se mueve es el principal: tiene que ser lo que realmente se paga, el total. Con el subtotal como principal, a cada factura le faltarían sus impuestos. Cambiar la convención después implica volver a enviar los eventos ya cargados.
El desglose: amountBreakdown
Section titled “El desglose: amountBreakdown”amountBreakdown lista los componentes que forman amount, para reporting. Es obligatorio en SALE_INVOICE, SALE_INVOICE_LINE y PSP_SETTLEMENT.
| Campo | Tipo | Descripción |
|---|---|---|
amountType | string | Código del componente. Debe estar permitido para el type del evento (ver la tabla más abajo). |
currencyCode | string | Código de moneda ISO 4217 del componente. Normalmente el currencyCode del evento. |
amount | number | Monto del componente. Siempre mayor que 0. |
isNegative | boolean | true cuando el componente resta del principal (una deducción), false cuando suma. |
Nunca incluyas el principal. El neto (o el total) es amount; no existe el tipo de monto NET. El desglose solo lleva las partes que forman el principal.
El desglose no es lo mismo que multiCurrencyAmounts: esa lista es el mismo monto expresado en otras monedas, mientras que el desglose son las partes que forman el monto.
Reglas de validación
Section titled “Reglas de validación”| Regla | Error |
|---|---|
amountType está permitido para el type del evento | ERR-3047 AmountTypeNotAllowed |
Cada par amountType + currencyCode aparece como máximo una vez | ERR-3048 AmountBreakdownDuplicate |
El amount de cada componente es mayor que 0 (el signo va en isNegative) | ERR-3049 AmountBreakdownAmountMustBePositive |
El currencyCode de cada componente es un código ISO 4217 válido | ERR-3050 InvalidAmountBreakdownCurrencyCode |
Cada fallo señala el componente con el problema en errors[].field: AmountBreakdown[<índice>].AmountType, .Amount o .CurrencyCode, y AmountBreakdown[<índice>] para un duplicado. Consulta Manejo de Errores.
TreasuryHub no verifica que los componentes sumen amount, ni que su moneda coincida con multiCurrencyAmounts. Mantener el desglose coherente con el principal es tu responsabilidad: los reportes leen los componentes tal como los envías.
Tipos de monto permitidos
Section titled “Tipos de monto permitidos”Cada tipo financiero acepta sus propios tipos de monto. Una deducción resta del principal y se envía con isNegative: true.
| Tipo | amountType | Significado | Deducción |
|---|---|---|---|
PSP_SETTLEMENT | GROSS | Total de los pagos que cubre el settlement, antes de cualquier deducción | — |
FEE | Comisión que se quedó el PSP | ✓ | |
FEE_TAX | Impuesto sobre la comisión del PSP (por ejemplo, el IVA de la comisión) | ✓ | |
DISPUTE_HOLD | Monto que el PSP retuvo por disputas o contracargos | ✓ | |
REFUND_DISCOUNT | Reembolsos que el PSP descontó del settlement | ✓ | |
RELEASED_HOLD | Monto retenido en un settlement anterior y liberado en este | — | |
SALE_INVOICE, SALE_INVOICE_LINE | SUBTOTAL | Monto antes de impuestos y descuentos | — |
TAX | Impuestos cobrados en la factura (por ejemplo, IVA) | — | |
DISCOUNT | Descuento otorgado al cliente | ✓ | |
WITHHOLDING | Impuestos que retiene el cliente (por ejemplo, ISR o IVA retenido) | ✓ |
FEE_TAX está separado de TAX a propósito: el impuesto que cobra un PSP sobre su comisión y el impuesto de una factura son conceptos distintos, y los reportes los mantienen separados.
El resto de los tipos financieros todavía no tiene tipos de monto habilitados: cualquier componente que se envíe para ellos devuelve ERR-3047, así que omite el campo. Se pueden habilitar tipos de monto nuevos para un tipo sin cambios en la API: cuando leas eventos, trata un amountType desconocido como válido.
Convención de signo
Section titled “Convención de signo”amountsiempre es positivo, en el evento y en cada componente. El sentido va enisNegative.- Las deducciones (✓ en la tabla) se envían con
isNegative: true; el resto de los componentes conisNegative: false. Una comisión viaja como"amount": 387.93, "isNegative": true, nunca como-387.93. - Si un componente va en contra de su sentido habitual (por ejemplo, una comisión que el PSP devuelve), invierte
isNegativeen ese componente. - Así los componentes suman el principal:
amount= suma de los componentes conisNegative: false− suma de los componentes conisNegative: true.
Ejemplos
Section titled “Ejemplos”Settlement de PSP
Section titled “Settlement de PSP”El PSP cobró 10,500.00 MXN, se quedó una comisión de 387.93 más 62.07 de impuesto sobre ella, y depositó el resto. El monto principal es el neto depositado:
GROSS − FEE − FEE_TAX = 10500.00 − 387.93 − 62.07 = 10050.00 = amount
{ "externalId": "STL-2026-10-15-0001", "type": "PSP_SETTLEMENT", "countryCode": "MX", "currencyCode": "MXN", "amount": 10050.00, "isNegative": false, "status": "BOOKED", "amountBreakdown": [ { "amountType": "GROSS", "currencyCode": "MXN", "amount": 10500.00, "isNegative": false }, { "amountType": "FEE", "currencyCode": "MXN", "amount": 387.93, "isNegative": true }, { "amountType": "FEE_TAX", "currencyCode": "MXN", "amount": 62.07, "isNegative": true } ], "payload": { "partnerIdentifier": "PSP-001", "partnerName": "Pasarela de Pagos MX", "settlementDate": "2026-10-15", "periodFrom": "2026-10-08", "periodTo": "2026-10-14", "payoutReference": "PO-20261015-8841", "transactionCount": 42 }}El id del settlement es el externalId del evento. Los eventos PSP_PAYIN que liquida lo referencian en sus relatedIds.
Línea de factura
Section titled “Línea de factura”Dos unidades a 500.00, un descuento de 50.00 e IVA del 16% sobre el subtotal con descuento. El monto principal es el total de la línea:
SUBTOTAL + TAX − DISCOUNT = 1000.00 + 152.00 − 50.00 = 1102.00 = amount
{ "externalId": "INV-A-10234-L1", "type": "SALE_INVOICE_LINE", "countryCode": "MX", "currencyCode": "MXN", "amount": 1102.00, "isNegative": false, "status": "BOOKED", "amountBreakdown": [ { "amountType": "SUBTOTAL", "currencyCode": "MXN", "amount": 1000.00, "isNegative": false }, { "amountType": "TAX", "currencyCode": "MXN", "amount": 152.00, "isNegative": false }, { "amountType": "DISCOUNT", "currencyCode": "MXN", "amount": 50.00, "isNegative": true } ], "payload": { "invoiceNumber": "A-10234", "customerIdentifier": "CUST-0042", "customerName": "Comercializadora del Norte SA de CV", "customerTaxId": "CNO010101AB1", "lineNumber": 1, "productCode": "SKU-7781", "description": "Licencia anual de software", "quantity": 2, "unitPrice": 500.00, "taxRate": 16 }}quantity, unitPrice y taxRate describen la línea; no son montos. Los montos que forman la línea van en amountBreakdown.
Actualizar el desglose
Section titled “Actualizar el desglose”En PUT /api/h2h/ingestion/financial-events/{id}, amountBreakdown se actualiza completo:
- Presente: reemplaza todos los componentes que tenía el evento. Envíalos todos, no solo los que cambiaron. Un array vacío (
[]) borra el desglose. - Omitido o
null: el desglose no se toca.
Al volver a leer el evento (GET), amountBreakdown es null si el evento nunca llevó desglose, y [] si un PUT lo borró.
El nuevo desglose se valida contra el type del evento almacenado, con las mismas reglas que en la creación. Un amountType no permitido para ese tipo devuelve ERR-3047 como error simple, sin array errors; el resto de los errores del desglose llegan dentro de errors, como en la creación. TreasuryHub no recalcula amount: si los componentes cambian el principal, envía el nuevo amount en la misma solicitud. Cada PUT exitoso crea una nueva versión del evento.
Por ejemplo, el PSP retuvo después 500.00 del settlement anterior por una disputa:
{ "amount": 9550.00, "amountBreakdown": [ { "amountType": "GROSS", "currencyCode": "MXN", "amount": 10500.00, "isNegative": false }, { "amountType": "FEE", "currencyCode": "MXN", "amount": 387.93, "isNegative": true }, { "amountType": "FEE_TAX", "currencyCode": "MXN", "amount": 62.07, "isNegative": true }, { "amountType": "DISPUTE_HOLD", "currencyCode": "MXN", "amount": 500.00, "isNegative": true } ]}Consulta Manejo de Errores para los códigos de error, y la referencia de la API de Financial Events para los esquemas completos.