Protected customer data in the Shopify integration

Shopify classifies customer name, address, email and phone as protected customer data, and sets requirements for apps that access it. This page separates two things that are usually blurred together: what Shopify requires, and what this integration currently does. Where a control cannot be confirmed from the code, it is marked as such rather than claimed.

Last reviewed against the implementation on

At a glance

Fields requested
Name, email, phone, and the Shopify customer id
Addresses
Never extracted — not from customers, not from orders
Stored in the ERP
Name and email on the party ledger. Not phone.
Raw payloads
Retained in webhook and sync logs — see below
Access tokens
Encrypted at rest (verified in code)

What this page covers

Connecting a Shopify store to an ERP means customer information moves between two systems. This page documents exactly which fields move, what happens to them, and what is deleted when someone asks for it.

It deliberately separates two things that marketing pages tend to merge:

  • What Shopify requires of any app handling protected customer data.
  • What this integration currently does, taken from the code.

Meeting a requirement and describing a requirement are not the same thing. Where something cannot be confirmed from the application code — anything about servers, backups, staff access or written policy — it is listed under Requires infrastructure verification rather than presented as done.

Not a legal document

This is engineering documentation describing observable behaviour. It is not a privacy policy, a data processing agreement, or legal advice, and it does not assert any certification or review outcome.

What Shopify requires

Shopify treats information relating to an identifiable customer as protected customer data. Fields it identifies specifically — name, address, email and phone — carry the stricter obligations, and apps requesting them are held to a higher tier of requirements than apps that only touch customer records without those fields.

The requirements relevant to an integration of this shape are, in plain terms:

Shopify protected customer data requirements relevant to this integration.
Shopify requiresIn plain language
Data minimizationProcess only the minimum personal data the app actually needs to work.
TransparencyTell merchants what personal data you process and why.
Purpose limitationUse it only for the purposes you stated.
Consent and opt-outRespect customer consent and opt-out decisions where they apply.
Data protection agreementsHave privacy and data protection agreements with your merchants.
Retention periodsDo not keep personal data longer than it is needed for.
EncryptionEncrypt personal data in transit and at rest.
Access controlLimit which staff can reach protected customer data, and keep an access log.
Backups and environmentsEncrypt backups, and keep test data separate from production data.
Incident responseHave a security incident response policy.

The authoritative and current text is Shopify's own — Protected customer data requirements. Where this page and Shopify's documentation disagree, Shopify's is correct and this page needs updating.

What data the integration uses

This table is derived from the code that reads Shopify's response, not from a list of what the API could return. The integration requests customer and order access, but only ever extracts four customer values.

Shopify customer fields used by the Bizmitra integration.
Field Used Purpose
Customer name Yes Becomes the name on the party ledger the invoice is billed to. An invoice must name who it is billed to.
Email Yes Identifies a returning customer so repeat orders reach one ledger instead of creating a new one each time. Stored on the ledger.
Phone Yes Carried so it can be sent back to Shopify on a customer export. Not written to the ERP ledger.
Shopify customer ID Yes The stable link between the store customer and the Bizmitra ledger. Survives a rename on either side.
Billing address No Never extracted.
Shipping address No Never extracted.
Geolocation, postcode, city No Never extracted.
Order history and totals per customer No Not built. Orders are imported as documents, not aggregated into a customer profile.
Payment instrument details No Never received. Payment arrives as an amount and a status, not card data.

Addresses are not extracted from orders either

A Shopify order payload carries billing and shipping addresses. The order importer passes the nested customer through the same four-field reader used for standalone customers, so no address reaches a Bizmitra record from either path. This is worth stating explicitly because "we only sync customers, not addresses" is often untrue once orders are involved.

Where the data goes

Shopify

A customer record, or an order carrying a nested customer.

Adapter

Reads four values only: name (first + last joined), email, phone, customer id. Everything else in the payload is ignored.

Handler

Skips the record entirely if it has neither a name nor an email.

Party ledger

Matched by stored id, then by email. Creates a Sundry Debtor ledger only if neither matches.

ERP use

The ledger is the billing party on the sales order, invoice, receipt and any credit note.

A customer record with no name and no email is discarded rather than written as an empty ledger. Shopify checkout-only records can legitimately look like that.

What is stored, and where

LocationCustomer data held
Party ledger (ERP)Name and email. Phone is not written here. The ledger is an accounting record referenced by posted invoices.
Entity mappingShopify customer id ↔ Bizmitra ledger id. No names, no contact details.
Sync jobThe four normalised values, plus the raw provider payload where one was captured.
Webhook logThe full raw webhook body as received from Shopify.
Application logsIdentifiers only — shop domain and Shopify customer id. No names, emails or phone numbers are written to application logs.

Raw payloads in logs

This deserves its own section because it is the one place where the integration holds more than the four fields it uses.

Incoming webhooks are logged with their full body as received, and sync jobs may store the raw provider payload alongside the normalised values. Those raw bodies contain fields the integration never reads — including the addresses listed as "not extracted" above.

Stated plainly

"Bizmitra does not use addresses" is accurate. "Addresses never touch Bizmitra storage" would not be accurate, because a raw orders/create body containing a shipping address is retained in the webhook log. The distinction matters, so the page makes it rather than rounding it off.

These logs exist for diagnosis and replay — they are what makes a failed sync recoverable rather than lost. There is no automated retention or pruning for them in the application today; see known gaps.

