Ts-Immo REST API

Reference for the Ts-Immo Client REST API — every endpoint exposed under /v1/gateway/, its authentication, parameters and concrete examples.

Base URL

https://api.ts-immo.org/v1/gateway

All Client API endpoints are served under the /v1/gateway/ prefix. Responses are JSON, identifiers are UUID v4 and dates follow ISO 8601.

Authentication

Every call must carry an active token. The Client API accepts either an OAuth2 bearer (user flow) or an API Token (programmatic use, e.g. the WordPress plugin), interchangeably.

# OAuth2 Bearer (user flow)
Authorization: Bearer <access_token>

# API Token (programmatic, e.g. WordPress plugin)
Authorization: Bearer <api_token>
# or:
X-TS-IMMO-KEY: <api_token>

Both formats are introspected by ts-identity. No scope constraint is enforced: any active token is accepted. Resource filtering relies on the item_ids and client_id carried by the token — a request whose token carries no item_id matches no listing.

Never share your API Token. Use environment variables and server-side secrets only.

Conventions

All JSON field names (requests and responses) are snake_case. Query parameters stay camelCase (e.g. ?crmReference=…, ?gatewayId=…). Null fields are omitted from responses. Dates are ISO 8601 (e.g. 2026-01-15T10:00:00Z).

Endpoints

Gateways

Full gateway lifecycle: create, update, enable, validate, delete, delegate to other clients and free-form metadata. The client_id is extracted from the token.

GET/v1/gateway/gatewaysList owned gateways
POST/v1/gateway/gatewaysCreate a gateway
GET/v1/gateway/gateways/{id}Gateway detail
PUT/v1/gateway/gateways/{id}Replace a gateway
PATCH/v1/gateway/gateways/{id}Partial update
POST/v1/gateway/gateways/{id}/enableEnable (ACTIVE)
POST/v1/gateway/gateways/{id}/pausePause (PAUSED)
POST/v1/gateway/gateways/{id}/validateValidate and enable
DELETE/v1/gateway/gateways/{id}Delete a gateway
GET/v1/gateway/gateways/delegatedList gateways delegated to the caller
POST/v1/gateway/gateways/{id}/delegationsCreate a delegation (owner)
GET/v1/gateway/gateways/{id}/delegationsList active delegations
DELETE/v1/gateway/gateways/{id}/delegations/{delegateClientId}Revoke a delegation
GET/v1/gateway/gateways/{id}/metadataRead metadata
PUT/v1/gateway/gateways/{id}/metadataReplace metadata
PATCH/v1/gateway/gateways/{id}/metadataMerge metadata

Synchronisations

Trigger and track a gateway's sync jobs, cancel them, and replay the output phase without re-fetching the CRM.

GET/v1/gateway/gateways/{id}/sync-jobsList sync jobs
GET/v1/gateway/gateways/{id}/sync-jobs/{jobId}Sync job detail
GET/v1/gateway/gateways/{id}/sync-jobs/{jobId}/progressJob progress
POST/v1/gateway/gateways/{id}/sync-jobsTrigger a synchronisation
POST/v1/gateway/gateways/{id}/sync-jobs/{jobId}/cancelCancel a synchronisation
POST/v1/gateway/gateways/{id}/output-replayReplay output (no CRM)

Audit

Read a gateway's management events and the full set of events for a sync run.

GET/v1/gateway/gateways/{id}/audit-eventsGateway management events
GET/v1/gateway/gateways/{id}/sync-jobs/{jobId}/audit-eventsSync run events

Listings

Read synchronised listings: list, detail, raw CRM model, cover thumbnail and reporting of the published URL.

GET/v1/gateway/propertiesList the token's listings
GET/v1/gateway/gateways/{id}/propertiesList a gateway's listings
GET/v1/gateway/properties/{id}Listing detail
HEAD/v1/gateway/properties/{id}Existence test + Last-Modified
GET/v1/gateway/properties/{id}/crm-modelRaw CRM model (redirect)
GET/v1/gateway/public/properties/{id}/coverCover thumbnail (redirect)
PUT/v1/gateway/properties/{id}/urlSet the published URL

