Dimensions

Managing chart of accounts and accounting dimensions

Overview

In accounting systems, financial transactions must be properly categorized for reporting and compliance. Transactions are assigned to GL accounts, departments, locations, projects, and other organizational segments based on a company’s accounting rules.

Ottimate represents these transaction classifications through dimensions. Each dimension links an Ottimate record to a corresponding entity in the client’s ERP/accounting system.

Key Characteristics:

  • Dimensions are company-specific - each company maintains its own set of dimensions
  • Dimensions must be synced from your ERP before invoices can be properly coded
  • The erp_dimension_id links Ottimate dimensions to your accounting system
  • Dimensions can be applied at both invoice header and line item level

Dimension Fields

Response Fields

FieldTypeDescription
idstringOttimate-assigned ID (e.g., dim_VOH21Up3M7HV)
namestringDimension name (e.g., “Food Cost”, “Marketing Department”)
erp_typestringThe dimension category label as displayed in your ERP (e.g., “Account”, “Department”). Client-specific — varies by accounting software.
ottimate_typestringOttimate’s standardized dimension type code (e.g., “account”, “department”)
codestringThe GL code or short identifier for this dimension in your ERP
reference_idstringA unique identifier that tracks this dimension across client systems (ERP, inventory management, Ottimate). Used for upsert matching on the bulk endpoint.
erp_dimension_idstringIdentifier from your ERP/accounting system
ottimate_company_idintegerCompany this dimension belongs to

Creation Fields

All fields below are required on both POST /v1/dimensions and POST /v1/dimensions/bulk.

FieldRequiredDescription
ottimate_company_idYesCompany ID this dimension belongs to
erp_typeYesDisplay type name as shown in your ERP (e.g., “Department”)
ottimate_typeYesOttimate’s standardized dimension type code (e.g., “department”)
nameYesDimension name
codeYesShort code (e.g., “MKT”, “5000”)
reference_idYesUnique identifier for upsert matching
erp_dimension_idYesIdentifier from your ERP/accounting system

Supported Dimension Types

The following dimension types are supported. The table shows equivalent entities across common ERP systems.

GL Account (account)

Classifies how a transaction will be recorded in the general ledger.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
accountAccountGL AccountGLAccountAccountAccount

Example:

1{
2 "id": "dim_VOH21Up3M7HV",
3 "name": "Food Cost",
4 "erp_type": "Account",
5 "code": "5000",
6 "reference_id": "acct-food-cost-001",
7 "ottimate_type": "account",
8 "erp_dimension_id": "5000",
9 "ottimate_company_id": 123
10}

Location (location)

Represents geographic locations like offices, facilities, or warehouses.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
locationLocationLocationLocationBranch/Location

Department (department)

Represents internal business units or functions.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
departmentDepartmentDepartmentDepartmentSubaccountDepartment

Project (project)

Tracks transactions related to a specific initiative, job, or capital effort.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
projectJobProjectJobProject

Task (task)

Represents specific tasks within a project.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
taskTaskCost Code

Cost Type (cost_type)

Categorizes different types of costs within projects.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
cost_typeCost TypeCost Code

Item (item)

Represents goods and services purchased from vendors.

Dimension TypeNetSuiteIntacctBusiness CentralAcumaticaQuickBooks Online
itemItemItemItemStockItemItem

Sync Patterns

Ottimate-Hosted ERP Integrations

When you use an Ottimate-hosted integration (e.g., QuickBooks, NetSuite, Sage), Ottimate automatically syncs dimensions from your ERP:

  • Initial sync happens during onboarding
  • Ongoing sync keeps dimensions updated automatically
  • No API calls needed - dimension management is handled by the integration

In this scenario, you primarily use the Dimensions API to read dimension data for reference or validation.

Custom ERP Integrations

If you’re building a custom integration with an unsupported ERP, you’re responsible for syncing dimensions:

  1. Extract dimension data from your ERP (chart of accounts, departments, etc.)
  2. Transform to Ottimate’s dimension format
  3. Load via the Dimensions API (POST /v1/dimensions or POST /v1/dimensions/bulk)
  4. Maintain ongoing sync as dimensions are added/updated in your ERP

Keep dimension data consistent between Ottimate and your ERP. Mismatched dimension IDs can cause issues during invoice export.


API Operations

List Dimensions

