REST API Reference
Complete reference for the Phony Cloud REST API.
Base URL
https://api.phony.cloud/v1Authentication
All API requests require authentication via Bearer token:
curl -H "Authorization: Bearer $PHONY_API_TOKEN" \
https://api.phony.cloud/v1/modelsGet your API token from the Dashboard → Settings → API Keys.
API Versioning
The API uses URL-based versioning:
| Version | Status | End of Life |
|---|---|---|
v1 | Current | - |
Breaking changes result in a new version. Non-breaking changes (new fields, endpoints) are added to the current version.
Rate Limits
| Plan | Requests/minute | Burst |
|---|---|---|
| Free | 60 | 10 |
| Starter | 300 | 50 |
| Team | 1,000 | 100 |
| Business | 5,000 | 500 |
Rate limit headers are included in every response:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1706745600Common Response Formats
Success Response
{
"data": { ... },
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-31T10:00:00Z"
}
}Error Response
{
"error": {
"code": "validation_error",
"message": "Invalid input",
"details": [
{ "field": "count", "message": "must be positive integer" }
]
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-31T10:00:00Z"
}
}Error Codes
| Code | HTTP Status | Description |
|---|---|---|
unauthorized | 401 | Invalid or missing API token |
forbidden | 403 | Insufficient permissions |
not_found | 404 | Resource not found |
validation_error | 422 | Invalid request parameters |
rate_limit_exceeded | 429 | Too many requests |
internal_error | 500 | Server error |
Endpoints
Generation
POST /generate
Generate synthetic data from a schema.
Request:
{
"schema": {
"generators": {
"first_name": {
"type": "model",
"source": "tr_TR/first_names",
"generation": { "mode": "word" }
},
"last_name": {
"type": "model",
"source": "tr_TR/last_names",
"generation": { "mode": "word" }
},
"email": {
"type": "template",
"pattern": "{{lowercase(first_name)}}.{{lowercase(last_name)}}@example.com"
}
},
"output": ["first_name", "last_name", "email"]
},
"count": 100,
"seed": 12345,
"format": "json"
}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
schema | object | Yes | PDL schema definition |
count | integer | Yes | Number of records (1-100,000) |
seed | integer | No | Random seed for determinism |
format | string | No | Output format: json, csv, ndjson |
Response:
{
"data": {
"records": [
{
"first_name": "Mehmet",
"last_name": "Yılmaz",
"email": "mehmet.yilmaz@example.com"
},
{
"first_name": "Ayşe",
"last_name": "Kaya",
"email": "ayse.kaya@example.com"
}
],
"count": 100,
"seed": 12345
},
"meta": {
"request_id": "req_abc123",
"generation_time_ms": 45
}
}Example:
curl -X POST https://api.phony.cloud/v1/generate \
-H "Authorization: Bearer $PHONY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"schema": {
"generators": {
"name": {
"type": "model",
"source": "tr_TR/first_names",
"generation": { "mode": "word" }
}
},
"output": ["name"]
},
"count": 10
}'Models
GET /models
List available models.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
locale | string | Filter by locale (e.g., tr_TR) |
type | string | Filter by type: builtin, custom, all |
page | integer | Page number (default: 1) |
per_page | integer | Items per page (default: 20, max: 100) |
Response:
{
"data": {
"models": [
{
"id": "tr_TR/first_names",
"name": "Turkish First Names",
"locale": "tr_TR",
"type": "builtin",
"ngram_order": 3,
"token_type": "char",
"created_at": "2026-01-01T00:00:00Z"
},
{
"id": "custom/company_names",
"name": "Custom Company Names",
"locale": "tr_TR",
"type": "custom",
"ngram_order": 3,
"token_type": "char",
"created_at": "2026-01-15T10:30:00Z"
}
],
"total": 45,
"page": 1,
"per_page": 20
}
}GET /models/:id
Get model details.
Response:
{
"data": {
"id": "tr_TR/first_names",
"name": "Turkish First Names",
"locale": "tr_TR",
"type": "builtin",
"ngram_order": 3,
"token_type": "char",
"token_count": 29,
"ngram_count": 1245,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}
}POST /models
Upload a custom model.
Request (multipart/form-data):
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | .phony model file |
name | string | Yes | Model name |
description | string | No | Model description |
Response:
{
"data": {
"id": "custom/my-model",
"name": "My Custom Model",
"locale": "tr_TR",
"type": "custom",
"ngram_order": 3,
"created_at": "2026-01-31T10:00:00Z"
}
}DELETE /models/:id
Delete a custom model.
Response:
{
"data": {
"deleted": true,
"id": "custom/my-model"
}
}Sync Jobs
GET /sync/jobs
List sync jobs.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: pending, running, completed, failed |
page | integer | Page number |
per_page | integer | Items per page |
Response:
{
"data": {
"jobs": [
{
"id": "job_abc123",
"name": "production-to-staging",
"status": "completed",
"source": "postgresql://prod.example.com/app",
"target": "postgresql://staging.example.com/app",
"tables": ["users", "orders", "products"],
"rows_processed": 150000,
"started_at": "2026-01-31T09:00:00Z",
"completed_at": "2026-01-31T09:05:32Z"
}
]
}
}POST /sync/jobs
Create and run a sync job.
Request:
{
"name": "production-to-staging",
"source": {
"type": "postgresql",
"connection_string": "postgresql://user:pass@prod.example.com/app"
},
"target": {
"type": "postgresql",
"connection_string": "postgresql://user:pass@staging.example.com/app"
},
"tables": [
{
"name": "users",
"columns": {
"first_name": { "generator": "tr_TR/first_names" },
"last_name": { "generator": "tr_TR/last_names" },
"email": { "generator": "template", "pattern": "{{uuid}}@example.com" },
"created_at": { "preserve": true }
}
}
]
}GET /sync/jobs/:id
Get sync job details.
DELETE /sync/jobs/:id
Cancel or delete a sync job.
Snapshots
GET /snapshots
List snapshots.
Response:
{
"data": {
"snapshots": [
{
"id": "snap_abc123",
"name": "pre-migration",
"database": "staging",
"size_bytes": 1073741824,
"tables": ["users", "orders", "products"],
"created_at": "2026-01-30T15:00:00Z",
"expires_at": "2026-02-28T15:00:00Z"
}
]
}
}POST /snapshots
Create a snapshot.
Request:
{
"name": "pre-migration",
"database": "staging",
"tables": ["users", "orders", "products"],
"expires_in_days": 30
}POST /snapshots/:id/restore
Restore from a snapshot.
Request:
{
"target_database": "staging",
"overwrite": true
}DELETE /snapshots/:id
Delete a snapshot.
Mock API
GET /mock/endpoints
List mock API endpoints.
Response:
{
"data": {
"endpoints": [
{
"id": "ep_abc123",
"path": "/api/users",
"method": "GET",
"schema": "users.pdl.json",
"url": "https://mock.phony.cloud/ep_abc123/api/users",
"requests_today": 1523,
"created_at": "2026-01-15T10:00:00Z"
}
]
}
}POST /mock/endpoints
Create a mock endpoint.
Request:
{
"path": "/api/users",
"method": "GET",
"schema": {
"generators": {
"id": { "type": "logic", "algorithm": "uuid_v7" },
"name": { "type": "model", "source": "tr_TR/full_names", "generation": { "mode": "word" } },
"email": { "type": "template", "pattern": "{{lowercase(name)}}@example.com" }
},
"output": ["id", "name", "email"]
},
"response": {
"count": 10,
"wrapper": { "data": "{{records}}", "total": "{{count}}" }
}
}DELETE /mock/endpoints/:id
Delete a mock endpoint.
Organizations
GET /org
Get current organization.
Response:
{
"data": {
"id": "org_abc123",
"name": "Acme Corp",
"plan": "team",
"members": 5,
"usage": {
"sync_jobs": { "used": 8, "limit": 15 },
"endpoints": { "used": 45, "limit": 150 },
"snapshots": { "used": 12, "limit": 50 },
"api_calls": { "used": 8500, "limit": 100000 }
},
"billing_cycle_end": "2026-02-15T00:00:00Z"
}
}GET /org/members
List organization members.
POST /org/members
Invite a member.
DELETE /org/members/:id
Remove a member.
SDKs
Official SDKs are available for common languages:
| Language | Package | Installation |
|---|---|---|
| PHP | phonycloud/phony-cloud | composer require phonycloud/phony-cloud |
| Python | phony-cloud | pip install phony-cloud |
| JavaScript/TypeScript | @phony/cloud | npm install @phony/cloud |
| Go | github.com/phonycloud/phony-go | go get github.com/phonycloud/phony-go |
PHP SDK Example
use Phonyland\Cloud\PhonyCloud;
$client = new PhonyCloud(getenv('PHONY_API_TOKEN'));
// Generate data
$result = $client->generate([
'schema' => [
'generators' => [
'name' => ['type' => 'model', 'source' => 'tr_TR/first_names', 'generation' => ['mode' => 'word']]
],
'output' => ['name']
],
'count' => 100
]);
foreach ($result->records as $record) {
echo $record->name . "\n";
}Python SDK Example
from phony_cloud import PhonyCloud
import os
client = PhonyCloud(os.environ['PHONY_API_TOKEN'])
# Generate data
result = client.generate(
schema={
'generators': {
'name': {'type': 'model', 'source': 'tr_TR/first_names', 'generation': {'mode': 'word'}}
},
'output': ['name']
},
count=100
)
for record in result.records:
print(record['name'])Webhooks
Configure webhooks in Dashboard → Settings → Webhooks.
Events
| Event | Description |
|---|---|
sync.started | Sync job started |
sync.completed | Sync job completed |
sync.failed | Sync job failed |
snapshot.created | Snapshot created |
snapshot.restored | Snapshot restored |
Payload
{
"event": "sync.completed",
"timestamp": "2026-01-31T10:00:00Z",
"data": {
"job_id": "job_abc123",
"name": "production-to-staging",
"rows_processed": 150000,
"duration_seconds": 332
}
}Signature Verification
Verify webhook authenticity using the X-Phony-Signature header:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PHONY_SIGNATURE'];
$expected = hash_hmac('sha256', $payload, $webhookSecret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}