Natural-language property search: the query is translated into a MongoDB filter by an LLM, validated against a strict whitelist and isolated per gateway.

POST/v1/gateway/properties/search/aiNatural-language search

Former listings

Browse listings removed from the live collection (gateway deletion, orphan cleanup, staff deletion) kept in cold storage. Read-only, restricted to the token's gateways.

GET/v1/gateway/properties/deletedSearch your former listings
GET/v1/gateway/properties/deleted/{archiveId}View a former listing

Mapping templates

Manage WordPress mapping templates (postmeta, taxonomies, statuses): default templates and the client's personal templates (create, update, duplicate).

GET/v1/gateway/templatesList templates
GET/v1/gateway/templates/{id}Template detail
POST/v1/gateway/templatesCreate a personal template
PUT/v1/gateway/templates/{id}Update a template
DELETE/v1/gateway/templates/{id}Delete a template
POST/v1/gateway/templates/{id}/duplicateDuplicate a template

Plugins

Downloadable single-file PHP extensions for the Ts-Immo Sync WordPress plugin. Access is automatically filtered by the token's plan.

GET/v1/gateway/pluginsList available plugins
GET/v1/gateway/plugins/{id}Plugin detail
GET/v1/gateway/plugins/{id}/downloadDownload the plugin file

Plugin Manager

Endpoints consumed by the Ts-Immo Plugin Manager WordPress hub: site pairing, signed addon catalogue, download, telemetry and support-ticket proxy. Auth: agency token.

POST/v1/gateway/plugin-manager/site/registerPairing / license check
GET/v1/gateway/plugin-manager/catalogAddon catalogue + kill-switch
GET/v1/gateway/plugin-manager/{code}/downloadDownload an addon (signed zip)
POST/v1/gateway/plugin-manager/auditPush the audit buffer
POST/v1/gateway/plugin-manager/fatalReport fatal errors
POST/v1/gateway/support/ticketsCreate a support ticket (proxy)

Site activation

Endpoint called by the Ts-Immo Sync WordPress plugin on activation to register its auth key and retrieve plan details.

POST/v1/gateway/site/activateActivate a WordPress site

PDF templates

Layout templates for property PDF sheets. Five predefined templates (luxe, design, standard, minimal, vitrine) plus custom templates.

GET/v1/gateway/pdf-templatesList PDF templates
GET/v1/gateway/pdf-templates/{id}Get a PDF template

Price estimations

DVF-anchored property valuation service (sale and rental). The billed gateway is resolved from the token (ESTIMATION or ESTIMATION_IA addon required).

POST/v1/gateway/estimationsIssue an estimation

Leads

Read prospects captured via the lead block of estimations. The gateway is resolved from the token (ESTIMATION addon required).

GET/v1/gateway/leadsList the gateway's leads

Syndication portals

Enrol or unenrol a gateway with partner portals configured in the back-office. Checks ownership and the portal's required addon.

GET/v1/gateway/gateways/{id}/portalsList portals + enrolment status
POST/v1/gateway/gateways/{id}/portals/{portalCode}/enrollEnrol the gateway with a portal
DELETE/v1/gateway/gateways/{id}/portals/{portalCode}/enrollUnenrol from a portal

Addons

Catalogue of addons offered for the gateway's market, with their activation status, plus subscribe / unsubscribe (Stripe via ts-identity).

GET/v1/gateway/gateways/{id}/addonsList addons + status
POST/v1/gateway/gateways/{id}/addons/{addonCode}Subscribe to an addon
DELETE/v1/gateway/gateways/{id}/addons/{addonCode}Unsubscribe from an addon

Invoices

Stripe invoices attached to the gateway owner. Restricted to the owner and FULL_ACCESS delegates.

