SKU.io · Engineering Research · Unlisted

Sales Tax Provider Integration Matrix

What it would actually cost and mean to integrate SKU.io with TaxJar, Avalara, Zamp, Numeral or Kintsugi — scored on integration surface, PHP/Laravel fit, domain fit, and commercial terms. Not a feature comparison of the products themselves.

20 August 2026 Context: SKU-8076 — Sales Tax Reporting PRD Stack: Laravel 11 · PHP 8.3 · Vue 3 Primary sources checked: vendor dev docs + Packagist API

00The call

Weighted scores out of 5 — the model and its weights are shown in §05 so you can disagree with them explicitly rather than implicitly.

3.8 RANK 1

Avalara

Ship first

Only one that survives a NetSuite bake-off. Live PHP SDK, 8.9M installs, global VAT/GST. No marketplace-facilitator primitive — we compensate by pre-classifying.

3.3 RANK 2

Zamp

Partner track

The only genuine software-platform partnership: sandbox + production, certified badge, recurring commission. No PHP SDK; US + Canada only.

3.0 RANK 3

TaxJar

Copy the API, not the vendor

Technically the best fit — and the worst bet. Maintenance mode post-Stripe, SDK stalled 15 months, ERP connectors sunset, price rising steeply.

2.9 RANK 4

Kintsugi

Design for, revisit at 1.0

Best architectural fit and a PHP SDK on 8.2+ — but it's v0.6.2 with 1,197 downloads. Pre-1.0 is not a compliance dependency.

These five are not one category — compare them accordingly

Avalara and TaxJar are tax engines you call. Zamp, Numeral and Kintsugi are managed compliance services that expose an API. That difference decides the integration shape far more than any feature row below.

Note also that four of the five publish "X vs Y" comparison pages about the other four. Every commercial cell in this matrix is marked for confidence and should be re-verified in a sales call before it informs a decision.

01Integration surface — the API you'd code against

The mechanics of the integration itself: what you authenticate with, what you call, what you can test against, and what the vendor is willing to commit to operationally.

verified from vendor developer docs or Packagist API ~ from vendor marketing or secondary source ? not documented publicly — confirm with vendor
DimensionAvalaraTaxJarZampNumeralKintsugi
Category Tax engine — enterpriseTax engine — SMBManaged service + APIManaged service, API-firstManaged service, AI-positioned
Authentication License key / BearerAuthorization: Token or BearerBearerBearer~API key
Base URL AvaTax REST v2api.taxjar.com/v2Zamp APIapi.numeralhq.com~Kintsugi API
Versioning strategy URL-versioned (v2)x-api-version date headerX-API-Version date headerX-API-Version2024-09-01 default, 2025-05-12 current?Not documented
Calculate (rate quote) CreateTransaction uncommittedPOST /v2/taxesPOST /calculations/tax/calculationsTax Estimates (read-only, repeatable)
Commit (record for filing) CommitTransactionPOST /v2/transactions/ordersPOST /transactionsTransactionsTransactions (permanent liability record)
Void / adjust VoidTransaction, AdjustTransactionDelete / update order?Not documented~Refund handling?Not documented
Refund / credit note
maps to our SalesCredit
RefundTransaction/v2/transactions/refunds?Implied by transactions~Documented capability?Not documented
Address validation ResolveAddressAddress validation endpointAddress validation endpoint?Not surfacedRequired ahead of estimation
Lookup granularity Full addressAddress / ZIPAddress, lat/long, postal code~AddressResolved address to local jurisdiction
Sandbox environment Yesapi.sandbox.taxjar.comYes + free trial env pre-registered in all 47 remote-seller states?Not documented~Yes
Published rate limit ?Not published~10,000 calls/min (Professional plans)1,000 req/min?Not published?Not published
Published latency target ?None?None~400ms p95?None?None
Idempotency keys ~Via transaction code reuse~Via transaction_id uniqueness?Not documented?Not documented~Keyed on your order ID
Webhooks / callbacks ~Available in platform~Limited?Not documented?Not documented?None documented

02PHP / Laravel fit — where build cost actually lives

All figures pulled live from the Packagist API on 2026-08-20. This section moves the estimate more than any other: the difference between a maintained SDK and writing your own client is roughly a fortnight, and the difference between a stable SDK and a pre-1.0 one is an unbounded maintenance tail.

DimensionAvalaraTaxJarZampNumeralKintsugi
Official PHP SDK YesYesNoNoYes
Package avalara/avataxclienttaxjar/taxjar-phpkintsugi-tax/tax-platform-sdk
Other SDK languages .NET, Java, Python, Ruby, JSRuby, Python, Node, C#, Java, GoJava, Python, RubyPython, TypeScript, Java, Ruby
Latest version 26.7.3v2.0.1v0.6.2
Last release 27 Jul 20268 May 2025 — 15 months ago7 Jul 2026
Total installs 8,879,8866,848,0321,197
Released versions 1022621
PHP constraint >=5.5.9 legacy shape — expect untyped array models^8.0>=8.2 matches our 8.3
API stability Stable, 1.0+Stable, 2.xn/a — we own the clientn/a — we own the clientPre-1.0 — breaking changes expected
Client we must build & maintain Thin wrapper onlyThin wrapper onlyFull REST client clean API, ~3–5 daysFull REST clientThin wrapper + version pinning
Laravel ecosystem presence Community wrappers existCommunity wrappers existNoneNoneNone

