Users with Khmer and English names, posts, comments, todos and quotes for social and list screens.
Need a feed, a profile page or a to-do list to practise with? This API has 30 users, many with Khmer names in both scripts (fullNameKm) and Cambodian addresses, plus 100 posts (some written in Khmer), 300 comments, 150 todos and quotes including traditional Khmer proverbs.
Relations work like a real backend: /users/1/posts, /posts/5/comments, /users/3/todos. Every list supports search, filters, sorting, field selection and pagination. Nothing is saved: the response shows what a real API would return, and the data stays the same for everyone.
const res = await fetch('https://toolorca.com/api/v1/users?country=KH&limit=3&select=fullName,fullNameKm,avatar');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/users?country=KH&limit=3&select=fullName,fullNameKm,avatar'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/users?country=KH&limit=3&select=fullName,fullNameKm,avatar")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/users?country=KH&limit=3&select=fullName,fullNameKm,avatar")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /users?country=KH&limit=3&select=fullName,fullNameKm,avatar
const res = await fetch('https://toolorca.com/api/v1/users/1');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/users/1'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/users/1")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/users/1")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
const res = await fetch('https://toolorca.com/api/v1/users/2/posts?limit=2');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/users/2/posts?limit=2'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/users/2/posts?limit=2")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/users/2/posts?limit=2")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /users/2/posts?limit=2
Example response
{
"data": [
{
"id":30,
"userId":2,
"title":"ពិធីបុណ្យអុំទូកនៅភ្នំពេញ",
"body":"ថ្ងៃនេះខ្ញុំចង់ចែករំលែកបទពិសោធន៍ខ្លះៗជាមួយអ្នកទាំងអស់គ្នា។ មនុស្សរាប់ពាន់នាក់មកមើលការប្រណាំងទូកនៅមាត់ទន្លេ។ ខ្ញុំសង្ឃឹមថាអត្ថបទនេះមានប្រយោជន៍សម្រាប់អ្នក។",
"lang":"km",
"tags": [
"cambodia",
"festival"
],
"reactions": {
"likes":1444,
"dislikes":6
},
"views":3715,
"createdAt":"2025-11-28T08:10:58Z"
},
{
"id":67,
"userId":2,
"title":"Pagination done right (part 6)",
"body":"Never load thousands of rows at once. Show a loading indicator at the end of the list. Tell the user when there is nothing more to load.",
"lang":"en",
"tags": [
"api",
"programming"
],
"reactions": {
"likes":655,
"dislikes":40
},
"views":4011,
"createdAt":"2025-11-22T17:50:14Z"
}
],
"meta": {
"total":4,
"limit":2,
"skip":0,
"page":1,
"pages":2
}
}
const res = await fetch('https://toolorca.com/api/v1/posts?lang=km&limit=2');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/posts?lang=km&limit=2'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/posts?lang=km&limit=2")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/posts?lang=km&limit=2")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
const res = await fetch('https://toolorca.com/api/v1/posts/1');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/posts/1'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/posts/1")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/posts/1")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /posts/1
Example response
{
"id":1,
"userId":19,
"title":"Getting started with REST APIs",
"body":"Start with GET requests, then try POST and PUT. A REST API lets your app read and change data over HTTP. Fake APIs are perfect for building screens before the real backend is ready.",
"lang":"en",
"tags": [
"api",
"programming"
],
"reactions": {
"likes":178,
"dislikes":42
},
"views":6500,
"createdAt":"2025-12-20T01:46:16Z"
}
const res = await fetch('https://toolorca.com/api/v1/posts/1/comments');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/posts/1/comments'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/posts/1/comments")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/posts/1/comments")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /posts/1/comments
Example response
{
"data": [
{
"id":1,
"postId":1,
"userId":26,
"body":"Thanks, this saved me hours.",
"likes":18,
"createdAt":"2025-12-20T10:46:16Z"
},
{
"id":101,
"postId":1,
"userId":22,
"body":"Bookmarked for later.",
"likes":119,
"createdAt":"2025-12-21T03:46:16Z"
},
{
"id":201,
"postId":1,
"userId":21,
"body":"Great post, thanks for sharing!",
"likes":106,
"createdAt":"2025-12-21T03:46:16Z"
}
],
"meta": {
"total":3,
"limit":30,
"skip":0,
"page":1,
"pages":1
}
}
Create a post. Returns 201 with id 101. Nothing is saved: the response shows what a real API would return, and the data stays the same for everyone.
Parameter
In
Type
Description
title required
body
string
Post title.
body required
body
string
Post text.
userId required
body
integer
Author.
curl -X POST 'https://toolorca.com/api/v1/posts' \
-H 'Content-Type: application/json' \
-d '{"title":"សួស្តី Flutter!","body":"My first post from my app.","userId":1}'
const res = await fetch('https://toolorca.com/api/v1/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"title": "សួស្តី Flutter!",
"body": "My first post from my app.",
"userId": 1
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.post(
Uri.parse('https://toolorca.com/api/v1/posts'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'title': 'សួស្តី Flutter!',
'body': 'My first post from my app.',
'userId': 1,
}),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val json = """
{
"title": "សួស្តី Flutter!",
"body": "My first post from my app.",
"userId": 1
}
""".trimIndent()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/posts")
.post(json.toRequestBody("application/json".toMediaType()))
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/posts")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{
\"title\": \"សួស្តី Flutter!\",
\"body\": \"My first post from my app.\",
\"userId\": 1
}
""".data(using: .utf8)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
POST /posts
Example response (201)
{
"id":101,
"title":"សួស្តី Flutter!",
"body":"My first post from my app.",
"userId":1,
"createdAt":"2026-11-14T05:15:25Z"
}
const res = await fetch('https://toolorca.com/api/v1/todos?userId=1&limit=3');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/todos?userId=1&limit=3'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/todos?userId=1&limit=3")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/todos?userId=1&limit=3")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
Tick a todo off (or change any field). PUT, POST and DELETE work too. Nothing is saved: the response shows what a real API would return, and the data stays the same for everyone.
const res = await fetch('https://toolorca.com/api/v1/todos/1', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"completed": true
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.patch(
Uri.parse('https://toolorca.com/api/v1/todos/1'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'completed': true,
}),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val json = """
{
"completed": true
}
""".trimIndent()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/todos/1")
.patch(json.toRequestBody("application/json".toMediaType()))
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
const res = await fetch('https://toolorca.com/api/v1/quotes?category=khmer-proverb&limit=2');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/quotes?category=khmer-proverb&limit=2'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/quotes?category=khmer-proverb&limit=2")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/quotes?category=khmer-proverb&limit=2")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /quotes?category=khmer-proverb&limit=2
Example response
{
"data": [
{
"id":21,
"quote":"ចេះមកពីរៀន មានមកពីរក",
"translation":"Knowledge comes from learning; wealth comes from working for it.",
"author":"Khmer proverb",
"category":"khmer-proverb",
"lang":"km"
},
{
"id":22,
"quote":"ទឹកឡើងត្រីស៊ីស្រមោច ទឹកស្រកស្រមោចស៊ីត្រី",
"translation":"When the water rises, fish eat ants; when it falls, ants eat fish. Fortunes change, so treat others well.",
"author":"Khmer proverb",
"category":"khmer-proverb",
"lang":"km"
}
],
"meta": {
"total":5,
"limit":2,
"skip":0,
"page":1,
"pages":3
}
}
One random quote (a new one on every call). Accepts category and lang.
Parameter
In
Type
Description
category
query
string
Optional category.
lang
query
string
Optional language.
curl 'https://toolorca.com/api/v1/quotes/random'
const res = await fetch('https://toolorca.com/api/v1/quotes/random');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/quotes/random'),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/quotes/random")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/quotes/random")!)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
GET /quotes/random
Example response
{
"id":25,
"quote":"ឃើញដំរីជុះ កុំជុះតាមដំរី",
"translation":"When you see the elephant relieve itself, do not try to copy it: do not imitate those far bigger than you.",
"author":"Khmer proverb",
"category":"khmer-proverb",
"lang":"km"
}
The data at a glance
users (30): name in English and, for Cambodian users, Khmer (family name first, as in Cambodia: ចាន់ សុខា); username, email at example.com, phone, gender, birth date, role, PNG avatar with initials, address with coordinates and company. Every user can log in through the Fake Auth API.
posts (100, every fifth one in Khmer) with tags, reactions and views; comments (300, three per post); todos (150, five per user) with priority and due date; quotes (25).
Frequently asked questions
Is this a JSONPlaceholder alternative?
Yes. The routes look familiar (/users, /posts, /comments, /todos), with richer fields, Khmer content and a consistent { data, meta } list format.
Are the people real?
No. Names, emails (example.com), phone numbers, addresses and companies are invented.
Does the data change?
No. Every request returns the same data, and write requests are not saved, so everyone sees the same results.
Can I show Khmer text from the API?
Yes. All responses are UTF-8 JSON. Make sure your app uses a font with Khmer glyphs (most phones have one).