GET/v1/gateway/gateways/{id}/invoicesList invoices
GET/v1/gateway/gateways/{id}/invoices/{invoiceId}Get an invoice

Sunlight exposure

Annual sunlight exposure analysis for a property (JSON or PDF report). SOLAR_EXPOSURE addon required on the gateway.

GET/v1/gateway/properties/{id}/sunlightSunlight analysis (JSON)
GET/v1/gateway/properties/{id}/sunlight/pdfSunlight report (PDF)

DVF (open data)

Open-data real-estate transactions (Demandes de Valeurs Foncières): search by filters, by geographic disc, and mutation detail. DVF addon required.

GET/v1/gateway/dvfDVF search by filters
GET/v1/gateway/dvf/{id}DVF mutation detail
GET/v1/gateway/dvf/geoDVF search by geographic disc

Insights

Behavioural visitor analytics and intent scoring for sites running the ts-immo-insights extension. Paginated dashboard reads (never raw events). INSIGHTS addon required. The gateway is passed in the path.

GET/v1/gateway/insights/{gatewayId}/overviewDashboard overview
GET/v1/gateway/insights/{gatewayId}/funnelConversion funnel
GET/v1/gateway/insights/{gatewayId}/properties/topProperty ranking
GET/v1/gateway/insights/{gatewayId}/properties/diagnosticsProperty performance diagnostics
GET/v1/gateway/insights/{gatewayId}/market/demandMarket demand
GET/v1/gateway/insights/{gatewayId}/leads/attributionLead channel attribution
GET/v1/gateway/insights/{gatewayId}/leadsScored visitors / window leads
GET/v1/gateway/insights/{gatewayId}/leads/{visitorId}Visitor detail
GET/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}Property detail (insights)
GET/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/owner-reportOwner report (weekly)
GET/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/leadsProspects interested in a property
GET/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/matching-leadsWaiting buyers for a property
GET/v1/gateway/insights/{gatewayId}/leads/{leadId}/matching-propertiesProperties matching a buyer
PUT/v1/gateway/insights/{gatewayId}/leads/{leadId}/outcomeSet a lead's outcome
GET/v1/gateway/insights/{gatewayId}/roiClosed-loop ROI

Notification preferences

Enable / disable automatic emails per category (sync, lifecycle, delegation, site). A single entry per client, shared across all their gateways.

GET/v1/gateway/notification-preferencesRead notification preferences
PATCH/v1/gateway/notification-preferencesUpdate preferences

Key endpoints in detail

The most-used endpoints are detailed below with their parameters, request bodies and sample responses.

POST/v1/gateway/gateways

Creates a gateway for the authenticated client. The provided item_id must be one of the token's item_ids. The plan is automatically extracted from the token.

Request body

