Migration Guide

Audience: Engineering teams migrating from the previous Complyt API to the Abacus Tax Engine API Last Updated: February 2026 Migration Support: Available through end of June 2026 - contact your account team

Overview

The Abacus Tax Engine API is a ground-up rebuild of the Tax Engine. The core concepts are the same - customers, exemptions, transactions - but the API contract has been modernised. The changes are consistent and mechanical: once you understand the patterns, the migration is straightforward.

What's the same:

  • Authentication approach (client credentials → Bearer token)
  • Three core resources: Customers, Exemptions, Transactions
  • Upsert semantics (safe to call on every order)
  • Tax calculation logic and output

What's changed:

  • All field names are snake_case (previously camelCase)
  • Upsert endpoints moved from path-based to body-based
  • Several fields have been regrouped into logical sub-objects
  • The source field is now a named integration enum
  • Exemptions have been significantly simplified
  • Several Complyt API management endpoints have been removed

At a Glance

Area Complyt API Abacus Tax Engine API
Base URL https://sandbox.complyt.io New URL (provided by your account team)
Auth endpoint POST /v1/token POST /v1/auth/token
Field naming camelCase snake_case
Internal ID field complytId id
Source field Numeric string "1""15" Named enum: api, netsuite, xero, etc.
Upsert pattern IDs in URL path IDs in request body
Customer address Single address object addresses.billing + addresses.shipping
Addresses in transactions shippingAddress, billingAddress at root Nested under addresses.shipping, addresses.billing
Customer reference in transactions customerId at root Nested under customer_details
Currency fields currency, refRate at root Nested under currency_details
Refund fields isRefundLinked, refundLinkedPercentage at root Nested under refund_info
Exemption scope Single state object + states array Single jurisdictions string array
Exemption type values FULLY full, partial
Exemption status values ACTIVE active, cancelled

1. Authentication

No conceptual change. You exchange client credentials for a short-lived Bearer token and pass it on every request.

Endpoint Change

Complyt API Abacus Tax Engine API
Path POST /v1/token POST /v1/auth/token

2. The source Field

In the Complyt API, source was an opaque numeric string ("1" through "15") assigned by Complyt to identify your integration.

In the Abacus Tax Engine API, source is a named enum that identifies the integration platform. Use the value that matches your system:

Platform source value
Direct API integration api
NetSuite netsuite
QuickBooks quickbooks
Xero xero
Sage Intacct sage_intacct
Priority priority
Zoho Books zoho_books
Salesforce salesforce
Stripe stripe
Shopify shopify

Use api if you are calling the API directly.

Use the same source value consistently. It forms part of the unique key for customers and transactions together with external_id. Changing it will cause records to be created as duplicates rather than updated.

3. Customers

Endpoint Mapping

Operation Complyt API Abacus Tax Engine API
List all GET /v1/customers GET /v1/customers/ - returns paginated response
Create or Update PUT /v1/customers/source/{source}/externalId/{externalId} PUT /v1/customers/
Get by internal ID GET /v1/customers/complytId/{id} GET /v1/customers/{id}
Get by external ID GET /v1/customers/source/{source}/externalId/{externalId} GET /v1/customers/{source}/{external_id}
Delete by internal ID (not in the Complyt API) DELETE /v1/customers/{id}
Delete by external ID (not in the Complyt API) DELETE /v1/customers/{source}/{external_id}

Upsert Pattern Change

In the Complyt API, source and externalId were URL path parameters. In the Abacus Tax Engine API, they move into the request body.

Complyt API:

PUT /v1/customers/source/3/externalId/CUST-001
Body: { "name": "Acme Corp", ... }

Abacus Tax Engine API:

PUT /v1/customers/
Body: { "source": "api", "external_id": "CUST-001", "name": "Acme Corp", ... }

Field Mapping

