/ /

Installation guide for Kintsugi Connector with Zuora

Updated 23 days ago

Step-by-step guide to set up the Zuora ↔ Vertex ↔ Kintsugi integration.

Prerequisites

  • Zuora Billing tenant (sandbox or production)

  • Vertex O Series account (sandbox or production)

  • Kintsugi Platform account with Zuora connection capability


Part 1: Zuora OAuth Credentials

Generate Client ID and Secret

  1. Log in to Zuora at https://rest.test.zuora.com (sandbox) or https://rest.zuora.com (production)

  2. Navigate to Settings → Administration → Manage Users

  3. Click on your user → OAuth Clients tab

  4. Click Create OAuth Client

  5. Give it a name (e.g. “Kintsugi Integration”)

  6. Select permissions: Full Access (or minimum: API Access, Billing, Finance)

  7. Click Create — save the Client ID and Client Secret immediately (secret is only shown once)

Test Authentication

curl -X POST "https://rest.test.zuora.com/oauth/token" \ -d "grant_type=client_credentials" \ -d "client_id=<YOUR_CLIENT_ID>" \ -d "client_secret=<YOUR_CLIENT_SECRET>"

Expected: access_token in response.


Part 2: Vertex O Series Setup

Get Vertex Credentials

  1. Go to SettingsSecurity & Credentials

    Screenshot 2026-06-02 at 12.28.00 AM.png

2. Select Rest API for O Series Calculation as show below, Partition needs to be selected as per your Orgs settings.

  1. Identity Provider - VERX IDP

  2. Save the Credentials

This will generate unique client id and client secret(Note them down)

Screenshot 2026-06-02 at 12.29.56 AM.png

Field

Where to Find

Example

Username

Vertex admin portal → API credentials

XeTXREBpKs1yTVuPVF4o

Password

Vertex admin portal → API credentials

(your password)

Trusted ID

Vertex admin portal → Security → Trusted IDs

(alphanumeric string)

SOAP URL

Vertex admin portal → Endpoints

https://nsconnect.vertexsmb.com/vertex-ws/services/CalculateTax90

Vertex Company Setup

  • A Company configured (e.g. company code: KINTSUGI)

  • A valid seller/origin address (physical nexus address)

  • Tax rules configured for your jurisdictions


Part 3: Install Vertex O Series Tax Connector in Zuora

Install the App

If you are installing app from market place

  1. In Zuora, go to Home Page → Marketplace

  2. Find Vertex O Series Tax Connector

  3. Click Install

  4.  

    • Username: Client ID from Part 2

    • Password: Client Secret from part 2

    • Security Token: Your Vertex Trusted ID

    • URL: https://nsconnect.vertexsmb.com/vertex-ws/services/CalculateTax90

If customer support installs for you

Enable Connect Tax Engines

  1. Submit a request to https://support.zuora.com to enable the Connect Tax Engines feature on your tenant

  2. In Zuora, go to Home Page → Purchases → Open app → Deploy

You should see below screen

setup tax info.png

  1. In custom , Click New and fill below and click Save Login

  • Username: Client ID from Part 2

  • Password: Client Secret from part 2

  • Security Token: Your Vertex Trusted ID

  • URL: https://nsconnect.vertexsmb.com/vertex-ws/services/CalculateTax90

  1. In Zuora , Click New and fill below and click Save Login

  • Select Sandbox or Production based on which type of instance you have. Check your instance url and form the url to fill. For below example the url will be
    ”https://test.zuora.com/apps/services/a/80”

Screenshot 2026-06-02 at 12.29.10 PM.png

 

  • username will be Client id , password will client secret as generated in Step 1

  • Click Create to deploy the app.

Note: If you face any error like

No organization associated to this tenant(Kintsugi Trial Tenant) please contact support@zuora.com

The contact support , they will give a temporary token

  • Go to Setup Tax Engine and Tax Date-> Setup New Tax Engine-> Connect → Enter token and error will be fixed. Try again with Part 3 and it should work.


Part 4: Configure the Tax Engine

Once the app is installed it should be available Billing Settings → Set up Tax Engine and Tax Date

app should appear in tax engine.png

Open Vertex → navigate to Company and Seller info, Fill out the addresses and Click Save.

If sellerInfo is null/empty, all Vertex tax calculations will fail with “The LocationRole being added is invalid”.

Verify Tax Engine

Note down Tax engine ID.

Get tax engine id.png

 

Get Tax Company ID

curl --location 'https://rest.test.zuora.com/oauth/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=<Zuora client id>' \ --data-urlencode 'client_secret=<Zuora client secret>'

From response take access_token and use access token to generate company tax id.

