# Transactful – full documentation B2B trade credit and wholesale onboarding for Shopify. Site: https://transactful.com This file concatenates the complete product documentation for LLM consumption. Page index: https://transactful.com/llms.txt --- # API overview & authentication Source: https://transactful.com/docs/api/overview/ The Transactful API gives you programmatic access to **your store's** credit data – companies under credit management, the ledger, applications, holds – for connecting ERPs, accounting tools, dashboards, or your own automation. ``` Base URL https://api.transactful.com/v1 Format JSON · UTF-8 · amounts as decimal strings with a currency Versioning Path-versioned (/v1); breaking changes only ever arrive in a new version ``` ## Authentication Create API keys in **Transactful → Settings → API**. Every key is scoped to the single store it was created in and carries the permissions you choose at creation: | Scope | Grants | |---|---| | `read_credit` | Companies' limits, balances, ledger entries, holds | | `read_applications` | Wholesale applications and their statuses | | `write_credit` | Adjustments, limit changes, place/lift holds | Send the key as a bearer token: ```bash curl https://api.transactful.com/v1/companies \ -H "Authorization: Bearer tk_live_9f2c…" ``` Keys can be rotated (old key keeps working for 24 h) and revoked instantly. Every key's last-used time is visible in settings; unused keys prompt a cleanup nudge after 90 days. ## Rate limits, idempotency, errors - **120 requests/minute** per store; `429` with `Retry-After` beyond it. - Write requests accept an `Idempotency-Key` header – retries with the same key never double-apply. - Errors are JSON with a stable machine code and a human sentence: ```json { "error": { "code": "limit_below_zero", "message": "Credit limit must be zero or greater." } } ``` ## Built inside Shopify's rules This API is designed against Shopify's [API License and Terms of Use](https://www.shopify.com/legal/api-terms) and [protected customer data requirements](https://shopify.dev/docs/apps/launch/protected-customer-data), and we hold ourselves to them explicitly: - **Merchant-scoped by construction.** A key returns data for its own store, full stop. There is no cross-store access, no aggregate endpoints, and no way to query another merchant's data. - **We never proxy Shopify's APIs.** Responses contain Transactful's records (applications, ledger entries, credit accounts) with Shopify **GID references** (e.g. `gid://shopify/Company/…`) – never embedded Shopify resources. To read the Shopify objects themselves, use Shopify's Admin API under your own store's credentials. - **Personal data is minimized.** Endpoints return buyer *business* data by default; personal contact fields require the `read_applications` scope, are never included in ledger or credit responses, and GDPR erasure propagates – a redacted person is redacted in API responses too. - **Your obligations flow down.** Our [Terms of Service](/terms/) require that anything you build on this API uses merchant data only to serve that merchant – the same standard Shopify holds us to. Reselling, aggregating, or brokering data accessed through this API is prohibited. - **No AI training.** We don't use merchant or customer data to train models, and our terms prohibit API consumers from doing so with data obtained through us. If you're evaluating this as part of app review or a security assessment and want more detail, email [hello@transactful.com](mailto:hello@transactful.com) – compliance questions get direct answers. --- # API reference Source: https://transactful.com/docs/api/reference/ All endpoints are relative to `https://api.transactful.com/v1`. IDs are prefixed (`co_`, `le_`, `app_`); timestamps are ISO 8601 UTC; amounts are decimal strings with an explicit currency. ## Companies ```bash GET /companies # list, paginated (cursor) GET /companies/{id} # one company's credit state ``` ```json { "id": "co_8fk2m1", "name": "Aldgate Homeware Co", "shopify_company_gid": "gid://shopify/Company/7391820", "status": "approved", "payment_terms": "NET_30", "credit_limit": { "amount": "10000.00", "currency": "GBP" }, "outstanding": { "amount": "8050.00", "currency": "GBP" }, "available_credit": { "amount": "1450.00", "currency": "GBP" }, "hold": null, "updated_at": "2026-07-24T16:41:09Z" } ``` `available_credit` is what checkout enforces: limit − outstanding − safety buffer. Filter with `?status=approved|on_hold` and `?updated_since=`. ## Ledger ```bash GET /companies/{id}/ledger # entries, newest first, paginated ``` ```json { "id": "le_92hd7a", "kind": "order_placed", // order_placed | payment | refund | cancellation | adjustment | opening_balance "amount": { "amount": "2340.00", "currency": "GBP" }, "shopify_order_gid": "gid://shopify/Order/5510238", "note": null, "occurred_at": "2026-07-24T09:12:44Z" } ``` The ledger is append-only: entries are never edited or deleted, so consumers can sync incrementally with `?after={entry_id}` and never re-reconcile. ## Adjustments, limits, holds Requires `write_credit`. All three actions appear on the company timeline attributed to the API key's label, exactly like a staff action. ```bash POST /companies/{id}/adjustments { "amount": "-500.00", "note": "Bank transfer 22 Jul ref 8841" } # note required PUT /companies/{id}/credit-limit { "amount": "12000.00", "reason": "Season uplift" } POST /companies/{id}/hold # place a manual hold { "note": "Dispute on invoice #1032" } DELETE /companies/{id}/hold # lift it ``` Automatic overdue holds can't be lifted via API while the triggering invoice remains unpaid – the same rule the admin UI enforces. ## Applications Requires `read_applications` (personal contact fields live here and nowhere else). ```bash GET /applications?status=submitted|in_review|needs_info|approved|rejected GET /applications/{id} ``` ```json { "id": "app_31xk8p", "status": "submitted", "business_name": "Fenwick & Daughters Ltd", "vat": { "number": "GB987654321", "status": "valid", "registry": "HMRC", "checked_at": "2026-07-24T14:02:11Z" }, "contact": { "name": "Sarah Fenwick", "email": "sarah@fenwickanddaughters.co.uk" }, "submitted_at": "2026-07-24T13:58:02Z" } ``` Decisions (approve/reject) are **not** available via API – approvals create Shopify resources and carry credit judgement, so they stay in the admin where the audit trail shows a person. Tell us if your workflow genuinely needs this; it would ship with explicit safeguards. --- # API webhooks Source: https://transactful.com/docs/api/webhooks/ Register webhook endpoints in **Settings → API → Webhooks** to receive events instead of polling. ## Events | Event | Fires when | |---|---| | `application.submitted` | A wholesale application arrives | | `application.approved` / `application.rejected` | A decision is made | | `credit.checkout_blocked` | An order was blocked at checkout (company, amount, available) | | `credit.limit_changed` | A limit or temporary limit changes | | `hold.applied` / `hold.lifted` | Any hold starts or ends (manual or automatic) | | `ledger.entry_created` | Any ledger entry (orders, payments, adjustments) | | `reconciliation.drift` | Nightly reconciliation found and corrected a discrepancy | Payloads contain the same objects as the [API reference](/docs/api/reference/) – Transactful records with Shopify GID references, never embedded Shopify resources, and no personal contact fields unless the endpoint was registered with the `read_applications` scope. ## Verifying deliveries Every delivery is signed: `X-Transactful-Signature` is an HMAC-SHA256 of the raw body using your endpoint's secret (shown once at creation). Reject anything that doesn't verify. ```ruby expected = OpenSSL::HMAC.hexdigest("SHA256", secret, request.raw_post) ok = ActiveSupport::SecurityUtils.secure_compare(expected, request.headers["X-Transactful-Signature"]) ``` ## Delivery semantics At-least-once, with retries over 24 h (backoff: 1 m, 5 m, 30 m, 2 h, 6 h, then hourly). Deduplicate on the `event_id` field. Endpoints failing for 7 consecutive days are disabled and you're emailed. Events are also visible in **Settings → API → Event log** for 30 days regardless of delivery. --- # The application form Source: https://transactful.com/docs/applications/application-form/ The application form is the front door of your wholesale program. Transactful hosts it (no theme code) and validates as the buyer types, so applications arrive complete and checkable. ## Fields | Section | Fields | Configurable | |---|---|---| | Business | Legal name, trading name, company number, website | Each field: required / optional / hidden | | Address | Registered address, trading address (if different) | Required by default | | Contact | Buyer name, role, email, phone | Email always required – it becomes the Shopify company contact | | Tax | VAT number with live validation | Require valid VAT to submit: on / off | | References | Trade references: business name, contact, email/phone | Count required: 0–5 (default 2) | | | *On submission, Transactful emails each reference a three-question form (how long trading together, typical monthly value, payment reliability). Replies attach to the application automatically; you never chase them.* | | | Documents | Uploads with a type and optional expiry date | Types you define (e.g. trade certificate, insurance) | | Terms | Checkbox: agree to your wholesale terms, with a link you set | Optional | | Extra | Up to 10 custom questions (text, select, yes/no) | Fully yours | ## VAT validation at submit If a VAT number is entered, it's validated live – [HMRC for UK numbers, VIES for EU](/docs/applications/vat-validation/) – and the result is shown to the buyer before submission: > ✓ GB 987 6543 21 – registered to ALDGATE TRADE SUPPLY LTD With **Require valid VAT** on, a failed check blocks submission with: > We couldn't verify this VAT number with HMRC. Check the number, or continue > without one and we'll follow up. (The "continue without" path appears only if you allow VAT-less applications.) ## Documents and expiry Each document type you define can require an expiry date (insurance certificates, licences). Expiry dates drive [automatic re-review](/docs/applications/approvals/#re-review): 30 days before a required document expires, the buyer gets a renewal email and the company is flagged in your queue. Uploads accept PDF, PNG, JPG up to 20 MB, stored encrypted; see [Permissions & data](/docs/reference/permissions-and-data/). ## Spam and abuse Submissions are rate-limited per IP, protected by an invisible challenge (no CAPTCHA for legitimate buyers), and duplicate applications for the same email or VAT number are merged into one queue entry with a "resubmitted" marker. ## Where the form lives - Hosted page: `apply.transactful.com/your-store` – add it to navigation. - The form inherits your logo and a light/dark accent you choose in settings; it's designed to look like part of your operation, not ours. --- # Approvals & rejections Source: https://transactful.com/docs/applications/approvals/ ## Approving Approval is one screen with three decisions: 1. **Catalog** – which wholesale price list the company sees. 2. **Payment terms** – Net 15/30/60/90, or deposit + remainder (e.g. 25% at checkout). 3. **Credit limit** – the maximum outstanding you'll carry. The screen shows [suggested starting points](/tools/wholesale-credit-limit-calculator/) based on terms and any order history. On confirm, Transactful creates in Shopify: the **Company**, a **company location** (from the trading address), and a **company contact** (the applicant, invited to activate their customer account). It assigns the catalog, payment terms, and tax exemption (if their [VAT validation](/docs/applications/vat-validation/) supports it), and opens the [credit account](/docs/credit/credit-limits/). The buyer receives the approval email. Elapsed time: seconds. If the applicant matches an **existing** Shopify company (by VAT number or domain), you'll be offered "attach to existing company" instead of creating a duplicate. ## Rejecting Rejection asks for a reason from your configurable list (e.g. "insufficient references", "outside our territory") plus optional free text. The buyer email contains only what you choose to share – the internal reason stays internal. Rejected applicants can reapply after a cool-down you set (default 90 days). ## Re-review Trust decays; Transactful watches for it. A company is flagged for re-review when: - a required document passes its expiry date (buyer gets renewal emails at 30 and 7 days before), - quarterly VAT revalidation fails, - or you set a manual review date ("check this account in 6 months"). Re-review is a queue like applications: you see what changed, then confirm the account, adjust the limit, or place a [credit hold](/docs/credit/credit-holds/). Nothing changes automatically except the flags – decisions stay yours. --- # Importing existing accounts Source: https://transactful.com/docs/applications/importing-existing-accounts/ Most stores arrive with a wholesale book already trading. **Your existing stockists never re-apply, and importing sends them nothing.** You bring them in quietly, set limits, and enforcement is live from that moment – buyers notice only if they try to order past a limit. ## Where accounts come from | Source | How | |---|---| | Existing Shopify companies | Transactful lists every company on your store; tick the ones to bring under credit management. Terms and catalogs they already have are untouched. | | Tagged customers (legacy wholesale apps) | Select customers by tag (e.g. `wholesale`); Transactful creates proper Shopify companies from them, one review screen at a time or in bulk. | | CSV | Company name, contact email, VAT number, terms, credit limit, current balance – download the template, fill it from your spreadsheet or accounting export, upload. Rows with problems are reported per-row; clean rows import anyway. | ## Opening balances If a stockist currently owes you £3,200, the import records a **£3,200 opening balance** – a first entry in their [ledger](/docs/credit/exposure-and-sync/), labelled as such, so available credit is correct from day one. As those old invoices are paid, record the payments (or let [Xero sync](/docs/receivables/xero-sync/) clear them automatically). No opening balance? They start clean at zero. Orders already in Shopify on payment terms are detected and offered as opening entries automatically – you confirm rather than type. ## What imported buyers experience Nothing, until you choose otherwise: - **No emails are sent by import.** No "welcome to our new system", no re-application, no password resets. - Their existing logins, prices, and terms keep working. - When you're ready, optionally send the (editable) **credit summary email** – "your account with us has a £10,000 limit; here's where to see your balance" – per company or in bulk. ## VAT numbers on import Imported VAT numbers are validated in the background ([HMRC / VIES](/docs/applications/vat-validation/)) and the results attached. Failures become **re-review flags**, not blocks – your trading relationships aren't interrupted by a lapsed registration you didn't know about; you're just told. ## Running alongside another app Transactful doesn't touch themes or prices, so it runs safely alongside an existing wholesale app while you transition: import your accounts, watch the ledger agree with reality for a couple of weeks, then retire the old app on your schedule. --- # The review queue Source: https://transactful.com/docs/applications/review-queue/ The review queue lives in your Shopify admin (**Apps → Transactful**). It shows every application with its validation results, flags, and history – designed so most decisions take under a minute. ## Statuses An application is always in exactly one state: | Status | Meaning | Who acts next | |---|---|---| | **Submitted** | Arrived, validations run | You | | **In review** | A staff member opened it | You | | **Needs info** | You asked the buyer for something | Buyer | | **Approved** | Company created, credit live | – | | **Rejected** | Declined, buyer notified | – | | **Withdrawn** | Buyer or you closed it without a decision | – | Allowed transitions: Submitted → In review → (Needs info ⇄ In review) → Approved / Rejected. Withdrawn is reachable from any open state. There are no other paths – an application can never be "approved" twice or edited after decision; corrections happen on the company record instead. ## Flags Applications carry advisory flags that never block you, only inform: **Name mismatch** (registry name ≠ applicant name), **Validation pending** (registry outage), **Resubmitted** (duplicate email/VAT merged), **Reference bounce** (a reference email was undeliverable). ## Needs info "Request information" opens a message to the buyer (your text, their reply by email or upload link). The application shows what you asked and when; replies attach automatically. Applications in **Needs info** for more than 14 days surface a gentle nudge in the queue – stale applications are lost revenue. ## Notes and the audit trail Internal notes are visible to staff only. Every action – status change, note, message, validation result, eventual approval terms – is recorded with actor and timestamp on an immutable timeline. When a buyer asks "why was I rejected?" or an auditor asks "who approved this limit?", the answer is on the record. --- # VAT validation Source: https://transactful.com/docs/applications/vat-validation/ ## Which registry, when The country prefix decides the check: - **GB** → HMRC's Check a VAT Number service. Response includes the registered business name and address. - **EU prefixes** (DE, FR, IE, NL, …) → the European Commission's **VIES** service. Response confirms validity and, for most member states, the registered name. Format problems (wrong length, failed GB checksum) are caught instantly, before any registry call – same logic as our free [VAT number checker](/tools/vat-number-checker/). ## The evidence trail Every successful check stores: the number as validated, registry response (name/address where provided), timestamp, and registry consultation ID (VIES provides one; it's your proof of due diligence for zero-rating). This evidence is attached to the application and the company record permanently – audits are a search, not an archaeology dig. ## Name matching If the registry returns a business name that doesn't resemble the applicant's legal name, the application is flagged **Name mismatch** in the review queue – not blocked. You decide; sometimes it's a trading-name difference, sometimes it's someone using a stranger's VAT number. ## When the registry is down HMRC and VIES both have outages. If a live check can't complete: - The buyer can still submit; the application is marked **Validation pending**. - Transactful retries automatically (15 min, 1 h, 6 h, 24 h) and updates the application when the registry answers. - You can approve anyway – the pending state is shown clearly, and the check completes retroactively. ## Revalidation VAT registrations lapse. Transactful revalidates every approved company's number **quarterly**; a number that stops being valid flags the company for [re-review](/docs/applications/approvals/#re-review) and (optionally, default on) pauses their tax exemption until resolved. --- # What buyers see Source: https://transactful.com/docs/credit/buyer-experience/ Buyers never leave Shopify. Their credit lives in the **customer account** they already use for orders – no separate portal, no second password. ## In the customer account A **Credit** section (a customer account extension) shows: - Credit limit, current balance, **available credit** – exact figures - Payment terms (e.g. Net 30) and any hold status, stated plainly - Open invoices with due dates, and paid history - Their documents, with expiry dates and a renewal upload when one is due ## At checkout Checkout is normal until a rule intervenes. The two messages (both editable per store, shown here as defaults): **Over limit:** > This order exceeds your available credit (£1,450.00 remaining). Reduce the > order total or contact us to arrange payment. **On hold:** > Ordering is paused on your account. Contact us to arrange payment and we'll > lift the hold straight away. Messages always show the buyer a number or a next step – never a bare "no". On standard OS 2.0 themes the same message also appears on the cart page before checkout begins. ## Emails buyers receive Application received · approved (with their terms and limit) · rejected · request for information · document expiring (30 and 7 days) · invoice reminder · overdue notice · hold applied · hold lifted. Every template is editable; every email states exact amounts and dates. Full list with default copy: [Emails & notifications](/docs/reference/notifications/). --- # Credit holds Source: https://transactful.com/docs/credit/credit-holds/ A **hold** stops a company ordering regardless of available credit. Checkout shows your hold message (default): > Ordering is paused on your account. Contact us to arrange payment and we'll > lift the hold straight away. ## Manual holds One click on the company's credit page, with an optional internal reason. Lift it the same way. Use it for disputes, suspected fraud, or "the owner said stop". ## Automatic overdue holds Configure per store: place a hold when any invoice is **N days overdue** (default off; common values 7 or 14). The sequence a buyer experiences: 1. Invoice passes due date → counted overdue, reminder emails begin ([notifications](/docs/reference/notifications/)). 2. N days overdue → hold applied automatically; buyer notified with the exact invoice(s) and amounts. 3. Payment recorded → **hold lifts automatically within seconds**. No waiting for you to notice. Manual holds never lift automatically – you placed them, you lift them. ## Holds vs limits A limit answers "how much more can they take?"; a hold answers "should they be ordering at all right now?". A held company can have plenty of available credit – the hold wins. Both states are visible on the company page, in the queue, and to the buyer in their account. --- # Credit limits Source: https://transactful.com/docs/credit/credit-limits/ ## Scope: company or location By default a limit belongs to the **company** – all locations share one pot, because that's how the legal entity owes you money. For buyers whose branches order independently, switch a company to **per-location limits**; each location then has its own limit and exposure, and the company view shows the roll-up. ## Currency Limits are held in your **store currency**. Orders in other presentment currencies count toward exposure at the exchange rate Shopify records on the order. Displayed amounts are always in store currency. ## Setting and changing limits Set the limit at [approval](/docs/applications/approvals/); change it any time from the company's credit page or directly from the Transactful panel on the Shopify company screen. Changes take effect at the next checkout – within seconds. Every change is recorded (who, when, old → new, optional reason) on the company timeline. **Raising** a limit needs no ceremony. **Lowering** it below current exposure is allowed – the buyer simply can't order until they pay down below the new limit; the checkout message shows available credit as £0.00 (never negative). ## Temporary limits For seasonal buying ("they need £30k for Christmas stock"), set a temporary limit with an end date. It supersedes the base limit until expiry, then reverts automatically. The timeline shows both. ## Safety buffer The buffer reserves headroom against the seconds-wide [sync window](/docs/credit/how-enforcement-works/#timing-honestly) and multi-order sprees: **available = limit − exposure − buffer**. Configure it store-wide as a percentage of each limit (default **5%**) or a fixed amount per company. Buyers never see the buffer – only their available credit. ## Starting limits: a rule of thumb Expected monthly order value × months outstanding on their terms × a confidence factor (50% new / 75% some history / 100% established). The [credit limit calculator](/tools/wholesale-credit-limit-calculator/) does this math, and the approval screen pre-fills it. --- # Exposure & sync Source: https://transactful.com/docs/credit/exposure-and-sync/ **Exposure is simply what a company currently owes you** – every unpaid order, minus every payment. Transactful keeps that number correct continuously, and this page explains how. ## What counts as exposure | Event | Effect on exposure | |---|---| | Order placed on payment terms | + order total (including tax and shipping) | | Invoice paid | − amount paid | | Order cancelled | − order total | | Refund issued | − refund amount (a paid, then refunded order nets to zero) | | Draft order sent, on terms, accepted | + total (it's a commitment) | | Order placed and paid at checkout (deposit or full) | + only the unpaid remainder | Orders that arrive outside enforcement (POS, other apps via API) **still count toward exposure** as soon as they exist – the ledger is complete even where pre-sale blocking isn't possible. ## The ledger, not a balance Transactful never stores a running balance that could silently rot. Every event is an entry in an append-only ledger; exposure is always *derived* by summing entries. Duplicate webhook deliveries (Shopify guarantees at-least-once, so duplicates happen) are recognized and ignored; out-of-order events (a payment webhook arriving before its order webhook) resolve correctly because entries are facts, not mutations. ## Nightly reconciliation Every night, Transactful re-derives every company's exposure directly from your Shopify order history and compares it with the ledger. Agreement is logged. Disagreement – from a missed webhook, an edited order, anything – produces a **drift alert**: you see the company, the two numbers, and the correcting entry that was applied. Drift is expected to be rare and small; a pattern of drift is our bug to fix, and visible enough that you'd know. ## The company credit page Each company's credit page shows: limit, exposure, available credit, the buffer, and the ledger itself – every entry with its order link, amount, and timestamp. When a buyer disputes their balance, you read them the ledger. ## Manual adjustments Sometimes reality isn't in Shopify: a bank transfer against an old invoice, an agreed write-off. Add a **manual adjustment** (+ or −) with a required note; it's a first-class ledger entry, attributed and permanent. There is no "edit balance" – only entries. --- # How credit enforcement works Source: https://transactful.com/docs/credit/how-enforcement-works/ ## The model Every approved company has: - a **credit limit** – set by you at approval, adjustable any time - **outstanding exposure** – what they currently owe you: unpaid orders, computed automatically from order events - **available credit** = limit − exposure − your configured [safety buffer](/docs/credit/credit-limits/#safety-buffer) ## Enforcement at checkout When a B2B buyer checks out, a Shopify checkout validation rule compares the order total against the company's available credit. Over the limit, checkout is blocked with a message you control – the default: > This order exceeds your available credit (£1,450.00 remaining). Reduce the > order total or contact us to arrange payment. This runs on Shopify's own checkout infrastructure. It works on **every plan** (Basic, Grow, Advanced, Plus) and requires zero theme changes. ## Where enforcement applies | Surface | Enforced? | |---|---| | Online store checkout (B2B buyer) | ✓ | | Draft orders / quotes | ✓ – validation applies to draft orders by default | | Cart page warnings | ✓ on standard OS 2.0 themes (the theme renders cart errors) | | Shopify POS | ✗ – Shopify does not run checkout validation at POS | | Orders created directly via API by other apps | ✗ – same platform limitation | | Order edits after checkout | ✗ – edits aren't re-validated by Shopify; the ledger updates immediately, and you're alerted if an edit takes the company over its limit | | Subscription and pre-order charges | ✗ – recurring/deferred charges bypass checkout validation | We say this plainly because a credit control you *think* covers everything is worse than one whose edges you know. POS and API orders still count toward exposure the moment they exist – they just can't be blocked pre-sale. ## Timing, honestly Exposure updates within seconds of order events (created, paid, cancelled, refunded). Between an order landing and the update, a second order could squeeze through – the window is seconds wide. Three mechanisms close it in practice: 1. the **safety buffer** you configure absorbs small overshoots, 2. pending-but-unpaid orders count as exposure immediately, 3. **nightly reconciliation** re-derives every balance from your full order history and [alerts on any drift](/docs/credit/exposure-and-sync/). ## If our data is ever unavailable If a company's credit data can't be read at checkout (a sync failure on our side), Transactful **fails open**: the order is allowed and you're alerted immediately. We will never make your store unsellable because our sync broke – a missed block is recoverable; blocked legitimate revenue is not. Merchants who prefer the opposite can enable **strict mode** (fail closed) in **Transactful → Settings → Enforcement**. ## What buyers see Buyers see their credit limit, current balance, and available credit inside their Shopify customer account – no separate portal, no extra login. See [what buyers see](/docs/credit/buyer-experience/). --- # Getting started Source: https://transactful.com/docs/getting-started/ ## Requirements - A Shopify store on any plan (Basic, Grow, Advanced, or Plus) - Shopify's B2B features turned on (see below) - A staff account with permission to install apps and manage customers ### New to Shopify B2B? Since April 2026, every Shopify plan includes native B2B: **companies** (business customers with their own pricing and payment terms) and **B2B checkout**. If you've been running wholesale through discount codes or a separate store, this is the built-in replacement. Enable it in **Settings → B2B** – it takes a minute and changes nothing for your retail customers. Shopify's own guide: [Getting started with B2B](https://help.shopify.com/en/manual/b2b). Transactful is built entirely on this foundation. ### Starting wholesale for the first time? Use the **Recommended setup** at install and read [starting wholesale from scratch](/docs/starting-wholesale/) – it makes the terms-and-limits decisions for you with sensible UK defaults. ### Already have wholesale customers? You don't start from zero and your stockists never re-apply – see [importing existing accounts](/docs/applications/importing-existing-accounts/) after install. ## 1. Install the app Install Transactful from the Shopify App Store. At install you'll approve the app's access to companies, customers, orders, and checkout validation – this is what powers approval and credit tracking ([full list of scopes](/docs/reference/permissions-and-data/)). Nothing is written to your theme at any point. ## 2. Configure your application form Under **Transactful → Application form**, choose what you require from buyers: which fields are mandatory, how many trade references, which document types (with expiry dates), and whether a VAT number is required to submit. See [the application form](/docs/applications/application-form/) for every option. ## 3. Publish the form Transactful hosts your form at `https://apply.transactful.com/your-store`, or on your own subdomain (e.g. `wholesale.your-store.com`) by adding a CNAME record shown in settings. Add the link to your store navigation – "Wholesale", "Trade accounts", "Stockists" – from **Online Store → Navigation**. This is a normal menu link; no theme edits. ## 4. Review your first application Applications appear in **Transactful → Review queue** with VAT numbers already validated and documents attached. Approve, reject, or request more information – the [review queue](/docs/applications/review-queue/) explains each path. ## 5. Approve with a credit limit On approval you pick three things: the **catalog** (wholesale price list), the **payment terms** (e.g. Net 30), and the **credit limit**. Transactful then creates the Shopify Company, location, and contact, assigns everything, and starts tracking exposure. From this moment enforcement is live: an order that would exceed available credit is blocked at checkout with a message you control. ## Verify it end to end 1. Approve a test application with a small limit (e.g. £100). 2. Log in as the buyer contact and add items over £100 to the cart. 3. Attempt checkout – you'll see the block message with the exact remaining credit. 4. Reduce the order below the limit – checkout proceeds on your payment terms. --- # What is Transactful? Source: https://transactful.com/docs/ Transactful manages how much you trust each wholesale buyer, end to end: 1. **Apply** – buyers complete your wholesale application (VAT number, trade references, documents). 2. **Approve** – you review and approve with payment terms, a catalog, and a **credit limit**. 3. **Enforce** – checkout is blocked automatically when an order would take a buyer over their available credit. 4. **Review** – holds when overdue, re-review when documents expire. ## What makes it different - **Nothing touches your theme.** Transactful is built entirely on Shopify's native B2B platform – admin extensions, customer account extensions, and checkout validation functions. No Liquid edits, no script injection, nothing to break when you change themes. - **Works on every Shopify plan.** Credit enforcement runs on Basic and Grow, not just Plus. - **VAT done right.** UK VAT numbers validated against HMRC, EU numbers against VIES, with correct exemption handling per company. ## Start where you are - **Running wholesale already?** Your stockists never re-apply – start with [importing existing accounts](/docs/applications/importing-existing-accounts/). - **Opening your first wholesale program?** The decisions are made for you in [starting wholesale from scratch](/docs/starting-wholesale/). - **A developer vetting this for a client?** The architecture, scopes, and what you'd maintain (nothing): [for developers](/docs/reference/for-developers/). - **Just installed?** [Getting started](/docs/getting-started/) takes you to a working credit check in 15 minutes. ## Your day with Transactful Most days, Transactful needs about two minutes: - **Morning glance** – the dashboard shows new applications, anything overdue, and any account flagged for re-review. Zeros across the board? Done. - **When an application arrives** – open it, check the pre-validated VAT and references, approve with a limit. Under a minute. - **When a buyer hits their limit** – nothing to do: checkout already said no, politely, with the number. You'll see it in the activity feed; call them if the order matters. - **Month end** – statements go out on their own (Ledger tier); the aging report is your chase list. The system works while you don't watch it – that's the point of enforcement. ## The manual **Wholesale applications** - [The application form](/docs/applications/application-form/) – what buyers see and what you collect - [VAT validation](/docs/applications/vat-validation/) – HMRC, VIES, and the evidence trail - [The review queue](/docs/applications/review-queue/) – statuses and the decision workflow - [Approvals & rejections](/docs/applications/approvals/) – what one approval creates - [Importing existing accounts](/docs/applications/importing-existing-accounts/) – your current stockists, no re-applying **Credit** - [How enforcement works](/docs/credit/how-enforcement-works/) – the model, end to end - [Credit limits](/docs/credit/credit-limits/) – setting, changing, and scoping limits - [Exposure & sync](/docs/credit/exposure-and-sync/) – how the numbers stay honest - [Credit holds](/docs/credit/credit-holds/) – pausing a buyer, automatically or by hand - [What buyers see](/docs/credit/buyer-experience/) – customer accounts and checkout messages **Purchasing rules** (Control tier) - [Purchasing rules](/docs/rules/purchasing-rules/) – minimums, case packs, exceptions, simulation **Receivables** (Ledger tier) - [Aging & collections](/docs/receivables/aging-and-collections/) – reports, statements, reminders - [Xero sync](/docs/receivables/xero-sync/) – invoices and payments, both directions **Reference** - [Emails & notifications](/docs/reference/notifications/) – every message Transactful sends - [Permissions & data](/docs/reference/permissions-and-data/) – scopes, storage, GDPR, uninstall --- # Aging & collections Source: https://transactful.com/docs/receivables/aging-and-collections/ The Ledger tier turns the credit ledger into a working receivables desk inside Shopify. ## The aging report Every company's outstanding invoices bucketed the way accountants expect: **current · 1–30 · 31–60 · 61–90 · 90+ days overdue**, with totals per company and for the book. Filter by bucket, sort by amount, export CSV. The headline number – total overdue – is on your dashboard every day. ## The collections queue A worklist of every overdue invoice, oldest first, each with one-click actions: send a reminder, log a promise-to-pay (with a date that resurfaces it), record an offline payment, apply a [credit hold](/docs/credit/credit-holds/), or write off (a [manual adjustment](/docs/credit/exposure-and-sync/#manual-adjustments) with a required note). Items leave the queue only by being paid, promised, held, or written off – nothing slips through by being scrolled past. ## Statements Monthly statements per company: opening balance, invoices, payments, closing balance, in your currency with your logo. Sent automatically on a day you choose, or on demand. Buyers also see statements in their customer account. ## Reminder sequences A default sequence you can edit: **3 days before due** (gentle) → **due date** → **7 days over** (firm) → **14 days over** (final, warns of hold if [automatic holds](/docs/credit/credit-holds/#automatic-overdue-holds) are on). Every message states invoice numbers, amounts, and dates; every send is logged on the company timeline. Per-company opt-outs exist for the accounts you handle personally. --- # Xero sync Source: https://transactful.com/docs/receivables/xero-sync/ Connect Xero once (OAuth, from Transactful settings) and the shop and the books stop diverging. ## What syncs | Direction | What | |---|---| | Transactful → Xero | B2B orders on terms become **ACCREC invoices** (draft or approved – your choice), with line items, tax, and due dates from the payment terms | | Transactful → Xero | Companies become Xero **contacts** (matched by VAT number or name; you confirm ambiguous matches once) | | Xero → Transactful | **Payments** recorded in Xero clear the corresponding exposure in the credit ledger – a bank-reconciled payment lifts overdue status and holds automatically | | Xero → Transactful | Credit notes reduce exposure | Sync runs continuously; the settings page shows the last successful exchange in both directions and any items needing attention (e.g. an invoice deleted in Xero that's still open in Shopify). ## Ground rules - **Shopify is the source of truth for orders; Xero for money received.** Transactful never creates orders from Xero or payments from guesswork. - Nothing is deleted by sync. Removing the connection stops the exchange and leaves both systems as they are. - UK-first: designed against UK VAT invoicing conventions (QuickBooks is on the roadmap – tell us if you need it). --- # For developers Source: https://transactful.com/docs/reference/for-developers/ If a merchant has asked you to vet Transactful, this page is for you. Short version: it's built the way you'd build it – entirely on Shopify's native B2B primitives, with nothing injected into the theme and nothing for you to maintain afterwards. ## Surfaces used | Concern | Implementation | |---|---| | Credit enforcement | Cart & Checkout Validation Function – runs on Shopify's checkout infrastructure, all plans | | Merchant UI | Embedded admin app (App Bridge/Polaris) + admin UI extensions on Company and Order pages | | Buyer credit view | Customer account UI extension | | Application form | Hosted page on our infrastructure (`apply.transactful.com/…`) – linked from navigation, not embedded | | Data freshness | Order webhooks into an append-only ledger; nightly reconciliation against the Orders API with drift alerting | ## What we never touch - **No theme modification.** No Liquid edits, no ScriptTags, no asset injection, no CSS overrides. `shopify theme pull` before and after install diffs empty. - **No order mutation.** We read orders; we never write them. - **No price manipulation.** Wholesale pricing is native Shopify catalogs, assigned at approval. ## How enforcement stays fast Checkout validation functions can't make network calls on standard plans, and we wouldn't want them to. Instead, Transactful continuously writes each company's available credit to **metafields on the Shopify Company/Location** (order webhooks feeding an append-only ledger); the validation function reads those metafields locally at checkout. Zero external calls in the checkout path – our backend being slow or down cannot slow the merchant's checkout. ## Reliability posture If credit data is unreadable at checkout, default behavior is [fail-open with an alert](/docs/credit/how-enforcement-works/#if-our-data-is-ever-unavailable) (strict mode available). Exposure is derived from an append-only event ledger – duplicate or out-of-order webhook delivery is handled by construction, and nightly reconciliation re-derives every balance from the API with discrepancy alerts. Platform edges are documented, not hidden: see [where enforcement applies](/docs/credit/how-enforcement-works/#where-enforcement-applies) for the POS/API caveats. ## Data and compliance Scopes are minimal and enumerated in [Permissions & data](/docs/reference/permissions-and-data/) – no products, no themes, no storefront content. Data is stored encrypted in the UK/EU region; Shopify's mandatory GDPR webhooks (customer request, customer redact, shop redact) are implemented. Uninstall removes the validation immediately and leaves all native Shopify data (companies, catalogs, terms, orders) exactly as it was; our data is exportable as CSV and deleted after 30 days. ## Is there an API? Yes – a merchant-scoped REST API plus signed webhooks for the application and credit lifecycle: [API overview](/docs/api/overview/), [reference](/docs/api/reference/), [webhooks](/docs/api/webhooks/). It's deliberately designed inside Shopify's API License and Terms (no Shopify-API proxying, single-store keys, PII minimization, obligations flowed down) – the compliance mapping is documented right in the [overview](/docs/api/overview/#built-inside-shopifys-rules). Everything Transactful creates in Shopify itself (companies, terms, catalogs, metafields) remains readable through Shopify's own Admin API under the store's credentials. CSV export also exists for one-off needs. ## Testing before you recommend it Transactful installs free on development stores. Approve a test application with a small limit (£100), place an over-limit order with a test B2B customer, and watch the block – the [getting started verification](/docs/getting-started/#verify-it-end-to-end) is a complete test script. Enforcement behaves identically on dev stores and production. ## What you'd maintain Nothing. There's no code in the store, no snippet to update on theme changes, no cron on the merchant's side. Your handover to the client is Shopify admin training, not infrastructure. Questions we haven't answered here: [hello@transactful.com](mailto:hello@transactful.com) – technical questions get technical answers. --- # Emails & notifications Source: https://transactful.com/docs/reference/notifications/ Emails send from `notifications@transactful.com` with your store name as the sender name and your reply-to address, or from your own domain once you add the DNS records shown in settings. Every template is editable; variables like `{{available_credit}}` are always exact figures. ## To buyers | Email | Trigger | Default subject | |---|---|---| | Application received | On submit | We've received your wholesale application | | Application approved | On approval | Your trade account with `{{store}}` is open | | Application rejected | On rejection | About your wholesale application | | Information requested | Needs-info | A question about your application | | Document expiring | 30 and 7 days before expiry | Your `{{document}}` needs renewing | | Invoice reminder | Per the [reminder sequence](/docs/receivables/aging-and-collections/#reminder-sequences) | Invoice `{{number}}` – due `{{date}}` | | Overdue notice | Invoice past due | Invoice `{{number}}` is overdue | | Hold applied | Hold placed | Ordering paused on your account | | Hold lifted | Hold released | You're good to order again | | Statement | Monthly (Ledger tier) | Your statement from `{{store}}` | The approved email includes their terms, limit, and a sign-in link. The rejected email contains only the reason text you chose to share. ## To you (merchant staff) | Notification | Trigger | |---|---| | New application | On submit – with validation summary | | Stale needs-info | Application waiting on buyer > 14 days | | Drift alert | Nightly reconciliation found a discrepancy | | Fail-open event | Checkout allowed because credit data was unreadable | | Re-review flag | Document expired / VAT revalidation failed | | Large exposure change | Single order > a threshold you set | Merchant notifications go to chosen staff emails; each type can be toggled. Everything here also appears in the in-app activity feed regardless of email settings. --- # Permissions & data Source: https://transactful.com/docs/reference/permissions-and-data/ ## Shopify permissions | Access | Why | |---|---| | Read & write companies | Create companies, locations, contacts at approval; store credit data on them | | Read & write customers | Invite the buyer contact; tax exemption settings | | Read orders | Compute exposure from order events; reconciliation | | Write checkout validations | The enforcement rule itself | | Read catalogs & price lists | Offer the catalog choice at approval | Transactful does **not** request access to your products, themes, or storefront content, and never writes to orders. ## Where data lives Application data, documents, and the credit ledger are stored in the UK/EU region, encrypted at rest and in transit. Documents live in object storage (Cloudflare R2) with access limited to your staff via the app. We are a data **processor** for your buyers' personal data; you are the controller – the [Privacy Policy](/privacy/) sets this out formally. ## GDPR requests Shopify's mandatory privacy webhooks are honoured automatically: customer data requests produce an export of what we hold about that person; customer redaction erases their personal data from applications while preserving the financial ledger in anonymized form (amounts and dates are accounting records; names and contacts are not). ## Uninstalling On uninstall: enforcement stops immediately (the validation is removed by Shopify), scheduled emails stop, and the Xero connection is severed. Your Shopify companies, catalogs, terms, and orders are untouched – they're yours and native. Transactful's own data (applications, documents, ledger) is retained for 30 days in case of reinstall, then permanently deleted; Shopify's 48-hour shop-redaction webhook, if triggered, deletes it sooner. You can export applications and the ledger as CSV at any time before or during this window. --- # Purchasing rules Source: https://transactful.com/docs/rules/purchasing-rules/ Purchasing rules (Control tier) validate orders against your trade terms on the same checkout surface as credit enforcement – cart, checkout, and draft orders, on every Shopify plan. ## Rule types | Rule | Example | |---|---| | Minimum order value | First order ≥ £500; repeat orders ≥ £250 | | Minimum quantity | At least 12 units per order, or per product | | Collection minimums | ≥ £150 from the Glassware collection if any glassware is ordered | | Case packs | Product X in multiples of 6 | | Maximums | No more than 40 units of a launch product per order | | Weight thresholds | Orders over 500 kg flagged for pallet shipping – or held below it | | Mixed conditions | Combine with AND/OR: value + quantity + collection | Every rule has a **buyer-facing explanation** you write once: > Candles ship in cases of 6 – adjust your quantity to a multiple of 6. Rules never fail silently; buyers always learn what to change. ## Scope and exceptions Rules apply store-wide to B2B orders by default, and can be scoped to specific catalogs or companies. **Exceptions** invert that: exempt a named company from a rule ("no first-order minimum for the buyer we met at the trade fair"), with a note and an optional expiry on the exception. ## First order vs repeat Rules can distinguish a company's **first order** from subsequent ones – the classic wholesale pattern of a higher opening commitment. ## Simulation before activation Activating a new rule against live buyers is nervous work, so every rule has a **simulate** step: Transactful replays your recent B2B orders (last 90 days) against the draft rule and shows which would have passed or failed, by company. Activate when the failures are the ones you intend. ## Evaluation order At checkout: credit hold → credit limit → purchasing rules, and the buyer sees the first blocking reason only. A held buyer isn't told about case packs; one clear problem at a time. --- # Starting wholesale from scratch Source: https://transactful.com/docs/starting-wholesale/ If you're opening a wholesale program for the first time, the hard part isn't software – it's the dozen small decisions you've never had to make. This page makes them for you; change any of them later as your book grows. ## The recommended setup At install, choose **"Recommended setup (UK wholesale)"** and Transactful configures everything below in one step: | Decision | Recommended default | Why | |---|---|---| | Application form | Business details, VAT number (required, validated), 2 trade references, terms checkbox | Enough to make a real decision; short enough that good buyers finish it | | Payment terms | **Proforma (pay first) for the first order, Net 30 after** | You learn they're real before you lend to them; buyers accept this readily | | Starter credit limit | **£500–£2,000** depending on order size | A limit you'd be relaxed losing once; raise it on payment history | | Safety buffer | 5% | Absorbs timing edges without anyone noticing | | Overdue reminders | 3 days before due · due date · 7 days over | Polite, automatic, and earlier than you'd get around to it | | Automatic holds | Off (turn on at ~10 active accounts) | With three stockists you'll know; with thirty you won't | Nothing here is exotic – it's what an experienced wholesale manager would set up, ready before your first applicant. ## Where do the first stockists come from? Transactful gives every "can I stock your products?" conversation a destination: your application link. Put it - in your store footer and navigation ("Wholesale"), - in your email signature and Instagram bio, - in your reply to every inbound retail enquiry – the DM asking "do you do wholesale?" gets a link, not a PDF. Buyers applying through a proper form with VAT validation also signals that your wholesale operation is serious – worth trusting with a first order the other way, too. ## Growing into credit A common first year with Transactful: 1. **Months 1–3:** everything proforma. The form and approvals are doing the work; the credit engine is idle. That's fine. 2. **First repeat buyers:** switch your reliable ones to Net 30 with a starter limit – one click on the company, the [calculator](/tools/wholesale-credit-limit-calculator/) suggests the number. 3. **From ~10 accounts:** turn on [automatic overdue holds](/docs/credit/credit-holds/) and let the [reminder sequence](/docs/receivables/aging-and-collections/) chase for you. Wholesale on terms is a flywheel of small, well-recorded trust decisions. Start smaller than feels impressive; the ledger makes raising limits easy and defensible. ## Learning the trade New to the concepts themselves? Start with [What is trade credit?](/blog/what-is-trade-credit/) and [Net 30 on Shopify](/blog/net-30-payment-terms-shopify/) – written for first-time wholesalers.