Complyt API Field Abacus Tax Engine API Field Notes
complytId id System-generated UUID
externalId external_id Moved to request body
source source Now a named enum - see Section 2
name name Unchanged
email email Unchanged
address addresses.billing / addresses.shipping See address change below
taxNumber tax_number
customerType customer_type Values unchanged
comment comment Unchanged
externalTimestamps.createdAt external_created_at Flattened
externalTimestamps.updatedAt external_updated_at Flattened
internalTimestamps.createdAt created_at Flattened, read-only
internalTimestamps.updatedAt updated_at Flattened, read-only

Customer Address Change

The Complyt API had a single address object on the customer. The Abacus Tax Engine API separates this into addresses.billing and addresses.shipping.

Complyt API:

{
  "address": {
    "street": "350 Fifth Avenue",
    "city": "New York",
    "state": "NY",
    "zip": "10118",
    "country": "US"
  }
}

Abacus Tax Engine API:

{
  "addresses": {
    "billing": {
      "street": "350 Fifth Avenue",
      "city": "New York",
      "state": "NY",
      "zip": "10118",
      "country": "US"
    },
    "shipping": {
      "street": "350 Fifth Avenue",
      "city": "New York",
      "state": "NY",
      "zip": "10118",
      "country": "US"
    }
  }
}

Both billing and shipping are optional. If you only have one address, populate whichever is relevant.

Customer Type Values

Unchanged:

Value Meaning
retail Standard tax rules apply
wholesale B2B resale - may require an exemption certificate
retail_exempt Retail customer with a blanket exemption
marketplace Marketplace facilitator rules apply

4. Transactions

This is the most significant change. The request has been reorganised into logical sub-objects.

Endpoint Mapping

Operation Complyt API Abacus Tax Engine API
List all GET /v1/transactions GET /v1/transactions/ - returns paginated response
Create or Update PUT /v1/transactions/source/{source}/externalId/{externalId} PUT /v1/transactions/
Get by internal ID GET /v1/transactions/complytId/{id} GET /v1/transactions/{id}
Get by external ID GET /v1/transactions/source/{source}/externalId/{externalId} GET /v1/transactions/{source}/{external_id}
Delete by internal ID (not in the Complyt API) DELETE /v1/transactions/{id}
Delete by external ID DELETE /v1/transactions/source/{source}/externalId/{externalId} DELETE /v1/transactions/{source}/{external_id}

Core Field Mapping

Complyt API Field Abacus Tax Engine API Field Notes
complytId id
externalId external_id Moved to request body
source source Now a named enum
documentName document_name
transactionType transaction_type Values changed to lowercase
transactionStatus transaction_status Values changed - see table below
isTaxInclusive is_tax_inclusive
transactionLevelDiscount transaction_level_discount
createdFrom created_from
(not in the Complyt API) transaction_date Issue date - used for exemption validity checks
currency currency_details.currency Moved into sub-object
refRate currency_details.manual_exchange_rate Moved into sub-object
isRefundLinked refund_info.is_refund_linked Moved into sub-object
refundLinkedPercentage refund_info.refund_linked_percentage Moved into sub-object
shippingAddress addresses.shipping Moved into sub-object
billingAddress addresses.billing Moved into sub-object
customerId customer_details.customer_id Moved into sub-object
externalTimestamps.createdAt external_created_at Flattened
externalTimestamps.updatedAt external_updated_at Flattened
transactionFilingStatus (removed) No longer part of the API
(not in the Complyt API) override_threshold true skips nexus threshold checks and forces tax calculation regardless of threshold status

Addresses - Structure Change

The Complyt API had shippingAddress and billingAddress at the root. The Abacus Tax Engine API nests all addresses under a single addresses object.

Complyt API:

{
  "shippingAddress": {
    "street": "350 Fifth Avenue",
    "city": "New York",
    "state": "NY",
    "zip": "10118",
    "country": "US"
  },
  "billingAddress": { "..." }
}

Abacus Tax Engine API:

{
  "addresses": {
    "shipping": {
      "street": "350 Fifth Avenue",
      "city": "New York",
      "state": "NY",
      "zip": "10118",
      "country": "US"
    },
    "billing": { "..." },
    "shipping_from": { "..." },
    "supplier": { "..." }
  }
}