curl -X GET "https://rest.test.zuora.com/settings/tax-companies?taxEngineId=<TAX_ENGINE_ID>" \ -H "Authorization: Bearer <token>"

Save the id from the response — this is the taxCompanyId needed for creating tax codes.


Part 5: Configure SOAP Request Template

Go to Request Template and paste below SOAP

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
          <SOAP-ENV:Body>
            <VertexEnvelope xmlns="urn:vertexinc:o-series:tps:7:0">
              <Login>
                <UserName>{{seller["username"]}}</UserName>
                <Password>{{seller["password"]}}</Password>
                <TrustedId>{{seller["security_token"]}}</TrustedId>
              </Login>
              <{% if document["preview_mode"] %}Quotation{% else %}Invoice{% endif %}Request documentDate="{{today}}" documentNumber="{{document["invoice_date"]}}" returnAssistedParametersIndicator="true" returnGeneratedLineItemsIndicator="true" transactionId="{{document["id"]}}" transactionType="SALE">
                <Seller>
                  <Company>{{seller["company_code"]}}</Company>
                  <PhysicalOrigin>
                    <StreetAddress1>{{seller["address1"]}}</StreetAddress1>
                    <StreetAddress2>{{seller["address2"]}}</StreetAddress2>
                    <City>{{seller["city"]}}</City>
                    <PostalCode>{{seller["zipCode"]}}</PostalCode>
                    <Country>{{seller["country"]}}</Country>
                  </PhysicalOrigin>
                </Seller>
                <Currency isoCurrencyCodeAlpha="{{document["currency"]}}"/>
                <OriginalCurrency isoCurrencyCodeAlpha="{{document["currency"]}}"/>
                {% for document_item in document_items %}
                <LineItem isMulticomponent="false" lineItemId="{{document_item["id"]}}" taxDate="{{document_item["taxDate"]}}" taxIncludedIndicator="false">
                  <Product productClass="{{document_item["subscriptionRatePlanChargeId"]}}">{{document_item["taxCode"]}}</Product>
                  {% if document_item["taxExemptStatus"]  1 or document_item["taxExemptStatus"]  "Yes" %}<Customer exemptionReasonCode="RESALE" isTaxExempt="true">{% else %}<Customer>{% endif %}
                    <CustomerCode>{{document_item["customer"]["accountNumber"]}}</CustomerCode>
                    <Destination>
                      <StreetAddress1>{{document_item["customer"]["address1"]}}</StreetAddress1>
                      <StreetAddress2>{{document_item["customer"]["address2"]}}</StreetAddress2>
                      <City>{{document_item["customer"]["city"]}}</City>
                      <MainDivision>{{document_item["customer"]["state"]}}</MainDivision>
                      <PostalCode>{{document_item["customer"]["zipCode"]}}</PostalCode>
                      <Country>{{document_item["customer"]["country"]}}</Country>
                    </Destination>
                    {% if document_item["taxExemptStatus"]  1 or document_item["taxExemptStatus"]  "Yes" %}<ExemptionCertificate exemptionCertificateNumber="{{document_item["taxExemptCertificateID"]}}"/>{% endif %}
                  </Customer>
                  {% if document["event_type"] == 'taxOverride' %}
                  <TaxOverride overrideType="NONTAXABLE"/>
                  {% endif %}
                  <Discount>
                    <DiscountAmount>{{document_item["discountAmount"]}}</DiscountAmount>
                  </Discount>
                  <Quantity>{{document_item["quantity"]}}</Quantity>
                  <UnitPrice>{{document_item["unitPrice"]}}</UnitPrice>
                  <ExtendedPrice>{{document_item["totalAmount"]}}</ExtendedPrice>
                  <FlexibleFields>
                    <FlexibleCodeField fieldId="1"/>
                    <FlexibleCodeField fieldId="2"/>
                    <FlexibleCodeField fieldId="3"/>
                    <FlexibleCodeField fieldId="4"/>
                    <FlexibleCodeField fieldId="5"/>
                    <FlexibleCodeField fieldId="6"/>
                    <FlexibleCodeField fieldId="7"/>
                    <FlexibleCodeField fieldId="8"/>
                    <FlexibleCodeField fieldId="9"/>
                    <FlexibleCodeField fieldId="10"/>
                    <FlexibleCodeField fieldId="11"/>
                    <FlexibleCodeField fieldId="12"/>
                    <FlexibleCodeField fieldId="13"/>
                    <FlexibleCodeField fieldId="14"/>
                    <FlexibleCodeField fieldId="15"/>
                    <FlexibleCodeField fieldId="16"/>
                    <FlexibleCodeField fieldId="17"/>
                    <FlexibleCodeField fieldId="18"/>
                    <FlexibleCodeField fieldId="19"/>
                    <FlexibleCodeField fieldId="20"/>
                    <FlexibleCodeField fieldId="21"/>
                    <FlexibleCodeField fieldId="22"/>
                    <FlexibleCodeField fieldId="23"/>
                    <FlexibleCodeField fieldId="24"/>
                    <FlexibleCodeField fieldId="25"/>
                    <FlexibleNumericField fieldId="1"/>
                    <FlexibleNumericField fieldId="2"/>
                    <FlexibleNumericField fieldId="3"/>
                    <FlexibleNumericField fieldId="4"/>
                    <FlexibleNumericField fieldId="5"/>
                    <FlexibleNumericField fieldId="6"/>
                    <FlexibleNumericField fieldId="7"/>
                    <FlexibleNumericField fieldId="8"/>
                    <FlexibleNumericField fieldId="9"/>
                    <FlexibleNumericField fieldId="10"/>
                    <FlexibleDateField fieldId="1"/>
                    <FlexibleDateField fieldId="2"/>
                    <FlexibleDateField fieldId="3"/>
                    <FlexibleDateField fieldId="4"/>
                    <FlexibleDateField fieldId="5"/>
                  </FlexibleFields>
                </LineItem>
                {% endfor %}
              </{% if document["preview_mode"] %}Quotation{% else %}Invoice{% endif %}Request>
            </VertexEnvelope>
          </SOAP-ENV:Body>
        </SOAP-ENV:Envelope>

