> ## Documentation Index
> Fetch the complete documentation index at: https://docs.numeral.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Platform

> Tax marketplace and platform sales, with your fees taxed separately

A platform calculation quotes tax for a sale where a [merchant](https://docs.numeral.com/v2026-11-01/objects/merchants.md) is the seller and you facilitate it. Use it if you're a marketplace, a payment processor, or a merchant of record. The order and your platform fees are taxed separately: the order where the customer is, the fees where the merchant is. Once the customer pays, record the sale with [Create platform transactions](#create-platform-transactions).

```text Where platform calculations fit theme={null}
Sale on your platform
├─ 1. Customer enters address
│     └─ POST /tax/platform/calculations
│          send:    customer + merchant + order (+ fees)
│          receive: order tax + fee tax + platform calculation id
└─ 2. Customer pays
      └─ POST /tax/platform/transactions
           send:    platform calculation id
           receive: list of transactions
```

Endpoints
[Create a platform calculationPOST/tax/platform/calculations](#create-a-platform-calculation)
[Create platform transactionsPOST/tax/platform/transactions](#create-platform-transactions)

## The Platform calculation object

### Attributes

**id** `string`

The ID of the platform calculation, `plat_calc_…`. Use it to create platform transactions.

**object** `string, value is "tax.platform_calculation"`

String representing the object's type.

**testmode** `boolean`

`true` if made with a test API key.

**customer\_currency\_code** `string`

ISO 4217 currency code of the calculation.

**customer** `object`

The customer as used for the calculation.

**customer.type** `enum`

`CONSUMER` or `BUSINESS`.

**merchant** `object`

The merchant used in this calculation.

**roles** `array of strings`

Echo of the `roles` you sent.

**line\_items** `array of objects`

Tax on the order, one entry per line item in `order_details`. Taxed where the customer is.

**line\_items\[].line\_item\_id** `string`

Numeral-generated ID for this line item.

**line\_items\[].product** `object`

Product information for this line item.

**line\_items\[].product.reference\_line\_item\_id** `string`

Echo of the `reference_line_item_id` you sent.

**line\_items\[].product.reference\_product\_id** `string`

The product ID in your system. `default-<category>` when the line was sent with `product_category`.

**line\_items\[].product.reference\_product\_name** `string`

The name of the product.

**line\_items\[].product.product\_tax\_code** `string`

The product category used to decide taxability.

**line\_items\[].tax\_jurisdictions** `array of objects`

One row per taxing jurisdiction.

**line\_items\[].tax\_jurisdictions\[].tax\_rate** `number`

Statutory rate for the jurisdiction, as a decimal fraction (`0.029` = 2.9%). Doesn't include flat fees.

**line\_items\[].tax\_jurisdictions\[].tax\_due\_decimal** `number`

Unrounded tax due for this jurisdiction, in the currency's smallest unit.

**line\_items\[].tax\_jurisdictions\[].fee\_amount** `number`

Flat fee charged by this jurisdiction, in the currency's smallest unit.

**line\_items\[].tax\_jurisdictions\[].rate\_type** `string`

Name of the tax, e.g. `GENERAL STATE SALES TAX`.

**line\_items\[].tax\_jurisdictions\[].tax\_authority\_name** `string`

Taxing jurisdiction, e.g. `Colorado` or `Adams`.

**line\_items\[].tax\_jurisdictions\[].tax\_authority\_type** `string`

Type of authority. Often empty.

**line\_items\[].tax\_jurisdictions\[].tax\_type** `enum`

`SALES`, `USE`, `VAT`, or `GST`.

**line\_items\[].tax\_jurisdictions\[].note** `string`

**New in 2026-11-01.** Why this row came out the way it did. Empty string for normally calculated tax. See [Notes](https://docs.numeral.com/v2026-11-01/objects/calculations.md#notes) for every value.

**line\_items\[].tax\_amount** `integer`

Tax for this line item, in the currency's smallest unit.

**line\_items\[].amount\_excluding\_tax** `integer`

Line amount before tax (`amount × quantity`).

**line\_items\[].amount\_including\_tax** `integer`

`amount_excluding_tax + tax_amount`.

**line\_items\[].quantity** `number`

Echo of the quantity you sent.

**fee\_line\_items** `array of objects`

Tax on your platform fees, one entry per line item in `fee_details`. Same fields as `line_items`, including `note` on every `tax_jurisdictions` row. Taxed where the merchant is, because the merchant pays the fee. Only present when `fee_details` is sent.

**totals** `object`

Totals for the order and for the fees, kept separate.

**totals.order** `object`

Totals for `line_items`.

**totals.order.tax\_amount** `integer`

Total tax on the order, in the currency's smallest unit.

**totals.order.amount\_excluding\_tax** `integer`

Order total excluding tax.

**totals.order.amount\_including\_tax** `integer`

Order total including tax.

**totals.order.currency** `string`

ISO 4217 currency code.

**totals.order.effective\_tax\_rate** `number`

**New in 2026-11-01.** `tax_amount / amount_excluding_tax` for the order, as a decimal fraction (`0.085` = 8.5%), up to 6 decimal places. Includes flat fees. `0` when nothing is taxed. See [Effective tax rate](https://docs.numeral.com/v2026-11-01/objects/calculations.md#effective-tax-rate).

**totals.fees** `object`

Totals for `fee_line_items`, with the same fields as `totals.order`. Its `effective_tax_rate` covers the fees only. Only present when `fee_details` is sent.

**location\_source** `enum`

`address` or `ip`: which input set the location.

**resolution\_precision** `enum`

`STREET`, `POSTAL_PLUS`, `POSTAL`, `PROVINCE`, `COUNTRY`, or `APPROXIMATED`.

**address\_used** `object`

The customer address the order was taxed for. Populated even when the location came from an IP.

**address\_used.address\_line\_1** `string`

**address\_used.address\_line\_2** `string`

**address\_used.address\_city** `string`

**address\_used.address\_province** `string`

ISO 3166-2 subdivision code.

**address\_used.address\_postal\_code** `string`

**address\_used.address\_country** `string`

ISO 3166-1 alpha-2 country code.

> [!NOTE]
>
> There's no combined order-plus-fees rate. The order and the fees are taxed in different places, so their rows often come from two different states. In the example, the order is taxed in Colorado (the customer) and the fee in California (the merchant).

```json The Platform calculation object theme={null}
{
  "testmode": true,
  "id": "plat_calc_1793039301789",
  "object": "tax.platform_calculation",
  "customer_currency_code": "USD",
  "customer": {
    "type": "CONSUMER"
  },
  "merchant": {
    "merchant_id": "mer_1781234567890"
  },
  "roles": ["marketplace_provider"],
  "line_items": [
    {
      "line_item_id": "li_1793039301701",
      "product": {
        "reference_line_item_id": "goods",
        "reference_product_id": "default-general-merchandise",
        "reference_product_name": "Default GENERAL_MERCHANDISE Product",
        "product_tax_code": "GENERAL_MERCHANDISE"
      },
      "tax_jurisdictions": [
        {
          "tax_rate": 0.029,
          "tax_due_decimal": 290,
          "fee_amount": 0,
          "rate_type": "GENERAL STATE SALES TAX",
          "tax_authority_name": "Colorado",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0.0075,
          "tax_due_decimal": 75,
          "fee_amount": 0,
          "rate_type": "GENERAL COUNTY LOCAL SALES TAX",
          "tax_authority_name": "Adams",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0.0375,
          "tax_due_decimal": 375,
          "fee_amount": 0,
          "rate_type": "GENERAL CITY LOCAL SALES TAX",
          "tax_authority_name": "Thornton",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0.01,
          "tax_due_decimal": 100,
          "fee_amount": 0,
          "rate_type": "GENERAL DISTRICT LOCAL SALES TAX",
          "tax_authority_name": "Colorado Regional Transportation District",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0.001,
          "tax_due_decimal": 10,
          "fee_amount": 0,
          "rate_type": "GENERAL DISTRICT LOCAL SALES TAX",
          "tax_authority_name": "Colorado Scientific and Cultural Facilities District",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        }
      ],
      "tax_amount": 850,
      "amount_excluding_tax": 10000,
      "amount_including_tax": 10850,
      "quantity": 1
    }
  ],
  "fee_line_items": [
    {
      "line_item_id": "li_1793039301702",
      "product": {
        "reference_line_item_id": "fee",
        "reference_product_id": "default-saas-general",
        "reference_product_name": "Default SAAS_GENERAL Product",
        "product_tax_code": "SAAS_GENERAL"
      },
      "tax_jurisdictions": [
        {
          "tax_rate": 0,
          "tax_due_decimal": 0,
          "fee_amount": 0,
          "rate_type": "EXEMPT STATE SALES TAX",
          "tax_authority_name": "California",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0,
          "tax_due_decimal": 0,
          "fee_amount": 0,
          "rate_type": "EXEMPT COUNTY LOCAL SALES TAX",
          "tax_authority_name": "Sacramento",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        },
        {
          "tax_rate": 0,
          "tax_due_decimal": 0,
          "fee_amount": 0,
          "rate_type": "EXEMPT CITY LOCAL SALES TAX",
          "tax_authority_name": "Sacramento",
          "tax_authority_type": "",
          "tax_type": "SALES",
          "note": ""
        }
      ],
      "tax_amount": 0,
      "amount_excluding_tax": 1000,
      "amount_including_tax": 1000,
      "quantity": 1
    }
  ],
  "totals": {
    "order": {
      "tax_amount": 850,
      "amount_excluding_tax": 10000,
      "amount_including_tax": 10850,
      "currency": "USD",
      "effective_tax_rate": 0.085
    },
    "fees": {
      "tax_amount": 0,
      "amount_excluding_tax": 1000,
      "amount_including_tax": 1000,
      "currency": "USD",
      "effective_tax_rate": 0
    }
  },
  "location_source": "address",
  "resolution_precision": "STREET",
  "address_used": {
    "address_line_1": "9500 Civic Center Drive",
    "address_city": "Thornton",
    "address_province": "CO",
    "address_postal_code": "80229",
    "address_country": "US"
  }
}
```

## Create a platform calculation

Quotes tax for an order and, optionally, your platform fees on it. Send `X-API-Version` on every request. [Try it in the API reference](https://docs.numeral.com/api-reference/v2026-11-01/endpoint/platform_calculations).

### Parameters

**customer** `object` *required*

Who is buying. At least one of `customer.address` or `customer.ip` is required.

**customer.address** `object`

The customer's address. The order is taxed here.

**customer.address.address\_line\_1** `string`

**customer.address.address\_line\_2** `string`

**customer.address.address\_city** `string`

**customer.address.address\_province** `string`

ISO 3166-2 subdivision code.

**customer.address.address\_postal\_code** `string`

**customer.address.address\_country** `string`

ISO 3166-1 alpha-2 country code.

**customer.address.address\_type** `enum`

`shipping` or `billing`.

**customer.ip** `object`

IP address for location lookup when you don't have a full address. See [IP-based tax resolution](https://docs.numeral.com/v2026-11-01/objects/calculations.md#ip-based-tax-resolution).

**customer.ip.value** `string` *required*

A valid IPv4 or IPv6 address.

**customer.ip.resolution** `enum` (default: strict)

What to do when the IP can't be resolved precisely enough: `strict`, `zero`, `approximate`, or `best_effort`. Numeral strongly recommends `strict` to stay as compliant as possible.

**customer.id** `string`

The `cust_…` ID or your own reference ID of a [customer](https://docs.numeral.com/v2026-11-01/objects/customers.md) you created in Numeral. Applies the customer's exemptions to the order: a tax-exempt customer gets zero tax, and exemption certificates on file apply for the destination jurisdiction. Not applied to `fee_details`, whose buyer is the merchant.

**customer.type** `enum` (default: CONSUMER)

`CONSUMER` or `BUSINESS`.

**customer.tax\_ids** `array of objects`

Tax IDs for business sales. Each has `type` (e.g. `gb_vat`) and `value`. See [tax IDs](https://docs.numeral.com/essentials/tax-ids.md).

**merchant** `object` *required*

The seller. See [Merchants](https://docs.numeral.com/v2026-11-01/objects/merchants.md).

**merchant.merchant\_id** `string` *required*

The merchant's `id` (`merch_…`) or your `reference_merchant_id`.

**merchant.type** `enum` (default: BUSINESS)

`BUSINESS` or `INDIVIDUAL`.

**merchant.tax\_ids** `array of objects`

Overrides the merchant's stored tax IDs for this calculation.

**order\_details** `object` *required*

The order. Taxed where the customer is.

**order\_details.customer\_currency\_code** `string` *required*

ISO 4217 currency code. See [supported currencies](https://docs.numeral.com/essentials/currencies.md).

**order\_details.tax\_included\_in\_amount** `boolean` *required*

Whether line item amounts already include tax.

**order\_details.automatic\_tax** `enum` *required*

* `auto` returns real rates only where you have an active tax registration, and 0 elsewhere.
* `disabled` always returns 0.
* `forced` returns real destination rates whatever your own registrations are. Use it as a payment processor to show the rates the merchant would owe. Only valid when `roles` is exactly `["payment_processor"]`. Customer exemptions, reverse charge and business rules still apply.

For US customer addresses, must be `auto` or `forced`.

**order\_details.line\_items** `array of objects` *required*

One entry per product.

**order\_details.line\_items\[].amount** `integer` *required*

**Per-unit** price in the currency's smallest unit. For a \$25.00 item, send `2500`. Taxable base is `amount × quantity`.

**order\_details.line\_items\[].quantity** `integer` *required*

Number of units.

**order\_details.line\_items\[].product\_category** `string`

Tax category from the [category list](https://docs.numeral.com/essentials/product-categories.md), e.g. `GENERAL_MERCHANDISE`.

**order\_details.line\_items\[].reference\_product\_id** `string`

Your product ID, as created in Numeral.

**order\_details.line\_items\[].reference\_line\_item\_id** `string`

Your line item ID, echoed back.

**roles** `array of enums` *required*

Your role in this sale. One or more of:

* `marketplace_provider`: you run a marketplace that connects buyers and sellers.
* `payment_processor`: you process the payment.
* `merchant_of_record`: you're the legal seller of record.

Roles also decide how many transactions [Create platform transactions](#create-platform-transactions) records.

**fee\_details** `object`

Your platform fees, taxed separately from the order. Taxed where the merchant is, because the merchant pays the fee. Same shape as `order_details`.

**fee\_details.customer\_currency\_code** `string` *required*

ISO 4217 currency code.

**fee\_details.tax\_included\_in\_amount** `boolean` *required*

Whether fee amounts already include tax.

**fee\_details.automatic\_tax** `enum` *required*

`auto` or `disabled`. `forced` isn't allowed: the fee is your own sale to the merchant, so your own registrations apply.

**fee\_details.line\_items** `array of objects` *required*

One entry per fee, with the same fields as `order_details.line_items`. `amount` is per unit.

**transacted\_at** `integer`

When the sale happened, Unix **seconds**. Rates and rules, such as sales tax holidays, are evaluated as of this time. Defaults to now.

**default\_customer\_type** `enum`

`CONSUMER` or `BUSINESS`. Used when `customer.id` isn't found in Numeral, instead of returning an error. Lets you always send a customer ID without creating the customer first. If the customer is found, its exemptions apply as normal.

### Returns

A [Platform calculation object](#the-platform-calculation-object).

```bash POST /tax/platform/calculations theme={null}
curl https://api.numeralhq.com/tax/platform/calculations \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Version: 2026-11-01' \
  -d '{
    "customer": {
      "type": "CONSUMER",
      "address": {
        "address_line_1": "9500 Civic Center Drive",
        "address_city": "Thornton",
        "address_province": "CO",
        "address_postal_code": "80229",
        "address_country": "US"
      }
    },
    "merchant": {
      "merchant_id": "mer_1781234567890",
      "type": "BUSINESS"
    },
    "order_details": {
      "customer_currency_code": "USD",
      "tax_included_in_amount": false,
      "automatic_tax": "auto",
      "line_items": [
        {
          "reference_line_item_id": "goods",
          "product_category": "GENERAL_MERCHANDISE",
          "amount": 10000,
          "quantity": 1
        }
      ]
    },
    "roles": ["marketplace_provider"],
    "fee_details": {
      "customer_currency_code": "USD",
      "tax_included_in_amount": false,
      "automatic_tax": "auto",
      "line_items": [
        {
          "reference_line_item_id": "fee",
          "product_category": "SAAS_GENERAL",
          "amount": 1000,
          "quantity": 1
        }
      ]
    }
  }'
```

```json Response theme={null}
{
  "id": "plat_calc_1793039301789",
  "object": "tax.platform_calculation",
  "totals": {
    "order": {
      "tax_amount": 850,
      "amount_excluding_tax": 10000,
      "amount_including_tax": 10850,
      "currency": "USD",
      "effective_tax_rate": 0.085
    },
    "fees": {
      "tax_amount": 0,
      "amount_excluding_tax": 1000,
      "amount_including_tax": 1000,
      "currency": "USD",
      "effective_tax_rate": 0
    }
  },
  "...": "see The Platform calculation object"
}
```

## Create platform transactions

Records the sale from a platform calculation once the customer pays. Numeral uses it for reporting and filing. [Try it in the API reference](https://docs.numeral.com/api-reference/v2026-11-01/endpoint/platform_transactions).

How many transactions are created depends on the `roles` in the calculation:

| Role | Order transaction | Fee transaction |
| - | - | - |
| `payment_processor` | Yes, `client_role: ["payment_processor"]` | Yes, separate, `client_role: []` |
| `marketplace_provider` | Yes, `client_role: ["marketplace_provider"]` | No |
| `merchant_of_record` | Yes, `client_role: ["merchant_of_record"]` | No |

Payment processors get two transactions, so the fee's tax is reported separately from the order's. Marketplace providers and merchants of record get one transaction. Fee tax, if calculated, is included in it.

### Parameters

**platform\_calculation\_id** `string` *required*

The `id` of the platform calculation to record.

**reference\_order\_id** `string` *required*

Your unique ID for this order.

**reference\_payment\_id** `string`

Your ID for the payment.

**transaction\_processed\_at** `integer`

When the sale was processed, as a Unix timestamp.

### Returns

An object with `object: "list"` and a `transactions` array: two transactions for payment processors, one otherwise.

**transactions** `array of objects`

The transactions created.

**transactions\[].id** `string`

The ID of the transaction, `tr_…`.

**transactions\[].object** `string, value is "tax.transaction"`

String representing the object's type.

**transactions\[].calculation\_id** `string`

The platform calculation this transaction was created from.

**transactions\[].reference\_order\_id** `string`

Your order ID, as sent.

**transactions\[].type** `enum`

`order` for the sale, or `fee` for the platform fee. `fee` transactions are created for payment processors only.

**transactions\[].client\_role** `array of strings`

Your role for this transaction. Empty on `fee` transactions.

**transactions\[].merchant** `object`

The merchant on the sale.

**transactions\[].merchant.id** `string`

The merchant's `id`.

**transactions\[].merchant.reference\_merchant\_id** `string`

Your reference ID for the merchant.

**transactions\[].testmode** `boolean`

`true` if made with a test API key.

```bash POST /tax/platform/transactions theme={null}
curl https://api.numeralhq.com/tax/platform/transactions \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Version: 2026-11-01' \
  -d '{
    "platform_calculation_id": "plat_calc_abc123",
    "reference_order_id": "order_12345",
    "reference_payment_id": "pay_67890",
    "transaction_processed_at": 1736300000
  }'
```

```json Payment processor theme={null}
{
  "object": "list",
  "transactions": [
    {
      "id": "tr_abc123",
      "object": "tax.transaction",
      "calculation_id": "plat_calc_abc123",
      "reference_order_id": "order_12345",
      "type": "order",
      "client_role": ["payment_processor"],
      "merchant": {
        "id": "merch_abc123",
        "reference_merchant_id": "my-seller-123"
      },
      "testmode": false
    },
    {
      "id": "tr_def456",
      "object": "tax.transaction",
      "calculation_id": "plat_calc_abc123",
      "reference_order_id": "order_12345",
      "type": "fee",
      "client_role": [],
      "merchant": {
        "id": "merch_abc123",
        "reference_merchant_id": "my-seller-123"
      },
      "testmode": false
    }
  ]
}
```

```json Marketplace provider theme={null}
{
  "object": "list",
  "transactions": [
    {
      "id": "tr_abc123",
      "object": "tax.transaction",
      "calculation_id": "plat_calc_abc123",
      "reference_order_id": "order_12345",
      "type": "order",
      "client_role": ["marketplace_provider"],
      "merchant": {
        "id": "merch_abc123",
        "reference_merchant_id": "my-seller-123"
      },
      "testmode": false
    }
  ]
}
```

## Errors

Errors return `code`, `type`, and `message`. Handle them by `type`. Full list in [Error Codes](https://docs.numeral.com/api-reference/v2026-11-01/error-codes.md).

| HTTP | `type` | When |
| - | - | - |
| 400 | `MISSING_FIELD` | A required field is missing. |
| 400 | `INCORRECT_TYPE` | A field has the wrong type. |
| 400 | `UNRECOGNIZED_FIELD` | An unknown field was sent. |
| 400 | `INVALID_IP_FORMAT` | `customer.ip.value` isn't a valid IPv4 or IPv6 address. |
| 404 | `MERCHANT_NOT_FOUND` | `merchant.merchant_id` doesn't exist, was deleted, or belongs to the other environment (test or live). |
| 404 | `CUSTOMER_NOT_FOUND` | `customer.id` doesn't exist and no `default_customer_type` was sent. |
| 404 | `CALCULATION_NOT_FOUND` | `platform_calculation_id` doesn't exist. |
| 422 | `IP_RESOLUTION_FAILED` | IP couldn't be resolved to a country (`strict` mode). |
| 422 | `IP_RESOLUTION_INSUFFICIENT_US` | IP resolved to a US state but no postal code. |
| 422 | `IP_RESOLUTION_INSUFFICIENT_CA` | IP resolved to Canada but no province. |

```json 404 customer theme={null}
{
  "code": 404,
  "type": "CUSTOMER_NOT_FOUND",
  "message": "Unable to find customer with ID: my-buyer-456 in test environment."
}
```

```json 404 calculation theme={null}
{
  "code": 404,
  "type": "CALCULATION_NOT_FOUND",
  "message": "Platform calculation not found"
}
```

```json 422 theme={null}
{
  "code": 422,
  "type": "IP_RESOLUTION_FAILED",
  "message": "Unable to resolve IP address to a country. Please provide a full address in customer.address."
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.