Missing or unavailable fields

Shopify does not guarantee every field on every record: access may not be approved, a field may be blank, or a checkout record may carry almost nothing. The integration is written for that, and this behaviour is verified in code rather than assumed:

SituationWhat happens
A field is absent or nullRead as null. Every field is read defensively; no absent key raises an error.
First or last name missingThe remaining part is used. If both are missing the name is null, not the string "null" or a stray space.
Name and email both missingThe record is skipped. Nothing is written.
Email missing but name presentA ledger is created under the name. Later matching falls back to the stored id, since there is no email to match on.
Name missing on an orderThe ledger is named from the order reference rather than left blank.
Phone missing or malformedDropped. On export it is only sent if it passes a strict format check, so one bad number cannot fail the whole customer.
Customer id missingNo mapping is recorded; matching falls back to email.

In short, a reduced or redacted customer payload degrades the record rather than breaking the sync, and the one case with nothing usable in it is dropped instead of stored.

Data sent back to Shopify

Customers can also be sent from Bizmitra to Shopify. What is sent is name (split back into first and last), email, phone where the ledger holds one in a readable form, and the Shopify customer id when the record is already linked.

Nothing else from the ERP is included — no ledger balances, no invoice history, no accounting data. And no customer data is sent anywhere other than Shopify: the integration has no third-party analytics, enrichment or advertising destination for it.

Verified controls

These are confirmed in the application code and can be checked by reading it.

ControlWhat is verified
AuthorisationOAuth. You approve the app from your own Shopify admin; Bizmitra never receives a store password, and access can be revoked from Shopify.
Access scopesThe app requests product, customer, order and inventory access only. It does not request the extended historical-order access that reaches beyond Shopify's standard 60-day window.
Encryption in transitAll calls to the Shopify Admin API are over HTTPS.
Token storageStored access and refresh tokens are encrypted at rest by the application, and are excluded from model serialisation so they cannot leak into an API response or log line.
Webhook authenticityEvery incoming webhook is verified against its Shopify signature before processing. Unsigned or tampered requests are rejected.
App-entry verificationRequests loading the app are signature-checked before any store context is trusted.
Data minimization in codeThe adapter extracts four customer values and ignores the rest of the payload — including address fields.
No PII in application logsConnect log statements record shop domains and ids only. No customer name, email or phone is written to application logs.
Compliance webhooks implementedThe three Shopify privacy webhooks are implemented and queued off the request thread. What each one does is documented below.

Requires infrastructure verification

The following cannot be established by reading the application code. They are properties of servers, databases, backups, staff process and written policy. They are listed here unresolved on purpose — turning an assumption into a claim is exactly what this page is trying to avoid.

Not verified from the codebase

Encryption at rest for the database and disks · encryption of backups · separation of test and production data · data loss prevention · restrictions on which staff can reach protected customer data · password and authentication policy for staff accounts · an access log of staff reads of protected customer data · a written security incident response policy · a data processing agreement offered to merchants · defined retention periods.

Several of these are explicit Shopify requirements. Their presence on this list means "not confirmable from this repository", not "absent" — and equally, not "present". If you are evaluating the integration for a business that needs these answered, ask for them directly and expect evidence rather than a page like this one.

Deletion and compliance requests

Shopify sends three privacy webhooks. All three are implemented. What each actually does today:

RequestWhat the integration does
customers/data_request Compiles what is held against that Shopify customer id — the id mapping and the internal record it points at — and records it for audit. Delivering that report to the merchant is a manual operational step; it is not automated.
customers/redact Deletes the external-to-internal id mapping for that customer on that store. It does not delete or anonymise the ERP party ledger, and it does not remove raw payloads already held in webhook or sync logs. Re-running it is safe.
shop/redact Deletes the store connection. Entity mappings and the conflict log are removed with it by database constraint. Sync jobs and webhook logs are intended to be removed the same way, but see the gap below. ERP accounting records are not deleted.

Why a customer ledger is not simply deleted

Once an invoice is posted, the party ledger it was billed to is part of a financial record, and Indian businesses are required to retain accounting records for years. Deleting it would break posted vouchers and your audit trail. That is a genuine tension between an erasure request and statutory bookkeeping, and resolving it is a policy decision — which is precisely why this page reports the current behaviour instead of implying it is settled.

Known gaps

Recorded here because a privacy page that lists only what works is not a privacy page. Each of these is a real finding from reviewing the code:

  • No retention or pruning of sync jobs and webhook logs. Nothing in the application deletes them on a schedule, so raw payloads accumulate indefinitely. Shopify's requirements include applying retention periods.
  • Redaction does not reach logged payloads. customers/redact removes the id mapping, but a raw webhook body for that customer can remain in the webhook log.
  • Redaction does not reach the ERP ledger. The name and email on the party ledger survive a redact request. See the note above on why this is not a one-line fix.
  • Shop redaction cascade is partly unverified. Entity mappings and the conflict log are confirmed to cascade. The sync-job and webhook-log tables are not created by a migration in this repository, so whether they carry the same cascading constraint has to be checked against the live database schema rather than read from code.
  • The data-request report is not delivered automatically. It is recorded for an operator to act on.

If any of these matter to your evaluation, they are reasonable things to ask about directly rather than infer from a website.

Bizmitra Assistant