Ledgerline privacy policy
Last updated: 6 November 2026
Ledgerline ("the app") is made by SKILLMERC (Pty) Ltd. It copies paid Shopify orders and refunds into the merchant's own FreeAgent account. This policy explains what the app reads, stores and shares.
What the app reads from Shopify
- Orders and refunds (read_orders scope): order number, dates, line items, prices, taxes, shipping, discounts, refunds and payment gateway names.
- Customer name, email, phone and billing address on those orders, only to create or match the customer as a contact in the merchant's FreeAgent account.
- Shop name and currency, and the app subscription status.
What the app stores
- The shop domain, Shopify access tokens and the plan.
- FreeAgent access and refresh tokens, encrypted with AES-256-GCM.
- The merchant's settings (chosen FreeAgent bank account and income categories).
- For each synced order: the Shopify order ID and number, the FreeAgent contact, invoice or credit note link and number, status and any error message.
- An activity log with order numbers and messages. Email addresses and phone numbers are removed from log messages before they are saved.
- An access log of every time the app reads customer contact details: who or what read them (for example the order webhook, or the merchant's preview), the shop, the purpose and the time. It does not contain the details themselves and is deleted after 90 days. The app does not keep copies of customer names, emails, phone numbers or addresses. They are sent to FreeAgent and not stored by the app.
Who the data is shared with
- FreeAgent, only for the account the merchant connects, to create contacts, invoices, credit notes and payment records.
- Hosting: Railway (application servers) and Supabase (database). No data is sold or used for advertising.
Retention and deletion
- Uninstalling deletes the Shopify and FreeAgent tokens at once and stops all syncing.
- 48 hours after uninstall Shopify sends a shop redact request and the app deletes all remaining data for that shop.
- Customer redact requests delete activity log lines for that customer's orders.
- Documents already created in FreeAgent belong to the merchant's books and stay in their FreeAgent account.
Security
- All connections use HTTPS or TLS: to Shopify, to FreeAgent and to the database.
- The database and its backups are encrypted at rest by our database host (AES-256). FreeAgent tokens are also encrypted by the app (AES-256-GCM) before they are stored.
- The app uses its own database account that can only reach Ledgerline's tables. Only the owner of SKILLMERC has access to the production systems.
- Test data and live data are kept apart: development uses a local test database and the FreeAgent sandbox.
Security incidents
If we find that data handled by the app may have been exposed, we contain it at once, work out which shops and data were affected within 24 hours, and email each affected merchant within 72 hours with what happened, what data was involved, what we did and what they should do. We also tell Shopify. After every incident we write down the cause and what we changed.
Contact
Kyle Pretorius, SKILLMERC: kyle@skillmerc.com
Data protection and data loss prevention
Version 1.0, 6 November 2026. Owner: Kyle Pretorius, SKILLMERC (kyle@skillmerc.com).
What personal data the app handles
Ledgerline reads the customer name, email, phone and billing or shipping address on paid Shopify orders (read_orders scope). It uses them only to find or create the customer as a contact in the merchant's own FreeAgent account and to put the invoice in that contact's name. The preview screen shows the same fields to the merchant. Nothing else uses them.
Data minimisation
- The app does not store customer names, emails, phones or addresses. They are held in memory during a sync and sent to FreeAgent.
- The database keeps per shop: the shop domain, the encrypted Shopify tokens, the plan, encrypted FreeAgent tokens, settings, and per order the Shopify order ID and number, the FreeAgent document link and number, status and errors.
- No
read_customersscope; backfill only uses order IDs from the orders it lists.
Loss prevention controls
- Encryption in transit: HTTPS for the app (Railway), TLS to Shopify and FreeAgent, and
ssl: requireto the database. - Encryption at rest: Supabase encrypts the database and its backups at rest (AES-256). On top of that, the app encrypts every OAuth token before storing it: Shopify access and refresh tokens and FreeAgent access and refresh tokens are AES-256-GCM ciphertext (
v1:format, random 96-bit IV per value). The 256-bit key is a Railway environment variable (TOKEN_ENC_KEY) and is never stored in the database or the code. Production refuses to encrypt or decrypt without it. Tokens stored before this change were encrypted in place by a database migration on 6 Nov 2026. - Least privilege: the app connects with its own database role
ledgerlinethat owns only theledgerlineschema and cannot read other projects' tables. - No personal data in logs: activity log lines carry order numbers, not customer details; every log message and stored error goes through a scrubber that replaces email addresses and phone numbers (
scrubPiiin src/db/repo.js, tested in test/access-log.test.js). - Access logging: every read of customer contact fields is logged (see access-logging below).
- Secrets: API keys and the encryption key live only in Railway variables and owner-only local files (mode 600), never in the code repository.
- Test and production data are separate: development uses an in-process test database and recorded fixtures; live testing uses Shopify development stores and the FreeAgent sandbox.
- Deletion: uninstall removes tokens at once; Shopify's shop/redact deletes all of a shop's rows; customers/redact deletes the log lines for that customer's orders.
Access logging
Table ledgerline.personal_data_access_log: actor (system:webhook, system:backfill, merchant:node tools/log-access.mjs.
Staff access
Only the owner, Kyle Pretorius, has access to the production database, hosting and developer accounts. Each account must have a unique strong password (at least 12 characters, generated by a password manager) and two-step verification wherever the provider offers it. The self-audit checks this.
Incidents
See incident-response.md.
Security incident response policy
Version 1.0, adopted 6 November 2026. Owner: Kyle Pretorius, SKILLMERC (kyle@skillmerc.com). Reviewed at least once a year and after every incident.
Scope
Any event that may have exposed, changed or destroyed data that Ledgerline handles: Shopify order and customer contact data read during a sync, Shopify access tokens, FreeAgent tokens, merchant settings and the activity log. It covers the app servers (Railway), the database (Supabase), the code and the developer accounts (Shopify Partners, FreeAgent developer, Railway, Supabase, GitHub).
Roles
SKILLMERC is a one-person company. Kyle Pretorius is the incident lead and makes every decision below. Automated tools he runs may help with the investigation but do not decide on notification.
Steps
- Detect and record (at once). Sources: Railway and Supabase alerts, the app's error logs, the personal data access log, unusual FreeAgent or Shopify API errors, reports from merchants, Shopify or FreeAgent. Open an incident note with the time found, what was seen and who reported it.
- Contain (within 1 hour of confirming). As needed: rotate the Shopify client secret in the Dev Dashboard, rotate the database password and TOKEN_ENC_KEY, revoke FreeAgent connections (merchants reconnect), stop the Railway service, block a compromised account or key.
- Assess (within 24 hours). Work out which shops and which data were affected, using the access log (actor, shop, purpose, time) and the database. Decide whether personal data was exposed.
- Notify. If personal data of merchants' customers may have been exposed: tell each affected merchant by email within 72 hours of becoming aware, with what happened, what data, what we did and what they should do. Tell Shopify through the Partner Dashboard support channel in the same window. Where Ledgerline acts as a processor, the merchant is the controller and decides on telling their customers and regulators; we give them the facts they need. SKILLMERC's own regulator notifications (for example the UK ICO or South Africa's Information Regulator) are made where the law requires it.
- Recover. Fix the cause, redeploy, confirm webhooks and syncs work, re-enable the service.
- Review (within 14 days). Write a short post-incident note: cause, timeline, what changed. Update this policy and the self-audit checklist.
Contacts
- Incident lead: Kyle Pretorius, kyle@skillmerc.com
- Shopify: Partner Dashboard support
- Hosting: Railway support, Supabase support