Template Variables (Liquid)

Object

Fields

Example

seller

username, password, security_token, company_code, address1, city, state, zipCode, country

{{seller["company_code"]}}

document

id, preview_mode, invoice_date, currency, event_type

{{document["id"]}}

document_item

id, taxDate, taxCode, quantity, unitPrice, totalAmount, discountAmount, subscriptionRatePlanChargeId

{{document_item["taxCode"]}}

document_item["customer"]

accountNumber, address1, address2, city, state, zipCode, country

{{document_item["customer"]["state"]}}

document_item (exemption)

taxExemptStatus (0/1/2), taxExemptCertificateID, taxExemptEntityUseCode

{{document_item["taxExemptStatus"]}}


Part 6: Kintsugi Connection Setup

In the Kintsugi UI

  1. Go to Data Sources → Search Zuora → Connect

Screenshot 2026-06-02 at 12.53.19 PM.png

 

  1.  

Field

Where Stored

Purpose

Client ID

Connection config (encrypted)

OAuth authentication

Client Secret

Connection config (encrypted)

OAuth authentication

Base URL

Connection config

API endpoint

Tax Engine ID

connection.config.zuora_vertex_tax_engine_id

Used in ensure_connector_tax_code

Tax Company ID

connection.config.zuora_vertex_tax_company_id

Used in ensure_connector_tax_code

Troubleshooting

Error

Cause

Fix

“The LocationRole being added is invalid”

sellerInfo is null/empty

Update sellerInfo with valid seller address

“TaxCode on invoice items must be predefined and activated”

Tax code doesn't exist or is inactive

Create/activate the tax code first

“Field 'taxCompanyId' is required”

Missing taxCompanyId in tax code creation

Include taxCompanyId from /settings/tax-companies

“Cannot find entity by key”

Wrong taxCompanyId format

Use the id field (UUID), not the companyCode

Tax calculated but TaxAmount = 0

Account address invalid for Vertex

Use 2-letter state abbreviation (CA, TX, NY)

Exemption not working with Vertex

SOAP template doesn't pass exemption data

Customize template or use bill run (not standalone invoice)

“Please deactivate the Tax Code before deleting”

Tax code is active

Deactivate first, then delete

“Please remove the Tax Code from all charges”

Tax code still assigned to charges

Remove from all charges first, then deactivate + delete


Key IDs Reference

Item

How to Get

Tax Engine ID

GET /settings/tax-engines/connector/<id>

Tax Company ID

GET /settings/tax-companies?taxEngineId=<engine-id>

Product ID

ZOQL: select Id, Name from Product

Rate Plan ID

ZOQL: select Id, Name from ProductRatePlan where ProductId = '<id>'

Charge ID

ZOQL: select Id, Name, TaxCode from ProductRatePlanCharge where ProductRatePlanId = '<id>'

Account ID

ZOQL: select Id, Name, AccountNumber from Account

What Kintsugi Automates

  1. Creates tax code on Vertex engine → POST /settings/tax-codes/connector

  2. Assigns tax code to all charges under that product → PUT /v1/object/product-rate-plan-charge/<id>

References

  1. Install vertex connector on Zuora

  2. Configuring Zuora Template

Was this article helpful?