Total Transactions 0
Approved 0
Pending 0
Determinations Today i 0

Determination Volume

Transactions Created

Recent Activity

Timestamp Action User Detail Status
Tax Assistant
Describe transactions in plain language or bulk-upload a spreadsheet
Template
Hi, I'm the DeterminedAI Tax Assistant. I can help you:

Add transactions — describe them in plain language and I'll classify the VAT/GST treatment
Answer tax questions — ask about rates, rules, registration requirements, or any VAT/GST topic
Analyze a CSV — upload any spreadsheet of transactions and I'll classify them all

Try: "We sell SaaS subscriptions from Germany to businesses in France"
Transaction Code i Description i Category i Supply Type i Confidence i Status i Actions i
Determination ID i Transaction ID i Date Lines Net Total Tax Total Currency Source
Entity Jurisdiction Registration Number Type Effective From Status Actions
Jurisdiction Tax Type Frequency Due Rule Actions

ERP Tax Code Mappings i

Jurisdiction Tax Treatment Supply Type ERP Tax Code Actions
Select Transaction & ERP
No saved transactions? Go to Transactions to set them up first, or select Custom payload to build manually.
POST /v1/tax/determine Header: X-API-Key: your_api_key
Request Payload (editable — modify and click Run)
Response
Select a saved transaction and ERP system, then click "Build & Run" to see the API response.
Quick Start — 3 Steps
1
Get Your API Key

Go to Account and click Generate API Key. Copy it immediately — it's only shown once.

2
Set Up Transactions

Go to Transactions and describe your products/services. Our AI classifies them for tax treatment.

3
Call the API

Send a POST request with your transaction details. We return the tax determination in milliseconds.

Authentication

DeterminedAI accepts two credential types on every data endpoint. Your integrations should use Option A.

Option A — API Key (ERPs, servers, scripts)

Send the key in the X-API-Key header. This is what every ERP connector uses.

curl -X POST https://determinedai.co/v1/tax/determine \
  -H "Content-Type: application/json" \
  -H "X-API-Key: txai_live_your_key_here" \
  -d '{ ... }'
Option B — Supabase JWT (dashboard only)

The dashboard you're looking at uses this path. You do not need to send this from your own code.

Authorization: Bearer <supabase_session_jwt>

Your API key starts with txai_live_. Keep it secret — never ship it in browser JavaScript, mobile apps, or public repos. If it leaks, rotate it immediately.

HTTP Response Codes

Every endpoint returns a standard HTTP status. Use these to decide whether to retry, surface an error, or ask the user to re-authenticate.

Status Meaning Retryable?
200 OK Determination succeeded. Parse line_results[].
400 Bad Request Payload failed validation (missing required field, bad ISO country, malformed amount). Response body has details. No — fix the request.
401 Unauthorized No X-API-Key header and no Authorization: Bearer token. You sent a request with no credentials. No — add the header.
403 Forbidden The API key you sent is not recognized, has been revoked, or the Bearer JWT is invalid/expired. Check the key in your ERP plugin matches your dashboard. No — rotate or re-paste the key.
409 Conflict Only on POST /v1/account/api-key: you already have an active key. Use the rotate endpoint to cycle it. No — use rotate.
429 Too Many Requests Monthly plan quota exceeded (500 on Starter, 25k on Professional, 250k on Scale). Response body: "Monthly API quota exceeded (N/M calls)…" No — upgrade plan or wait for next month.
500 Server Error Unexpected error. Capture the response body and contact support with the determination_id if one was returned. Yes, with exponential backoff.
503 Service Unavailable Authentication or account database is temporarily unreachable. This is a transient infrastructure issue — we fail closed rather than silently accept unverified keys. Yes — retry after 1-5s with backoff.

Connector behavior: the NetSuite SuiteScript plug-in will flag the transaction with custbody_taxai_needs_review = true on any non-200 response and optionally apply a zero-rate fallback (if custscript_taxai_fallback is enabled), so bookkeeping is never blocked by an API outage — but the line is queued for human review.

Base URL & Endpoints

Base URL: https://determinedai.co