ParamTypeReq.Description
item_idstring*Item identifier (must be one of the token's item_ids)
namestring*Gateway name
marketstring*Market code (e.g. fr, de, us)
categorystring*Category code (e.g. professional, agency)
modePROD | TESTOperating mode. Default: PROD
input_connectorConnectorRef*Primary input connector (CRM)
output_connectorsConnectorRef[]Output connectors
input_connectorsConnectorRef[]List of input connectors (multi-input mode, MULTI_INPUTS addon)
logo_urlstringAbsolute logo URL (auto-detected if empty)
{
  "item_id": "item-123",
  "name": "Apimo -> WordPress",
  "market": "fr",
  "category": "professional",
  "mode": "PROD",
  "input_connector": {
    "connector_type": "APIMO",
    "connector_id": "770e8400-e29b-41d4-a716-446655440000",
    "config": { "api_key": "apimo-api-key", "provider": "12345" }
  },
  "output_connectors": [
    {
      "connector_type": "TS_SYNC",
      "connector_id": "880e8400-e29b-41d4-a716-446655440000",
      "config": {
        "url": "https://www.your-agency.com",
        "plugin_auth_key": "your-plugin-auth-key"
      }
    }
  ]
}

201 Created response — the created gateway and an API Token generated for programmatic use (e.g. WordPress plugin), nullable:

{
  "gateway": { "id": "660e8400-...", "item_id": "item-123", "status": "DRAFT", "...": "..." },
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...."
}

POST/v1/gateway/gateways/{id}/sync-jobs

Creates and immediately starts a sync job. The gateway must be in ACTIVE status.

ParamTypeReq.Description
idstring*Gateway identifier
crmReferencestring (query)Sync only the listing whose crm_reference matches, without orphan cleanup
forceboolean (query)If true, rewrites the whole catalogue in FORCED_FULL mode. Default: false
# Full sync
curl -X POST "https://api.ts-immo.org/v1/gateway/gateways/GATEWAY_ID/sync-jobs" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Single-property sync
curl -X POST "https://api.ts-immo.org/v1/gateway/gateways/GATEWAY_ID/sync-jobs?crmReference=REF-12345" \
  -H "X-TS-IMMO-KEY: your-api-token"
With no parameter, a full synchronisation (FULL) runs. crmReference dispatches a single listing and skips orphan cleanup. force=true rewrites the whole catalogue (FORCED_FULL). A 409 is returned if a job is already running.

GET/v1/gateway/properties

Returns the listings of the gateways tied to the token's item_ids (including delegated gateways). No parameters: filtering is automatic.

200 OK response — an array of TsImmoProperty (normalised real-estate model, snake_case fields, null fields omitted):

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "gateway_id": "660e8400-e29b-41d4-a716-446655440000",
    "stream_id": "770e8400-e29b-41d4-a716-446655440000",
    "crm_source": "apimo",
    "reference": "REF-12345",
    "crm_reference": "CRM-12345",
    "type": "apartment",
    "sub_type": "duplex",
    "offer_type": "sale",
    "status": "available",
    "title": { "fr": "Bel appartement 3 pièces", "en": "Beautiful 3-room apartment" },
    "description": { "fr": "Lumineux duplex traversant...", "en": "Bright through-duplex..." },
    "bedrooms": 2,
    "bathrooms": 1,
    "floor": "3",
    "orientation": "S",
    "financial": {
      "transaction": {
        "price": { "amount": 350000, "currency": "EUR" }
      }
    },
    "location": {
      "city": "Paris",
      "postal_code": "75001",
      "countryCode": "FR",
      "geo": { "latitude": 48.8566, "longitude": 2.3522 }
    },
    "sizes": {
      "liveable_area": { "size": 75.5, "unit": "sq_m" }
    },
    "images": [
      { "url": "https://cdn.example.com/photo1.jpg", "ordinal": 0 }
    ],
    "property_url": "https://www.your-agency.com/property/apartment-paris",
    "cover_thumbnail": "https://cdn.example.com/photo1-thumb.jpg",
    "created_at": "2026-01-01T00:00:00Z",
    "updated_at": "2026-01-15T10:00:00Z",
    "fetched_at": "2026-01-15T10:00:00Z"
  }
]
The TsImmoProperty model has 90+ fields (financial, location, detailed areas, amenities, mandate, co-ownership, diagnostics…). Only the main ones are shown here; text fields (title, description, uri) are multilingual (I18nText), prices are { amount, currency } objects and areas are { size, unit } objects (unit ∈ sq_m, sq_ft, are, acre).

PUT/v1/gateway/properties/{id}/url

Callback used by the client plugin to set the URL of a listing's published page after synchronisation. Updates the property_url field.

ParamTypeReq.Description
idstring*Listing UUID
urlstring (body)*Public URL of the listing on the client site
curl -X PUT "https://api.ts-immo.org/v1/gateway/properties/PROPERTY_ID/url" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://www.your-agency.com/property/apartment-t3-paris" }'