Retrieve all dimensions for a company, optionally filtered by ERP type:

$GET /v1/dimensions?ottimate_company_id=123&erp_type=Account

Response:

1{
2 "version": "1.0.0",
3 "count": 100,
4 "page": 1,
5 "limit": 20,
6 "dimensions": [
7 {
8 "id": "dim_VOH21Up3M7HV",
9 "name": "Food Cost",
10 "erp_type": "Account",
11 "code": "5000",
12 "reference_id": "acct-food-cost-001",
13 "ottimate_type": "account",
14 "erp_dimension_id": "5000",
15 "ottimate_company_id": 123
16 },
17 {
18 "id": "dim_XKL45Qp8N2RT",
19 "name": "Beverage Cost",
20 "erp_type": "Account",
21 "code": "5100",
22 "reference_id": "acct-beverage-cost-001",
23 "ottimate_type": "account",
24 "erp_dimension_id": "5100",
25 "ottimate_company_id": 123
26 }
27 ]
28}

Add detail=basic to shorten each item in the dimensions array to just id, name, erp_dimension_id, and erp_typecode, reference_id, ottimate_type, and ottimate_company_id are omitted. Use this when you only need enough information to display or match a dimension, not to re-submit it.

Get Single Dimension

Retrieve a specific dimension by ID:

$GET /v1/dimensions/dim_VOH21Up3M7HV

Response:

1{
2 "version": "1.0.0",
3 "success": true,
4 "dimension": {
5 "id": "dim_VOH21Up3M7HV",
6 "name": "Food Cost",
7 "erp_type": "Account",
8 "code": "5000",
9 "reference_id": "acct-food-cost-001",
10 "ottimate_type": "account",
11 "erp_dimension_id": "5000",
12 "ottimate_company_id": 123
13 }
14}

Create Single Dimension

Create a new dimension. All fields shown below are required — including code.

$POST /v1/dimensions
$Content-Type: application/json
$
${
> "ottimate_company_id": 123,
> "erp_type": "Department",
> "ottimate_type": "department",
> "name": "Marketing Department",
> "code": "MKT",
> "reference_id": "dept-mkt-001",
> "erp_dimension_id": "DEPT-MKT-001"
>}

Response (200 OK):

1{
2 "version": "1.0.0",
3 "dimension": {
4 "id": "dim_ABC12345XYZ",
5 "name": "Marketing Department",
6 "erp_type": "Department",
7 "code": "MKT",
8 "reference_id": "dept-mkt-001",
9 "ottimate_type": "department",
10 "erp_dimension_id": "DEPT-MKT-001",
11 "ottimate_company_id": 123
12 }
13}

The created object is returned nested under a dimension key, matching the shape of the get-single-dimension response. There is no created_date or other timestamp field in the response.

Single-create does not upsert. Unlike the bulk endpoint, POST /v1/dimensions rejects a request whose reference_id + erp_type combination already exists for the company, with a 400 response:

1{
2 "message": {
3 "detail": ["A dimension with reference_id 'dept-mkt-001' and erp_type 'Department' already exists."]
4 }
5}

To update an existing dimension, use the bulk endpoint below (which upserts by reference_id + erp_type).

Bulk Create/Update Dimensions

Create or update multiple dimensions in a single request. This endpoint uses upsert behavior - existing dimensions (matched by reference_id + erp_type) are updated, new dimensions are created. This is different from single-create (POST /v1/dimensions), which rejects duplicates instead of updating them — see the note above.

$POST /v1/dimensions/bulk
$Content-Type: application/json
$
${
> "ottimate_company_id": 123,
> "dimensions": [
> {
> "erp_type": "Department",
> "ottimate_type": "department",
> "name": "Operations Department",
> "code": "OPS",
> "reference_id": "dept-ops-001",
> "erp_dimension_id": "DEPT-OPS-001"
> },
> {
> "erp_type": "Department",
> "ottimate_type": "department",
> "name": "Finance Department",
> "code": "FIN",
> "reference_id": "dept-fin-001",
> "erp_dimension_id": "DEPT-FIN-001"
> }
> ]
>}

Response (200 OK):