Method Endpoint Description
POST /v1/tax/determine Raw tax determination — universal format
POST /v1/erp/netsuite/calculate NetSuite SuiteTax native format
POST /v1/erp/xero/calculate Xero accounting format (ACCREC / ACCPAY)
POST /v1/erp/quickbooks/calculate QuickBooks Online format
POST /v1/erp/dynamics365/calculate Dynamics 365 Finance & SCM format
POST /v1/erp/sap/calculate SAP S/4HANA & Business One format
POST /v1/erp/sage-intacct/calculate Sage Intacct format
POST /v1/tax/chat Conversational tax assistant
GET /v1/setup/catalog Retrieve your saved transaction catalog
POST /v1/setup/erp-mapping Create ERP tax code mappings
GET /v1/setup/erp-mapping Retrieve current ERP mappings
GET /v1/setup/erp-mapping/defaults/{erp} Get default mappings for a specific ERP
POST /v1/tax/batch-upload Batch upload transactions (CSV or free-text)
POST /v1/compliance/registrations Add a VAT/GST registration
GET /v1/compliance/registrations List all VAT/GST registrations
POST /v1/compliance/filing-rules Add a filing rule (deadline schedule)
GET /v1/compliance/filing-rules List filing rules and deadlines
GET /v1/account/me Current user, plan, usage, key prefix (Bearer JWT only)
POST /v1/account/api-key Generate a new API key (returned once — store immediately)
POST /v1/account/api-key/rotate Invalidate the current key and issue a new one
Example — Raw API (/v1/tax/determine)

The universal endpoint. Send transaction details and get back the full VAT/GST determination with audit trail.

Request
POST /v1/tax/determine
Content-Type: application/json
X-API-Key: txai_live_your_key

{
  "transaction_id": "INV-2024-001",
  "transaction_type": "sale",
  "transaction_date": "2024-03-15",
  "direction": "AR",
  "seller": {
    "entity_id": "seller-001",
    "name": "Acme SaaS Inc.",
    "country": "US",
    "tax_registrations": [{
      "jurisdiction": "DE",
      "tax_id": "DE123456789",
      "scheme": "VAT"
    }]
  },
  "customer": {
    "customer_id": "cust-42",
    "country": "DE"
  },
  "line_items": [{
    "line_id": "line-1",
    "description": "Cloud SaaS subscription",
    "amount": "99.00",
    "currency": "EUR",
    "product_code": "SAAS-001"
  }]
}
Response
{
  "transaction_id": "INV-2024-001",
  "determination_id": "det_abc123...",
  "timestamp": "2024-03-15T10:30:00Z",
  "line_results": [{
    "line_id": "line-1",
    "supply_type": "electronically_supplied_service",
    "tax_treatment": "standard",
    "rate": 0.19,
    "tax_amount": 18.81,
    "net_amount": 99.00,
    "jurisdiction": "DE",
    "place_of_supply": "DE",
    "gl_tax_code": "VAT-DE-STD-19",
    "confidence_score": 0.97,
    "rule_reference":
      "EU VAT Dir. Art. 58",
    "characterization_reasoning":
      "B2C ESS — tax at customer loc",
    "user_obligation":
      "Charge 19% DE VAT via OSS"
  }],
  "total_tax": 18.81,
  "total_net": 99.00,
  "currency": "EUR",
  "warnings": []
}
Key Request Fields
seller.country (required) — ISO 2-letter code customer.country (required) — ISO 2-letter code seller.entity_id, .name (required) customer.tax_id (optional) — presence = B2B line_items[].description (required) — drives AI classification line_items[].incoterm (optional) — DDP, FOB, CIF, etc. for goods direction (default: AR) — AR (Accounts Receivable) = selling, AP (Accounts Payable) = buying line_items[].product_code (optional) — matches catalog for instant lookup
Key Response Fields
rate — decimal (0.19 = 19%), not percentage tax_treatment — standard | reduced | zero_rated | exempt | reverse_charge | outside_scope place_of_supply — where tax is due (ISO country) user_obligation — plain-English action required rule_reference — legal basis (e.g. "EU VAT Dir. Art. 58") gl_tax_code — suggested GL posting code self_assess_rate — for AP reverse charge (buyer self-assesses) erp_tax_code — your ERP-specific tax code (if mappings configured)
ERP-Specific Integrations

Each ERP endpoint accepts payloads in that system's native format — no translation layer needed. Responses include ERP-native tax codes, rule_reference (legal basis for audit defense), and ready-to-post structures.