03Domain fit — does it understand a multichannel seller?

This is the section that should decide the choice, because it's the only one where SKU.io's position is unusual. We know the sales channel for every order via sales_orders.sales_channel_id → sales_channels.integration_instance_id → integrations.name. Shopify's native report cannot know this. Avalara's Shopify connector cannot know this. If the provider can't receive that fact, the advantage dies at the API boundary.

DimensionAvalaraTaxJarZampNumeralKintsugi
Per-transaction marketplace-facilitator flag
★ the decisive criterion
No primitive. Marketplaces are a company-level configuration, not a transaction attribute. isSellerImporterOfRecord is import duty, not facilitator — an expensive thing to misread. First class. exemption_type:"marketplace" + provider on /v2/taxes and /v2/transactions. Applies state law as at transaction_date. Platform-level. Auto-identifies marketplace transactions, excludes from filing, retains for nexus. Per-transaction field unconfirmed. Not documented. Presumably via exemptions. Not documented. Presumably via exemptions.
Recognised marketplaces Manual configurationAmazon, eBay, Etsy, Walmart built in; others via exemption_type aloneAmazon, eBay, Etsy connectors?Amazon, Shopify, WooCommerce
State-and-date-aware facilitator logic NoYes — exempt only if that state had a facilitator law on the transaction dateDocumented per-state nexus treatment??
Nexus monitoring API Yes, enterpriseEconomic Nexus Insights — the category blueprintYes, with per-state marketplace treatmentYesYes, incl. free tier
Product tax codes / taxability Extensive catalogueYesSingle un-paginated tax-codes endpointProducts resourceProducts with categories
Exemption certificates Yes (CertCapture)YesYesYesYes, on the customer object
Filing & remittance Yes — ReturnsYes — AutoFileYes — fully managedYes — managedYes
Geography Global — VAT, GST, e-invoicingUS-firstUS + Canada onlyUS + VAT, 32 currenciesUS + VAT/GST
Covers pod-au-1 (fleur, curvy) YesLimitedNoPartialPartial
Multi-currency YesLimitedUSD / CAD32 currenciesYes
Vendor-named rollout model Calculate-then-postL1 report → L2 estimate — matches our staging exactly

A correction the PRD needs regardless of vendor

docs/plans/sales-tax-reporting.md states that economic-nexus thresholds in many states exclude marketplace sales. The real picture is close to an even split and is state-specific: roughly 20+ states include marketplace-facilitated sales in threshold maths (Alaska, California, Connecticut …), roughly 20 exclude them (Alabama, Arizona, Colorado, Florida …), and some (Oklahoma, Pennsylvania) exclude only conditionally on the facilitator having collected.

Phase 3 therefore needs a per-state includes_marketplace_sales attribute on TaxNexusThreshold, not a global exclusion rule. Getting it wrong under-reports exposure across half the country — precisely the failure the feature exists to prevent.

04Commercial & partnership terms

Whether integrating is a cost line or a revenue line. Every cell here is vendor-published and should be treated as a starting position, not a fact.

DimensionAvalaraTaxJarZampNumeralKintsugi
Partner program type Certified Integration / ISV / OEM-embeddedStripe ecosystemSoftware-platform partnershipReferralIntegration listing
Partner sandbox + production access Yes, via certificationSelf-serveYes, explicit?Self-serve
Revenue share ?Not publishedRecurring commission, no upfront cost12-month commission on referrals?Not published
Certification / directory listing Certified Integration — 1,400+ listedZamp CertifiedCo-marketing, webinars, blogListing
White-label / embedded UX OEM-embedded partner typeEmbedded registrations, filings, reportsWhite-label offered?
Dedicated technical partner support Preferred Developer programStandard supportYes, through integration & launchPrivate Slack channelStandard support
Pricing model Enterprise, modular, quotePer-transaction tiersAll-inclusive quote, no per-filing feePer-event, no monthly minimumFreemium + per-event
Published price points ~Quote only~Rising >100%; legacy pricing ends 1 Oct 2026~~$8.6k–$14.9k/yr mid-market~$75/filing · $150/registration~Free tier · $75/filing
Onboarding friction Self-serve dev accountSelf-serveToken issued by emailing supportSales-ledSelf-serve + free tier
Competitor already integrated Cin7, NetSuite, BrightpearlManyCin7
Vendor trajectory Stable incumbentMaintenance mode; ERP connectors sunsetGrowth-stageGrowth-stageEarly-stage

05Weighted scorecard

Scores 1–5 per dimension, weighted as below. This is a judgement model, not an objective measurement — the weights encode the view that marketplace-facilitator support matters most because it is the only dimension where SKU.io's position is genuinely unusual, and that build cost matters second because it is the most reliably estimable.

