diff --git a/content/docs/integration-guidance/api-reference/payment_intent_network.md b/content/docs/integration-guidance/api-reference/payment_intent_network.md index 7e41391..bc88a90 100644 --- a/content/docs/integration-guidance/api-reference/payment_intent_network.md +++ b/content/docs/integration-guidance/api-reference/payment_intent_network.md @@ -80,7 +80,12 @@ The beneficiary provider will receive a PaymentIntentUpdate notification with settlement details. -This message has no fields defined. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| settlement_amount | [tzero.v1.common.Decimal](../common_common/#tzero-v1-common-Decimal) | | The settlement amount in USD that the pay-in provider owes the beneficiary provider for this payment intent. Locked from the chosen quote at confirm-time as (payment_amount / rate) − fix. | +| rate | [tzero.v1.common.Decimal](../common_common/#tzero-v1-common-Decimal) | | USD/ exchange rate locked in for this settlement. Matches the rate forwarded to the beneficiary in PaymentIntentUpdate.FundsReceived. | +| fix | [tzero.v1.common.Decimal](../common_common/#tzero-v1-common-Decimal) | | Flat USD charge retained by the pay-in provider per transfer, already subtracted from settlement_amount. Surfaced so the pay-in provider can audit the settlement formula: settlement = (payment_amount / rate) − fix. | + @@ -379,6 +384,7 @@ This message has no fields defined. | REJECT_REASON_PROVIDER_NOT_ALLOWED | 30 | | | REJECT_REASON_AMOUNT_TOO_SMALL | 40 | The pay-in amount would yield a zero or negative beneficiary settlement (pay_in / rate − fix) at every active quote. | | REJECT_REASON_NO_VALID_OFFER | 50 | The (pay-in provider, payment method) tuple was not offered on this intent. Either the intent was rejected during creation, or this provider's GetPaymentDetails response was invalid for the requested method. | +| REJECT_REASON_TRANSACTION_REFERENCE_ALREADY_USED | 60 | Transaction_reference is already attached to a different pay-in with the same payment_method. References must be unique per payment_method; retry with a fresh transaction_reference, or treat the prior pay-in as the authoritative confirmation. | diff --git a/content/docs/integration-guidance/api-reference/payment_intent_pay_in_provider.md b/content/docs/integration-guidance/api-reference/payment_intent_pay_in_provider.md index 98fcc5c..86c2452 100644 --- a/content/docs/integration-guidance/api-reference/payment_intent_pay_in_provider.md +++ b/content/docs/integration-guidance/api-reference/payment_intent_pay_in_provider.md @@ -48,6 +48,7 @@ Request for payment details. | currency | [string](../scalar/#string) | | The currency for the pay-in. ISO 4217 currency code (e.g., "EUR", "GBP", "KES"). | | amount | [tzero.v1.common.Decimal](../common_common/#tzero-v1-common-Decimal) | | The amount to be paid in the specified currency. | | travel_rule | [GetPaymentDetailsRequest.TravelRuleData](#tzero-v1-payment_intent-GetPaymentDetailsRequest-TravelRuleData) | | Travel rule data for this payment | +| beneficiary_provider_id | [uint32](../scalar/#uint32) | | The T-0 provider ID of the beneficiary provider (the FI the funds are destined for). Stable, opaque identifier — pay-in providers can use this directly to resolve the beneficiary in their own systems. | diff --git a/proto/tzero/v1/payment_intent/network.proto b/proto/tzero/v1/payment_intent/network.proto index 59e906b..fa800fe 100644 --- a/proto/tzero/v1/payment_intent/network.proto +++ b/proto/tzero/v1/payment_intent/network.proto @@ -489,7 +489,45 @@ message ConfirmFundsReceivedResponse { * The beneficiary provider will receive a PaymentIntentUpdate notification * with settlement details. */ - message Accept {} + message Accept { + /** + * The settlement amount in USD that the pay-in provider owes the + * beneficiary provider for this payment intent. Locked from the chosen + * quote at confirm-time as (payment_amount / rate) − fix. + */ + tzero.v1.common.Decimal settlement_amount = 10 [ + (buf.validate.field).required = true, + (buf.validate.field).cel = { + message: "settlement_amount must be greater than zero" + expression: "this.unscaled > 0" + } + ]; + + /** + * USD/ exchange rate locked in for this settlement. + * Matches the rate forwarded to the beneficiary in PaymentIntentUpdate.FundsReceived. + */ + tzero.v1.common.Decimal rate = 20 [ + (buf.validate.field).required = true, + (buf.validate.field).cel = { + message: "rate must be greater than zero" + expression: "this.unscaled > 0" + } + ]; + + /** + * Flat USD charge retained by the pay-in provider per transfer, + * already subtracted from settlement_amount. Surfaced so the pay-in + * provider can audit the settlement formula: settlement = (payment_amount / rate) − fix. + */ + tzero.v1.common.Decimal fix = 30 [ + (buf.validate.field).required = true, + (buf.validate.field).cel = { + message: "fix must be non-negative" + expression: "this.unscaled >= 0" + } + ]; + } /** * Funds rejected. @@ -514,6 +552,13 @@ message ConfirmFundsReceivedResponse { * the requested method. */ REJECT_REASON_NO_VALID_OFFER = 50; + /** + * Transaction_reference is already attached to a different pay-in + * with the same payment_method. References must be unique per + * payment_method; retry with a fresh transaction_reference, or + * treat the prior pay-in as the authoritative confirmation. + */ + REJECT_REASON_TRANSACTION_REFERENCE_ALREADY_USED = 60; } } } diff --git a/proto/tzero/v1/payment_intent/pay_in_provider.proto b/proto/tzero/v1/payment_intent/pay_in_provider.proto index 4a9287b..1170efb 100644 --- a/proto/tzero/v1/payment_intent/pay_in_provider.proto +++ b/proto/tzero/v1/payment_intent/pay_in_provider.proto @@ -75,6 +75,13 @@ message GetPaymentDetailsRequest { */ TravelRuleData travel_rule = 60 [(buf.validate.field).required = true]; + /** + * The T-0 provider ID of the beneficiary provider (the FI the funds are + * destined for). Stable, opaque identifier — pay-in providers can use this + * directly to resolve the beneficiary in their own systems. + */ + uint32 beneficiary_provider_id = 70 [(buf.validate.field).uint32.gt = 0]; + message TravelRuleData { /** * The natural or legal person or legal arrangement who is identified