Facility Verify API
Integration documentation for verifying ministry facility documents and reporting publication status.
v1.0Overview
This API lets platforms look up publishable ministry documents (TTBİS, simple accommodation, daily rental) and report whether related listings are published. All endpoints below require HTTP Basic Authentication, except the health endpoints, which are public.
Contents
Authentication
Every request must include an Authorization header with HTTP Basic credentials.
Use the platform username and password provided by the platform administrator.
Authorization: Basic base64(username:password)
Document types
The document-list response always includes three arrays. Each array has its own schema — field sets are not the same across document types.
| Response field | documentType |
Description |
|---|---|---|
ttbisDocuments |
ttbis |
Tourism Operation Certificates (TTBİS) |
simpleAccommodationDocuments |
simpleAccommodation |
Simple Accommodation certificates |
dailyRentalDocuments |
dailyRental |
Daily Rental (short-term housing) certificates |
Shared fields (all types)
traceId, documentType, documentNo,
documentDate, documentOwner, city, district
Type-specific fields
| Array | Additional fields |
|---|---|
ttbisDocuments |
documentStatus, facilityName, facilityType,
facilitySubType, facilityClass,
documentOwnerNationalIds, documentOwnerTaxNos
|
simpleAccommodationDocuments |
documentPersonType, taxNo,
yetkiliTcKimlikNo, basvuruKimlikNo, isletmeKimlikNo,
title, facilityName, facilityType
|
dailyRentalDocuments |
companyTitle, documentPersonType,
taxNo, documentOwnerNationalIds, neighbourhood
|
documentOwnerNationalIds / documentOwnerTaxNos are arrays and may contain
multiple values for multi-partner facilities.
Typical flow
-
Call
GET /document-listwith the owner's tax/national ID and/or document number (andsupplierIdwhen searching bydocNoonly). - Pick the relevant document and save its
traceId. -
When the listing goes live or is removed, call
POST /publication-notificationswith thattraceId(send it again with the sametraceIdanddocumentNowhenever the status changes, or with a freshly issuedtraceIdfrom a new document list call). - On onboarding, every platform must send a bulk publication notification for all of its currently live domestic listings, and keep them up to date afterwards (new publications and removals).
1. Document list
Returns verified ministry documents. At least one of identifyNo or
docNo is required. When both are provided, results must match both.
When searching by docNo only (without identifyNo),
supplierId is required; requests with only
docNo are rejected.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
identifyNo |
string | Conditional |
Digits only. 10 digits = tax number (VKN),
11 digits = national ID (TCKN). Leading zeros are significant.
Required if docNo is not provided.
|
docNo |
string | Conditional |
Document number (belgeNo). Required if identifyNo is not provided.
|
supplierId |
integer | Conditional |
Id of the supplier (B2B provider) from which the platform sources the listing.
Obtained from GET /options/platforms (use the value field).
Required only when searching by docNo without identifyNo.
Not needed when identifyNo is provided. Must be an approved platform id.
|
Why supplierId?
Listings supplied by B2B providers often come without a tax/national ID. In that case the platform
verifies the facility by document number alone, and supplierId records which supplier
the listing was sourced from — keeping identity-less document searches traceable.
Success response
200
{
"apiVersion": "1.0",
"identifyNo": "1234567890",
"docNo": null,
"count": 3,
"ttbisDocuments": [
{
"traceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"documentType": "ttbis",
"documentNo": "03-284",
"documentDate": "2022-01-15",
"documentStatus": "Belgeli Tesisler",
"documentOwner": "Example Owner",
"facilityName": "Example Facility",
"facilityType": "...",
"facilitySubType": "...",
"facilityClass": "...",
"documentOwnerNationalIds": ["11111111111"],
"documentOwnerTaxNos": ["1234567890"],
"city": "İstanbul",
"district": "..."
}
],
"simpleAccommodationDocuments": [
{
"traceId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"documentType": "simpleAccommodation",
"documentNo": "SA-1001",
"documentDate": "2023-05-20",
"documentOwner": "Example Owner",
"documentPersonType": "...",
"taxNo": "1234567890",
"yetkiliTcKimlikNo": "11111111111",
"basvuruKimlikNo": "...",
"isletmeKimlikNo": "...",
"title": "...",
"facilityName": "Example Facility",
"facilityType": "...",
"city": "Ankara",
"district": "..."
}
],
"dailyRentalDocuments": [
{
"traceId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"documentType": "dailyRental",
"documentNo": "DR-2002",
"documentDate": "2024-02-10",
"documentOwner": "Example Owner",
"companyTitle": "...",
"documentPersonType": "...",
"taxNo": "1234567890",
"documentOwnerNationalIds": ["11111111111"],
"city": "İzmir",
"district": "...",
"neighbourhood": "..."
}
]
}
Each document contains a traceId — store it for publication notifications.
A traceId is issued per request: every call returns a new traceId
for each document, and each one stays valid for publication notifications.
Examples
Search by identifyNo:
curl -u 'USERNAME:PASSWORD' \
'https://YOUR_HOST/document-list?identifyNo=1234567890'
Search by docNo (supplierId required):
curl -u 'USERNAME:PASSWORD' \
'https://YOUR_HOST/document-list?docNo=03-284&supplierId=12'
2. Publication notifications
Reports whether the listings of a previously verified document are published.
Send the traceId received from the document list response. A document may have
several listings, so publication state is reported as an array.
traceId must still be publishable: its document number is looked
up in the ministry documents of the trace's document type. If it is not there (revoked, expired or no
longer published by the ministry), the request is rejected with 409.
isPublished: false is recorded as usual, while
a request containing any isPublished: true listing is rejected with
409. When the ministry data holds a cancellation date or a document
status for the cancelled document, the error message repeats them.
documentNo and listingUrl must carry the opposite
isPublished value, so a listing alternates
true ↔ false. A listing that repeats the state it is
already in is skipped: no new notification is written for it and its entry in the
response carries a warning naming the date of that existing state. Its
createdAtUtc is that same date, not the time of the call.
listingUrl carrying the same state twice has its second entry skipped.
Removals sent without a listingUrl share one state per document, so two consecutive
URL-less isPublished: false notifications produce the same warning.
isPublished: false is recorded, but
its entry in the response carries a warning because no earlier publication notification
exists for it. Listings with nothing to warn about omit the field.
Headers
| Header | Value | Required |
|---|---|---|
Authorization |
Basic credentials | Yes |
Content-Type |
application/json |
Yes |
Request body
{
"traceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"documentNo": "03-284",
"listings": [
{
"listingUrl": "https://example.com/listing/123",
"isPublished": true
},
{
"listingUrl": "https://example.com/listing/456",
"isPublished": false
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
traceId |
string (UUID) | Yes | Trace id from document-list response. |
documentNo |
string | Yes | Must match the document associated with the traceId. |
listings |
array | Yes | Listings of the document. Must contain at least one item. |
listings[].isPublished |
boolean | Yes | true when the listing is live; false when removed/unpublished. |
listings[].listingUrl |
string | Conditional |
Absolute URL. Required when isPublished is true.
Optional when isPublished is false.
|
Success responses
201 Created — a notification is recorded for each listing in the request. Every call records new notifications; the latest ones for a listing reflect the current state.
{
"traceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"documentNo": "03-284",
"listings": [
{
"listingUrl": "https://example.com/listing/123",
"isPublished": true,
"createdAtUtc": "2026-07-30T12:00:00Z"
},
{
"listingUrl": "https://example.com/listing/456",
"isPublished": false,
"createdAtUtc": "2026-07-30T12:00:00Z",
"warning": "https://example.com/listing/456 is reported as isPublished false but this is its first notification; no earlier publication notification exists for it."
}
]
}
When a listing repeats the state it is already in, the request still succeeds with 201; only that entry is skipped and warned, while the others are recorded:
{
"traceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"documentNo": "03-284",
"listings": [
{
"listingUrl": "https://example.com/listing/123",
"isPublished": true,
"createdAtUtc": "2026-07-28T09:15:00Z",
"warning": "https://example.com/listing/123 is already isPublished true as of 2026-07-28T09:15:00Z; only state changes are recorded, so no new notification was written for it."
},
{
"listingUrl": "https://example.com/listing/456",
"isPublished": true,
"createdAtUtc": "2026-07-30T12:00:00Z"
}
]
}
Example
curl -u 'USERNAME:PASSWORD' \
-X POST 'https://YOUR_HOST/publication-notifications' \
-H 'Content-Type: application/json' \
-d '{
"traceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"documentNo": "03-284",
"listings": [
{ "listingUrl": "https://example.com/listing/123", "isPublished": true }
]
}'
3. Platform options
Returns approved selectable platforms as { label, value }[].
Use value as supplierId when searching by docNo without
identifyNo.
Headers
| Header | Value | Required |
|---|---|---|
Authorization |
Basic credentials | Yes |
Success response
200
[
{
"label": "Acme Supplier",
"value": "12"
}
]
Example
curl -u 'USERNAME:PASSWORD' \
'https://YOUR_HOST/options/platforms'
4. Create platform
Creates a platform by name. New platforms start with
isApproved=false. After admin approval they appear in
GET /options/platforms and can be used as supplierId.
Headers
| Header | Value | Required |
|---|---|---|
Authorization |
Basic credentials | Yes |
Content-Type |
application/json |
Yes |
Request body
{
"name": "Acme Supplier"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Platform display name (max 200 characters). Must be unique. |
Success response
201
{
"id": 12,
"name": "Acme Supplier",
"isApproved": false
}
Example
curl -u 'USERNAME:PASSWORD' \
-X POST 'https://YOUR_HOST/platforms' \
-H 'Content-Type: application/json' \
-d '{"name":"Acme Supplier"}'
5. Health check
Liveness endpoint for uptime checks and orchestrators. This is the only endpoint that does not require authentication, and it never contains facility or platform data.
It only reports that the API process is alive and serving requests. No dependency is contacted, so the result is always 200.
Response
200 GET /health
{
"status": "Healthy",
"version": "1.0",
"timestamp": "2026-01-01T00:00:00.0000000+00:00"
}
| Field | Type | Description |
|---|---|---|
status |
string | Always Healthy when the process answers |
version |
string | API version serving the request |
timestamp |
string | UTC time the response was produced (ISO 8601) |
/health. A dependency outage must not restart the process, so
/health deliberately stays 200 in that case.
Example
curl 'https://YOUR_HOST/health'
Rate limiting
Your platform may be given a request quota. The quota is counted per endpoint and is shared across all API instances, so it does not matter which server answers your call.
The window opens on your first request to that endpoint and lasts 15 minutes. It is never extended by further requests: if you open the window at 10:14 it resets at 10:29, even if you spend the whole quota at 10:25.
| Header | When | Meaning |
|---|---|---|
X-RateLimit-Limit |
every rate-limited response | Requests allowed per window |
X-RateLimit-Remaining |
every rate-limited response | Requests left in the current window |
X-RateLimit-Reset |
every rate-limited response | Unix timestamp (seconds, UTC) at which the window resets |
Retry-After |
429 only | Seconds to wait before retrying |
Once the quota is spent the API answers 429 with the standard error body.
Read X-RateLimit-Remaining to pace yourself instead of waiting for the rejection.
X-RateLimit-* headers.
GET /health is never rate limited.
Example
HTTP/1.1 429 Too Many Requests
Retry-After: 240
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1755437340
{
"error": "Rate limit exceeded. Retry after 240 seconds."
}
Error responses
All error responses use this JSON structure:
{
"error": "Human-readable error message"
}
| Status | When |
|---|---|
| 400 |
Invalid or missing query/body parameters (wrong types, identifyNo length or non-digit characters,
docNo without supplierId, invalid supplierId,
publication body validation)
|
| 401 | Missing or invalid Basic Authentication credentials, or platform not approved / credentials not yet delivered |
| 404 | traceId not found (POST /publication-notifications) |
| 409 |
Platform name already exists (POST /platforms), or the document behind the
traceId is missing from the ministry documents, or it is cancelled and the request
publishes a listing (POST /publication-notifications)
|
| 429 |
The platform spent its request quota for the current window; retry after the number of seconds in
Retry-After (see Rate limiting)
|
| 500 | Unexpected server-side error |
| 504 | The request exceeded the server request timeout |
Example errors
{
"error": "supplierId is required when searching by docNo without identifyNo"
}
{
"error": "identifyNo must be between 10 and 11 characters long"
}
{
"error": "identifyNo must contain digits only"
}
{
"error": "traceId must be a valid UUID"
}
{
"error": "listings[1].listingUrl is required when isPublished is true."
}
{
"error": "documentNo '03-284' is not publishable; it is not present in the verified 'ttbis' documents."
}
{
"error": "documentNo '03-284' is cancelled in the verified 'ttbis' documents and can no longer be published. Cancellation date: 2024-11-03 00:00:00+00. Only listings with isPublished false are accepted for it."
}
{
"error": "The request timed out."
}