<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>API &amp; endpoints — Boise Business Portal</title>
  <meta name="description" content="Read-only JSON API for the Boise Business Portal directory. Live listings, promoted-only feed, and per-listing detail endpoints.">
  <meta name="theme-color" content="#0b4f8b">
  <meta name="robots" content="index,follow">
  <link rel="canonical" href="https://boisebusinessportal.com/api/">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="/assets/portal.css?v=20260721b">
  <style>
    .api-body { background: var(--bg-2); padding: 3rem 0 5rem; }
    .api-body section { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 2rem; margin-bottom: 1.5rem; }
    .api-body h2 { font-family: "Fraunces", Georgia, serif; font-weight: 500; color: var(--ink); font-size: 1.5rem; margin: 0 0 1rem; letter-spacing: -0.015em; }
    .api-body h3 { color: var(--ink); font-size: 1rem; font-weight: 700; margin: 1.5rem 0 0.5rem; }
    .api-body p, .api-body li { color: var(--ink-2); line-height: 1.6; }
    .api-body ul { padding-left: 1.25rem; margin-bottom: 0.9rem; }
    .endpoint { background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px; padding: 0.9rem 1.1rem; margin: 0.75rem 0; font-family: "JetBrains Mono", ui-monospace, Menlo, monospace; font-size: 0.9rem; }
    .endpoint .method { display: inline-block; background: var(--green); color: #fff; padding: 0.15rem 0.55rem; border-radius: 4px; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; margin-right: 0.5rem; }
    .endpoint .path { color: var(--brand-dark); }
    .endpoint .desc { display: block; font-family: "Inter", sans-serif; font-size: 0.86rem; color: var(--muted); margin-top: 0.4rem; }
    pre { background: #0d1b2a; color: #d0e2f4; padding: 1rem 1.2rem; border-radius: 8px; overflow-x: auto; font-family: "JetBrains Mono", ui-monospace, Menlo, monospace; font-size: 0.82rem; line-height: 1.55; margin: 0.5rem 0 1rem; }
    code { background: var(--bg-3); color: var(--ink); padding: 0.12rem 0.4rem; border-radius: 4px; font-family: "JetBrains Mono", ui-monospace, Menlo, monospace; font-size: 0.88em; }
  </style>
</head>
<body>
  <header class="site">
    <div class="row">
      <a class="brand" href="/">
        <span class="brand-mark">BB</span>
        <span>Boise Business Portal<small>Local businesses · Boise, Idaho</small></span>
      </a>
      <nav class="top">
        <a href="/#directory">Directory</a>
        <a href="/services/">Get listed</a>
        <a class="cta" href="/services/#contact">Contact</a>
      </nav>
    </div>
  </header>

  <main>
    <section class="header-area" style="padding: 3rem 0 2rem;">
      <div class="wrap-narrow">
        <p style="margin-bottom:0.6rem;color:var(--muted);font-size:0.85rem;letter-spacing:0.14em;text-transform:uppercase;">Developers</p>
        <h1 style="font-family:'Fraunces',serif;font-weight:500;font-size:clamp(2rem,4.5vw,3rem);color:var(--ink);letter-spacing:-0.015em;line-height:1.1;">API &amp; endpoints.</h1>
        <p style="color:var(--ink-2);font-size:1.1rem;line-height:1.5;margin-top:0.75rem;max-width:620px;">The directory is available as read-only JSON. All endpoints are CORS-open, cacheable, and versioned via the <code>schema</code> field.</p>
      </div>
    </section>

    <div class="api-body">
      <div class="wrap-narrow">

        <section>
          <h2>Endpoints</h2>

          <div class="endpoint">
            <span class="method">GET</span><span class="path">/api/listings.json</span>
            <span class="desc">Full directory of <b>live</b> listings, ordered as they appear in the source registry. Includes promoted flag per entry.</span>
          </div>

          <div class="endpoint">
            <span class="method">GET</span><span class="path">/api/promoted.json</span>
            <span class="desc">Promoted listings only — a convenience feed if you only want the featured set.</span>
          </div>

          <div class="endpoint">
            <span class="method">GET</span><span class="path">/api/listings/&lt;slug&gt;.json</span>
            <span class="desc">Per-listing detail. Same object as the full catalog, wrapped in <code>{ host, listing, schema }</code>.</span>
          </div>
        </section>

        <section>
          <h2>Sample response shape</h2>
          <p>Every listing object looks like this. Fields marked <code>null</code> may be present or omitted.</p>
<pre>{
  "slug": "exteriorglow",
  "name": "Exterior Glow Landscaping",
  "tagline": "Full-service residential landscaping in the Treasure Valley.",
  "description": "…",
  "industry": "Landscaping",
  "category": ["home services", "outdoor", "residential"],
  "tags": ["landscaping", "lawn care", "boise", "treasure valley", "residential"],
  "status": "live",
  "promoted": true,
  "live_url": "https://exteriorglowlandscaping.com/",
  "showcase_url": "/business/exteriorglow/",
  "primary_image": "/assets/biz-exteriorglow-logo.jpg",
  "features": ["Front-yard transformations", "…"],
  "service_area": ["Boise", "Eagle", "Meridian", "Boise foothills"],
  "contact": { "phone": null, "email": null },
  "locality": { "city": "Boise", "region": "ID" }
}</pre>
        </section>

        <section>
          <h2>Conventions</h2>
          <ul>
            <li><b>Status:</b> <code>live</code> = public. Demos and inactive entries never appear in the API.</li>
            <li><b>URLs:</b> <code>showcase_url</code> is portal-relative (<code>/business/&lt;slug&gt;/</code>); <code>live_url</code> is the business's own site (absolute URL); <code>primary_image</code> is portal-relative (<code>/assets/...</code>).</li>
            <li><b>Caching:</b> JSON endpoints have a short public cache (~5 min). Safe to poll every few minutes.</li>
            <li><b>Schema versioning:</b> the top-level object carries a <code>schema</code> field. If we change the shape, the schema id bumps.</li>
          </ul>
        </section>

        <section>
          <h2>Try it</h2>
<pre>curl https://boisebusinessportal.com/api/listings.json | jq '.listings[] | .name'</pre>
<pre>curl https://boisebusinessportal.com/api/listings/edgyroot.json | jq '.listing.features'</pre>
        </section>

      </div>
    </div>
  </main>

  <footer class="site">
    <div class="row">
      <div>
        <a class="brand" href="/" style="margin-bottom:0.75rem;">
          <span class="brand-mark">BB</span>
          <span>Boise Business Portal<small>Local businesses · Boise, Idaho</small></span>
        </a>
      </div>
      <div>
        <h4>Site</h4>
        <ul>
          <li><a href="/">Directory</a></li>
          <li><a href="/services/">Get listed</a></li>
          <li><a href="/services/#contact">Contact</a></li>
        </ul>
      </div>
      <div>
        <h4>About</h4>
        <ul>
          <li><a href="/branding/">Branding</a></li>
          <li><a href="/privacy/">Privacy policy</a></li>
          <li><a href="/terms/">Terms &amp; conditions</a></li>
          <li><a href="/api/">API &amp; endpoints</a></li>
        </ul>
      </div>
      <div>
        <h4>Contact</h4>
        <ul>
          <li><a href="/services/#contact">Get in touch</a></li>
          <li>Boise, ID 83702</li>
        </ul>
      </div>
    </div>
    <div class="meta-row">
      <div>© Boise Business Portal · Boise, Idaho</div>
      <div>Made in the Treasure Valley</div>
    </div>
  </footer>
</body>
</html>