Dimension (weight)AvalaraTaxJarZampNumeralKintsugi
Marketplace-facilitator support 25%2.05.03.02.02.5
PHP / Laravel build cost 20%5.03.02.52.03.5
API quality & operability 15%4.04.04.54.03.5
Vendor viability & trajectory 15%5.01.03.03.02.0
Commercial / partnership upside 15%3.01.05.02.02.5
Geographic coverage 10%5.02.02.03.04.0
Avalara3.80
Zamp3.33
TaxJar2.95
Kintsugi2.93
Numeral2.55

The spread is narrow — 2.55 to 3.80 — which is itself the finding. No option dominates. Avalara wins on everything except the dimension that matters most, and TaxJar wins that one dimension while failing nearly every other. That asymmetry is the argument for an abstraction rather than a bet.

06Integration shapes & effort

Three genuinely different integrations hide under the single word "integrate". Deciding which one you're buying should precede choosing a vendor.

ShapeWhat SKU.io doesWhat we give upRough effortViable with
A · Push-only
report & file
Keep capturing tax exactly as today; push committed transactions so the provider can file returns. No calculation. Nothing. Purely additive to the existing PRD, and reversible. ~3–4 weeksincl. abstraction + one providerAll five
B · Calculate-at-order Call the provider for a rate at order/quote time, then commit. Replaces TaxRateManager for opted-in tenants. The latency budget, and the outage failure mode — a third party now sits in order entry. +2–3 weeksper providerAll five
C · Embedded compliance The provider's registrations / nexus / filing UX is surfaced inside SKU.io. We're the channel, they're the back office. Control of the finance surface — but gains a revenue line. Partnership-dependentZamp, Numeral (white-label), Kintsugi

Recommended sequence

1 · Abstraction before integration. Five vendors, three under five years old, one in maintenance mode, a category consolidating fast. The only irreversible mistake is coupling managers to a vendor SDK. A narrow TaxProviderInterfacecalculate · commit · void · refund · validateAddress — costs little and buys optionality.

2 · Ship Avalara first, as Shape A. Send pre-classified transactions: we do the marketplace split on our side, where the channel data lives. Their weakest point becomes our value-add rather than our blocker.

3 · Open the Zamp platform-partner conversation in parallel. Cheap to explore, and the free trial environment allows prototyping before signing. Two questions to settle on the first call: the per-transaction marketplace-facilitator field, and any non-North-America roadmap.

4 · Design for Kintsugi; adopt their L1→L2 sequencing regardless of vendor. Don't lead with TaxJar — copy its interface shape instead. Skip Numeral unless a prospect arrives already on it.

07Implementation constraints in this codebase

  • Not a Modules/ module. Every existing module is a source of orders or accounting data; a tax provider is a service the app calls. Belongs in app/Services/Tax/ behind a contract, driven from SalesTaxSettings.
  • Bind the interface explicitly. The App\Contracts namespace has a known unbound-interface trap in this repo — bind in a service provider and add a test that resolves it.
  • Don't leak vendor models. Avalara's >=5.5.9 constraint means untyped array models; wrap in app/Data/ Laravel Data objects at the provider boundary.
  • Repository rule applies. Persisting external transaction IDs and commit status goes through a repository, never Model::create() with logic in a manager.
  • Commit path is a queued, tenant-aware job (TenantAwareJob) on order close / sales-credit creation — never inline in the request. Use the Tracked Job pattern for historical backfills.
  • Timezone is a real bug source. sales_orders.order_date is UTC; provider transaction_date is jurisdiction-local for state-law purposes. Convert via Helpers::dateUtcToLocal() or transactions land in the wrong filing period at month boundaries.
  • Provider is a per-tenant setting, not a platform decision — hitlights on Avalara and caviarco on Zamp must both work.
  • Availability is not a correctness assumption. A 500 from a tax API must never block order creation: fall back to the existing TaxRateManager figure, queue the commit, reconcile later.
  • Credentials via SecretsManagerServiceProvider — config defines avalara.sandbox.* / avalara.production.*, provider resolves to avalara.auth.*. Config::preventStrayRequests() in tests.

08Evidence & confidence

What this matrix is and isn't standing on.

Verified from primary sources

  • All PHP SDK figures — version, release date, install count, PHP constraint — queried live from the Packagist API on 2026-08-20.
  • Endpoint names, auth schemes and versioning read from each vendor's own developer documentation.
  • TaxJar's marketplace-facilitator parameters read from TaxJar's own support article.
  • Zamp's published throughput and latency figures, and its partner-program terms, from Zamp's developer and partnership pages.

Weak or unverified — treat as questions, not findings

  • All pricing. Sourced from vendor and competitor-authored pages. Four of the five publish comparison content about the other four.
  • TaxJar's decline. Corroborated by the stalled SDK (a hard fact) but the narrative around it comes from competitor blogs.
  • Marketplace support for Zamp, Numeral and Kintsugi. Genuinely undocumented publicly — a first-call question, not a gap I could confirm.
  • Idempotency and webhooks are under-documented across all five. Assume nothing.
  • Effort estimates are judgement, not measurement.