✓GoodCodes

GoodCodes API

GoodCodes validates e-commerce discount codes by driving a real browser: it adds real products to the cart, applies each code at the discount field, and reads the site's own response. You get a definitive verdict per code, the discount it produced, and a screenshot as proof.

Interactive OpenAPI reference: /v1/docs · Manage keys: Account → API keys

Authentication

Every request carries your API key in the X-API-Key header. Keys are minted on the account page — the secret is shown once at creation and can be revoked at any time.

X-API-Key: sk_live_…

Usual flow

  1. Submit a batch — sites + codes (product URLs optional). You get a batch_id back immediately.
  2. Poll GET /v1/batches/{batch_id} every few seconds (or give a webhook_url and get pinged when the batch finishes).
  3. Read results — one entry per code with its classification, discount amount, and screenshot link.

Validation is real browser work: expect roughly 30 seconds to a few minutes per site depending on the store. The first visit to a brand-new site takes longest; repeat visits replay a learned profile and are much faster.

1 · Submit a batch

POST /v1/batches

curl -X POST https://goodcodes.io/v1/batches \
  -H "X-API-Key: sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "sites": [
      {
        "site_url": "snowehome.com",
        "codes": ["WELCOME10", "SAVE20"],
        "product_urls": ["https://snowehome.com/products/sheet-set"]
      },
      {"site_url": "sakara.com", "codes": ["ATOMICBLONDESAKARA"]}
    ],
    "webhook_url": "https://your-app.example/hooks/goodcodes"
  }'

Response — 202 Accepted:

{"batch_id": "ed5d3a1a26c146b2…", "status": "queued", "sites": 2, "codes": 3}

2 · Poll the batch

GET /v1/batches/{batch_id}

{
  "batch_id": "ed5d3a1a26c146b2…",
  "status": "running",                  // queued | running | done
  "created_at": "2026-08-02T17:45:06",
  "finished_at": null,
  "sites": [
    {
      "site_url": "https://snowehome.com",
      "status": "done",                 // queued | running | done | failed
      "error": null,
      "results": [
        {
          "id": "6f906604fa8048ce…",
          "code": "WELCOME10",
          "status": "done",             // pending | done
          "classification": "valid",
          "valid": true,
          "discount_amount": 30.0,
          "subtotal_before": 300.0,
          "total_after": 270.0,
          "currency": "USD",
          "notes": null,
          "charged": true,
          "screenshot_url": "/v1/results/6f906604fa8048ce…/screenshot"
        }
      ]
    }
  ]
}

Classifications

ClassificationMeaningBilled
validThe code applied and reduced the total. discount_amount, subtotal_before, total_after are filled in.yes
invalidThe site rejected the code as unknown/dead.yes
expiredThe site said the code has expired.yes
min_spendThe code is recognized but the cart is below its spend threshold.yes
conditions_not_metThe code is recognized but this cart doesn't qualify (product/category exclusions, membership, …). It may work on a different cart.yes
ambiguousThe site responded but the outcome couldn't be read with confidence.no
no_promo_fieldThe checkout was walked to its payment wall and provably has no promo/coupon entry point.no
requires_signinEvery checkout route requires an account — codes can't be validated anonymously.no
unsupported_flowThe store has no standard add-to-cart path (configurators, quiz funnels).no
errorThe run failed (site down, blocked, timeout). Not a verdict on the code.no

Billing

You're charged $0.10 per code whose validation went through — products were added, the code was submitted, and the site gave a definitive answer — regardless of the verdict. The five billed classifications above are exactly that set. Errors, blocks, and sites where a code can't be submitted at all cost nothing. See your ledger at Usage or GET /v1/usage:

{"charged_codes": 12, "total": 1.20, "currency": "USD", "price_per_code": 0.10}

Screenshots

GET /v1/results/{result_id}/screenshot returns a PNG of the cart at the moment the code was applied — the proof behind every verdict. Add ?which=before for the pre-application state.

curl -H "X-API-Key: sk_live_…" \
  https://goodcodes.io/v1/results/RESULT_ID/screenshot -o proof.png

Complete example (Python)

import time, httpx

API = "https://goodcodes.io/v1"
H = {"X-API-Key": "sk_live_…"}

batch = httpx.post(f"{API}/batches", headers=H, json={
    "sites": [{"site_url": "snowehome.com", "codes": ["WELCOME10"]}],
}).json()

while True:
    b = httpx.get(f"{API}/batches/{batch['batch_id']}", headers=H).json()
    if b["status"] == "done":
        break
    time.sleep(5)

for site in b["sites"]:
    for r in site["results"]:
        print(site["site_url"], r["code"], r["classification"],
              r["discount_amount"], r["screenshot_url"])

Endpoint summary

EndpointPurpose
POST /v1/batchesSubmit sites + codes → batch_id
GET /v1/batches/{id}Batch status + per-code results
GET /v1/batchesList your recent batches
GET /v1/results/{id}/screenshotProof screenshot (PNG)
GET /v1/usageCharge ledger summary

Full request/response schemas: interactive OpenAPI reference.