GETMYSHADE API TEST WEBSITE

Search products, shades, concerns…

For Developers

Integrating the GetMyShade API

How this storefront connects to the real GetMyShade API — the pattern to follow, the one setup step people skip, and the issues you're most likely to run into.

Security comes first

Your API key authenticates and bills every request to your brand — treat it exactly like a password. It must only ever live in a server-side environment variable, never in client-side code, never in a public repository, and never in a URL query string. If a key is ever accidentally exposed, revoke it and generate a new one immediately. Every example on this page uses an obviously fake placeholder key for that reason.

The core pattern: proxy, never call directly

This storefront never calls the GetMyShade API from the browser. Every request flows browser → your own backend route → GetMyShade. Your backend attaches the API key, forwards the request, and streams the response back. This keeps your key out of the browser's network tab entirely, and it's exactly the shape this site uses:

// app/api/gms/[...path]/route.ts  (server-side only)
const GMS_API_KEY = process.env.GMS_API_KEY // never NEXT_PUBLIC_GMS_API_KEY
const GMS_API_BASE = 'https://api.getmyshade.com/functions/v1'

export async function GET(req: Request, { params }) {
  const upstream = await fetch(`${GMS_API_BASE}/${params.path.join('/')}`, {
    headers: { Authorization: `Bearer ${GMS_API_KEY}` },
  })
  return new Response(await upstream.text(), { status: upstream.status })
}

// Your frontend then calls YOUR route, never the API directly:
// fetch('/api/gms/api-v1-match', { method: 'POST', body: ... })
Integration flow
1

Get your API key

Create a GetMyShade account and generate an sk_live_… key from your dashboard. This key identifies your brand and is billed against your plan — treat it like a password.

2

Store it server-side only

Save the key as a server-only environment variable (e.g. GMS_API_KEY). Never prefix it with NEXT_PUBLIC_, VITE_, or any convention that ships it to the browser bundle, and never commit it to source control.

3

Build a thin proxy route

Add one server-side route in your own app that attaches the Authorization header and forwards requests to the GetMyShade API. Your frontend calls your own route, never the API directly.

4

Upload your product catalog

Before any scan can recommend products, GetMyShade needs to know what you sell. Upload your products and shade variants via the dashboard or the bulk-create endpoint — see the dedicated section below.

5

Call analyze or match

From your frontend, submit a selfie (upload or live camera capture) through your own proxy route to /api-v1-analyze or /api-v1-match.

6

Render the ranked results

Display the returned matches using the image_url provided per match, and handle the case where a category has no qualifying match (see "Handling the response" below).

7

Log events and watch usage

Call /api-v1-log for key events (view, add_to_cart) for your own analytics, and periodically check /api-v1-usage against your plan quota.

Why uploading your catalog matters

GetMyShade's AI analyzes a face and returns a skin tone, undertone, and confidence score — but it can only recommend products that actually exist in your catalog. If you haven't uploaded any products yet, a scan will complete successfully and still return zero matches. This is the single most common source of "the API isn't working" confusion, and it isn't a bug — there's simply nothing to rank against.

  • Upload products before testing your integration end to end.
  • Aim for a broad shade range per product — enough depth and undertone coverage that a real range of customers can get a genuine match, not just a narrow subset.
  • After uploading, confirm it landed by checking GET /api-v1-brand catalog.total_products and catalog.total_variants should both be greater than zero.

Handling the response safely

  • Use the image_url field on each match for product photos — don't try to re-derive it from your own local catalog.
  • Check meta.no_match_product_types and show users a clear message for any category with no qualifying match, instead of silently showing nothing.
  • The API doesn't return pricing — that stays entirely your own data, attached client-side after matching.
  • Don't assume list uniqueness guarantees beyond what the API documents; render defensively (e.g. combine SKU with array index for list keys).

Common issues and how to solve them

I'm getting MISSING_API_KEY or INVALID_API_KEY

Confirm your key is actually set as a server-side environment variable and hasn't been truncated when copied. Send it as either an Authorization: Bearer sk_live_… header or an x-api-key header — not as a query parameter, and never from client-side code.

My scan completes successfully, but no products are recommended

This almost always means your product catalog is empty or hasn't finished uploading. The AI analysis can succeed perfectly while still returning zero matches if there's nothing in your catalog to rank. Check GET /api-v1-brand and confirm catalog.total_products and catalog.total_variants are both greater than zero.

I'm getting CORS errors calling the API

You're likely calling the API directly from browser JavaScript. Route the request through your own backend instead — the browser should only ever talk to your server, and your server talks to GetMyShade.

Some product categories never return a match

This is a catalog coverage gap, not a bug — it means none of your uploaded shades for that category are close enough to the scanned skin tone. Check the response's meta.no_match_product_types array and show users a clear message rather than nothing; consider broadening your shade range for that category over time.

I'm being rate-limited (429 responses)

Implement exponential backoff with jitter, and only retry on 429 or 5xx responses — cap retries at a small number (e.g. 4 attempts). Don't retry on 4xx errors like invalid input or auth failures, since retrying won't change the outcome.

Product images aren't loading in my match results

Use the image_url field returned directly on each match object. Don't try to cross-reference matches back to your own local catalog by SKU — your internal SKU scheme has no guaranteed relationship to how you named things when uploading, so that kind of lookup is fragile and will silently fail.

Duplicate-looking entries or React key warnings when rendering matches

Treat the matches array defensively: don't assume sku is unique for rendering-list purposes. Combine it with the array index for your list keys (e.g. `${match.sku}-${index}`) so a rendering hiccup never causes items to visually disappear or merge.

Key hygiene checklist

  • Never commit an API key to git, even in a private repository.
  • Never send it from browser-side JavaScript or embed it in a mobile app binary.
  • Never paste it into chat tools, tickets, or logs that outlive the moment you needed it.
  • Do rotate it immediately from your dashboard if you suspect any exposure.