NetSuite SuiteTax
POST /v1/erp/netsuite/calculate
Required: subsidiary_country, ship_to.country, lines[].item_id, lines[].amount
Optional: entity_tax_id (B2B), incoterm, lines[].item_type (Service, InvtPart)
Returns: tax_details[] with tax_code, tax_rate (%), tax_amount, jurisdiction, rule_reference
Xero
POST /v1/erp/xero/calculate
Required: contact_country, line_items[].description, line_items[].unit_amount
Optional: invoice_type (ACCREC/ACCPAY), contact_tax_number, seller_country (default: GB)
Returns: line_items[] with tax_type (OUTPUT2, ZERORATEDOUTPUT, etc.), rule_reference + ready-to-POST invoice_data
QuickBooks Online
POST /v1/erp/quickbooks/calculate
Required: bill_country, line_items[].amount
Optional: company_country (default: US), customer_tax_id, ship_country, bill_state/ship_state
Returns: line_tax_details[] with tax_code_ref (TAX/NON), rule_reference + ready-to-write txn_tax_detail
Dynamics 365
POST /v1/erp/dynamics365/calculate
Required: company_country, party_country, ship_to.country, lines[].amount
Optional: party_tax_registration, document_type (SalesOrder/PurchaseOrder), party_tax_group
Returns: lines[].tax_components[] with tax_code, tax_rate, jurisdiction, rule_reference + tax_summary[]
SAP S/4HANA & Business One
POST /v1/erp/sap/calculate
Required: company_country, ship_to.country, lines[].line_number, lines[].net_amount
Optional: customer_vat_number, tax_procedure (TAXD, TAXUSJ), source_system (S4HANA/B1), plant
Returns: lines[].conditions[] with condition_type (MWST), tax_rate, jurisdiction_code, rule_reference + bapiret2[] messages
Sage Intacct
POST /v1/erp/sage-intacct/calculate
Required: ship_to_country, lines[].amount
Optional: company_country (default: US), customer_tax_id, tax_solution_id
Returns: tax_entries[] with detail_id, tax_authority, tax_rate (%), tax_amount, taxable_amount, rule_reference
Installing the ERP Plugin — Where to Paste Your Key

Each ERP stores the DeterminedAI API key in its own native secret/config store. You paste it once and the connector sends it on every outgoing call as X-API-Key.

NetSuite (SuiteScript)

Upload TaxAI_SuiteTax_Plugin.js as a SuiteTax Plug-in, then set these script parameters on the deployment record:

custscript_taxai_api_url   = https://determinedai.co
custscript_taxai_api_key   = txai_live_xxxxxxxx...
custscript_taxai_timeout   = 15000
custscript_taxai_fallback  = T  # zero-rate if API down

Full walkthrough: connectors/netsuite/SETUP.md in the integration bundle.

Xero (Python middleware)

Instantiate XeroTaxMiddleware in your backend with the key as a constructor arg — ideally loaded from an env var, never hardcoded:

middleware = XeroTaxMiddleware(
  taxai_api_url=os.environ["TAXAI_API_URL"],
  taxai_api_key=os.environ["TAXAI_API_KEY"],
  xero_client_id=os.environ["XERO_CLIENT_ID"],
  xero_client_secret=os.environ["XERO_CLIENT_SECRET"],
)

Full walkthrough: connectors/xero/SETUP.md.

QuickBooks, D365, SAP, Sage Intacct

These ERPs don't have a drop-in plugin bundle — your backend calls the /v1/erp/<erp>/calculate endpoint directly from whichever webhook or event handler creates invoices/bills in that system. Send the key in X-API-Key:

POST /v1/erp/quickbooks/calculate
X-API-Key: txai_live_xxxxxxxx...
Content-Type: application/json

# See Code Examples below for a full request

Store the key in your backend's secret manager (AWS Secrets Manager, GCP Secret Manager, Vercel environment variables, etc.) — never in source control.

Testing the connection

Before wiring up real invoices, smoke-test your key against a simple determination:

