Quick start
No sign-up or API key needed.
Every endpoint is a plain GET request that returns JSON. Fetch the 20 newest Geylang listings:
curl "https://nanrentiantang10.net/api/v1/girls?area=geylang&limit=20"
const res = await fetch('https://nanrentiantang10.net/api/v1/girls?area=geylang&limit=20');
const { data, meta } = await res.json();
for (const girl of data) {
console.log(girl.id, girl.name, girl.price, girl.url);
}
console.log(`${meta.total} matching profiles`);
import requests
r = requests.get("https://nanrentiantang10.net/api/v1/girls",
params={"area": "geylang", "limit": 20}, timeout=15)
r.raise_for_status()
for girl in r.json()["data"]:
print(girl["id"], girl["name"], girl["price"], girl["url"])
$json = file_get_contents('https://nanrentiantang10.net/api/v1/girls?area=geylang&limit=20');
$body = json_decode($json, true);
foreach ($body['data'] as $girl) {
echo $girl['id'] . ' ' . $girl['name'] . ' ' . $girl['price'] . PHP_EOL;
}
Browse by area
?area=geylang
Central51
?area=central
East20
?area=east
West14
?area=west
North7
?area=north
Massage36
?massage=true
Each card links to the area page on the site. Use the same filters in the API, as shown on each card.
API index · Endpoints
All paths are relative to https://nanrentiantang10.net/api/v1.
| Endpoint | What it returns | Use it for |
|---|---|---|
GET/ | API index: version, total count, current dataVersion, links to every endpoint. | Health check, discovering endpoints. |
GET/girls | Paginated, filterable list of profiles. See parameters. | Listing pages, search, area pages. |
GET/girls/{id} | One profile. 404 means it is no longer listed. | Profile detail pages. |
GET/export | Every active profile in one response (~335 KB before gzip). | Mirroring the whole database into your own cache. |
GET/sync | Tiny manifest: dataVersion plus { id, hash, updatedAt } for every profile. hash changes whenever anything in that profile changes. | Detecting new, changed and removed profiles cheaply. |
GET/areas | Areas (Geylang, Central, East, West, North, Massage) with live counts. | Navigation menus. |
GET/openapi.json | OpenAPI 3 description of this API. | Code generators, Postman, Swagger UI. |
List response shape
{
"data": [ { ...profile }, ... ],
"meta": {
"total": 42, "page": 1, "limit": 20, "pages": 3,
"dataVersion": "a3d43ec827000957",
"lastModified": "2026-10-19T09:11:53.820Z"
},
"links": { "self": "...", "next": "...?page=2", "prev": null },
"attribution": { "text": "Data from nanrentiantang ...", "url": "https://nanrentiantang10.net/", ... }
}
Query parameters for /girls
Combine any of them.
| Parameter | Example | Description |
|---|---|---|
area | geylang | geylang, central, east, west or north (Chinese area names also work). |
massage | true | Only massage listings. |
verified | true | Only listings with the verified badge. |
caution | false | caution marks listings our admins flagged as unverified. Use caution=false to hide them. |
featured | true | Only featured listings. |
has_video | true | Only listings with at least one video. |
q | thai bedok | Keyword search across name, title, location, price, services and ID. Space-separated words must all match. |
ids | 1872,1862 | Fetch specific profiles (up to 100). Ideal after a /sync diff. |
updated_since | 2026-10-01 | Only profiles whose updatedAt is after this ISO date or Unix-millisecond timestamp. Good for “new listings”; to detect every edit, use the hash in /sync. |
sort | newest | newest (default, by updatedAt), oldest, or id (highest ID first). |
page | 2 | Page number, starting at 1. |
limit | 50 | Results per page, 1–100. Default 20. |
fields | name,price,cover,url | Return only these fields (id is always included). Smaller, faster responses for list views. |
Example: verified Thai girls in the East with video, lightweight card fields only:
https://nanrentiantang10.net/api/v1/girls?area=east&verified=true&has_video=true&q=thai&fields=name,price,cover,area,url
Profile object
Fields returned for each profile.
| Field | Type | Description |
|---|---|---|
id | string | Stable profile ID, same as on the site (/escort/{id}). |
name, title | string | Display name and bilingual headline. |
url | string | Canonical profile page on nanrentiantang. Link to it when you show the profile. |
area | object | { slug, zh, label }: URL slug (e.g. east), Chinese area name, and display label (e.g. East Area). |
location, geo | string, object|null | Neighbourhood text (e.g. Bedok) and approximate { lat, lng }. |
age, height, weight, cup | string | As written by the listing, e.g. 28 Years Old, 163cm. |
price, prices | string, string[] | Main price line and all price lines. |
services | string[] | Service list, bilingual. |
specialService, room, overnight | string | Free text (HTML already stripped, line breaks as \n). |
contact | object | { phone, whatsapp, telegram, wechat, callEnabled, smsEnabled }. whatsapp is in international format without + (ready for https://wa.me/{whatsapp}); phone is the local Singapore number. Values may be null. |
verified, caution, featured, massage, hasVideo | boolean | Status flags (see parameters). |
cover, images | object, object[] | { url, thumbnail }. Use thumbnail for grids and url for full size. |
videos | string[] | MP4 URLs. |
commentCount | number | Number of user reviews on the profile page. |
postedDate, updatedAt | string|null | YYYY-MM-DD listing date and ISO 8601 last-update time. |
Live example
{
"id": "1937",
"name": "JingJing-晶晶",
"title": "迷人的容颜,温柔的双手,带来极致放松和难忘体验 A Charming Face, Gentle Hands, Bringing Ultimate Relaxation and Unforgettable Experience",
"url": "https://nanrentiantang10.net/escort/1937",
"area": {
"slug": "east",
"zh": "东部",
"label": "East Area 东部地区"
},
"location": "Joo Chiat Road 如切路",
"geo": {
"lat": 1.3074844,
"lng": 103.9039877
},
"age": "28 Years Old",
"height": "160cm",
"weight": "48KG",
"cup": "38C",
"price": "$160/60mins/1 Shot FJ",
"prices": [
"$160/60mins/1 Shot FJ"
],
"services": [
"Shower together/鸳鸯浴",
"Simple massage/简单按摩",
"Bath oral sex",
"Deep throat/深喉",
"Nipples/舔奶头",
"Painting/舔鲍鱼(这个服务很多人喜欢)",
"Roam/漫游",
"COB/射身",
"Grasp root/抓根",
"Chest push/胸推",
"CIM/无套口爆(这个服务很多人喜欢)",
"Kiss/接吻",
"Frenching/舌吻(这个服务很多人喜欢)",
"69Type/69式",
"BBBJ/无套口交",
"CBJ/有套口交",
"FJ/有套做爱"
],
"specialService": "",
"room": "Room&CD Included 包房包套",
"overnight": "详情请咨询",
"contact": {
"phone": "86709163",
"whatsapp": "6586709163",
"telegram": null,
"wechat": null,
"callEnabled": true,
"smsEnabled": true
},
"verified": false,
"caution": false,
"featured": true,
"massage": false,
"hasVideo": true,
"cover": {
"url": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-508879295-optimized.jpg",
"thumbnail": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-508879295-optimized.webp"
},
"images": [
{
"url": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-508879295-optimized.jpg",
"thumbnail": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-508879295-optimized.webp"
},
{
"url": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-63130150-optimized.jpg",
"thumbnail": "https://nanrentiantang.cdncdncdnglodbal.com/1937-1792401115772-63130150-optimized.webp"
}
],
"videos": [
"https://nanrentiantang.cdncdncdnglodbal.com/1937-1792402943507-260389179.mp4?t=1792406826774"
],
"commentCount": 0,
"postedDate": "2026-10-19",
"updatedAt": "2026-10-19T09:11:53.820Z"
}
Images and videos trimmed for this page. The API returns all of them. Text fields are returned exactly as listed, so some may be bilingual.
Caching & sync
Recommended setup.
The database changes a few times a day, not every second. Keep your own copy and refresh it in the background. Your site gets faster, and you stay far below the rate limit.
Mirror once
Download
/exportand store it (memory, Redis, a JSON file or your database).Poll cheaply
Every 15–30 minutes, request
/export(or/sync) with theIf-None-Matchheader set to the lastETag. If nothing changed you get304 Not Modifiedwith an empty body.Apply changes
On
200, replace your copy. With/sync, compare each ID’shashwith the one you stored, fetch only the changed ones via/girls?ids=…, and delete IDs that disappeared.Serve from your cache
Serve your visitors from your own copy, never by calling our API on every page view.
Every data response includes ETag, X-Data-Version and Cache-Control: public, max-age=300 headers.
// Server-side cache that refreshes itself every 15 minutes
const BASE = 'https://nanrentiantang10.net/api/v1';
let cache = { etag: null, girls: [], byId: new Map() };
async function refresh() {
try {
const res = await fetch(`${BASE}/export`, {
headers: cache.etag ? { 'If-None-Match': cache.etag } : {}
});
if (res.status === 304) return; // unchanged — keep cache
if (!res.ok) return; // 429 / 5xx — keep serving old data
const body = await res.json();
cache = {
etag: res.headers.get('ETag'),
girls: body.data,
byId: new Map(body.data.map(g => [g.id, g]))
};
} catch (err) {
console.error('nanrentiantang sync failed', err);
}
}
await refresh();
setInterval(refresh, 15 * 60 * 1000);
// In your routes: cache.girls, cache.byId.get('1872') ...
import requests
BASE = "https://nanrentiantang10.net/api/v1"
cache = {"etag": None, "girls": {}}
def refresh():
headers = {"If-None-Match": cache["etag"]} if cache["etag"] else {}
r = requests.get(f"{BASE}/export", headers=headers, timeout=20)
if r.status_code == 304:
return # nothing changed
if r.status_code != 200:
return # rate limited or server error: keep the old copy
cache["etag"] = r.headers.get("ETag")
cache["girls"] = {g["id"]: g for g in r.json()["data"]}
# run refresh() from a scheduler (cron, APScheduler...) every 15-30 minutes
Rate limits & errors
Fair use is up to 60 requests per minute per IP; our edge network may apply stricter limits to abusive traffic.
Responses include RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers.
Need a higher limit? Contact us for a business quota.
| Status | Meaning | What to do |
|---|---|---|
| 200 | OK | Store the body and its ETag. |
| 304 | Not modified | Keep using your cached copy. |
| 400 | Invalid parameter | Read error.message; fix the query. |
| 404 | Profile not listed / unknown endpoint | Remove the profile from your cache. |
| 429 | Too many requests | Wait Retry-After seconds and serve from your cache meanwhile. |
| 5xx | Temporary server problem | Retry later with backoff; keep serving cached data. |
{
"error": {
"status": 400,
"code": "invalid_parameter",
"message": "\"area\" must be one of: geylang, central, east, west, north.",
"docs": "https://nanrentiantang10.net/singapore-escort-api"
}
}
Try it
Send a real request from your browser.
Terms of use & attribution
- Free and read-only. No key or sign-up. We may change limits or block clients that abuse the service.
- Attribution required. Wherever you display our data, show “Data from nanrentiantang” and link each profile to its
url. - Don’t alter listings. Show prices, services and contact details as provided. Don’t present the listings as your own original content.
- Keep it fresh. Sync at least once a day and remove profiles within 24 hours after they disappear from
/syncor return404. - Media. You may display images and videos by their URLs. Please don’t bulk re-host or watermark them as your own.
- Adults only. Content is for viewers aged 18+. You are responsible for complying with the laws that apply to your site and audience.
- No warranty. Data is provided as-is. Version
v1stays backwards-compatible; breaking changes will ship as/api/v2.
<p>Data from <a href="https://nanrentiantang10.net/">nanrentiantang</a></p>
Business & custom API
Higher limits, custom endpoints and partner data.
The free API covers most websites and bots. If you run a larger site or need data the public API does not include, contact the nanrentiantang admin team. We can set up:
Higher rate limits
A dedicated quota above 60 requests/minute for high-traffic sites and apps.
Custom APIs
Extra filters, your own data format, push updates or endpoints built for your product.
Watermark-free images
Original photos without the nanrentiantang watermark for licensed partners.
Comments & reviews
User reviews and their photo / video attachments included in the API.
Talk to the admin team
Tell us your website or app, expected traffic and what you need.
FAQ
Is there a Singapore escort API I can use for free?
Yes. nanrentiantang provides a free, read-only JSON API at https://nanrentiantang10.net/api/v1. No API key or sign-up is needed. Please cache responses and link back to each profile URL.
How do I download the whole Singapore escort database?
Call https://nanrentiantang10.net/api/v1/export. It returns every active profile in one JSON response. Re-request it with the If-None-Match header and you get a 304 Not Modified when nothing changed.
How often is the data updated?
New listings are added daily. Our servers refresh their copy every few hours, so polling the /sync endpoint every 15 to 30 minutes is enough to stay current.
What are the rate limits?
Up to 60 requests per minute per IP address. Requests over the limit get HTTP 429 with a Retry-After header. Cached and 304 responses are the best way to stay well under the limit.
Can I get higher rate limits, watermark-free images or comments in the API?
Yes. Business users can ask for higher rate limits, custom endpoints, original images without watermark, and user comments / reviews in the API. Email [email protected] or message @mai_quyenn on Telegram.
Can I call the API from the browser?
Yes, CORS is open (Access-Control-Allow-Origin: *). For a production website we recommend fetching on your server and caching the result, so your visitors do not each hit the API.