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/gatewayAll 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.
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.
/v1/gateway/gatewaysList owned gateways/v1/gateway/gatewaysCreate a gateway/v1/gateway/gateways/{id}Gateway detail/v1/gateway/gateways/{id}Replace a gateway/v1/gateway/gateways/{id}Partial update/v1/gateway/gateways/{id}/enableEnable (ACTIVE)/v1/gateway/gateways/{id}/pausePause (PAUSED)/v1/gateway/gateways/{id}/validateValidate and enable/v1/gateway/gateways/{id}Delete a gateway/v1/gateway/gateways/delegatedList gateways delegated to the caller/v1/gateway/gateways/{id}/delegationsCreate a delegation (owner)/v1/gateway/gateways/{id}/delegationsList active delegations/v1/gateway/gateways/{id}/delegations/{delegateClientId}Revoke a delegation/v1/gateway/gateways/{id}/metadataRead metadata/v1/gateway/gateways/{id}/metadataReplace metadata/v1/gateway/gateways/{id}/metadataMerge metadataSynchronisations
Trigger and track a gateway's sync jobs, cancel them, and replay the output phase without re-fetching the CRM.
/v1/gateway/gateways/{id}/sync-jobsList sync jobs/v1/gateway/gateways/{id}/sync-jobs/{jobId}Sync job detail/v1/gateway/gateways/{id}/sync-jobs/{jobId}/progressJob progress/v1/gateway/gateways/{id}/sync-jobsTrigger a synchronisation/v1/gateway/gateways/{id}/sync-jobs/{jobId}/cancelCancel a synchronisation/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.
/v1/gateway/gateways/{id}/audit-eventsGateway management events/v1/gateway/gateways/{id}/sync-jobs/{jobId}/audit-eventsSync run eventsListings
Read synchronised listings: list, detail, raw CRM model, cover thumbnail and reporting of the published URL.
/v1/gateway/propertiesList the token's listings/v1/gateway/gateways/{id}/propertiesList a gateway's listings/v1/gateway/properties/{id}Listing detail/v1/gateway/properties/{id}Existence test + Last-Modified/v1/gateway/properties/{id}/crm-modelRaw CRM model (redirect)/v1/gateway/public/properties/{id}/coverCover thumbnail (redirect)/v1/gateway/properties/{id}/urlSet the published URLAI-assisted search
Natural-language property search: the query is translated into a MongoDB filter by an LLM, validated against a strict whitelist and isolated per gateway.
/v1/gateway/properties/search/aiNatural-language searchFormer 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.
/v1/gateway/properties/deletedSearch your former listings/v1/gateway/properties/deleted/{archiveId}View a former listingMapping templates
Manage WordPress mapping templates (postmeta, taxonomies, statuses): default templates and the client's personal templates (create, update, duplicate).
/v1/gateway/templatesList templates/v1/gateway/templates/{id}Template detail/v1/gateway/templatesCreate a personal template/v1/gateway/templates/{id}Update a template/v1/gateway/templates/{id}Delete a template/v1/gateway/templates/{id}/duplicateDuplicate a templatePlugins
Downloadable single-file PHP extensions for the Ts-Immo Sync WordPress plugin. Access is automatically filtered by the token's plan.
/v1/gateway/pluginsList available plugins/v1/gateway/plugins/{id}Plugin detail/v1/gateway/plugins/{id}/downloadDownload the plugin filePlugin 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.
/v1/gateway/plugin-manager/site/registerPairing / license check/v1/gateway/plugin-manager/catalogAddon catalogue + kill-switch/v1/gateway/plugin-manager/{code}/downloadDownload an addon (signed zip)/v1/gateway/plugin-manager/auditPush the audit buffer/v1/gateway/plugin-manager/fatalReport fatal errors/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.
/v1/gateway/site/activateActivate a WordPress sitePDF templates
Layout templates for property PDF sheets. Five predefined templates (luxe, design, standard, minimal, vitrine) plus custom templates.
/v1/gateway/pdf-templatesList PDF templates/v1/gateway/pdf-templates/{id}Get a PDF templatePrice estimations
DVF-anchored property valuation service (sale and rental). The billed gateway is resolved from the token (ESTIMATION or ESTIMATION_IA addon required).
/v1/gateway/estimationsIssue an estimationLeads
Read prospects captured via the lead block of estimations. The gateway is resolved from the token (ESTIMATION addon required).
/v1/gateway/leadsList the gateway's leadsSyndication portals
Enrol or unenrol a gateway with partner portals configured in the back-office. Checks ownership and the portal's required addon.
/v1/gateway/gateways/{id}/portalsList portals + enrolment status/v1/gateway/gateways/{id}/portals/{portalCode}/enrollEnrol the gateway with a portal/v1/gateway/gateways/{id}/portals/{portalCode}/enrollUnenrol from a portalAddons
Catalogue of addons offered for the gateway's market, with their activation status, plus subscribe / unsubscribe (Stripe via ts-identity).
/v1/gateway/gateways/{id}/addonsList addons + status/v1/gateway/gateways/{id}/addons/{addonCode}Subscribe to an addon/v1/gateway/gateways/{id}/addons/{addonCode}Unsubscribe from an addonInvoices
Stripe invoices attached to the gateway owner. Restricted to the owner and FULL_ACCESS delegates.
/v1/gateway/gateways/{id}/invoicesList invoices/v1/gateway/gateways/{id}/invoices/{invoiceId}Get an invoiceSunlight exposure
Annual sunlight exposure analysis for a property (JSON or PDF report). SOLAR_EXPOSURE addon required on the gateway.
/v1/gateway/properties/{id}/sunlightSunlight analysis (JSON)/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.
/v1/gateway/dvfDVF search by filters/v1/gateway/dvf/{id}DVF mutation detail/v1/gateway/dvf/geoDVF search by geographic discInsights
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.
/v1/gateway/insights/{gatewayId}/overviewDashboard overview/v1/gateway/insights/{gatewayId}/funnelConversion funnel/v1/gateway/insights/{gatewayId}/properties/topProperty ranking/v1/gateway/insights/{gatewayId}/properties/diagnosticsProperty performance diagnostics/v1/gateway/insights/{gatewayId}/market/demandMarket demand/v1/gateway/insights/{gatewayId}/leads/attributionLead channel attribution/v1/gateway/insights/{gatewayId}/leadsScored visitors / window leads/v1/gateway/insights/{gatewayId}/leads/{visitorId}Visitor detail/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}Property detail (insights)/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/owner-reportOwner report (weekly)/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/leadsProspects interested in a property/v1/gateway/insights/{gatewayId}/properties/{propertyUuid}/matching-leadsWaiting buyers for a property/v1/gateway/insights/{gatewayId}/leads/{leadId}/matching-propertiesProperties matching a buyer/v1/gateway/insights/{gatewayId}/leads/{leadId}/outcomeSet a lead's outcome/v1/gateway/insights/{gatewayId}/roiClosed-loop ROINotification preferences
Enable / disable automatic emails per category (sync, lifecycle, delegation, site). A single entry per client, shared across all their gateways.
/v1/gateway/notification-preferencesRead notification preferences/v1/gateway/notification-preferencesUpdate preferencesKey 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
| Param | Type | Req. | Description |
|---|---|---|---|
item_id | string | * | Item identifier (must be one of the token's item_ids) |
name | string | * | Gateway name |
market | string | * | Market code (e.g. fr, de, us) |
category | string | * | Category code (e.g. professional, agency) |
mode | PROD | TEST | — | Operating mode. Default: PROD |
input_connector | ConnectorRef | * | Primary input connector (CRM) |
output_connectors | ConnectorRef[] | — | Output connectors |
input_connectors | ConnectorRef[] | — | List of input connectors (multi-input mode, MULTI_INPUTS addon) |
logo_url | string | — | Absolute 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.
| Param | Type | Req. | Description |
|---|---|---|---|
id | string | * | Gateway identifier |
crmReference | string (query) | — | Sync only the listing whose crm_reference matches, without orphan cleanup |
force | boolean (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"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"
}
]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.
| Param | Type | Req. | Description |
|---|---|---|---|
id | string | * | Listing UUID |
url | string (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" }'POST/v1/gateway/properties/search/ai
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.
| Param | Type | Req. | Description |
|---|---|---|---|
query | string (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.
| Param | Type | Req. | Description |
|---|---|---|---|
domain | string | * | Root URL of the WordPress site (e.g. https://your-site.com) |
plugin_auth_key | string | * | Auth key generated by the plugin |
theme_id | string | — | Active 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
}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.
| Param | Type | Req. | Description |
|---|---|---|---|
property_type | enum | * | apartment, house, land, commercial, office, parking, building, program, goodwill, other |
offer_type | enum | * | sale, rental, auction, seasonal_rental, program, life_annuity_sale, lease_transfer, leasehold |
liveable_area_sqm | number | * | Liveable area in m² (between 5 and 10,000) |
address / postal_code | string | — | Free-form address or postal code. Primary source for geocoding. |
latitude, longitude | number | — | Fallback coordinates, used only when no address is provided |
rooms, bedrooms, ... | integer | — | Optional features refining the estimation (rooms, floor, garages, EPC, condition, etc.) |
lead | object | — | Optional prospect-capture block (first_name, last_name, email, project_timeframe_months) |
with_commentary | boolean | — | Attaches 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.
| Param | Type | Req. | Description |
|---|---|---|---|
page | integer (query) | — | Zero-based page index. Default: 0 |
size | integer (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.
| Param | Type | Req. | Description |
|---|---|---|---|
id | string | * | Gateway identifier |
addonCode | string | * | Addon code in the ts-identity catalogue |
period | MONTHLY | ANNUAL | * | Subscription cadence |
currency | string | * | ISO code; must exist in the addon's pricing |
metadata | object | — | Opaque 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.
| Param | Type | Req. | Description |
|---|---|---|---|
gatewayId | string | * | Gateway identifier |
from | date (query) | — | Window lower bound (ISO date). Default: to - 29d |
to | date (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).
| Param | Type | Req. | Description |
|---|---|---|---|
sync | boolean | — | Synchronisation emails (completed, overflow, timeout, disabled) |
gateway_lifecycle | boolean | — | Gateway lifecycle emails (created, deleted, validated, paused…) |
delegation | boolean | — | Delegation emails (granted to the owner / the delegate) |
site | boolean | — | Site 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"
}| Param | Type | Req. | Description |
|---|---|---|---|
200 / 201 / 204 | — | Success (200 OK, 201 Created, 204 No Content) | |
302 | — | Redirect to a pre-signed URL (CRM model, cover thumbnail) | |
400 | BAD_REQUEST | — | Validation: missing, malformed or out-of-range argument |
401 | AUTH_FAILED | — | Missing, invalid or expired token |
403 | FORBIDDEN | — | Unauthorised route or write on a default resource |
404 | NOT_FOUND | — | Resource not found (or outside the token's scope) |
409 | CONFLICT | — | Business state conflict (e.g. job already running, theme_id already used) |
422 | — | Unprocessable entity (e.g. gateway without client_id, property without coordinates) | |
503 | DOWNSTREAM_ERROR | — | External service unavailable (ts-identity, CRM, S3, Mistral…) |