1{
2 "version": "1.0.0",
3 "success_count": 3,
4 "created_count": 2,
5 "updated_count": 1,
6 "fail_count": 0,
7 "created": [
8 {
9 "id": "dim_DEF67890ABC",
10 "ottimate_company_id": 123,
11 "ottimate_type": "department",
12 "name": "Operations Department",
13 "code": "OPS",
14 "erp_type": "Department",
15 "reference_id": "dept-ops-001",
16 "erp_dimension_id": "DEPT-OPS-001"
17 },
18 {
19 "id": "dim_GHI11223DEF",
20 "ottimate_company_id": 123,
21 "ottimate_type": "department",
22 "name": "Finance Department",
23 "code": "FIN",
24 "erp_type": "Department",
25 "reference_id": "dept-fin-001",
26 "erp_dimension_id": "DEPT-FIN-001"
27 }
28 ],
29 "updated": [
30 {
31 "id": "dim_VOH21Up3M7HV",
32 "ottimate_company_id": 123,
33 "ottimate_type": "account",
34 "name": "Food Cost (Updated)",
35 "code": "5000",
36 "erp_type": "Account",
37 "reference_id": "acct-food-cost-001",
38 "erp_dimension_id": "5000"
39 }
40 ],
41 "failures": []
42}

created and updated each carry the full dimension object (the same fields as the single-create response), not just id and name.

Validation is all-or-nothing. If any item in the dimensions array is missing a required field or has a type that can’t be resolved, the entire request is rejected with 400 Bad Request and no dimensions are created or updated — not even the valid ones. For example, omitting code on one item out of ten fails the whole batch:

1{
2 "message": {
3 "dimensions": [{}, {}, {"code": ["This field is required."]}]
4 }
5}

fail_count / failures in a 200 response are reserved for the rare case where an individual item passes validation but fails during the write itself (for example, a record-level conflict). Because validation is checked up front for every item, this happens far less often than the all-or-nothing case above — plan for the 400 case first.


Using Dimensions in Invoices

Dimensions are applied to invoices and line items to categorize transactions for proper GL coding.

Invoice Header Dimensions: Used for header-level coding that applies to the entire invoice (e.g., department, location).

Line Item Dimensions: Used for item-level coding when different line items should be coded to different accounts.

1{
2 "ottimate_company_id": 123,
3 "ottimate_location_id": 456,
4 "ottimate_vendor_id": 789,
5 "invoice_number": "INV-001",
6 "dimensions": {
7 "Department": "DEPT-MKT-001",
8 "Location": "LOC-001"
9 },
10 "line_items": [
11 {
12 "description": "Office Supplies",
13 "amount": 150.00,
14 "dimensions": {
15 "Account": "5000"
16 }
17 }
18 ]
19}

The dimension keys in the dimensions object are the display type names (e.g., “Account”, “Department”), and the values are the erp_dimension_id values.


Best Practices

  • Sync dimensions before invoices - Ensure all required dimensions exist before creating invoices that reference them.
  • Use the bulk endpoint for efficiency - When syncing your chart of accounts, use POST /v1/dimensions/bulk to reduce API calls and to update existing dimensions in place.
  • Match ERP identifiers exactly - The erp_dimension_id must match your ERP’s identifier for successful invoice export.
  • Use consistent reference_ids - The reference_id field determines upsert matching on the bulk endpoint; use a consistent naming convention.
  • Cache dimension mappings - Fetch and cache the dimension list at integration startup to avoid repeated API calls.
  • Handle validation errors - A single invalid item in a bulk request fails the entire batch (400, nothing created). Validate your payload client-side before sending, and check the failures array for any items reported in a 200 response.

Troubleshooting

”Dimension not found” when coding invoice

  • Verify the dimension exists: GET /v1/dimensions?ottimate_company_id=123&erp_type=Account
  • Check you’re using the correct erp_dimension_id value
  • Ensure the dimension belongs to the same company as the invoice

Invoice export fails with dimension error

  • Verify the erp_dimension_id matches exactly what’s in your ERP
  • Check that all required dimension types are populated on the invoice

Bulk create returns 400 for the whole batch

  • One invalid item rejects every item in the request, including otherwise-valid ones. The response body identifies which array index failed and why.
  • Common issues: missing code, missing reference_id, missing erp_type or ottimate_type
  • Fix the flagged item(s) and resend the full batch

Dimensions not syncing from ERP

  • For Ottimate-hosted integrations, check sync status in the dashboard
  • For custom integrations, verify your API calls are succeeding