Mock data API · 29 types · 4 locales

Ship the screen before the API exists

Describe your data as a JSON layout and get realistic records back — nested, conditional, relational, reproducible by seed, in English, Korean, Japanese, or Chinese.

No credit card 1,000 requests / mo free Try it below — no account
count
locale
seed
layout.json editable
response.json
example response
[
  {
    "id": "b3f1c8a2-4d19-4c30-9f2a-5b8e7d441ce0",
    "name": "Marion Whitfield",
    "email": "[email protected]",
    "age": 34,
    "plan": "pro",
    "signed_up": "2026-03-14",
    "address": { "city": "Rotterdam", "zipcode": "30012" }
  },
  {
    "id": "7c04ae51-8b62-4f19-9d03-2ea6c1f80b95",
    "name": "Priya Raman",
    "email": "[email protected]",
    "age": 41,
    "plan": "free",
    "signed_up": "2026-05-02",
    "address": { "city": "Leeds", "zipcode": "51884" }
  }
]

GET /v1/layouts/user-profile?count=2&seed=42&locale=en

anonymous demo · 20 requests per minute

How it works

Three steps to a dataset

1 Describe the shape

Write a layout in JSON — or import sample JSON, a JSON Schema, an OpenAPI component, or SQL DDL.

layout.json
{
  "id":    { "type": "uuid" },
  "name":  { "type": "name" },
  "email": { "type": "email" }
}
2 Call the API

One GET, any count. Pass a seed and the response is deterministic.

terminal
curl -H "X-API-Key: $KEY" \
  "$API/v1/layouts/user-profile\
?count=100&seed=42"
3 Wire it in

Point fixtures, Storybook mocks, or seed scripts at the endpoint — or freeze a snapshot.

response.json
[
  {
    "id": "b3f1c8a2-4d19-…",
    "name": "Marion Whitfield",
    "plan": "pro"
  }
]

Type catalog

29 field types, one line each

Hover a type to see a sample value. Every one of them works in the demo above.

Basic

integer
decimal
boolean
string
enum

Date & time

date
datetime
time

Identifiers

uuid
sequence
slug

Media

image_url
color

Personal data

name
phone
address
city
zipcode
street

Text

word
sentence
paragraph
description
product_name

Finance

currency
price

Nested

object
array

Beyond random

Mock data that behaves like production data

Random strings are easy. Shipping screens needs structure, conditionals, and data that stays put between test runs.

Nested structure & conditional fields

Objects in objects, arrays of objects, as deep as your real payloads go. A field can depend on a sibling — a trial_ends_at that only exists when plan is "trial".

layout.json
{
  "plan": {
    "type": "enum",
    "options": { "values": ["free", "trial", "pro"] }
  },
  "trial_ends_at": {
    "type": "date",
    "condition": { "field": "plan", "equals": "trial" }
  },
  "billing": {
    "type": "object",
    "properties": {
      "card_last4": {
        "type": "string",
        "options": { "length": 4, "charset": "numeric" }
      }
    }
  }
}

Same seed → same data.

Two identical requests, run a week apart, byte-for-byte equal. A failing test stays failing until you fix it — not until the data shifts. Growing a locale's data pool is the one thing that moves the result; a snapshot pins a set for good.

run #1 · mon 09:14 · seed=42
[
  {
    "id": "b3f1c8a2-4d19-…",
    "name": "Marion Whitfield",
    "age": 34,
    "plan": "pro"
  }
]
≡ identical
run #2 · fri 17:52 · seed=42
[
  {
    "id": "b3f1c8a2-4d19-…",
    "name": "Marion Whitfield",
    "age": 34,
    "plan": "pro"
  }
]
terminal
GET /v1/bundles/store-fixtures?seed=42

{
  "users":      [ /*  50 records */ ],
  "orders":     [ /* 200 records */ ],
  "line_items": [ /* 600 records */ ]
}

Relational data that resolves

Group the layouts that belong together into a bundle — users, orders, line items — and generate the whole set in one request, each with its own record count. Every layout in the bundle shares a single seed, so the set reproduces as a unit, not layout by layout.