curl https://determinedai.co/v1/tax/determine \
  -H "X-API-Key: $TAXAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id":"test-1",
       "transaction_type":"sale",
       "direction":"AR",
       "seller":{"entity_id":"s","name":"T","country":"US"},
       "customer":{"country":"DE"},
       "line_items":[{"line_id":"1",
         "description":"SaaS subscription",
         "amount":"99.00","currency":"EUR"}]}'

A 200 with line_results means your key is live. 403 means re-copy the key from the Account page; 503 means retry in a few seconds.

ERP Connector Setup — Step-by-Step Guide

Each ERP speaks a different auth model, a different tax data shape, and a different deployment story. Pick your system from the dropdown to see the step-by-step guide for that integration.

Covers QBO International (UK, CA, AU, IE, ZA, Global) and QBO-US legacy manual sales tax. QBO-US with Automated Sales Tax is detected at initialization and blocked with a clear error so your onboarding flow can stop the integration before persisting tokens.
Supported QBO editions
  • QBO International (UK, CA, AU, IE, ZA, Global) — fully supported, manual tax codes
  • QBO-US legacy manual sales tax — supported
  • QBO-US with Automated Sales Tax (AST)not supported. The middleware detects AST at init and raises QBOUnsupportedConfigError; catch this in your onboarding flow and block the integration.
Step 1. Create an Intuit app
  1. Sign in at developer.intuit.com and go to My Apps → Create an app
  2. Pick QuickBooks Online and Payments
  3. Under Scopes, enable com.intuit.quickbooks.accounting
  4. Add your OAuth2 redirect URI and copy your Client ID + Client Secret from Keys & credentials
Step 2. Run the OAuth2 authorization flow

Use Intuit's OAuth 2.0 Playground or your own server to walk the user through authorization. You will end up with four values: realm_id, access_token (~1h), refresh_token (~100d, rotates on use), and expires_in. Persist all four in your secrets store.

Step 3. Install and initialize the middleware
pip install httpx

from qbo_middleware import QBOTaxMiddleware, QBOUnsupportedConfigError

middleware = QBOTaxMiddleware(
    taxai_url="https://determinedai.co",
    taxai_api_key="txai_live_...",
    qbo_client_id="YOUR_INTUIT_CLIENT_ID",
    qbo_client_secret="YOUR_INTUIT_CLIENT_SECRET",
    environment="production",  # or "sandbox"
)

# This probes CompanyInfo + Preferences; raises
# QBOUnsupportedConfigError if the org is QBO-US with AST on.
try:
    await middleware.set_tokens(
        realm_id=stored["realm_id"],
        access_token=stored["access_token"],
        refresh_token=stored["refresh_token"],
        expires_in=stored["expires_in"],
    )
except QBOUnsupportedConfigError as e:
    return error_response(str(e))
Step 4. Create invoices with tax
result = await middleware.create_invoice_with_tax(
    doc_number="INV-2024-042",
    customer_ref="42",
    customer_name="Acme GmbH",
    bill_country="DE",
    customer_tax_id="DE123456789",  # B2B -> EU reverse charge
    currency_code="EUR",
    line_items=[{
        "description": "Cloud analytics - annual SaaS",
        "amount": 1188.00,
        "quantity": 1,
        "item_ref": "SAAS-001",
    }],
)
invoice_id = result["Invoice"]["Id"]
Tax code mapping

QBO TaxCode numeric IDs are company-specific. On set_tokens() the middleware caches the name → id lookup for the org's active tax codes. If your company's tax code names don't match what DeterminedAI returns, configure the mapping via POST /v1/setup/erp-mapping with erp_system: "quickbooks".

Full walkthrough

See connectors/quickbooks/SETUP.md for the complete guide including AST detection internals, error handling, production checklist, and the live sandbox validation notes.

Code Examples
Python
import requests

