# Creates several account determination rules in one call.

`POST /inventory/account-determination-rules/bulk`

Group: Inventory › Account Determination Rules · Operation ID: `bulkCreateAccountDeterminationRules`

All or nothing. Every entry is checked before any is written, so one rejected entry leaves the store untouched and the whole call fails. The duplicate check compares the entries against each other as well as against stored rules, so two entries pinning the same combination within one entity collide. The response is the created rules in the same order as the input. Use POST inventory/account-determination-rules to create a single rule.

[Open in the interactive reference](https://docs.api.lensing.ai/?op=bulkCreateAccountDeterminationRules)

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | `"v1"` | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |
| `Idempotency-Key` | header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with `400 IDEMPOTENCY_NOT_SUPPORTED` rather than silently ignored. |

## Request body

Required, `application/json`: bulkCreateAccountDeterminationRulesInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `accountDeterminationRules` | array of object | yes | The rules to create, each with its dimensions, accounts and overrides. If any entry is invalid, nothing is created and the whole call fails. |
| `accountDeterminationRules[].ruleName` | string | yes | A free-text label for the rule. Required. It is not unique and is never read when matching. It names the rule in a duplicate error and in the application. |
| `accountDeterminationRules[].priority` | number | no | The tie-breaker between rules of equal specificity. The lower number wins. An omitted priority counts as 0, which outranks any positive value, so set it on every rule when precedence matters. |
| `accountDeterminationRules[].isActive` | boolean | no | Whether the rule takes part in account determination. Defaults to true. |
| `accountDeterminationRules[].matching` | object | yes | The dimensions this rule is pinned to. Omitting a dimension makes the rule match every value of it. Only one rule per entity may hold a given combination of transaction type, item type, item category and location. |
| `accountDeterminationRules[].matching.entityId` | string | yes | The legal entity this rule belongs to. Required. See id on GET base/entities. Matching and the duplicate check are both scoped to it, so a posting only ever sees rules of its own entity. |
| `accountDeterminationRules[].matching.bookId` | string | no | The accounting book this rule is pinned to. See id on GET accounting/books/:id. Omit to leave the rule matching every value of this dimension. |
| `accountDeterminationRules[].matching.itemTypeId` | string | no | The item type this rule is pinned to. See id on GET inventory/item-types/:id. Omit to leave the rule matching every value of this dimension. |
| `accountDeterminationRules[].matching.itemCategoryId` | string | no | The item category this rule is pinned to. See id on GET inventory/item-categories/:id. Omit to leave the rule matching every value of this dimension. |
| `accountDeterminationRules[].matching.locationId` | string | no | The warehouse location this rule is pinned to. See id on GET inventory/warehouses/:id. Omit to leave the rule matching every value of this dimension. |
| `accountDeterminationRules[].matching.inventoryLocationType` | string | no | An advisory classification of the location. It is stored on the rule and never read when matching, so it does not affect which rule the posting selects. Omit for none. |
| `accountDeterminationRules[].matching.transactionTypeContext` | string, one of `"RECEIPT"`, `"SHIPMENT"`, `"SALES_RETURN"`, `"SALES_INVOICE"`, `"SALES_CREDIT_MEMO"`, `"PURCHASE_RETURN"`, `"PURCHASE_INVOICE"`, `"PURCHASE_CREDIT_MEMO"`, `"INVENTORY_INCREASE"`, `"INVENTORY_DECREASE"`, `"INVENTORY_REVALUATION"`, `"WAREHOUSE_TRANSFER"`, `"INTERCOMPANY_TRANSFER"`, `"DEFAULT"` | no | The document kind this rule is pinned to. Passing DEFAULT and omitting the field are equivalent: both make the rule match every transaction type. WAREHOUSE_TRANSFER and INTERCOMPANY_TRANSFER are the kinds used for transfer postings. |
| `accountDeterminationRules[].accounts` | object | no | The GL accounts this rule assigns. Every one is optional. Leave one unassigned and the rule does not decide that posting, so a less specific rule does. |
| `accountDeterminationRules[].accounts.inventoryAssetAccountId` | string | no | The account for inventory value on the balance sheet. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.cogsAccountId` | string | no | The cost of goods sold account. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.cogsClearingAccountId` | string | no | The cost of goods sold clearing account. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.deferredCogsAccountId` | string | no | The deferred cost of goods sold account. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.salesRevenueAccountId` | string | no | The sales revenue account. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.salesReturnAccountId` | string | no | The sales return account. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.salesStockInTransitAccountId` | string | no | The sales stock-in-transit account. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.grniClearingAccountId` | string | no | The goods-received-not-invoiced clearing account, for inventory items. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.grncClearingAccountId` | string | no | The goods-returned-not-credited clearing account. It is the offset leg booked on purchase returns and credit memos. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.servicesReceivedNotInvoicedAccountId` | string | no | The clearing account for services received but not yet invoiced, for non-inventory items. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.expenseAccountId` | string | no | The expense account for non-inventory items and description lines. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.purchasePriceVarianceAccountId` | string | no | The purchase price variance account, under standard costing. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.inventoryAdjustmentGainAccountId` | string | no | The account for positive inventory count and adjustment differences. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.inventoryAdjustmentLossAccountId` | string | no | The account for negative inventory count and adjustment differences. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.revaluationGainAccountId` | string | no | The account for gains from inventory revaluation. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.revaluationLossAccountId` | string | no | The account for losses from inventory revaluation. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.soldQuantitiesRevaluationAccountId` | string | no | The account for the revaluation of quantities already sold. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.purchaseReturnVarianceGainAccountId` | string | no | The account for gains on purchase returns. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.purchaseReturnVarianceLossAccountId` | string | no | The account for losses on purchase returns. See id on GET accounting/accounts/:id. It can be overridden per reason code. Omit to leave it unassigned. |
| `accountDeterminationRules[].accounts.fxRateDiffAccountId` | string | no | The account that absorbs FX rate differences between receipt and invoice posting. See id on GET accounting/accounts/:id. Omit to leave it unassigned. |
| `accountDeterminationRules[].reasonCodeOverrides` | array of object | no | The per-reason-code account overrides. When a document line uses one of these reason codes, its account replaces the rule account named by parentAccountType. |
| `accountDeterminationRules[].reasonCodeOverrides[].reasonCodeId` | string | yes | The reason code that triggers this override. See id on GET inventory/reason-codes/:id. |
| `accountDeterminationRules[].reasonCodeOverrides[].accountId` | string | yes | The account to post instead of the rule account. See id on GET accounting/accounts/:id. |
| `accountDeterminationRules[].reasonCodeOverrides[].parentAccountType` | string, one of `"inventoryAdjustmentGainAccount"`, `"inventoryAdjustmentLossAccount"`, `"salesReturnAccount"`, `"purchaseReturnVarianceGainAccount"`, `"purchaseReturnVarianceLossAccount"`, `"grncClearingAccount"` | yes | Which rule account this override replaces. Only six of the twenty accounts can be overridden. |

Example:

```json
{
  "accountDeterminationRules": [
    {
      "ruleName": "Finished goods — receipts",
      "priority": 10,
      "matching": {
        "entityId": "81e8beb1-1415-4012-9012-8138580f43dc",
        "itemCategoryId": "a2f47b91-0c6d-4e38-95b1-7d3e6a428c50",
        "transactionTypeContext": "RECEIPT"
      },
      "accounts": {
        "inventoryAssetAccountId": "1c9e4b07-52da-4f38-9016-3b7e05c2a94f",
        "grniClearingAccountId": "4f0b7d29-6e13-4a85-b2c7-90d1f83e6a52"
      }
    }
  ]
}
```

## Response

`200` Success

Under `data` (bulkCreateAccountDeterminationRulesOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `created` | array of object | yes | The created rules, in the same order as the input. Match entries to inputs by index. |
| `created[].id` | string | yes | The unique identifier for the created rule. |

## Response headers

- `Idempotency-Replayed` — Present and `true` only when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent as `false`.

## Errors

| Code | Status |
| --- | --- |
| `REFERENCE_NOT_FOUND` | 400 |
| `DUPLICATE_RULE_TUPLE` | 400 |
| `UNKNOWN_PARENT_ACCOUNT_TYPE` | 400 |
| `IDEMPOTENCY_KEY_CONFLICT` | 409 |
| `IDEMPOTENCY_PAYLOAD_MISMATCH` | 422 |

## Statuses

- `400` — Invalid request or business failure. Codes: REFERENCE_NOT_FOUND, DUPLICATE_RULE_TUPLE, UNKNOWN_PARENT_ACCOUNT_TYPE
- `401` — Missing or invalid access token
- `403` — Not authorized
- `404` — Not found
- `409` — The Idempotency-Key is still being processed by another request.
- `422` — The Idempotency-Key was already used with a different request payload.
- `429` — Too many requests
- `500` — Internal server error
