Skip to content

Developer notes

Technical reference for developers who customize Xero Accounting Sync.

Item Value
Add-on id kv_xero
Function prefix fn_kv_xero_
Language variables kv_xero.*
CSS scope .kv-xero
PHP namespace Tygh\Addons\KvXero
Preset accounting (generated by kv new --kind integration)
Class Role
Client\BaseClient HTTP (cURL, TLS verification, timeouts), JSON, Retry-After and rate limit headers, error mapping, masked logging
Client\Api OAuth 2.0 (authorization code, rotating refresh token under a database lock) and the Accounting API calls
Client Client per company, the connection test
Sync Contact, invoice, payment, credit note, refund and item sync; tax allocation; the map table
Accounts, Secret Credentials (test and live) sealed with AES-256-GCM; one account per store owner or per vendor
Config, Access Settings, owner mode, who may see and manage what
Queue, Jobs, JobException Job queue: back-off 5 min / 15 min / 1 h / 3 h / 12 h, per-job isolation, overlap lock; handlers in Jobs::handle(), recurring work in Jobs::schedule()
Log Event log with masking, filters, CSV, retention
Table Purpose
?:kv_xero_accounts Credentials per company (secrets sealed), last connection check, token cache
?:kv_xero_log Log
?:kv_xero_jobs Queue
?:kv_xero_map What was sent to the accounting system (Xero ids, payload hash)

PHP hook change_order_status_post (queues the invoice, payment and credit note jobs). Template hooks: only the License card in the add-on settings. Nothing is printed on the storefront, so full page cache and Varnish are unaffected.

The base URL can be overridden for tests in config.local.php (development only):

$config['kv_xero_base_url'] = 'http://127.0.0.1:11923';

node tests/mock-server/server.js 11923 starts a local stand-in of the Xero identity service and Accounting API; node tests/e2e/e2e.mjs runs the end-to-end test (real orders, OAuth flow, refunds) against it; php tests/unit.php runs the unit tests.

Admin templates live in design/backend/templates/addons/kv_xero/. Do not edit them in a store; they are replaced on update.

  • API sources: Xero’s published OpenAPI descriptions (github.com/XeroAPI/Xero-OpenAPI: xero_accounting.yaml, xero-identity.yaml). The rate limits (60 calls a minute, 5,000 a day per organisation, Retry-After on 429) and the 60 day rolling refresh token come from Xero’s developer documentation, whose pages could not be fetched as text during development: check them against developer.xero.com.
  • Refresh tokens are single use. Accounts::locked() serialises the refresh with GET_LOCK, and a second process re-reads the account after the lock, so cron and an admin click never burn the same token.
  • Idempotency keys: kv-inv-<order>-<hash>, kv-pay-<order>, kv-cn-<order>, kv-rf-<order>, kv-al-<order>.
  • Map table entities: customer, invoice, payment, credit, refund (payment or allocation), item.
  • CS-Cart stores taxes either per line (applies P_) or per order (subtotal calculation); Sync::allocate() handles both.