How to format an api response as a markdown table
- Step 1Capture a representative response — Hit the endpoint in your API client (curl, Insomnia, Postman) and copy the JSON. For a list endpoint, copy the array under
data/items/results— the array of objects is what becomes rows. - Step 2Redact secrets first — If the sample contains tokens, keys, or session IDs, run it through md-secret-redactor before pasting here. Bearer tokens, AWS keys (
AKIA…), and JWTs are common in real responses and must not land in published docs. - Step 3Flatten nested fields you want to show — Nested objects render as
[object Object]. If you wantuser.emailin the table, promote it to a top-levelemailkey in the sample before converting, or document the nested object in its own table. - Step 4Paste and Run — Paste the array into the input (or upload the saved
.json). There are no options — press Run and the table appears, with columns drawn from every object's keys. - Step 5Review optional-field columns — Confirm the column set matches your endpoint's documented schema. A missing column means no sample object included that field; add a record that exercises it if you need it documented.
- Step 6Embed and convert if needed — Paste the table into your reference page. To publish as HTML, send it to md-to-html; for a docx handoff, md-to-docx.
Common API field types and how they render
How typical REST response values look in the output table. All cells go through String(value ?? "").
| Response field | Example JSON value | Cell output |
|---|---|---|
| String id / slug | "usr_8f2a" | usr_8f2a |
| Numeric id / count | 10234 | 10234 |
| Boolean flag | true | true |
| ISO timestamp string | "2026-06-13T08:30:00Z" | 2026-06-13T08:30:00Z (plain text) |
| Null optional field | null | (empty cell) |
| Nested object | {"city":"NYC"} | [object Object] — flatten first |
| Array of tags | ["a","b"] | a,b |
Workflow: from endpoint to embedded table
The recommended pipeline for documenting a list endpoint safely. Each step is a single tool.
| Step | Tool | Why |
|---|---|---|
| 1. Capture | API client | Copy the array of result objects |
| 2. Redact | md-secret-redactor | Strip tokens/keys/JWTs from the sample |
| 3. Flatten | your editor | Promote nested fields you want as columns |
| 4. Convert | this tool | Union of keys → GFM pipe table |
| 5. Publish | md-to-html | Render the doc page (optional) |
Tier limits
Markdown-family limits. A typical paginated API page (25–100 records) is far under even the Free cap.
| Tier | Upload size | Paste characters | Files/run |
|---|---|---|---|
| Free | 1 MB | 500,000 | 1 |
| Pro | 10 MB | 5,000,000 | 10 |
| Pro-media | 50 MB | 20,000,000 | 50 |
| Developer | 500 MB | unlimited | unlimited |
Cookbook
Real response shapes from typical REST endpoints. Tokens shown redacted; convert only redacted samples.
A list endpoint's data array
The common case: a paginated list response. Copy the array under data and convert it; the envelope (page, total) is documented separately.
Response:
{
"page": 1,
"data": [
{"id": "u_1", "name": "Ada", "active": true},
{"id": "u_2", "name": "Lin", "active": false}
]
}
Paste just the data array →
| id | name | active |
| --- | --- | --- |
| u_1 | Ada | true |
| u_2 | Lin | false |Optional fields that appear on some records
Endpoints often return a field only when relevant (a deprecation notice, an error detail). The union rule gives every such field a column; records without it show an empty cell — exactly how you'd document an optional field.
Input:
[
{"id": 1, "status": "ok"},
{"id": 2, "status": "deprecated", "sunsetOn": "2026-12-01"}
]
Output:
| id | status | sunsetOn |
| --- | --- | --- |
| 1 | ok | |
| 2 | deprecated | 2026-12-01 |Flatten a nested object before converting
Nested objects render as [object Object]. Promote the fields you want into top-level keys in the sample, then convert. This keeps the table readable without losing the data you care about.
Raw record:
{"id": 7, "user": {"name": "Sam", "email": "sam@x.com"}}
Flatten to:
[{"id": 7, "user.name": "Sam", "user.email": "sam@x.com"}]
Output:
| id | user.name | user.email |
| --- | --- | --- |
| 7 | Sam | sam@x.com |Redact a token before it reaches the doc
A real response may echo a token. Run md-secret-redactor first; it replaces Bearer tokens and JWTs with placeholders, so the converted table is safe to publish.
Before redaction:
[{"session": "Bearer abc123def456ghi789", "role": "admin"}]
After md-secret-redactor:
[{"session": "Bearer [REDACTED]", "role": "admin"}]
Then convert →
| session | role |
| --- | --- |
| Bearer [REDACTED] | admin |A URL value with a pipe is kept intact
API responses sometimes embed query strings or filters containing |. The tool escapes the pipe so the cell stays in one column.
Input:
[{"endpoint": "/search?q=a|b", "hits": 12}]
Output:
| endpoint | hits |
| --- | --- |
| /search?q=a\|b | 12 |Edge cases and what actually happens
You pasted the whole response envelope, not the array
Single-row tablePasting {"page":1,"data":[...]} is a single object, so you get a one-row table with columns page and data — and the data value shows as [object Object] because it's a nested array/object. Paste only the inner array of result objects.
Nested response objects show as [object Object]
By designThe tool uses String(), not JSON.stringify, so a nested object value is [object Object]. Flatten the fields you want to document into top-level keys before converting, or give the nested structure its own table.
Array-valued fields collapse to comma-joined text
By designA tags: ["a","b"] field becomes a,b. For a list of nested objects (items: [{...},{...}]) the result is [object Object],[object Object]. Document collection fields separately rather than inline.
Auth token left in the sample
Security riskThe tool does not redact anything — whatever you paste is converted verbatim. A Bearer token, API key, or JWT in the sample will appear in the published table. Always run md-secret-redactor on real responses first.
Response is JSONL / NDJSON (one object per line)
Invalid JSON inputStreaming endpoints emit newline-delimited JSON, which is not a single valid JSON document. The tool returns Invalid JSON input.. Wrap the lines in [ ... ] with commas between objects first.
Empty result set
Empty arrayA response whose data array is [] returns Empty array.. Capture a sample that actually contains records, or document the empty-state shape in prose.
A string field contains a newline
Row breakA multi-line value (e.g. a formatted message field) breaks the table row because newlines aren't escaped. Replace newlines with spaces in the sample, or repair the result with md-table-repair.
Large numeric IDs
PreservedNumeric values are coerced with String(), so an integer id like 90071992547409 is reproduced as text exactly. Note that the source JSON itself can lose precision beyond 2^53 during parsing — if your IDs are that large, your API should return them as strings.
Inconsistent field casing across records
Two columnsIf some objects use userId and others userid, the union treats them as two distinct columns. Normalize key casing in the sample before converting if you want a single column.
Very wide responses
ExpectedSome endpoints return 30+ fields per object, producing an unreadably wide table. Trim the sample to the documented fields before converting, or split into grouped tables (identity, status, metadata).
Frequently asked questions
How do I document just the result list, not the pagination envelope?
Paste only the inner array of objects — the part under data, items, or results. The envelope fields (page, total, next) belong in a separate prose section. If you paste the whole envelope object you'll get a one-row table where the array field shows as [object Object].
Will optional fields get their own column?
Yes. Columns are the union of every key across every object in the array, so a field that only appears on some records still gets a column. Records that don't include it show an empty cell — which reads naturally as 'optional/absent' in docs.
How are nested response objects handled?
They render as the literal text [object Object], because each cell is produced with String(), not JSON.stringify. Flatten the nested fields you want (promote user.email to a top-level key) before converting, or document the nested object in its own table.
How do I keep tokens out of the published table?
Run the sample through md-secret-redactor first. It replaces Bearer tokens, generic API keys, AWS access keys (AKIA…), and JWTs with placeholders. This tool itself does no redaction — it converts exactly what you paste.
Can I convert a streaming / NDJSON response?
Not directly. Newline-delimited JSON isn't a single valid JSON document, so the tool returns Invalid JSON input.. Wrap the lines into a JSON array ([obj, obj, ...]) first, then convert.
Does it preserve ISO date and large-number fields?
Date strings are kept verbatim as text. Numbers are coerced to their text form. Be aware that JSON parsing itself can lose precision for integers above 2^53 — well-designed APIs return very large IDs as strings, which this tool then preserves exactly.
Are there any conversion options?
No. There's nothing to configure — paste the array (or upload one .json file) and Run. The column set, separators, and escaping are all automatic. The related csv-to-md-table tool does have a header toggle if your source is CSV.
Is the response uploaded to a server?
No. Conversion runs entirely in your browser tab. The JSON never leaves your machine. The only server write is an anonymous usage counter for signed-in dashboards, with no content, which you can disable in settings.
What if a field value contains a pipe character?
It's escaped to \|, so a URL with ?a=1|b=2 or a shell snippet stays inside one cell. Newlines, however, are not escaped — strip them from multi-line string fields before converting.
How do I publish the table as HTML for a docs site?
Send the generated Markdown to md-to-html. For a Word/docx handoff to a tech-writing team, use md-to-docx. Both are siblings in the markdown tool family.
How many records can I convert at once?
As many as fit the tier limit. Free allows a 1 MB upload or 500,000 pasted characters — comfortably hundreds to thousands of records. Pro raises that to 10 MB / 5,000,000 characters and beyond. Practically, you'll want to trim a sample to a handful of representative records for docs anyway.
Why does an array field show repeated [object Object] entries?
An array of nested objects (e.g. items: [{...},{...}]) is coerced with String(), which joins the elements — and each element stringifies to [object Object]. That's expected; document collection-of-objects fields with their own table rather than inline.
Privacy first
All Markdown processing runs locally in your browser using JavaScript. No file is ever uploaded to JAD Apps servers — only metadata counters are saved for signed-in dashboard stats.