API Documentation

Access your property intelligence data programmatically. The RealiQ REST API is available on the Enterprise plan.

Authentication

All API requests require an API key passed via the Authorization header. API keys can be created and managed from Settings > API Keys in your dashboard.

curl -H "Authorization: Bearer nc_live_abc123..." \
  https://www.realiq.uk
/api/v1/properties

API keys start with nc_ and are hashed with SHA-256 before storage. Keep your keys secret.

Rate Limiting

Each API key is limited to 1,000 requests per day. When exceeded, the API returns a 429 Too Many Requests response. Rate limit counters reset at midnight UTC.

Response Format

All responses use a standard JSON envelope.

Success (list)

{
  "data": [ ... ],
  "meta": {
    "count": 50,
    "has_more": true,
    "cursor": "eyJpZCI6IjUwIn0"
  }
}

Success (single)

{
  "data": { ... }
}

Error

{
  "error": {
    "message": "Invalid API key",
    "code": "UNAUTHORIZED"
  }
}

Pagination

List endpoints support cursor-based pagination. Pass cursor and optional limit (default 50, max 100).

GET /api/v1/properties?limit=25&cursor=eyJpZCI6IjI1In0

Endpoints

GET/api/v1/properties

List properties with optional filters.

Query Parameters

ParameterTypeDescription
sectorstringFilter by sector (e.g. Office, Industrial, Industrial Open Storage, Retail)
citystringFilter by city name
postcodestringFilter by postcode prefix
min_pricenumberMinimum asking price
max_pricenumberMaximum asking price
curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/properties?sector=Industrial&limit=10"

Example Response

{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "name": "Apex Business Park",
      "address": "Unit 5, Apex Park, Leeds LS11 5QA",
      "sector": "Industrial",
      "asking_price": 4250000,
      "niy": 6.85,
      "total_rent": 291125,
      "number_of_tenants": 3,
      "wault": 5.2,
      "created_at": "2026-02-10T14:30:00Z"
    }
  ],
  "meta": { "count": 1, "has_more": false, "cursor": null }
}

GET/api/v1/properties/:id

Get a single property with its tenancy schedule.

curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/properties/a1b2c3d4-..."

GET/api/v1/matches

List investor-property matches with scores and AI commentary.

Query Parameters

ParameterTypeDescription
statusstringFilter by status: new, reviewed, contacted, passed
min_scorenumberMinimum match score (0-100)
investor_iduuidFilter matches for a specific investor
curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/matches?min_score=90&status=new"

GET/api/v1/comparables

List comparable transactions from your evidence database.

Query Parameters

ParameterTypeDescription
sectorstringFilter by sector
citystringFilter by city
start_datedateTransaction date from (YYYY-MM-DD)
end_datedateTransaction date to (YYYY-MM-DD)
curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/comparables?sector=Office&city=Manchester"

GET/api/v1/investors

List investors with their acquisition profiles.

Query Parameters

ParameterTypeDescription
namestringSearch by investor name
typestringFilter by investor type
curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/investors?type=fund"

GET/api/v1/investors/:id

Get a single investor with all their acquisition requirements.

curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/investors/e5f6g7h8-..."

PATCH/api/v1/investors/:id

Update an investor: send any of name, type, notes or active. Types are Institution, Private, REIT, Fund, Family Office, Prop Co or Other. Requires a key with write scope.

curl -X PATCH \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"type": "Prop Co", "notes": "Trading co, off-market only"}' \
  https://www.realiq.uk
/api/v1/investors/e5f6g7h8-...

GETPOST/api/v1/investors/:id/contacts

List an investor's contacts, or add one. POST takes name (required), email, phone, role and is_primary; setting is_primary demotes any existing primary. POST requires write scope.

curl -X POST \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "Jane Doe", "email": "jane@fund.com", "role": "Head of Acquisitions", "is_primary": true}' \
  https://www.realiq.uk
/api/v1/investors/e5f6g7h8-.../contacts

GETPATCH/api/v1/requirements/:id

