QR codes and signs

Mint printed signs, bind their codes to listings, and read the scan analytics they produce.

Base URL
https://api.caroom.us

QR groups

A group ties one or more printed QR codes to a single listing, so a windshield sign and a rear-window sign lead to the same place. Scans are counted per group.

Create a QR group

POST/leads/groups

Creates an empty group. The client generates the UUID, which makes the call idempotent — retrying with the same id will not create a second group.

Authentication Bearer token

Parameters

idstringRequired

UUID for the new group, generated by the caller. Sent form-encoded.

cURL
1curl -X POST "https://api.caroom.us/leads/groups" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  --data-urlencode "id=f0b46589-2a53-45c0-9d11-78094e8c6159"
Response schema
{
  "id": string,
  "listingId": integer,
  "userId": integer,
  "externalURL": string,
  "assigned": boolean,
  "active": boolean,
  "scan_count": integer,
  "updatedAt": string
  "createdAt": string,
}

List QR groups

GET/leads/groups

Returns every group belonging to the caller, paginated, each with its codes and scan count.

Authentication Bearer token

Query parameters

pageinteger

Page number, 1-based.

per_pageinteger

Groups per page.

  • The listing covers all groups the account owns, including ones with no codes attached yet.
cURL
1curl "https://api.caroom.us/leads/groups?page=1&per_page=100" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"
Response schema
[
  {
    "id": string,
    "listingId": integer,
    "userId": integer,
    "externalURL": string,
    "assigned": boolean,
    "active": boolean,
    "scan_count": integer,
    "updatedAt": string,
    "createdAt": string,
    "codes": [
      {
        "id": string,
        "qrGroupId": string,
        "updatedAt": string
        "createdAt": string
      }
    ],
    "car": {},
    "scans": integer,
    "views": integer,
    "stickerStatus": boolean
  }
]

Retrieve a QR group

GET/leads/groups/:group_id

Returns one group with its codes, the listing it points at, and its scan and view counters.

Authentication Bearer token

Path parameters

group_idstringRequired

UUID of the group.

cURL
1curl "https://api.caroom.us/leads/groups/10229ca2-e22a-48fb-ad6c-a94be24e807a" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"
Response schema
[
  {
    "id": string,
    "listingId": integer,
    "userId": integer,
    "externalURL": string,
    "assigned": boolean,
    "active": boolean,
    "scan_count": integer,
    "updatedAt": string,
    "createdAt": string,
    "codes": [
      {
        "id": string,
        "qrGroupId": string,
        "updatedAt": string
        "createdAt": string
      }
    ],
    "car": {},
    "scans": integer,
    "views": integer,
    "stickerStatus": boolean
  }
]

Add a QR code to a group

PATCH/leads/groups/:group_id

Attaches a printed code to the group, optionally with a label describing where the sign is placed.

Authentication Bearer token

Path parameters

group_idstringRequired

UUID of the group.

Parameters

qrCodeIdstringRequired

UUID printed on the sign.

namestring

Label for the placement, e.g. "Back Windshield".

cURL
1curl -X PATCH "https://api.caroom.us/leads/groups/f0b46589-2a53-45c0-9d11-78094e8c6159" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "qrCodeId": "ca3e5d2f-55cf-4459-918a-3443b3953819",
6    "name": "Back Windshield"
7  }'
Response schema
{
  "id": string,
  "qrGroupId": string,
  "updatedAt": string
  "createdAt": string
}

Remove a QR code from a group

DELETE/leads/groups/:group_id

Detaches a code from the group. The code stays valid and can be attached elsewhere.

Authentication Bearer token

Path parameters

group_idstringRequired

UUID of the group.

Parameters

qrCodeIdstringRequired

UUID of the code to detach.

cURL
1curl -X DELETE "https://api.caroom.us/leads/groups/4f8a009f-eca7-4b71-9b60-1905054f9a0d" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{ "qrCodeId": "ca3e5d2f-55cf-4459-918a-3443b3953819" }'

QR codes

Individual printed codes: what they resolve to when scanned, what they are bound to, and what they are called in the owner’s dashboard.

Resolve a scanned code

GET/leads/qr/:qr_code_id

Call this whenever a code is scanned. It returns what the code is bound to and records the scan. Send a stable device fingerprint so returning devices are recognised without a login, and leave the browser’s User-Agent intact — the analytics depend on it.

Authentication Bearer token

Path parameters

qr_code_idstringRequired

UUID printed on the sign.

  • x-fingerprint-id is required — generate it on the client, for example with FingerprintJS.
  • Do not override or strip the User-Agent header.
cURL
1curl "https://api.caroom.us/leads/qr/54662dd8-8ed4-4a3c-a263-6f9303c83921" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  -H "x-fingerprint-id: $VISITOR_ID"
Response schema
{
  "id": string,
  "groupId": string,
  "listingId": integer,
  "externalURL": string,
  "active": boolean,
  "scans": integer,
  "views": integer,
  "car": {}
}

Associate a code with a listing

PATCH/leads/qr/:qr_code_id