Natural-language property search. Input is treated as hostile: control characters stripped, length truncated to 500, LLM output validated against a whitelist. The gateway_id filter is always forced from the token.

ParamTypeReq.Description
querystring (body)*Natural-language search (max 500 characters)
curl -X POST "https://api.ts-immo.org/v1/gateway/properties/search/ai" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "query": "3-bedroom apartment near Lyon, max 500000 EUR, with a pool" }'

The response returns the matching properties (max 50), the total count and the generated MongoDB filter (for transparency):

{
  "results": [ { "id": "...", "type": "apartment", "offer_type": "sale", "...": "..." } ],
  "total_count": 5,
  "filter": {
    "type": "apartment",
    "bedrooms": { "$gte": 3 },
    "amenities": { "$all": ["pool"] },
    "financial.transaction.price.amount": { "$lte": 500000 }
  }
}

POST/v1/gateway/site/activate

Validates that at least one of the client's gateways has a TS_SYNC output connector whose URL matches the domain. If found, the plugin_auth_key is propagated and an activation record is created.

ParamTypeReq.Description
domainstring*Root URL of the WordPress site (e.g. https://your-site.com)
plugin_auth_keystring*Auth key generated by the plugin
theme_idstringActive WordPress theme identifier (optional)

Sample response:

{
  "success": true,
  "status": "activated",
  "domain": "https://your-site.com",
  "activated_at": "2026-03-26T10:00:00Z",
  "plan": "pro",
  "expires_at": "2027-03-26T00:00:00Z",
  "biens_max": 500
}
Returns 422 no_matching_gateway if no TS_SYNC gateway matches the domain. The gateway owner is notified by email.

POST/v1/gateway/estimations

Issues a DVF-anchored price estimation. The caller passes no gateway identifier: it is resolved from the token. At least (address | postal_code) or (latitude, longitude) must be provided — the geocoded address wins over coordinates.

Two tiers: ESTIMATION (algorithm only) and ESTIMATION_IA (superset, with a French AI commentary when with_commentary=true). The body must be snake_case, otherwise required fields fail with a 400.
ParamTypeReq.Description
property_typeenum*apartment, house, land, commercial, office, parking, building, program, goodwill, other
offer_typeenum*sale, rental, auction, seasonal_rental, program, life_annuity_sale, lease_transfer, leasehold
liveable_area_sqmnumber*Liveable area in m² (between 5 and 10,000)
address / postal_codestringFree-form address or postal code. Primary source for geocoding.
latitude, longitudenumberFallback coordinates, used only when no address is provided
rooms, bedrooms, ...integerOptional features refining the estimation (rooms, floor, garages, EPC, condition, etc.)
leadobjectOptional prospect-capture block (first_name, last_name, email, project_timeframe_months)
with_commentarybooleanAttaches a French AI commentary (ESTIMATION_IA addon only)
{
  "property_type": "house",
  "offer_type": "sale",
  "liveable_area_sqm": 120,
  "address": "10 Rue de la République, 74300 Cluses",
  "postal_code": "74300",
  "construction_year": 1985,
  "epc_category": "B",
  "with_commentary": true
}

200 OK response — central / low / high range, confidence level, applied adjustments, comparables and (on ESTIMATION_IA) a commentary:

{
  "request_id": "8c1c0c5e-...",
  "offer_type": "sale",
  "central":   { "total": 415000, "price_per_sqm": 3458, "currency": "EUR" },
  "low_bound": { "total": 385000, "price_per_sqm": 3208, "currency": "EUR" },
  "high_bound":{ "total": 448000, "price_per_sqm": 3733, "currency": "EUR" },
  "confidence": { "level": "MEDIUM", "sample_size": 17, "final_radius_km": 1.5 },
  "adjustments": [ { "code": "DPE_A_B", "percent": 0.03 } ],
  "top_comparables": [ { "source": "DVF", "sold_price": 395000, "price_per_sqm": 3291 } ]
}

GET/v1/gateway/leads

Paginated list of prospects captured via the lead block of estimations, sorted by creation date descending.

ParamTypeReq.Description
pageinteger (query)Zero-based page index. Default: 0
sizeinteger (query)Page size (1..200). Default: 50
{
  "items": [
    {
      "id": "uuid",
      "first_name": "Marie",
      "last_name": "Dupont",
      "email": "marie.dupont@example.com",
      "project_timeframe_months": 6,
      "offer_type": "SALE",
      "property_type": "HOUSE",
      "estimated_central_total": 415000,
      "currency": "EUR",
      "created_at": "2026-05-02T23:14:58Z"
    }
  ],
  "page": 0,
  "size": 50,
  "total_elements": 87,
  "total_pages": 2
}

POST/v1/gateway/gateways/{id}/addons/{addonCode}

Buys the addon for the gateway. The price is resolved server-side from the catalogue. Idempotent: if the addon is already active, the existing purchase is returned. Restricted to the owner or a FULL_ACCESS delegate.

ParamTypeReq.Description
idstring*Gateway identifier
addonCodestring*Addon code in the ts-identity catalogue
periodMONTHLY | ANNUAL*Subscription cadence
currencystring*ISO code; must exist in the addon's pricing
metadataobjectOpaque metadata passed to ts-identity
curl -X POST "https://api.ts-immo.org/v1/gateway/gateways/GATEWAY_ID/addons/ESTIMATION" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "period": "MONTHLY", "currency": "EUR" }'