Read or update an acquisition mandate. PATCH accepts name, sectors, locations, min_lot_size, max_lot_size, min_yield, max_yield, min_wault_years, tenant_covenant_min (A/B/C), return_criteria_list, notes, is_hot and active. Re-run matching afterwards to rescore. Requires write scope.

curl -X PATCH \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"sectors": ["Multi-Let Industrial"], "min_yield": 6.5, "return_criteria_list": ["Core Plus", "Value-Add"]}' \
  https://www.realiq.uk
/api/v1/requirements/a1b2c3d4-...

GET/api/v1/tenancies

List tenancies across all properties.

Query Parameters

ParameterTypeDescription
property_iduuidFilter tenancies for a specific property
tenant_namestringSearch by tenant name
curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/tenancies?tenant_name=Amazon"

GET/api/v1/stats

Get portfolio overview statistics.

curl -H "Authorization: Bearer nc_live_abc123..." \
  "https://www.realiq.uk
/api/v1/stats"

Example Response

{
  "data": {
    "properties_count": 188,
    "total_value": 1510000000,
    "total_rent": 104100000,
    "investors_count": 109,
    "matches_count": 12120,
    "comparables_count": 923,
    "sector_breakdown": {
      "Industrial": 72,
      "Office": 48,
      "Retail": 35,
      "Mixed Use": 18,
      "Other": 15
    }
  }
}

POST/api/v1/extract

Run AI extraction on a document (PDF, DOCX or XLSX). Requires a key with write scope. The result lands in pending review for you to commit in the web app.

Small files (under 4.5MB): multipart

curl -X POST \
  -H "Authorization: Bearer nc_..." \
  -F "file=@brochure.pdf" \
  https://www.realiq.uk
/api/v1/extract

Large files (up to 30MB+): upload to storage, then extract

A request body sent to the function is capped at ~4.5MB, so larger brochures are uploaded straight to storage first, then extracted by reference. Three steps: get a signed URL, PUT the file to it, then call extract with the returned storage_path.

# 1. Get a signed upload URL
curl -X POST \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"filename": "big-brochure.pdf"}' \
  https://www.realiq.uk
/api/v1/uploads
# -> { "data": { "upload_url": "https://...", "storage_path": "<org>/api/..." } }

# 2. PUT the file straight to storage
curl -X PUT --data-binary @big-brochure.pdf \
  -H "Content-Type: application/pdf" \
  "<upload_url from step 1>"

# 3. Run extraction on the uploaded file
curl -X POST \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"storage_path": "<storage_path from step 1>"}' \
  https://www.realiq.uk
/api/v1/extract

To backfill a whole folder, see scripts/bulk-upload.py, which loops these three steps over every document.

Example Response

{
  "data": {
    "extraction_id": "f1a2b3c4-...",
    "property": {
      "name": "Phoenix House",
      "address": "45 High Street, Birmingham B2 4LP",
      "sector": "Office",
      "asking_price": 3750000,
      "niy": 7.2
    },
    "tenancies_count": 4,
    "comparables_count": 2,
    "validation": {
      "score": 87,
      "status": "passed"
    }
  }
}

GET/api/v1/extractions

List your extractions. Defaults to status=pending_review (documents extracted but not yet committed to the portfolio). Cursor-paginated.

curl -H "Authorization: Bearer nc_..." \
  "https://www.realiq.uk
/api/v1/extractions?status=pending_review&limit=100"

POST/api/v1/extractions/commit

Commit pending-review extractions to your portfolio (properties, tenancies and comparables) in bulk, so an API backfill does not need committing one at a time in the app. With no body it commits the next batch of up to 50; pass extraction_ids to commit specific ones. Runs without AI matching by default to keep it fast; pass match: true to score as you commit, or Run Matching in the app afterwards. Loop while meta.has_more is true. Requires write scope.

curl -X POST \
  -H "Authorization: Bearer nc_..." \
  -H "Content-Type: application/json" \
  -d '{"match": false}' \
  https://www.realiq.uk
/api/v1/extractions/commit
# -> { "data": [ { "extraction_id": "...", "outcome": "saved", "property_id": "...", "comparables_inserted": 3 }, ... ],
#      "meta": { "count": 50, "has_more": true } }