{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/withreach/json-schema/withreach-transaction-details-mode-a-schema.json",
  "title": "Tax linking",
  "description": "Suppliers or billing platforms provide tax details to Reach. Reach correlates this submission to the PSP webhook using `PspTransactionId`. Both `PspTransactionId` and `PspName` are required. The submission and the webhook may arrive in either order—both are persisted and correlated once both have arrived. For refunds, set `ParentPspTransactionId` to the original payment's `PspTransactionId`, or set `ParentReference` to the original submission's `Reference`, and use negative amounts throughout.",
  "x-generated": "2026-10-28",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/withreach-transaction-details-api-openapi.yml#/components/schemas/TransactionDetailsModeA",
  "type": "object",
  "required": [
    "PspTransactionId",
    "PspName",
    "Reference",
    "Currency",
    "ShippingAddress",
    "TaxProviderId",
    "TaxProviderReferenceId",
    "TaxDate",
    "Items"
  ],
  "properties": {
    "PspTransactionId": {
      "type": [
        "string",
        "null"
      ],
      "minLength": 1,
      "maxLength": 255,
      "description": "Transaction ID from the PSP. This is the correlation key Reach uses to match this submission to the PSP webhook. Omitted in Tax only. See the [PSP Transaction ID mapping](https://docs.withreach.com/reference/transaction-details#the-psptransactionid-field) table for the exact field to use for each PSP.\n\n- **PayPal payments:** `purchase_units[].payments.captures[].id` (the capture ID, not the order ID).\n- **PayPal refunds:** `id` from the refund response.\n- **Adyen payments:** `pspReference` from the payment response.\n- **Adyen refunds:** `pspReference` from the refund response (not `paymentPspReference`).\n- **Checkout.com payments:** `id` from `/payments` response.\n- **Checkout.com refunds:** `action_id` from `/payments/{payment_id}/refunds` response.\n- **Stripe payments:** `charges.data.id` from `/payment_intents` response.\n- **Stripe refunds:** `id` from `/refunds` response."
    },
    "PspName": {
      "type": "string",
      "description": "PSP that processed the payment. Omitted in Tax only",
      "enum": [
        "ADYEN",
        "PAYPAL",
        "CHECKOUT",
        "STRIPE",
        "KLARNA"
      ]
    },
    "ParentPspTransactionId": {
      "type": [
        "string",
        "null"
      ],
      "minLength": 1,
      "maxLength": 255,
      "description": "The `PspTransactionId` of the original payment being reversed. Set this field to indicate a refund or reversal—no separate boolean is needed. When present, all `Amount`, `TaxAmount`, `TaxableAmount`, and `NonTaxableAmount` values in `Items` must be negative.\n\n- **PayPal:** use the original capture ID.\n- **Adyen:** use the original payment `pspReference`.\n- **Checkout.com refunds:** `id` from original `/payments` response.\n- **Stripe refunds:** original `charges.data.id` from `/payment_intents` response.\n\nAlternatively, identify the original by its `Reference` using `ParentReference`. Send one or the other, not both."
    },
    "Reference": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "Your order ID or internal reference for this transaction."
    },
    "ParentReference": {
      "type": [
        "string",
        "null"
      ],
      "minLength": 1,
      "maxLength": 255,
      "description": "The `Reference` of the original transaction being reversed. Use this instead of `ParentPspTransactionId` when you hold the original transaction's `Reference` but not its PSP transaction ID, for example when the original was submitted as Tax only. Set this field to indicate a refund or reversal; no separate boolean is needed. When present, all `Amount`, `TaxAmount`, `TaxableAmount`, and `NonTaxableAmount` values in `Items` must be negative.\n\n**Send either `ParentPspTransactionId` or `ParentReference`, not both.** Sending both returns `400` with a field error on `ParentReference`. The value must match the `Reference` of exactly one earlier non-refund submission for your merchant. If it matches none, or more than one, the request returns `400` with a field error on `ParentReference`."
    },
    "Currency": {
      "type": "string",
      "minLength": 3,
      "maxLength": 3,
      "description": "ISO 4217 three-letter currency code. Case sensitive. Validated against an allowlist.",
      "enum": [
        "AED",
        "AFN",
        "ALL",
        "AMD",
        "ANG",
        "AOA",
        "ARS",
        "AUD",
        "AWG",
        "AZN",
        "BAM",
        "BBD",
        "BDT",
        "BGN",
        "BHD",
        "BIF",
        "BMD",
        "BND",
        "BOB",
        "BRL",
        "BSD",
        "BTN",
        "BWP",
        "BYN",
        "BZD",
        "CAD",
        "CDF",
        "CHF",
        "CLP",
        "CNY",
        "COP",
        "CRC",
        "CUP",
        "CVE",
        "CZK",
        "DJF",
        "DKK",
        "DOP",
        "DZD",
        "EGP",
        "ERN",
        "ETB",
        "EUR",
        "FJD",
        "FKP",
        "GBP",
        "GEL",
        "GHS",
        "GIP",
        "GMD",
        "GNF",
        "GTQ",
        "GYD",
        "HKD",
        "HNL",
        "HTG",
        "HUF",
        "IDR",
        "ILS",
        "INR",
        "IQD",
        "IRR",
        "ISK",
        "JMD",
        "JOD",
        "JPY",
        "KES",
        "KGS",
        "KHR",
        "KMF",
        "KPW",
        "KRW",
        "KWD",
        "KYD",
        "KZT",
        "LAK",
        "LBP",
        "LKR",
        "LRD",
        "LSL",
        "LYD",
        "MAD",
        "MDL",
        "MGA",
        "MKD",
        "MMK",
        "MNT",
        "MOP",
        "MRU",
        "MUR",
        "MVR",
        "MWK",
        "MXN",
        "MYR",
        "MZN",
        "NAD",
        "NGN",
        "NIO",
        "NOK",
        "NPR",
        "NZD",
        "OMR",
        "PAB",
        "PEN",
        "PGK",
        "PHP",
        "PKR",
        "PLN",
        "PYG",
        "QAR",
        "RON",
        "RSD",
        "RUB",
        "RWF",
        "SAR",
        "SBD",
        "SCR",
        "SDG",
        "SEK",
        "SGD",
        "SHP",
        "SLE",
        "SLL",
        "SOS",
        "SRD",
        "SSP",
        "STN",
        "SVC",
        "SYP",
        "SZL",
        "THB",
        "TJS",
        "TMT",
        "TND",
        "TOP",
        "TRY",
        "TTD",
        "TWD",
        "TZS",
        "UAH",
        "UGX",
        "USD",
        "UYU",
        "UZS",
        "VED",
        "VES",
        "VND",
        "VUV",
        "WST",
        "XAF",
        "XCD",
        "XOF",
        "XPF",
        "YER",
        "ZAR",
        "ZMW",
        "ZWL"
      ]
    },
    "ShippingAddress": {
      "allOf": [
        {
          "$ref": "#/$defs/Address"
        }
      ],
      "description": "Customer or subscriber shipping address for tax jurisdiction determination."
    },
    "WarehouseAddress": {
      "allOf": [
        {
          "$ref": "#/$defs/Address"
        }
      ],
      "description": "Address from which the goods are shipped, for tax jurisdiction determination. Recommended for cross-border or supplier shipments where the ship-from location affects the tax calculation."
    },
    "TaxProviderId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "Transaction ID returned by your tax provider for this calculation."
    },
    "TaxProviderReferenceId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "The reference your system passed into the tax provider when requesting the tax calculation."
    },
    "BusinessIdentificationNumber": {
      "type": "string",
      "maxLength": 50,
      "description": "Tax ID or VAT registration number. Provides evidence for why tax may be zero on B2B transactions."
    },
    "TaxDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
      "description": "Local date and time of the tax calculation. Format: `yyyy-MM-ddTHH:mm:ss`—no timezone offset, no fractional seconds."
    },
    "Items": {
      "type": "array",
      "description": "Line items on the transaction. Must contain at least one item.",
      "minItems": 1,
      "maxItems": 500,
      "items": {
        "$ref": "#/$defs/LineItem"
      }
    }
  },
  "$defs": {
    "Address": {
      "title": "Address",
      "description": "A postal address used for tax jurisdiction determination.",
      "type": "object",
      "required": [
        "Street",
        "City",
        "Country"
      ],
      "properties": {
        "Street": {
          "type": "string",
          "maxLength": 255,
          "description": "Street address line."
        },
        "City": {
          "type": "string",
          "maxLength": 100,
          "description": "City name."
        },
        "Region": {
          "type": "string",
          "maxLength": 100,
          "description": "State, province, or region code (e.g. `\"CA\"` for California, `\"NSW\"` for New South Wales). Free text, not validated as an ISO 3166-2 code. Recommended for US and Canadian addresses."
        },
        "Country": {
          "type": "string",
          "minLength": 2,
          "maxLength": 2,
          "description": "ISO 3166-1 alpha-2 country code. Case sensitive. Validated against an allowlist.",
          "enum": [
            "AD",
            "AE",
            "AF",
            "AG",
            "AI",
            "AL",
            "AM",
            "AO",
            "AQ",
            "AR",
            "AS",
            "AT",
            "AU",
            "AW",
            "AX",
            "AZ",
            "BA",
            "BB",
            "BD",
            "BE",
            "BF",
            "BG",
            "BH",
            "BI",
            "BJ",
            "BL",
            "BM",
            "BN",
            "BO",
            "BQ",
            "BR",
            "BS",
            "BT",
            "BV",
            "BW",
            "BY",
            "BZ",
            "CA",
            "CC",
            "CD",
            "CF",
            "CG",
            "CH",
            "CI",
            "CK",
            "CL",
            "CM",
            "CN",
            "CO",
            "CR",
            "CU",
            "CV",
            "CW",
            "CX",
            "CY",
            "CZ",
            "DE",
            "DJ",
            "DK",
            "DM",
            "DO",
            "DZ",
            "EC",
            "EE",
            "EG",
            "EH",
            "ER",
            "ES",
            "ET",
            "FI",
            "FJ",
            "FK",
            "FM",
            "FO",
            "FR",
            "GA",
            "GB",
            "GD",
            "GE",
            "GF",
            "GG",
            "GH",
            "GI",
            "GL",
            "GM",
            "GN",
            "GP",
            "GQ",
            "GR",
            "GS",
            "GT",
            "GU",
            "GW",
            "GY",
            "HK",
            "HM",
            "HN",
            "HR",
            "HT",
            "HU",
            "ID",
            "IE",
            "IL",
            "IM",
            "IN",
            "IO",
            "IQ",
            "IR",
            "IS",
            "IT",
            "JE",
            "JM",
            "JO",
            "JP",
            "KE",
            "KG",
            "KH",
            "KI",
            "KM",
            "KN",
            "KP",
            "KR",
            "KW",
            "KY",
            "KZ",
            "LA",
            "LB",
            "LC",
            "LI",
            "LK",
            "LR",
            "LS",
            "LT",
            "LU",
            "LV",
            "LY",
            "MA",
            "MC",
            "MD",
            "ME",
            "MF",
            "MG",
            "MH",
            "MK",
            "ML",
            "MM",
            "MN",
            "MO",
            "MP",
            "MQ",
            "MR",
            "MS",
            "MT",
            "MU",
            "MV",
            "MW",
            "MX",
            "MY",
            "MZ",
            "NA",
            "NC",
            "NE",
            "NF",
            "NG",
            "NI",
            "NL",
            "NO",
            "NP",
            "NR",
            "NU",
            "NZ",
            "OM",
            "PA",
            "PE",
            "PF",
            "PG",
            "PH",
            "PK",
            "PL",
            "PM",
            "PN",
            "PR",
            "PS",
            "PT",
            "PW",
            "PY",
            "QA",
            "RE",
            "RO",
            "RS",
            "RU",
            "RW",
            "SA",
            "SB",
            "SC",
            "SD",
            "SE",
            "SG",
            "SH",
            "SI",
            "SJ",
            "SK",
            "SL",
            "SM",
            "SN",
            "SO",
            "SR",
            "SS",
            "ST",
            "SV",
            "SX",
            "SY",
            "SZ",
            "TC",
            "TD",
            "TF",
            "TG",
            "TH",
            "TJ",
            "TK",
            "TL",
            "TM",
            "TN",
            "TO",
            "TR",
            "TT",
            "TV",
            "TW",
            "TZ",
            "UA",
            "UG",
            "UM",
            "US",
            "UY",
            "UZ",
            "VA",
            "VC",
            "VE",
            "VG",
            "VI",
            "VN",
            "VU",
            "WF",
            "WS",
            "YE",
            "YT",
            "ZA",
            "ZM",
            "ZW"
          ]
        },
        "Postcode": {
          "type": "string",
          "maxLength": 20,
          "description": "Postal or ZIP code. No country-specific format check is applied."
        }
      }
    },
    "ItemTax": {
      "title": "Item Tax",
      "description": "A single tax charge at one jurisdiction level for a line item.",
      "type": "object",
      "required": [
        "Name",
        "Type",
        "JurisdictionName",
        "JurisdictionLevel",
        "JurisdictionCountryCode",
        "JurisdictionRegionCode",
        "TaxableAmount",
        "NonTaxableAmount",
        "TaxRate",
        "TaxAmount"
      ],
      "properties": {
        "Name": {
          "type": "string",
          "maxLength": 255,
          "description": "Name for this tax charge."
        },
        "Type": {
          "type": "string",
          "maxLength": 50,
          "description": "Tax type as classified by the tax provider. Typical values: `SALES`, `USE`, `EXCISE`, `COMMUNICATIONS`, `USF`, `DISTRICT`. Listed values are not enforced."
        },
        "JurisdictionName": {
          "type": "string",
          "maxLength": 255,
          "description": "Name of the taxing jurisdiction (e.g. `\"California\"`, `\"Los Angeles County\"`)."
        },
        "JurisdictionLevel": {
          "type": "string",
          "description": "Geographic level of the taxing jurisdiction. Allowlist is case sensitive.",
          "enum": [
            "FEDERAL",
            "STATE",
            "COUNTY",
            "CITY",
            "DISTRICT"
          ]
        },
        "JurisdictionCountryCode": {
          "type": "string",
          "minLength": 2,
          "maxLength": 2,
          "description": "ISO 3166-1 alpha-2 country code of the taxing jurisdiction. Case sensitive. Validated against an allowlist.",
          "enum": [
            "AD",
            "AE",
            "AF",
            "AG",
            "AI",
            "AL",
            "AM",
            "AO",
            "AQ",
            "AR",
            "AS",
            "AT",
            "AU",
            "AW",
            "AX",
            "AZ",
            "BA",
            "BB",
            "BD",
            "BE",
            "BF",
            "BG",
            "BH",
            "BI",
            "BJ",
            "BL",
            "BM",
            "BN",
            "BO",
            "BQ",
            "BR",
            "BS",
            "BT",
            "BV",
            "BW",
            "BY",
            "BZ",
            "CA",
            "CC",
            "CD",
            "CF",
            "CG",
            "CH",
            "CI",
            "CK",
            "CL",
            "CM",
            "CN",
            "CO",
            "CR",
            "CU",
            "CV",
            "CW",
            "CX",
            "CY",
            "CZ",
            "DE",
            "DJ",
            "DK",
            "DM",
            "DO",
            "DZ",
            "EC",
            "EE",
            "EG",
            "EH",
            "ER",
            "ES",
            "ET",
            "FI",
            "FJ",
            "FK",
            "FM",
            "FO",
            "FR",
            "GA",
            "GB",
            "GD",
            "GE",
            "GF",
            "GG",
            "GH",
            "GI",
            "GL",
            "GM",
            "GN",
            "GP",
            "GQ",
            "GR",
            "GS",
            "GT",
            "GU",
            "GW",
            "GY",
            "HK",
            "HM",
            "HN",
            "HR",
            "HT",
            "HU",
            "ID",
            "IE",
            "IL",
            "IM",
            "IN",
            "IO",
            "IQ",
            "IR",
            "IS",
            "IT",
            "JE",
            "JM",
            "JO",
            "JP",
            "KE",
            "KG",
            "KH",
            "KI",
            "KM",
            "KN",
            "KP",
            "KR",
            "KW",
            "KY",
            "KZ",
            "LA",
            "LB",
            "LC",
            "LI",
            "LK",
            "LR",
            "LS",
            "LT",
            "LU",
            "LV",
            "LY",
            "MA",
            "MC",
            "MD",
            "ME",
            "MF",
            "MG",
            "MH",
            "MK",
            "ML",
            "MM",
            "MN",
            "MO",
            "MP",
            "MQ",
            "MR",
            "MS",
            "MT",
            "MU",
            "MV",
            "MW",
            "MX",
            "MY",
            "MZ",
            "NA",
            "NC",
            "NE",
            "NF",
            "NG",
            "NI",
            "NL",
            "NO",
            "NP",
            "NR",
            "NU",
            "NZ",
            "OM",
            "PA",
            "PE",
            "PF",
            "PG",
            "PH",
            "PK",
            "PL",
            "PM",
            "PN",
            "PR",
            "PS",
            "PT",
            "PW",
            "PY",
            "QA",
            "RE",
            "RO",
            "RS",
            "RU",
            "RW",
            "SA",
            "SB",
            "SC",
            "SD",
            "SE",
            "SG",
            "SH",
            "SI",
            "SJ",
            "SK",
            "SL",
            "SM",
            "SN",
            "SO",
            "SR",
            "SS",
            "ST",
            "SV",
            "SX",
            "SY",
            "SZ",
            "TC",
            "TD",
            "TF",
            "TG",
            "TH",
            "TJ",
            "TK",
            "TL",
            "TM",
            "TN",
            "TO",
            "TR",
            "TT",
            "TV",
            "TW",
            "TZ",
            "UA",
            "UG",
            "UM",
            "US",
            "UY",
            "UZ",
            "VA",
            "VC",
            "VE",
            "VG",
            "VI",
            "VN",
            "VU",
            "WF",
            "WS",
            "YE",
            "YT",
            "ZA",
            "ZM",
            "ZW"
          ]
        },
        "JurisdictionRegionCode": {
          "type": "string",
          "maxLength": 10,
          "description": "ISO 3166-2 state or region code (e.g. `\"CA\"` for California). Required for all jurisdiction. Not validated against code list."
        },
        "TaxableAmount": {
          "type": "number",
          "format": "decimal",
          "multipleOf": 0.0001,
          "minimum": -1000000000000000,
          "maximum": 1000000000000000,
          "description": "The portion of the line item amount subject to this tax. A decimal value with at most 15 integer digits and at most 4 fractional digits. Must be **negative** for reversal/refund tax lines."
        },
        "NonTaxableAmount": {
          "type": "number",
          "format": "decimal",
          "multipleOf": 0.0001,
          "minimum": -1000000000000000,
          "maximum": 1000000000000000,
          "description": "The portion of the line item amount exempt from this tax. A decimal value with at most 15 integer digits and at most 4 fractional digits. Use `0.00` if the full amount is taxable, ommiting it is a `400` error."
        },
        "TaxRate": {
          "type": "number",
          "format": "decimal",
          "description": "Tax rate as a decimal in the closed range [0, 1]. For example, `0.0625` represents 6.25%.",
          "minimum": 0,
          "maximum": 1
        },
        "TaxAmount": {
          "type": "number",
          "format": "decimal",
          "multipleOf": 0.0001,
          "minimum": -1000000000000000,
          "maximum": 1000000000000000,
          "description": "Tax amount charged for this jurisdiction. A decimal value with at most 15 integer digits and at most 4 fractional digits. Must be **negative** for reversal/refund tax lines."
        },
        "TransactionType": {
          "type": "integer",
          "format": "int64",
          "description": "Avalara AFC transaction type code. Identifies the nature of the communication service being taxed. Pass the value directly from your AFC response. Required when using an Avalara AFC-based tax provider."
        },
        "ServiceType": {
          "type": "integer",
          "format": "int64",
          "description": "Avalara AFC service type code. Identifies the customer class or service category. Pass the value directly from your AFC response. Required when using an Avalara AFC-based tax provider."
        }
      }
    },
    "LineItem": {
      "title": "Line Item",
      "description": "A single line item on the transaction.",
      "type": "object",
      "required": [
        "Sku",
        "Description",
        "Quantity",
        "Amount",
        "ProviderTaxCode",
        "ProviderTaxCategory",
        "ProviderParentTaxCategory",
        "TaxAmount",
        "ItemTaxes"
      ],
      "properties": {
        "Sku": {
          "type": "string",
          "maxLength": 255,
          "description": "Product SKU code."
        },
        "Description": {
          "type": "string",
          "maxLength": 100,
          "description": "A text description of the line item."
        },
        "CountryOfOrigin": {
          "type": "string",
          "description": "ISO 3166-1 alpha-2 country code of the country from which the goods originate. Used for cross-border and supplier shipments.",
          "pattern": "^[A-Z]{2}$"
        },
        "Quantity": {
          "type": "integer",
          "format": "int64",
          "description": "Quantity of this item. Must be zero or greater. Oversized value fails as a malformed-body 400 error, not a field error.",
          "minimum": 0,
          "maximum": 9223372036854776000
        },
        "Amount": {
          "type": "number",
          "format": "decimal",
          "multipleOf": 0.0001,
          "minimum": -1000000000000000,
          "maximum": 1000000000000000,
          "description": "Line item amount. A decimal value with at most 15 integer digits and at most 4 fractional digits. Must be **negative** for reversal/refund line items."
        },
        "ProviderTaxCode": {
          "type": "string",
          "maxLength": 100,
          "description": "Tax code used for this item by the tax provider. Pass the value directly from your tax provider response. Not free text."
        },
        "ProviderTaxCategory": {
          "type": "string",
          "maxLength": 100,
          "description": "Tax category classification assigned by the tax provider (e.g. `\"DIGITAL_STREAMING\"`). Not free text."
        },
        "ProviderParentTaxCategory": {
          "type": "string",
          "maxLength": 100,
          "description": "Parent tax category assigned by the tax provider (e.g. `\"DIGITAL_GOODS\"`). Not free text."
        },
        "TaxAmount": {
          "type": "number",
          "format": "decimal",
          "multipleOf": 0.0001,
          "minimum": -1000000000000000,
          "maximum": 1000000000000000,
          "description": "Total tax for this line item. Must equal the sum of all `ItemTaxes[].TaxAmount` values within a tolerance of 0.01. A decimal value with at most 15 integer digits and at most 4 fractional digits. Must be **negative** for reversal/refund line items."
        },
        "ItemTaxes": {
          "type": "array",
          "description": "Jurisdiction-level tax breakdown for this line item. Must contain at least one entry. The sum of all `TaxAmount` values here must equal the line item's `TaxAmount` within 0.01.",
          "minItems": 1,
          "maxItems": 100,
          "items": {
            "$ref": "#/$defs/ItemTax"
          }
        },
        "WarehouseAddress": {
          "allOf": [
            {
              "$ref": "#/$defs/Address"
            }
          ],
          "description": "Address this item ships from, for tax jurisdiction determination. Overrides the transaction-level `WarehouseAddress` for this item. Use when a single order ships from more than one origin."
        }
      }
    }
  }
}