POST /v1/generate-table
Generates data for one table, returned as JSON or as CSV. The response has no manifest and no schema.
To validate a request and see its estimated cost without generating data, send the same body to
POST /v1/estimate-table.
Request
The body is one table, with the table properties name, rowCount, fields and primaryKey (see
Building a Request), and the dataset-level properties $schema, csvFormat,
schemaVersion and seed, all at the top level:
| Property | Type | Default | Description |
|---|---|---|---|
$schema |
string? |
none | URL of a JSON Schema for the request, used by an editor to validate and complete a request file. Accepted and ignored. |
csvFormat |
CsvFormatRequest |
see CSV formatting | Formatting settings for the CSV. |
fields |
FieldRequest[] |
required | The fields that generate the table's columns. Must contain at least one field. See Building a Request. |
name |
string |
required | Table name. |
primaryKey |
string[]? |
none | Columns that form the table's primary key, in key order. The columns are checked, but the response has no schema to declare the key in. See Declaring a primary key. |
rowCount |
integer |
required | Number of rows to generate. At least 1. |
schemaVersion |
string |
"1.0" |
Version of the request contract the request uses. |
seed |
integer? |
random | Seed for the request. The same request with the same seed produces the same data. |
curl -X POST https://api.alchemy.example/v1/generate-table \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
--data @request.json
Response
The default response is JSON, with name, rowCount, columns, the table's data as a csv string,
and the amount charged. With Accept: text/csv, the response is the CSV data only: the header row and
every generated row, written with the request's csvFormat or the defaults. The Content-Type is
text/csv for the default UTF-8 encoding. Any other encoding adds its
charset, so Utf8Bom returns text/csv; charset=utf-8, and both UTF-16 encodings return
text/csv; charset=utf-16:
curl -X POST https://api.alchemy.example/v1/generate-table \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/csv" \
-o customer.csv \
--data @request.json
Content negotiation follows the same rules as
POST /v1/generate-dataset: the q= quality values determine the type when
Accept lists both types, on a tie the type listed first is used, and any other Accept value, or no
Accept header, returns JSON.
Every response includes the X-Alchemy-Generated-Bytes header. See
Getting Started for billing.
A billed request also returns the amount charged, in the X-Alchemy-Cost and X-Alchemy-Currency
headers and, in a JSON response, in the cost and currency properties. See
What the call cost.
Errors
All error responses are RFC 7807 ProblemDetails bodies. type is a fixed urn:alchemy:error:...
identifier for the error. Use type to identify an error, rather than title or detail, which are
text and can change.
400, because the request body is missing:
{
"type": "urn:alchemy:error:missing-request-body",
"title": "Request body is required.",
"status": 400
}
400, because the body is not valid JSON, or contains a property that does not exist. Unknown
properties are rejected, not ignored. detail gives the JSON path of the property:
{
"type": "urn:alchemy:error:malformed-request-body",
"title": "Request body could not be read.",
"status": 400,
"detail": "Unknown property 'country' at $.fields[0].country. Check it against the properties that type accepts. A property of a nested object must be written inside that object."
}
400, because a field's settings are invalid. In this example, map contains a sub-field that the
field type does not have:
{
"type": "urn:alchemy:error:invalid-generation-request",
"title": "Invalid generation request.",
"status": 400,
"detail": "map names sub-field 'x', which a Boolean field does not have. Its sub-fields are value.",
"path": "$.fields[1]",
"table": "customers",
"fieldIndex": 1,
"fieldType": "Boolean",
"columns": ["is_active"]
}
When the response identifies the field, path is its location in the request body, table is the
name of its table, fieldIndex is its position in fields, fieldType is its type, and
columns lists the columns its map writes to. Some field errors, such as two boundingLocation
filters that cannot be combined, do not include these properties.
401, because the API key is missing or invalid:
{
"type": "urn:alchemy:error:unauthorized",
"title": "Missing or invalid API key.",
"status": 401
}
402, because the balance does not cover the cost of the request:
{
"type": "urn:alchemy:error:insufficient-credit",
"title": "Insufficient credit.",
"status": 402,
"detail": "This call costs 0.0042 USD and your balance is 0.001 USD. If automatic top-up is enabled one has been requested. Retry shortly. Otherwise, top up to continue."
}
413, because the request body is larger than the maximum size. detail states the maximum:
{
"type": "urn:alchemy:error:request-body-too-large",
"title": "Request body is too large.",
"status": 413
}
400, because a field's type is not a field type:
{
"type": "urn:alchemy:error:malformed-request-body",
"title": "Request body could not be read.",
"status": 400,
"detail": "Unknown field type 'Foo' at $.fields[0]."
}
503, because the service is busy. The Retry-After header gives the number of seconds to wait before
retrying. See When the service is busy:
{
"type": "urn:alchemy:error:service-busy",
"title": "The service is busy.",
"status": 503
}
503, because the reference data the request reads is temporarily unavailable. The Retry-After
header gives the number of seconds to wait before retrying. See
When the service is busy:
{
"type": "urn:alchemy:error:reference-data-unavailable",
"title": "Reference data is temporarily unavailable.",
"status": 503
}
503, because billing is temporarily unavailable. Retry the request later:
{
"type": "urn:alchemy:error:billing-unavailable",
"title": "Billing is temporarily unavailable. Please try again shortly.",
"status": 503
}
A request that returns an error is not charged.
Example
{
"seed": 42,
"name": "widget",
"rowCount": 5,
"fields": [
{
"type": "Number",
"mode": "Sequential",
"start": 100,
"map": { "value": { "column": "id", "dataType": "Integer" } }
}
]
}
Sample output:
| id |
|---|
| 100 |
| 101 |
| 102 |
| 103 |
| 104 |