Points a code at a listing, or at an external URL for signs that lead somewhere outside Caroom.

Authentication Bearer token

Path parameters

qr_code_idstringRequired

UUID printed on the sign.

Parameters

listingIdinteger

Listing the code should resolve to.

advertTypestring

What is being advertised, e.g. PROPERTY or TRADE.

externalURLstring

Destination outside Caroom, instead of a listing.

cURL
1curl -X PATCH "https://api.caroom.us/leads/qr/54662dd8-8ed4-4a3c-a263-6f9303c83921" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "listingId": 135,
6    "advertType": "PROPERTY"
7  }'

Rename a QR code

PATCH/leads/qr/:qr_code_id/name

Sets the label shown in the dashboard, so a code can be identified by campaign or placement. The body is form-encoded. Returns the updated code with its group.

Authentication Bearer token

Path parameters

qr_code_idstringRequired

UUID of the code.

Parameters

namestringRequired

New label, e.g. "Spring Sale — Main Showroom".

cURL
1curl -X PATCH "https://api.caroom.us/leads/qr/54662dd8-8ed4-4a3c-a263-6f9303c83921/name" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  --data-urlencode "name=Spring Sale - Main Showroom"
Response
{
  "id": "9394b410-8441-4f68-97e0-15164787d4df",
  "name": "Spring Sale - Main Showroom",
  "qrGroupId": "8fc02583-8d2f-4601-8646-2c6558d83d37",
  "createdAt": "2025-11-20T10:32:51.995Z",
  "updatedAt": "2025-11-20T10:43:29.304Z",
  "qrGroup": {
    "id": "8fc02583-8d2f-4601-8646-2c6558d83d37",
    "advertType": null,
    "userId": 3,
    "listingId": null,
    "externalURL": null,
    "assigned": false,
    "active": true,
    "scan_count": 0,
    "createdAt": "2025-11-20T10:31:27.114Z",
    "updatedAt": "2025-11-20T10:31:27.114Z"
  }
}

Remove a QR code’s name

DELETE/leads/qr/:qr_code_id/name

Clears the custom label. The code itself stays active and can be renamed later.

Authentication Bearer token

Path parameters

qr_code_idstringRequired

UUID of the code.

  • Returns 200 or 204 on success, 404 if the code does not exist, and 400 if the UUID is malformed.
cURL
1curl -X DELETE "https://api.caroom.us/leads/qr/9050b551-9139-41c6-9540-b58be739f3c2/name" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"

List your leads and their groups

GET/leads/mine

Returns the caller’s leads with the QR group attached to each, including scan counts and scan timestamps. This is the data behind the seller dashboard.

Authentication Bearer token

Query parameters

pageinteger

Page number, 1-based.

per_pageinteger

Leads per page.

  • details.page comes back as a string, not a number.
cURL
1curl "https://api.caroom.us/leads/mine?page=1&per_page=10" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"
Response
{
  "details": {
    "total_count": 12,
    "page": "1",
    "per_page": 10,
    "total_pages": 2
  },
  "leads": [
    {
      "id": 135,
      "subject": "2022 BMW X3",
      "suggestedPrice": null,
      "uniqueId": "PR64FV",
      "group": {
        "id": "8fc02583-8d2f-4601-8646-2c6558d83d37",
        "userId": 3,
        "active": true,
        "scan_count": 4,
        "createdAt": "2025-11-20T10:31:27.114Z",
        "updatedAt": "2025-11-20T10:31:27.114Z",
        "codes": [],
        "scan_timestamps": []
      },
      "car": {
        "year": 2022,
        "make": "BMW",
        "plate": null,
        "mileage": 32000,
        "carId": 8891,
        "postcodeState": null
      }
    }
  ]
}

Retrieve scan counters for a lead

GET/leads/:lead_id/counters

Returns the scan and view counters for a lead’s signs.

Authentication Bearer token

Path parameters

lead_idintegerRequired

ID of the lead.

cURL
1curl "https://api.caroom.us/leads/135/counters" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"

Printed signs

Minting and activating the physical signs. Codes are produced in batches against a category, and the short /q links printed on them resolve to the activation flow.

Mint a batch of signs

POST/q

Generates a run of QR codes for printing, tagged with a batch identifier so a production run can be traced later.

Authentication Bearer token (admin)

Parameters

countintegerRequired

How many codes to mint.

batchIdstringRequired

Label for the production run, e.g. "ChAugust2025Batch1".

categoryIdintegerRequired

Sign category the batch belongs to.

cURL
1curl -X POST "https://api.caroom.us/q" \
2  -H "Authorization: Bearer $CAROOM_ADMIN_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "count": 8050,
6    "batchId": "ChAugust2025Batch1",
7    "categoryId": 1
8  }'

Create a sign category

POST/sign-categories

Defines a physical sign product — its description and the numeric prefix its codes carry.

Authentication Bearer token (admin)

Parameters

descriptionstringRequired

Product description, e.g. "Sign PVC 'For Sale' 10x6".