shipping_from and supplier are new optional fields. shipping_from is used when origin-based tax rules apply. Both can be safely omitted.

The shipping address in the response includes a matched_address object with the validated, geocoded address used for jurisdiction determination:

Field Description
address Standardised address after geocoding
latitude / longitude Resolved coordinates
confidence Match quality score: 1.0 = exact, < 0.7 triggers low_confidence_warning
match_level Granularity of the match (e.g., street, city, zip, state, unmatched)
address_corrected true if the geocoded result differs from the submitted address
low_confidence_warning true if confidence is below 0.7 - review the matched address

Customer Reference - Structure Change

The Complyt API had customerId at the root. The Abacus Tax Engine API moves customer-related fields under customer_details, and adds two new ways to reference a customer:

Complyt API:

{
  "customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Abacus Tax Engine API - option 1: by internal UUID:

{
  "customer_details": {
    "customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  }
}

Abacus Tax Engine API - option 2: by external ID:

{
  "customer_details": {
    "customer_external_id": "CUST-001",
    "customer_source": "api"
  }
}

Abacus Tax Engine API - option 3: inline upsert:

{
  "customer_details": {
    "customer": {
      "external_id": "CUST-001",
      "source": "api",
      "name": "Acme Corp",
      "external_created_at": "2024-01-01T00:00:00Z",
      "external_updated_at": "2024-01-01T00:00:00Z"
    }
  }
}

Line Items - Field Mapping

Complyt API Field Abacus Tax Engine API Field Notes
unitPrice unit_price Can be negative for credit lines
quantity quantity
lineAmount (removed) Abacus Tax Engine API calculates unit_price × quantity automatically
taxCode tax_code
description description
name name
(not in the Complyt API) discount Item-level discount amount
(not in the Complyt API) manual_sales_tax_rate Single decimal rate override (e.g., 0.0825) - bypasses automatic calculation
(not in the Complyt API) manual_sales_tax_rates Per-jurisdiction rate map (e.g., {"state": 0.06, "city": 0.0125}) - see Manual Tax Rates guide
(not in the Complyt API) exemption_id UUID of an exemption certificate to apply to this item
(not in the Complyt API) exemption_reason Free-text reason (e.g., resale_certificate)

Remove lineAmount from your requests. It is not accepted in the Abacus Tax Engine API.

Transaction Status Values

Complyt API Value Abacus Tax Engine API Value
PENDING active
COMPLETED paid
FAILED cancelled

Currency - Structure Change

Complyt API:

{
  "currency": "EUR",
  "refRate": 1.0856
}

Abacus Tax Engine API:

{
  "currency_details": {
    "currency": "EUR",
    "manual_exchange_rate": 1.0856
  }
}

manual_exchange_rate is optional. If omitted, the Abacus Tax Engine API fetches the exchange rate automatically.

Refund Fields - Structure Change

Complyt API:

{
  "isRefundLinked": true,
  "refundLinkedPercentage": 0.5
}

Abacus Tax Engine API:

{
  "refund_info": {
    "is_refund_linked": true,
    "refund_linked_percentage": 0.5
  }
}

refund_linked_percentage is a decimal fraction, not a percentage: 0.5 means 50%, 1.0 means full refund.

Transaction Response Body

The Abacus Tax Engine API returns significantly richer output than the Complyt API. Key new sections:

tax object - the primary field for reading total tax owed:

Field Description
total_tax Total tax across all line items and shipping fee
effective_tax_rate Blended effective rate for the transaction

amounts object - aggregated monetary breakdown:

Field Description
total_items_amount Sum of all line item total_price_after_discounts
taxable_items_amount Portion attributable to taxable items
tangible_items_amount Portion attributable to tangible items
non_taxable_amount Portion for non-taxable items
final_transaction_amount Total after all discounts
total_discount Aggregate of all item-level discounts
transaction_level_discount Transaction-wide discount distributed pro-rata

Per-item response fields (new):

Field Description
total_price Gross line amount (unit_price × quantity)
total_price_after_discount Final taxable base after all discounts
relative_transaction_discount Portion of transaction-level discount allocated to this item
tangible_category "tangible" or "intangible"
taxable_category "taxable" or "not_taxable"
taxability_reason Why the item was taxed or not - see values below
jurisdiction_tax_breakdown Per-jurisdiction breakdown from automatic rate lookup (state/county/city/mta/spd)
manual_jurisdiction_tax_breakdown Per-jurisdiction breakdown derived from manual_sales_tax_rates (present only when manual rates were submitted)
is_exempt true if the item was fully exempted

taxability_reason values:

Value Meaning
standard_rated Standard tax rate applied
zero_rated Taxable at 0% (VAT/GST exports)
reduced_rated A reduced rate applies
product_exempt Product category is exempt
customer_exempt Customer has an active exemption certificate
reverse_charge Reverse charge mechanism applies
not_collecting No obligation to collect in this jurisdiction
not_subject_to_tax Outside the scope of taxable activity

Common values shown above. See the API reference for the full list of taxability_reason values.

Complete Transaction Response Example
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "external_id": "INV-2024-00456",
  "source": "api",
  "transaction_date": "2024-06-15T14:30:00Z",
  "document_name": "INV-2024-00456",
  "is_tax_inclusive": false,
  "transaction_type": "invoice",
  "transaction_status": "active",
  "created_from": null,
  "external_created_at": "2024-06-15T14:30:00Z",
  "external_updated_at": "2024-06-15T14:30:00Z",
  "created_at": "2024-06-15T14:30:05Z",
  "updated_at": "2024-06-15T14:30:05Z",
  "tax": {
    "total_tax": "8.27",
    "effective_tax_rate": "0.082500"
  },
  "amounts": {
    "total_items_amount": "99.98",
    "taxable_items_amount": "99.98",
    "tangible_items_amount": "99.98",
    "non_taxable_amount": "0.00",
    "final_transaction_amount": "99.98",
    "total_discount": "0.00",
    "transaction_level_discount": "0.00"
  },
  "currency_details": {
    "currency": "USD",
    "manual_exchange_rate": null,
    "exchange_rate_info": null
  },
  "refund_info": {
    "is_refund_linked": null,
    "refund_linked_percentage": null
  },
  "addresses": {
    "billing": {
      "street": "123 Main St", "city": "New York", "state": "NY",
      "zip": "10001", "country": "US"
    },
    "shipping": {
      "street": "350 Fifth Avenue", "city": "New York", "state": "NY",
      "zip": "10118", "country": "US",
      "matched_address": {
        "address": {
          "street": "350 5TH AVE", "city": "NEW YORK", "state": "NY",
          "zip": "10118", "country": "US"
        },
        "latitude": 40.7484,
        "longitude": -73.9967,
        "confidence": 1.0
      }
    },
    "shipping_from": null,
    "supplier": null
  },
  "customer_details": {
    "customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "customer_external_id": "CUST-001",
    "customer_source": "api",
    "customer_type_override": null,
    "customer": { "..." }
  },
  "items": [
    {
      "name": "Bluetooth Headphones",
      "tax_code": "ELECTRONICS",
      "unit_price": "49.99",
      "quantity": "2.0",
      "total_price": "99.98",
      "discount": "0.00",
      "total_price_after_discount": "99.98",
      "relative_transaction_discount": "0.00",
      "tangible_category": "tangible",
      "taxable_category": "taxable",
      "taxability_reason": "standard_rated",
      "is_exempt": false,
      "tax": {
        "total_tax": "8.27",
        "effective_tax_rate": "0.082500"
      },
      "jurisdiction_tax_breakdown": {
        "state": {
          "jurisdiction_type": "state",
          "gross_sales": "99.98",
          "taxable_amount": "99.98",
          "non_taxable_amount": "0.00",
          "tax_rate": "0.062500",
          "tax_due": "6.25"
        },
        "county": {
          "jurisdiction_type": "county",
          "tax_rate": "0.002500",
          "tax_due": "0.25"
        },
        "city": {
          "jurisdiction_type": "city",
          "tax_rate": "0.012500",
          "tax_due": "1.25"
        }
      }
    }
  ],
  "shipping_fee": null
}

Paginated List Responses

The GET /v1/transactions/ and GET /v1/customers/ endpoints return a cursor-paginated response rather than a bare array:

{
  "data": [ ... ],
  "cursors": {
    "after": "eyJpZCI6IjEyMyJ9",
    "before": null,
    "has_next": true,
    "has_previous": false,
    "limit": 20
  }
}
Query parameter Default Max Description
limit 20 100 Number of records per page
after - - Cursor from cursors.after to fetch the next page
before - - Cursor from cursors.before to fetch the previous page

If you were iterating over a bare array response, update your code to read from data and use cursors.has_next + cursors.after to paginate through results.

5. Exemptions

Exemptions have been substantially simplified. The nested Complyt API structure has been flattened.

Endpoint Mapping

Operation Complyt API Abacus Tax Engine API
List all GET /v1/exemptions GET /v1/exemptions/
Create POST /v1/exemptions POST /v1/exemptions/
Get by ID GET /v1/exemptions/complytId/{id} GET /v1/exemptions/{id}
Update PUT /v1/exemptions/complytId/{id} PUT /v1/exemptions/{id}
Delete DELETE /v1/exemptions/complytId/{id} DELETE /v1/exemptions/{id}

Field Mapping

Complyt API Field Abacus Tax Engine API Field Notes
complytId id
exemption.customerId customer_id Wrapper object removed
exemption.country country
exemption.state + states[] jurisdictions[] See structural change below
exemption.validationDates.fromDate start_date
exemption.validationDates.toDate end_date null = no expiration
exemption.certificate.certificateId certificate_id Simplified to UUID
exemption.exemptionType exemption_type Values changed
exemption.exemptionStatus exemption_status Values changed
exemption.classification (removed) No longer required
exemption.status (removed) Replaced by exemption_status

Jurisdiction Change

The Complyt API required a single state object plus a separate states array. The Abacus Tax Engine API unifies these into a single jurisdictions string array.

Complyt API (single state):

{
  "exemption": {
    "country": "US",
    "state": { "abbreviation": "CA", "code": "06", "name": "California" }
  },
  "states": []
}

Complyt API (multiple states):

{
  "exemption": { "country": "US", "state": null },
  "states": [
    { "abbreviation": "CA", "code": "06", "name": "California" },
    { "abbreviation": "NY", "code": "36", "name": "New York" }
  ]
}

Abacus Tax Engine API:

{ "country": "US", "jurisdictions": ["CA"] }
{ "country": "US", "jurisdictions": ["CA", "NY", "TX"] }
{ "country": "US", "jurisdictions": [] }

An empty jurisdictions array means the exemption applies to all jurisdictions within the country.

Exemption Type Values

Complyt API Value Abacus Tax Engine API Value
FULLY full
(partial) partial

Exemption Status Values

Complyt API Value Abacus Tax Engine API Value
ACTIVE active
INACTIVE / revoked cancelled

6. Endpoints Removed

These Complyt API endpoints do not exist in the Abacus Tax Engine API. The functionality has been internalised or is no longer needed.

Contact your account team if a missing endpoint is blocking your integration - some may be added as additional use cases are identified.

Complyt API Endpoint Notes
GET/PUT /v1/nexus/* Nexus tracking is handled internally
GET/PUT /v1/clientTracking/* Internal only
GET/PUT /v1/product-tax-mappings/* Product classification is driven by tax_code on each line item
GET /v1/sales_tax_rates/* Rate lookups are internal to the tax engine
GET /v1/gt_rates/* GST/VAT rate lookups are internal
GET /v1/addresses/validate Address validation happens automatically on every transaction
GET /v1/vat/validate Contact your account team for VAT validation options
GET/PUT /v1/files File management is not part of the new Tax Engine API
POST /v1/api_key API credential management via the new admin portal
GET /v1/secret_key No longer needed

7. Migration Checklist

Work through these steps in order:

Authentication

  • Update auth endpoint from POST /v1/token to POST /v1/auth/token
  • Rename request fields: clientIdclient_id, clientSecretclient_secret
  • Update response parsing: accessTokenaccess_token, expiresInexpires_in, etc.
  • Update base URL to the new URL provided by your account team

Source field

  • Replace numeric source values (e.g., "3") with named enum values (e.g., "api", "netsuite")
  • Confirm the correct source value with your account team if unsure

Customers

  • Move source and externalId from URL path into request body
  • Rename fields: externalIdexternal_id, taxNumbertax_number, customerTypecustomer_type, customerStatuscustomer_status
  • Flatten timestamps: externalTimestamps.createdAtexternal_created_at, etc.
  • Restructure address: addressaddresses.billing and/or addresses.shipping
  • Rename complytIdid in stored references
  • Update get-by-external-ID calls to new URL format

Transactions

  • Move source and externalId from URL path into request body
  • Rename all top-level camelCase fields to snake_case
  • Restructure addresses: shippingAddressaddresses.shipping, billingAddressaddresses.billing
  • Move customer reference: customerIdcustomer_details.customer_id
  • Move currency fields: currency + refRatecurrency_details.currency + currency_details.manual_exchange_rate
  • Move refund fields: isRefundLinked + refundLinkedPercentagerefund_info.is_refund_linked + refund_info.refund_linked_percentage
  • Remove lineAmount from line items
  • Remove transactionFilingStatus if used
  • Ensure unit_price is included on every line item - it is now required
  • Update list-response parsing: read records from data[] and paginate using cursors.after / cursors.has_next
  • Update transaction_type enum values: SALEinvoice, RETURNrefund
  • Update transaction_status enum values: PENDINGactive, COMPLETEDpaid, FAILEDcancelled
  • Update response parsing: read total tax from tax.total_tax
  • Update response parsing: read transaction totals from amounts.*
  • Update response parsing: handle new per-item fields (total_price_after_discount, taxable_category, taxability_reason, is_exempt)

Exemptions

  • Remove the exemption wrapper object - all fields move to the top level
  • Replace state object + states array with jurisdictions string array
  • Flatten validationDates: fromDatestart_date, toDateend_date
  • Simplify certificate: certificate.certificateIdcertificate_id
  • Update exemption_type values: FULLYfull
  • Update exemption_status values: ACTIVEactive
  • Remove classification and status fields

Housekeeping

  • Remove any calls to endpoints that no longer exist
  • Test all flows in the staging environment before cutover

8. Abacus Tax Engine API - Endpoint Reference

Auth API

Method Path Description
POST /v1/auth/token Exchange client credentials for a Bearer token
POST /v1/auth/verify Return the decoded claims of the current token

Tax Engine API

Method Path Description
GET /v1/customers/ List all customers
PUT /v1/customers/ Create or update a customer
GET /v1/customers/{id} Get a customer by internal UUID
GET /v1/customers/{source}/{external_id} Get a customer by source and external ID
DELETE /v1/customers/{id} Soft-delete a customer by internal UUID
DELETE /v1/customers/{source}/{external_id} Soft-delete a customer by source and external ID
GET /v1/exemptions/ List all exemptions
POST /v1/exemptions/ Create an exemption
GET /v1/exemptions/{id} Get an exemption by internal UUID
PUT /v1/exemptions/{id} Update an exemption
DELETE /v1/exemptions/{id} Soft-delete an exemption
GET /v1/transactions/ List all transactions
PUT /v1/transactions/ Create or update a transaction
GET /v1/transactions/{id} Get a transaction by internal UUID
GET /v1/transactions/{source}/{external_id} Get a transaction by source and external ID
DELETE /v1/transactions/{id} Soft-delete a transaction by internal UUID
DELETE /v1/transactions/{source}/{external_id} Soft-delete a transaction by source and external ID

Questions?

Reach out to your account team or the Tax Engine migration support channel. Migration support is available through end of June 2026.