resp = requests.post(
    "https://determinedai.co/v1/tax/determine",
    headers={
        "X-API-Key": "txai_live_your_key",
        "Content-Type": "application/json",
    },
    json={
        "transaction_id": "INV-001",
        "transaction_type": "sale",
        "direction": "AR",
        "seller": {
            "entity_id": "s1",
            "name": "My Co",
            "country": "US"
        },
        "customer": {"country": "DE"},
        "line_items": [{
            "line_id": "1",
            "description": "SaaS subscription",
            "amount": "99.00",
            "currency": "EUR"
        }]
    }
)
data = resp.json()
line = data["line_results"][0]
print(f"Rate: {line['rate']}")       # 0.19
print(f"Tax:  {line['tax_amount']}") # 18.81
print(f"Code: {line['gl_tax_code']}")# VAT-DE-STD-19
JavaScript / Node.js
const resp = await fetch(
  "https://determinedai.co/v1/tax/determine",
  {
    method: "POST",
    headers: {
      "X-API-Key": "txai_live_your_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      transaction_id: "INV-001",
      transaction_type: "sale",
      direction: "AR",
      seller: {
        entity_id: "s1",
        name: "My Co",
        country: "US",
      },
      customer: { country: "DE" },
      line_items: [{
        line_id: "1",
        description: "SaaS subscription",
        amount: "99.00",
        currency: "EUR",
      }],
    }),
  }
);
const data = await resp.json();
const line = data.line_results[0];
console.log(line.rate);        // 0.19
console.log(line.tax_amount);  // 18.81
console.log(line.gl_tax_code); // VAT-DE-STD-19
Managing Your API Key

Your API key is the identity your ERPs use to authenticate with DeterminedAI. Manage it from the Account page or directly via the API.

Generate

Creates your first key. Returns the plaintext exactly once — copy it before closing the dialog.

POST /v1/account/api-key
Authorization: Bearer <session_jwt>

# Response (once, never again)
{
  "api_key": "txai_live_xxxxxxxxxxxxxxxx",
  "prefix":  "xxxxxxxx",
  "message": "Store this key securely..."
}
Rotate (revoke old + issue new)

Use this if your key is compromised, if an employee with key access leaves, or on a scheduled rotation. The old key stops working immediately.

POST /v1/account/api-key/rotate
Authorization: Bearer <session_jwt>

# Response
{
  "api_key": "txai_live_yyyyyyyyyyyyyyyy",
  "prefix":  "yyyyyyyy",
  "message": "Old key has been invalidated..."
}
Key Facts
  • Format: txai_live_ prefix + 32 URL-safe base64 characters. Total length ~42 chars.
  • Storage: we store only a SHA-256 hash — we cannot recover or display your plaintext key after generation. If you lose it, rotate.
  • One active key per account. Calling generate while a key exists returns 409 Conflict; use rotate instead.
  • Identity: the same key works across every ERP connector, the universal /v1/tax/determine endpoint, and any custom scripts. There's no per-ERP key.
  • Dashboard key preview shows only the first 8 characters (e.g. txai_live_aBcDeFgH••••••••). The full key is never re-displayed after generation.
  • Compromised? Rotate immediately. There is no grace period — after rotation, any request with the old key returns 403 Forbidden.
Plans & API Quotas
Plan API Calls / Month ERP Integrations Transactions
Starter (Free) 500 1 ERP 50
Professional ($249/mo) 25,000 2 ERPs Unlimited
Scale ($699/mo) 250,000 All ERPs Unlimited

API calls are counted per /v1/tax/determine (or equivalent ERP endpoint) request. Quotas reset on the 1st of each month UTC. Overage returns 429 Too Many Requests with a message telling you your current count and the plan ceiling — upgrade from the Account page to resume immediately.

Need Help?

Use the Help chat in the bottom-right corner, or reach out via Contact. We're happy to help with your integration.

Tax Engine — Subscription
Plan API Calls / Month Transactions ERPs History Support Price
Starter 500 50 1 30 days Community $0 Current
Professional 25,000 Unlimited 2 1 year Email $249/mo
Scale 250,000 Unlimited All Full + export Priority $699/mo
Enterprise Unlimited Unlimited All + custom Full + export Dedicated + SLA Custom Contact
OSS Compliance — Per Service

Separate from your Tax Engine subscription. Your current OSS status: No OSS services purchased.

Service What you get Billing Price
Registration Non-Union OSS registration with Revenue, ROS cert capture, first return included One-time $1,000
Quarterly Return Draft, review, file a single quarter. ECB FX + Excel work product included. One-time $250
Unlimited Filing All 4 quarters, ROS automation, cert expiry alerts, amendment support $799 / year $799

Saved snapshots

+ New snapshot

My registrations

Already registered for Non-Union OSS with Revenue? Import your existing registration — upload your ROS Digital Certificate and we'll take over quarterly filing without the wizard.