Snapshots: freeze a set, serve it forever

Pin any generated set to its own URL. Hand-edit records if you need a specific case, then let CI, demos, and teammates fetch exactly the same data every time.

terminal
POST /v1/snapshots
{ "layout_slug": "user-profile", "name": "Checkout QA",
  "slug": "checkout-qa", "count": 500, "seed": 42 }

GET /v1/snapshots/checkout-qa
# the same 500 records, every time
schema.sql → layout.json
CREATE TABLE users (
  id    UUID PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  plan  VARCHAR(20) DEFAULT 'free'
);

→ imported: layout "users" · 3 fields inferred

Start from the schema you already have

Paste sample JSON, a JSON Schema, an OpenAPI component, or CREATE TABLE DDL — Apiryner infers the layout and you edit from there. Nobody retypes 40 fields.

Four locales, native-looking values

Names, addresses, phone formats, and product copy that read native in English, Korean, Japanese, and Chinese. One query param — try locale=ko in the demo above.

?locale=ko
{
  "name": "김서연",
  "city": "서울",
  "phone": "010-4821-7739",
  "product": "보온 스테인리스 텀블러"
}

Use cases

Where the data ends up

Frontend prototyping

Real-shaped data in Storybook and prototypes before the backend exists.

UserTable.stories.ts
const users = await fetch(
  "…/v1/layouts/user-profile?count=12&seed=7"
).then((r) => r.json());

Test fixtures

Deterministic fixtures — a failing test reproduces on every machine.

users.test.ts
beforeAll(async () => {
  users = await api.generate("user-profile",
    { count: 50, seed: 1337 }); // always the same 50
});

Demo environment seeding

Fill staging with data that looks real in screenshots and sales demos.

db/seeds.rb
users = apiryner.generate("user-profile",
  count: 100, seed: 42, locale: "ko")
User.insert_all(users)

Load testing

Export once as CSV, then replay the same rows through k6 or JMeter.

terminal
GET /v1/layouts/user-profile?count=100&format=csv
# → fixtures/users.csv, versioned with the repo

API & SDKs

Call it from anywhere

The HTTP API is live today — anything that can make a request works, no client library needed. The npm SDK ships with a CLI, React/Vue adapters, and an MCP server for AI agents. Swift Package Manager and Gradle SDKs are written and tested but not published yet.

api.apiryner.com/v1 · JSON or CSV X-API-Key header · seed for reproducibility
terminal
# no SDK needed — it's just HTTP
terminal
curl -s -H "X-API-Key: $APIRYNER_KEY" \
  "https://api.apiryner.com/v1/layouts/user-profile\
?count=100&seed=42&locale=ko" | jq '.[0].name'

"김서연"

Questions, answered

Is it free?

The free tier covers 1,000 API requests and 10,000 generated records a month, up to 100 records per request, with 10 layouts, 3 API keys, and 3-level nesting. Every field type, every locale, and snapshots are included. No credit card to sign up, and the demo on this page needs no account at all.

Do I need an account to try it?

No. The demo above hits the real generation engine, limited to 20 requests per minute per IP and 5 records per run. An account lifts both and gives you saved layouts, API keys, bundles, and snapshots.

What exactly does the seed guarantee?

The same layout, seed, count, and locale return byte-for-byte identical output — across days, SDKs, and regions. Change any one of them and you get a new, equally deterministic set. The one thing outside your control is the data pool itself: when we add names or cities to a locale, previously generated values shift. Pin a snapshot when you need a set that can never move.

Can I import a schema I already have?

Yes. Paste sample JSON, a JSON Schema, an OpenAPI component, or CREATE TABLE DDL, and Apiryner infers a layout you can edit before saving.

Which locales are supported?

English, Korean, Japanese, and Chinese. Names, addresses, phone numbers, and text values all localize; structural values such as uuid, slug, and dates stay ASCII.

Can I keep a generated dataset fixed?

Snapshots pin any generated set to its own URL that returns the same records every time. You can hand-edit records first if you need a specific case in there.

Your first dataset is two minutes away

Free covers 1,000 requests a month — no card, no sales call. The demo above is the product.