Commercial Units Developer API commercialunits.com →

Quickstart

Get your live listings onto your own website in a few minutes. This page is copy-paste — the only thing you need to fill in is your API key.

1. Create an API key

  1. Sign in to your Commercial Units dashboard.
  2. Go to Settings → Developer → Create API key.
  3. Copy the key. It looks like sg_live_3f9aK2pLqWzXyR7vT1mN8cD4 and is shown once — store it somewhere safe.

The lowercase prefix is your country (sg = Singapore, my = Malaysia, uk = United Kingdom, …). It decides which base URL to use:

PrefixBase URL
sg_https://api.commercialunits.com
othershttps://api.<cc>.commercialunits.com (e.g. api.my.commercialunits.com)

See Endpoints → Base URL for the full table. The examples below use Singapore.

2. Fetch your listings with curl

curl "https://api.commercialunits.com/v1/listings?per_page=5" \
  -H "Authorization: Bearer sg_live_3f9aK2pLqWzXyR7vT1mN8cD4"

You'll get JSON back:

{
  "items": [
    {
      "id": "8b1f3c2a-4d5e-4f6a-9b0c-1d2e3f4a5b6c",
      "title": "Corner retail unit, ground floor — Suntec City",
      "size_sqft": 1450,
      "usage_types": ["Retail", "Shop"],
      "price": 9.50,
      "currency": "SGD",
      "building_name": "Suntec City",
      "street_address": "3 Temasek Boulevard",
      "images": ["https://commercialunits.com/images/listings/8b1f3c2a/cover.jpg"],
      "cover_image_index": 0,
      "url": "https://commercialunits.com/sg/listings/8b1f3c2a-4d5e-4f6a-9b0c-1d2e3f4a5b6c",
      "status": "active"
    }
  ],
  "page": 1, "per_page": 5, "total": 1, "pages": 1
}

Get a single listing by id:

curl "https://api.commercialunits.com/v1/listings/8b1f3c2a-4d5e-4f6a-9b0c-1d2e3f4a5b6c" \
  -H "Authorization: Bearer sg_live_3f9aK2pLqWzXyR7vT1mN8cD4"

3. Allow your website's origin (for browser fetch)

If you'll call the API from a browser on your site, register your origin so CORS works:

Dashboard → Settings → Developer → Allowed origins → add https://www.yourcompany.com (and any other origins, e.g. staging.).

If you instead fetch server-side (recommended — keeps the key private), you can skip this step: server-to-server calls aren't subject to CORS.

4. Render listings on a page

Drop this into an HTML page. It fetches your active listings and renders a card grid; images embed directly from their public URLs.

<!doctype html>
<meta charset="utf-8" />
<title>Available Spaces</title>
<style>
  .cu-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; }
  .cu-card { border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; font-family: system-ui, sans-serif; }
  .cu-card img { width: 100%; height: 170px; object-fit: cover; display: block; background: #f3f4f6; }
  .cu-body { padding: 12px 14px; }
  .cu-title { font-weight: 600; margin: 0 0 4px; }
  .cu-meta { color: #6b7280; font-size: 14px; margin: 2px 0; }
  .cu-price { font-weight: 600; margin-top: 6px; }
</style>

<h1>Available Spaces</h1>
<div id="listings" class="cu-grid">Loading…</div>

<script type="module">
  // For production, prefer proxying through your own server so the key isn't
  // exposed in the browser — see the CORS & Embedding guide.
  const API_BASE = 'https://api.commercialunits.com';
  const API_KEY  = 'sg_live_3f9aK2pLqWzXyR7vT1mN8cD4';

  const fmtPrice = (l) =>
    l.price == null ? 'Price on request' : `${l.currency ?? ''} ${l.price}`.trim();

  function card(l) {
    const cover = l.images?.[l.cover_image_index ?? 0];
    const size = l.size_sqft ? `${l.size_sqft.toLocaleString()} sqft` : '';
    const use = (l.usage_types ?? []).join(' · ');
    return `
      <a class="cu-card" href="${l.url}" target="_blank" rel="noopener">
        ${cover ? `<img src="${cover}" alt="${l.title ?? ''}" loading="lazy">` : '<img alt="">'}
        <div class="cu-body">
          <p class="cu-title">${l.title ?? l.building_name ?? 'Listing'}</p>
          <p class="cu-meta">${[l.building_name, size].filter(Boolean).join(' · ')}</p>
          <p class="cu-meta">${use}</p>
          <p class="cu-price">${fmtPrice(l)}</p>
        </div>
      </a>`;
  }

  async function load() {
    const el = document.getElementById('listings');
    try {
      const res = await fetch(`${API_BASE}/v1/listings?per_page=24`, {
        headers: { Authorization: `Bearer ${API_KEY}` },
      });
      if (!res.ok) throw new Error(`API ${res.status}`);
      const { items } = await res.json();
      el.innerHTML = items.length ? items.map(card).join('') : 'No active listings.';
    } catch (err) {
      el.textContent = `Could not load listings (${err.message}).`;
    }
  }
  load();
</script>

That's a working syndication page. To page through more than one page of results, loop page=1..pages (see Endpoints).

Next steps