Merchant app

Connect a platform

For a platform with no OAuth handshake — trade a one-time code for keys.

Shopify can tell us who a merchant is, so it gets an OAuth handshake and the merchant never sees a credential. Most platforms cannot — a WordPress plugin, a nopCommerce extension, anything installed rather than authorized has a settings screen and nothing else. This is the mechanism for that case, and it is what an integration built against this API for such a platform should use.

Why a one-time code instead of a key field

The obvious design is a field labelled Secret key, and it is the wrong one for a reason that has nothing to do with cryptography: a long-lived secret pasted into a form is a secret that ends up in a support-ticket screenshot, an email thread, a shared password manager, a screen-share with a developer. It is handled by people, repeatedly, forever.

So the merchant pastes a short code instead — single-use, expires in 24 hours, worth nothing the moment it is redeemed. Nobody handles a long-lived credential at any point; the plugin exchanges the code once and stores what it gets back itself, server-side.

The exchange

  1. The merchant generates a code from Settings → Integrations → Connect another platform in the admin platform. Shown once.
  2. Your plugin's own settings screen accepts it and redeems it, from your server, immediately:
bash
curl -X POST "https://www.genfashion.app/api/integrations/connect/redeem" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "GF-7QK2-M4XP-9DTW",
    "siteUrl": "https://shop.example.com",
    "storeName": "Shop Example"
  }'

Dashes and capitals in code are not significant — normalise on your side too if you let a merchant retype it from an email, rather than failing on punctuation.

json
{
  "ok": true,
  "publishableKey": "sk_publishable_…",
  "secretKey": "sb_secret_…",
  "apiBase": "https://…/api/storefront/v1",
  "widgetUrl": "https://…/embed/v1.js",
  "allowedOrigins": ["https://shop.example.com"],
  "storeName": "Shop Example"
}

siteUrl seeds the publishable key's origin allowlist directly — the merchant never types an origin and so cannot typo one. Store secretKey server-side and never render it, including on your own settings screen; there is no way to retrieve it again, so if it is lost the merchant generates a new code and reconnects.

What to do with what comes back

  • Use publishableKey and widgetUrl to embed the storefront widget on product pages — the same script tag, with widgetUrl as its src.
  • Use secretKey for anything server-to-server: syncing your catalogue into GenFashion, or calling the Try-On API directly if you are not using the packaged widget.

Failure modes

This endpoint is called from your server with no credential of its own yet, so it cannot be authenticated the normal way. Two things follow from that:

  • Unknown, already-redeemed and expired codes all return the same `INVALID_CODE` error. Distinguishing them would tell a prober that a code exists at all, which is most of the work of guessing one. Treat any INVALID_CODE response the same: tell the merchant to generate a new one.
  • It sends no CORS headers. This must be called from your backend, never from a browser — their absence is what stops a browser from being able to.

A malformed or missing siteUrl returns SITE_URL_REQUIRED instead, which is safe to distinguish because it says nothing about whether the code itself is valid.