06 / Compliance design
Compliance posture
Last updated May 30, 2026
SellerArmor is designed to comply with Amazon’s Business Solutions Agreement, the March 2026 BSA Agent Policy, and applicable Canadian and US privacy law (PIPEDA, sectoral US laws). This page documents the architectural decisions and operational controls behind that compliance — not promises, the choices we actually shipped.
1. BSA Agent Policy alignment
1.1 Seller is the final actor on every case
SellerArmor drafts case text and attachments. You review the draft inside the SellerArmor dashboard and click Submityourself in Seller Central. We do not automatically submit cases on your behalf. There is no code path in our application that creates a case in the Selling Partner API or in the Cases endpoint. This removes ambiguity about whether SellerArmor is “acting as an agent” under the BSA.
1.2 Automated systems self-identify
Every request our backend makes to the Selling Partner API carries an explicit User-Agent header identifying SellerArmor as the originating tool, with version and contact information. Centralized in our SP-API HTTP client so it cannot be omitted on new endpoints. The BSA Agent Policy requires self-identification by automated systems; we implemented this from day one rather than retrofit it after enforcement.
1.3 Read-only SP-API role set
The only OAuth roles SellerArmor ever requests are the minimum needed to detect reimbursable discrepancies: Amazon Fulfillment, Inventory & Order Tracking, Finance & Accounting, and Selling Partner Insights. No write-enabled roles are requested, ever. A compromised refresh token cannot modify your account, create listings, change pricing, or file cases.
1.4 Template feedback loop avoids BSA §4.2
Our case-template library is refined by tracking the outcomes of filed cases. Outcome data is used only to score and select among pre-written, human-authored template variants — never to train, fine-tune, or develop machine learning models. BSA §4.2 prohibits using Amazon materials or services for AI/ML model development; the selection-based approach is designed to sit outside that prohibition by construction, not by promise.
1.5 Kill switch
A boolean environment variable (KILL_SWITCH_ENABLED) flips every outbound SP-API request into an immediate refusal without contacting Amazon. Used to halt operations within seconds if Amazon issues an enforcement notice, if we discover a regression, or if a security incident requires a stop. The check sits in the centralized HTTP client; new endpoints inherit it automatically.
2. Authentication
2.1 Login
SellerArmor accounts use email + password authentication on top of Supabase Auth. Passwords are stored hashed with bcrypt (cost factor 10 by default; Supabase manages this internally). Password minimum length is enforced at 12 characters at the form layer for new passwords; complexity requirements beyond that are deferred to authenticator-app MFA (below) rather than character-class rules that push users toward weak-but-compliant passwords.
2.2 Multi-factor authentication (TOTP)
Users may enroll a TOTP authenticator app (1Password, Authy, Google Authenticator, etc.) as a second factor in Settings → Security. When MFA is enabled, the session remains at Authenticator Assurance Level 1 (aal1) after password entry until the user enters a valid 6-digit code, at which point the session is upgraded to aal2. The challenge happens on every fresh login — not just the first one — and a configurable session lifetime enforces re-authentication periodically.
Recovery: if a user loses access to their authenticator app, they email support@sellerarmor.com from the address tied to the account. We verify ownership before resetting the factor. Self-service recovery codes are on the roadmap.
2.3 Password reset
Users initiate a password reset from the login page or from the Security panel. Supabase Auth sends a single-use link, valid for one hour, scoped to the user’s email. Following the link places the user in a recovery session that authorizes one password update and nothing else. The reset flow does not reveal whether an email address is registered with SellerArmor, to prevent account-existence enumeration.
2.4 Session model
Supabase Auth issues a JWT plus a refresh token after login. The access JWT is short-lived (typically 60 minutes) and rotated via the refresh token. Both are stored in HttpOnly, SameSite=Lax, Secure cookies on the sellerarmor.com domain. They never appear in JavaScript-accessible storage, eliminating XSS-based token theft.
Sign out everywhere in Settings → Security calls auth.signOut({ scope: "global" }), which revokes every refresh token issued for the user — every browser, every device — in one operation.
3. Authorization & access control
3.1 Row-Level Security (RLS)
Every Postgres table that contains seller-scoped data is protected by Supabase Row-Level Security. Policies join through seller_id → sellers.user_id so an authenticated request can only ever see rows attached to its own user. The browser-side anon JWT can do nothing without RLS — every read and write goes through a policy check.
3.2 Service-role separation
Two Supabase clients exist in the codebase. The SSR client uses the anon key plus the session cookie and is subject to RLS. The admin client uses the service-role key, bypasses RLS, and is used only inside server actions, route handlers, and Inngest workflows for operations that must run with full database access (writing the encrypted refresh token after OAuth, hard-deleting accounts, inserting parsed report rows). The service-role key is never imported in a Client Component and never reaches the browser.
3.3 Least-privilege OAuth scopes
The SP-API roles we request (§1.3) are the minimum that the detection rules need. Adding a write-enabled role would require a code change, a Solution Provider Portal re-approval, and a re-consent from every connected seller — the friction is deliberate.
3.4 Middleware-enforced route protection
Next.js middleware short-circuits every request to a protected path (/dashboard/*, /auth/amazon/*) and verifies a valid session before the page renders. Unauthenticated requests are redirected to /login with a next parameter so the user lands where they were headed after signing in. Signed-in users hitting /login or /signup are bounced to the dashboard, preventing accidental re-authentication on top of an existing session.
4. Audit trail & logging
4.1 Append-only audit log
A dedicated audit_log table records every meaningful action against seller data, with no UPDATE or DELETE grants at the database role level. Each row captures the seller, the actor (system, seller, or admin), the action slug, a machine-readable detail JSONB, and a timestamp. Tracked actions include:
seller_connected— SP-API OAuth completed or re-authorized.report_fetched— an SP-API report request reached terminal state.discrepancy_detected— a detection rule surfaced a new claim.case_drafted— a draft was generated for a discrepancy.case_filed— the seller marked a case as filed in Seller Central.outcome_matched— the outcome loop reconciled a filed case to an Amazon decision.audit_run— a free-audit scan was kicked off.
4.2 Retention
Audit log entries are retained for seven years regardless of seller account status, in line with the operational ceiling for tax and tax-adjacent records. The retention is set in the schema and enforced at the application layer; cleanup beyond seven years happens via a scheduled Inngest job, not opportunistic deletion.
4.3 Export
Sellers can view their own audit trail at /dashboard/audit-log and request a full export by emailing support@sellerarmor.com from the email tied to the account. We respond within five business days with a CSV or JSON dump.
4.4 Application logs
Application and SP-API request logs are stored by Vercel and Inngest with their default retention windows. Logs include request paths, response codes, and durations but not the bodies of SP-API responses or any decrypted refresh token. Sensitive header values are scrubbed before logging.
5. Data protection at rest
5.1 Refresh-token encryption
OAuth refresh tokens are never written to the database in plaintext. Before insertion, each token is encrypted with AES-256-GCM using a 32-byte key held in the REFRESH_TOKEN_ENCRYPTION_KEY environment variable (kept in Vercel encrypted env, never in source). The stored payload is the format base64(iv) : base64(authTag) : base64(ciphertext); the GCM authentication tag detects any tampering on read. The plaintext token only exists in memory for the duration of an SP-API call, and is never written to logs.
5.2 Database encryption
The primary Postgres database is hosted by Supabase in ca-central-1 (Montréal, Canada). The disk underlying the database is encrypted at rest with AES-256by the underlying cloud provider. Database backups are encrypted with the same scheme and retained per Supabase’s tier defaults.
5.3 Object storage
Raw SP-API report archives, when stored, are placed in encrypted-at-rest object storage in United States data centers, accessed only by our backend services over server-to-server authenticated channels. No public buckets, no signed URLs that escape the backend.
5.4 Other secrets
Every other secret named in our deploy notes (Supabase service-role JWT, LWA client secret, Anthropic API key, Resend API key, Inngest signing key) is stored in Vercel’s encrypted environment variable system, scoped per-environment. They never appear in source, in commit history, in build output, or in client-side bundles.
6. Data protection in transit
6.1 Edge TLS
All inbound traffic to sellerarmor.comterminates on Vercel’s edge over TLS 1.3 (TLS 1.2 fallback only for legacy clients). HTTP requests are redirected to HTTPS at the edge; HSTS is set by default. Vercel manages certificate rotation.
6.2 Service-to-service traffic
Every outbound call from our backend — to the Selling Partner API, the LWA token endpoint, Supabase, Inngest, Resend, and Anthropic — runs over HTTPS with provider-issued credentials. No plaintext HTTP is used internally. SP-API and LWA requests additionally carry our self-identifying User-Agent (§1.2).
6.3 Cookies
Session cookies are HttpOnly, Secure, and SameSite=Lax. OAuth CSRF state cookies are also HttpOnly and expire after 10 minutes. No authentication-bearing cookie is ever marked SameSite=None without an accompanying CSRF defense.
7. PII handling
7.1 Strip at parse time
Customer personally-identifiable information is stripped from incoming SP-API reports before the parsed rows reach the database. The stripping is implemented in a shared stripPii helper that runs on every Settlement, Customer-Returns, and adjacent report. Stripped fields include customer name, shipping address (street, city, postal code), phone, email, and free-form customer_comments(the column itself is dropped from the schema). What remains is anonymized transaction data — SKU, FNSKU, quantity, dates, order IDs — which is sufficient for our detection rules and Amazon’s case workflows.
7.2 What we deliberately do not collect
Customer browsing data. Customer demographics. Cardholder data. Aggregate seller pricing strategies we could reconstruct from ledger reads. We collect the minimum data needed for the stated detection rules and nothing else.
7.3 Customer-return free text
The free-text customer comment column on the customer-returns report frequently contains buyer-identifying information (names, full addresses, sometimes attached email signatures). We drop that column at the schema level — it is not optional or configurable.
8. Data subject rights & access revocation
8.1 Account deletion
Users can delete their SellerArmor account from Settings → Danger zone → Delete account. The flow requires two confirmations: typing the account email exactly and re-entering the current password. On submit, the auth.users row is hard-deleted via Supabase admin; an ON DELETE CASCADE foreign key chain unwinds across every seller-keyed table (sellers, report_runs, ledger_events, settlement_events, reimbursement_events, customer_returns, removal_shipments, inbound_shipment_items, fee_preview_snapshots, discrepancies, filed_cases, match_proposals, audit_log).
8.2 SP-API access revocation
Sellers can revoke SellerArmor’s SP-API authorization from inside Amazon Seller Central → Manage Apps. Once Amazon notifies us of the revocation, our scheduled cleanup deletes the encrypted refresh token within 24 hours and purges ingested account data within 30 days from primary storage. Audit-trail rows are retained for the seven-year window described in §4.2.
8.3 Data export
Sellers can request a full data export by emailing privacy@sellerarmor.com from the email tied to their account. We respond within five business days with a CSV or JSON archive covering every record we hold under that user.
8.4 Access correction
Most user-controlled data on SellerArmor — connected accounts, notification preferences (when shipped), email — is editable directly inside the app. Corrections that require admin intervention can be requested at the same privacy address with the same five-business-day SLA.
9. Incident response
We commit to notifying Amazon within 24 hours of any suspected security incident involving SP-API data, in line with the Solution Provider Agreement. Affected sellers are notified by email at the address on file with the timing and detail required by applicable breach-notification law. The incident response runbook lives in version control and is updated whenever a near-miss surfaces a gap.
10. Subprocessors
SellerArmor relies on the following third-party processors. Each is contractually bound to confidentiality and security obligations consistent with our own.
- Vercel (Vercel Inc., USA) — application hosting and edge TLS termination. Region:
iad1(US East). - Supabase (Supabase Inc., USA / EU) — Postgres database, authentication, and object storage. Region:
ca-central-1(Montréal, Canada). - Inngest (Inngest Inc., USA) — durable workflow runner for report ingestion and outcome matching.
- Cloudflare (Cloudflare Inc., USA) — DNS for
sellerarmor.com. - ImprovMX (Plug And Pay LLC, USA) — inbound email forwarding for
@sellerarmor.comsupport addresses. - Resend (Resend Inc., USA) — outbound transactional email (signup verification, password reset).
- Anthropic(Anthropic PBC, USA) — Claude API for case-draft generation. SP-API data passed to Claude is scoped to a single discrepancy at a time; no model training on Amazon-derived data (§1.4); Anthropic’s API zero-retention terms apply.
11. Compliance contact
For BSA, Selling Partner Agreement, or security questions — including from Amazon representatives — email compliance@sellerarmor.com. For privacy-specific requests, see privacy@sellerarmor.com.
SellerArmor is operated by CircuitVista Inc., a corporation incorporated in Ontario, Canada.