prefixIdstringRequired

Numeric prefix stamped on codes in this category.

cURL
1curl -X POST "https://api.caroom.us/sign-categories" \
2  -H "Authorization: Bearer $CAROOM_ADMIN_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "description": "Sign PVC For Sale 10x6",
6    "prefixId": "1401"
7  }'

Follow a printed short link

GET/q/:code

The URL printed on the sign. It returns the activation or listing page as HTML rather than JSON — an unactivated sign lands on the welcome flow.

Authentication None

Path parameters

codestringRequired

Short code printed on the sign, e.g. BGsMf.

cURL
1curl "https://api.caroom.us/q/BGsMf"

Retrieve what a short link points at

GET/q/:code/data

The JSON behind the redirect above — use this instead of scraping the HTML page.

Authentication None

Path parameters

codestringRequired

Short code printed on the sign.

cURL
1curl "https://api.caroom.us/q/04lSL/data"

Scan analytics

Every scan, view and link change is recorded as an event. One query endpoint reads them back — filtered by code, group, listing, type or date — and returns both the raw events and the aggregates behind the dashboard charts.

Query scan activity

GET/leads/activity

Returns the caller’s activity events alongside a `stats` block — total and unique scans, top devices, browsers and locations, and scans broken down by date and by hour. With no filters it covers every event the caller can see; the query parameters below narrow it and can be combined.

Authentication Bearer token

Query parameters

typestring

Restricts the result to one kind of event.

qrIdstring

UUID of a single code.

qrGroupIdstring

UUID of a group — covers every code printed for that listing.

listingIdinteger

Only events for this listing.

start_datestring

Earliest event date to include, as YYYY-MM-DD.

end_datestring

Latest event date to include, as YYYY-MM-DD.

pageinteger

Page number, 1-based.

limitinteger

Events per page. Only `events_list` is paginated.

  • `stats` is computed over the whole filtered set, not just the page in `events_list`.
  • Date filters are inclusive and match on the event’s creation date.
cURL
1curl "https://api.caroom.us/leads/activity?type=qr_scan&qrGroupId=7d1f5db5-2637-4832-9761-a47dda1921e0&start_date=2026-07-01&end_date=2026-07-09" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN"
Response schema
{
  "events": {
    "details": {
      "page": integer,
      "limit": integer,
      "total": integer,
      "totalPages": integer
    },
    "events_list": [
      {
        "fingerprint": string,
        "ipAddress": string,
        "geoLocation": {
          "country": string,
          "region": string,
          "city": string,
          "latitude": number,
          "longitude": number,
          "timezone": string
        },
        "userAgent": string,
        "deviceType": string,
        "browserType": string,
        "os": string,
        "scanCount": integer,
        "view_count": integer,
        "referralSource": string,
        "eventType": string,
        "listingId": integer,
        "qrGroupId": string,
        "qrId": string,
        "createdAt": string
      }
    ]
  },
  "stats": {
    "totalScans": integer,
    "uniqueScans": integer,
    "topDevices": [{ "device": string, "count": integer }],
    "topBrowsers": [{ "browser": string, "count": integer }],
    "topLocations": [{ "location": string, "count": integer }],
    "scansByDate": [{ "date": string, "count": integer }],
    "scansByHour": [{ "hour": integer, "count": integer }]
  }
}

Record an event

POST/analysis/events

Writes one activity event. Scans made through the code endpoints are recorded for you — call this for the interactions the API cannot see, such as a viewer tapping a phone number on the listing.

Authentication Bearer token

Parameters

eventTypestringRequired

One of `qr_scan`, `listing_view`, `listing_linked`, `listing_unlinked` or `contact_clicked`.

fingerprintstringRequired

Stable device identifier, the same value sent as `x-fingerprint-id` when resolving a code. It is what separates unique scans from repeat ones.

qrIdstring

UUID of the code the event came from.

qrGroupIdstring

UUID of that code’s group.

listingIdinteger

Listing the event relates to.

referralSourcestring

URL the viewer arrived from.

geoLocationobject

Where the event happened. Send it when the client has already resolved a position; otherwise it is derived from the IP address.

  • Leave the browser’s User-Agent intact — the device, browser and OS breakdowns are derived from it.
cURL
1curl -X POST "https://api.caroom.us/analysis/events" \
2  -H "Authorization: Bearer $CAROOM_ACCESS_TOKEN" \
3  -H "Content-Type: application/json" \
4  -d '{
5    "eventType": "contact_clicked",
6    "fingerprint": "fb-fallback-unknown",
7    "qrId": "c05eb0bd-e021-46ad-9acb-c59cae63f5aa",
8    "qrGroupId": "b34eb6d4-c03e-402e-9e43-d17b27efddad",
9    "listingId": 1,
10    "referralSource": "https://www.example.com",
11    "geoLocation": {
12      "country": "United States",
13      "region": "California",
14      "city": "San Francisco",
15      "latitude": 37.7749,
16      "longitude": -122.4194,
17      "timezone": "America/Los_Angeles"
18    }
19  }'