GET/v1/gateway/insights/{gatewayId}/overview

Dashboard overview over a window. gatewayId is passed in the path and checked against the token scope; the INSIGHTS addon must be active (otherwise 409). Includes a comparison with the previous window.

ParamTypeReq.Description
gatewayIdstring*Gateway identifier
fromdate (query)Window lower bound (ISO date). Default: to - 29d
todate (query)Inclusive upper bound. Default: today (UTC)
{
  "unique_visitors": 1432,
  "sessions": 1879,
  "page_views": 5421,
  "leads": 28,
  "conversion_rate": 0.0195,
  "hot_leads": 7,
  "urgent_leads": 2,
  "series": [
    { "date": "2026-05-01", "unique_visitors": 52, "sessions": 67, "page_views": 198, "leads": 1 }
  ]
}

PATCH/v1/gateway/notification-preferences

Partial update of preferences. Each field is optional: an omitted or null field leaves the stored value unchanged. Defaults are all true (opt-out).

ParamTypeReq.Description
syncbooleanSynchronisation emails (completed, overflow, timeout, disabled)
gateway_lifecyclebooleanGateway lifecycle emails (created, deleted, validated, paused…)
delegationbooleanDelegation emails (granted to the owner / the delegate)
sitebooleanSite activation emails
curl -X PATCH "https://api.ts-immo.org/v1/gateway/notification-preferences" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "sync": false }'

Error codes

Errors follow the standard envelope shared by all ts-services APIs: a human-readable message, a machine code, a timestamp and an optional detail.

{
  "message": "Human-readable message",
  "code": "ERROR_CODE",
  "timestamp": "2026-04-18T10:00:00Z",
  "detail": "Optional technical detail, may be null"
}
ParamTypeReq.Description
200 / 201 / 204Success (200 OK, 201 Created, 204 No Content)
302Redirect to a pre-signed URL (CRM model, cover thumbnail)
400BAD_REQUESTValidation: missing, malformed or out-of-range argument
401AUTH_FAILEDMissing, invalid or expired token
403FORBIDDENUnauthorised route or write on a default resource
404NOT_FOUNDResource not found (or outside the token's scope)
409CONFLICTBusiness state conflict (e.g. job already running, theme_id already used)
422Unprocessable entity (e.g. gateway without client_id, property without coordinates)
503DOWNSTREAM_ERRORExternal service unavailable (ts-identity, CRM, S3, Mistral…)