← All insights
Insights · Supplier APIs

API product setup for suppliers: how a wholesale promo merch operation actually goes from manual exports to a real-time API

Every wholesale customer eventually asks for an API. Most promo merch suppliers respond by exposing their CMS directly — and regret it within a month. Here's the architecture pattern that scales, taken from a real build for a 19,000-SKU two-brand supplier.

MMas, Founder· May 10, 2026· 13 min read

You sell wholesale promo merchandise. Your retail catalogue lives on WooCommerce, Shopify or a custom WordPress stack. It works. The retail side runs beautifully. Then a wholesale partner asks the question that breaks everything:

"Can you send me a CSV of your stock? Daily? With pricing? Updated when things change? Oh — and our system needs to call yours, not the other way around. Can you do that?"

What they're asking for is an API. What most suppliers do in response is one of three bad things:

  • Build a manual export pipeline — one CSV per customer per week, by hand, drifting out of date the moment it lands.
  • Expose their WooCommerce or Shopify REST API directly to the customer — turning their CMS into a public read endpoint, with all the security and contract problems that creates.
  • Hire a developer to build a bespoke integration per customer — and discover six months later they're maintaining 14 different one-off integrations.

None of those scale. Each adds drag every time a new wholesale customer signs. Each one limits the business by spreadsheet maintenance instead of sales effort. (We've written a parallel piece on the same custom-vs-templated trade-off for agency client portals — read it here.)

This article walks through the architecture pattern we use at AppBox when a promo merch supplier needs to stop doing manual exports and start behaving like a real wholesale platform — pulled from a recent build for a wholesale operation we'll call SwaggMerch (19,000+ SKUs across two brands, two separate WordPress sites, a growing roster of wholesale partners). The same pattern works for SanMar resellers, AlphaBroder distributors, PromoStandards-aligned suppliers, branded apparel wholesalers and anyone whose retail catalogue is the source of truth and whose wholesale operation has outgrown spreadsheets. If your front-of-house promo website is also part of the question, our promo websites guide covers the customer-facing side of the same problem.

The cardinal rule: do not expose your CMS

The single most important architectural decision in a wholesale API project is also the most counterintuitive one: your CMS must not be the API your customers consume. WooCommerce, Shopify, Magento, custom WordPress — all of them have REST APIs. All of them are tempting to plug a customer into directly. Don't. Here's why.

Reason 1: every change you make ripples instantly into customer code

The retail team renames a product attribute. A wholesale customer's API integration breaks at 3am. You didn't deploy a release. You didn't touch the API contract. Someone in retail just edited a product label. Without an isolation layer between the source of truth and the customer-facing endpoint, every internal change is a public release.

Reason 2: WooCommerce / Shopify aren't designed for high-volume read traffic

A WooCommerce REST endpoint serving a wholesale customer polling every 60 seconds is a database query colliding with every front-end retail page load. You'll see slow product pages, timeouts, cache invalidations, mysterious checkout errors. The CMS is built to serve humans, not machines.

Reason 3: per-customer pricing is impossible without an isolation layer

Your retail price is the price on the website. Your wholesale price for Customer A is 30% off list. Your wholesale price for Customer B is tier-based on annual spend. Your wholesale price for Customer C excludes three categories that are partner-locked. None of that lives cleanly inside WooCommerce. You need a layer where you can apply per-customer rules without touching the source.

Reason 4: API key lifecycle is impossible to do well at the CMS layer

When a wholesale customer's contract ends, you need to revoke their key cleanly. When a key leaks, you need to rotate it instantly. When you want usage analytics per customer, you need a layer that owns the authentication. Bolting that onto WooCommerce or Shopify means plugins, plugin conflicts, and a security surface area you don't want to maintain.

Architecture rule. The CMS is the source of truth. A separate database mirrors it. A separate API layer sits in front of the database and serves customers. Data only flows out of the CMS — never back in. Customers never see the CMS. The internal team never sees the API. The two sides are designed to be independent.

The architecture, in one diagram

Here is the shape of every supplier-API build we ship:

  • Source of truth — your existing CMS (WooCommerce, Shopify, Magento, custom). Internal team works exactly as today.
  • Mirror layer — a separate database (Supabase / Postgres) that holds a copy of every product, price and stock level.
  • Sync mechanism — webhooks for real-time + a nightly reconciliation job for safety.
  • Customer-facing API — Next.js endpoints, with auth, rate limiting, per-customer pricing logic, and versioning.
  • Admin portal — where you control what each customer sees, manage pricing tiers, issue API keys, watch usage.

One direction, by design. Data only flows out from the CMS — nothing the API or portal does can corrupt the source catalogue. Customers never touch your CMS. Your internal team never touches the API. Each side gets the workflow they actually need.

Two sync mechanisms, running in parallel

A common mistake is to pick one sync strategy. Real-time webhooks are great until one fails silently. Nightly batch jobs are great until your customer asks why a product showed in stock at 9am and was already sold out at 9:05am. The right answer is to run both.

Live layer — webhooks

WooCommerce, Shopify and most modern CMSes fire webhooks on product, price and stock changes. A simple flow:

  • 1. CMS fires an event when a product, price or stock value changes.
  • 2. A Next.js endpoint receives the event, verifies the signature, and writes the change to the mirror database.
  • 3. The change is reflected in the customer-facing API within seconds.

Latency is measured in seconds. This is the experience you're selling — wholesale customers see live numbers, not yesterday's CSV.

Safety layer — nightly reconciliation

Webhooks miss. Networks fail. Someone manually edits a product in the CMS while the webhook endpoint is briefly down. To guarantee nothing slips through, run a full reconciliation every night:

  • 1. Pull every product, price and stock level from the CMS REST API.
  • 2. Diff against the mirror database.
  • 3. Correct any drift automatically. Log every correction so you can audit what happened.

This catches missed webhooks, manual CMS edits, and any deployment-induced gaps. Customers never see the mess underneath. Your support inbox stops getting "your stock is wrong" tickets.

Real example. For SwaggMerch — a wholesale promo supplier with two brands and 19,000+ SKUs — the live layer is WooCommerce webhooks landing in Supabase via Next.js. The safety layer runs at 02:00 every night, full pull from both WooCommerce REST APIs, diff against Supabase, automatic correction. In the first six weeks of operation, reconciliation has corrected 0.4% of records — invisible to customers, but every one of those would have been a support ticket.

Per-customer pricing, visibility and contracts

The mirror layer makes per-customer logic trivial. A row-level security policy in Postgres, a few simple rules tables, and the API can serve the right view to the right customer without ever modifying the source catalogue.

Three tables that solve 90% of wholesale logic

  • customers — one row per wholesale customer, with their tier, contract start/end, and metadata.
  • customer_visibility — which categories, brands or specific products this customer can see. Default-deny is safer than default-allow.
  • customer_pricing_rules — tier-based discount, fixed price overrides, contract pricing on specific SKUs.

When a request comes in with a customer's API key, the API joins these three tables against the mirror, returns only what's visible, and applies pricing on the way out. Every change to visibility or pricing happens in the portal — never in the CMS. The retail team never sees this layer at all.

The contract endpoints customers actually want

Wholesale partners don't want a generic "list every product" endpoint. They want predictable contract endpoints they can build against:

  • GET /v1/products — paginated, filterable by category / brand / SKU, returns only products visible to this customer with this customer's price.
  • GET /v1/products/:sku — single product, full attributes, current stock, current price for this customer.
  • GET /v1/stock — lightweight stock-only endpoint for high-frequency polling. SKU + on-hand. Designed to be cheap.
  • GET /v1/pricing — bulk price lookup for a batch of SKUs. Saves the customer from making 1,000 single-product calls.
  • GET /v1/changes?since=... — delta endpoint for incremental sync. The customer pulls only what changed since their last call.

Version everything from day one. /v1/ in the URL. New fields are additive. Removals require a new version. Customers will integrate against this contract and expect it to be stable for years.

Authentication and API key management

Don't use OAuth for B2B wholesale APIs. Don't use JWT. Use long-lived API keys, scoped per customer, with clean lifecycle controls. Wholesale partners' integration teams want a single header, not an OAuth dance.

  • Issue keys per customer (never per user) — keys belong to the contract.
  • Allow multiple active keys per customer for staged rotation. Old key + new key both valid during a 30-day overlap.
  • Rate limit per key — 60 requests per minute per customer is generous for wholesale integrations and protects you from rogue scripts.
  • Log every request to an audit table — timestamp, key ID, endpoint, status code, response time. Your portal reads from this for usage analytics.
  • Surface a one-click revoke in the admin portal. When a contract ends, revoke is instant — and irreversible.

Outbound webhooks: the optional upgrade

Polling every minute is fine. Pushing changes to customers as they happen is better. Once the inbound webhook + reconciliation pipeline is solid, an outbound webhook layer is a relatively small add-on:

  • Customer registers a webhook URL in the portal.
  • When a product, price or stock change lands in the mirror, queue an outbound delivery to every customer who has visibility on that change.
  • Sign every delivery with a per-customer secret. Retry with exponential backoff on failure. Dead-letter after N retries.

For most wholesale customers, daily polling against /v1/changes?since=... is more than enough. Outbound webhooks are a premium-tier feature — and a real differentiator versus competitors still emailing CSVs.

What this actually costs to build

A well-scoped supplier API + admin portal is not a six-month enterprise project. The real cost depends on three variables: how many CMSes you're mirroring (one source vs multiple brands), how many customers you want supported on day one (one pilot vs full rollout), and how much per-customer logic you need at launch.

ScopeSetup (USD)Monthly (USD)Timeline
Single brand, 1 pilot customer, basic pricing$3,000 – $5,000$165 – $2504 weeks
Two brands, multi-customer portal, tiered pricing$5,000 – $7,500$300 – $4006–8 weeks
Three+ brands, outbound webhooks, advanced analytics$7,500 – $10,000$400 – $4508–12 weeks

Indicative ranges as of May 2026. Real number lands in the middle column for most promo merch wholesalers we work with. Hosting includes Supabase, Vercel, monitoring, daily reconciliation and ongoing support.

For context: SwaggMerch's full build — two brands, 19,000+ SKUs, custom admin portal, per-customer pricing tiers, real-time webhooks, nightly reconciliation, usage analytics — landed at the middle column. Live in eight weeks.

What we don't recommend

A few patterns we see often that cause more problems than they solve:

  • PromoStandards alone. PromoStandards is a great industry-wide spec, but most wholesale customers want JSON, REST and pagination — not SOAP. Build a modern REST API and offer a PromoStandards adapter on top if you really need it.
  • Zapier as your sync engine. Zapier is a fine glue layer for low-volume internal automation. It is not a sync engine for 19,000-SKU wholesale catalogues. The math breaks fast.
  • Multi-tenant SaaS-style architecture from day one. You are one supplier with N customers, not a SaaS with N tenants. A simple per-customer rules table beats a complex multi-tenant architecture every time.
  • OAuth for B2B wholesale. Long-lived API keys with scoped permissions are vastly simpler for partners' integration teams. OAuth is right for end-user apps. Wholesale isn't.
  • Building before you have a pilot customer. Don't build in the abstract. Confirm one wholesale partner who'll integrate against the API on day one. Their feedback will save you months. (For examples of operations layers we've shipped alongside supplier API work, see Indy Ink and Good Collective.)

Frequently asked questions

Do I need to keep WordPress / Shopify as the source of truth?

For most promo merch suppliers, yes. The internal team already knows it. The retail side runs on it. Forcing a CMS migration to ship a wholesale API is the wrong fight to pick. A mirror layer keeps both sides independent.

What if WooCommerce webhooks aren't reliable enough?

They mostly are. The reconciliation safety net catches the small percentage that miss. If webhooks are truly unavailable, scheduled polling against the WooCommerce REST API every 1–5 minutes is a workable fallback — at the cost of slightly higher latency.

Should I expose product images via the API?

Yes — but mirror them to your own storage layer (Supabase Storage, S3, Cloudflare R2). Hotlinking from WordPress turns every customer page view into a hit on your CMS, which is exactly what we built the mirror to avoid.

How do I handle a customer who wants real-time push, not polling?

Add outbound webhooks as a paid tier. Customer registers their endpoint URL. You push every relevant change with a signed payload, retry on failure, dead-letter after N attempts. Most customers are happy with polling; the ones that need push will pay for it.

How long does this take to build?

Six to eight weeks for a typical two-brand promo merch operation with one or two pilot customers. Add two weeks per major brand or per advanced add-on (outbound webhooks, AI image enrichment, advanced analytics).

What if I'm a smaller supplier under 5,000 SKUs?

The architecture is the same. The build is faster and cheaper because there's less data to mirror and fewer customer pricing edge cases on day one. Real-world floor for a single-brand 5,000-SKU build with one pilot customer: about $3,000 USD setup, four weeks.

Discovery call

Built one supplier API. Want to see how yours would look?

Book a 30-minute call. We'll map your CMS, your customer types, your sync needs and your pricing logic — and tell you what we'd build, in what order, for what price.

Related case studies