conversation_id.
How it works
- Create the dataset once. Give it a name, its columns and the column(s) that identify a row. Rippit returns a
dataset_id. - Ask for an upload slot for that dataset. Rippit returns a one-time upload link.
- Upload one file to that link: Parquet (recommended) or JSON Lines.
- Tell Rippit the upload is finished, then check the job until it says
done.
Before you start
Get an API token. In Rippit, open Tables, click Add table, then Add API Table, and create or copy a token. You need to be a workspace admin. Keep it in an environment variable such asRIPPIT_API_TOKEN, not in a script or a chat.
Authentication. Send your token in the apitoken header on every request:
https://integrations.maestroqa.com/api/v2/bulk_ingest
Bulk upload has to be switched on for your account. If it isn’t, requests return 403 with “Your account does not have API ingest enabled.” Ask your Rippit contact to turn it on.
How datasets behave
Primary key (pkey_cols). The column or columns that identify a row, such as account_id. Uploading a row with a key that’s already there replaces that row, so it’s safe to re-run the same export every hour or every day. For an append-only dataset, like an event log, leave pkey_cols empty and set "append_only_dataset": true. Every uploaded row is kept, so re-uploading the same file creates duplicates. One of the two is required.
Updated-at column (updated_at_col). Optional. When the same key arrives more than once, the row with the later value in this column wins. Without it, the most recent upload wins.
Columns. You declare them when you create the dataset. If a later file has a column the dataset doesn’t, it’s added automatically. You can’t change the primary key after the dataset is created.
Column types:
Column names: letters, numbers and underscores only, starting with a letter or underscore, and at most 128 characters. Names starting with
__ are reserved. At most 500 columns.
Parquet or JSON Lines?
Use Parquet when you can. Columns keep their types, files are much smaller and processing is much faster. Every column has to fit its declared type: if afloat column holding 1.5 is declared int, the job fails with a message naming that column. Files that finished before the failure stay written, so fix the type and upload again.
Use JSON Lines (.jsonl, one JSON object per line) when you build rows by hand. Each line is checked on its own, and lines that don’t fit come back in rejected with their line number while the rest are written. Text that fits the column type is accepted, for example "12" for an int or "2026-09-27T14:02:11Z" for a datetime.
The API
1. Create the dataset
name is any label up to 128 characters, such as Accounts (billing). Calling it again with the same name returns the same dataset_id with status: "exists", so your script can always call it first.
To see your datasets, with their dataset_ids:
2. Ask for an upload slot
format is parquet or jsonl. The response is the same as for conversations:
3. Upload the file
Send a multipart form POST toupload_url. Include every entry in upload_fields exactly as you received it, and attach the file as file. Don’t send your Rippit credentials on this request. A successful upload returns 204.
4. Mark the upload finished
5. Check the job
status is done or failed.
row is the 0-based line number in your file (JSON Lines only). A failed job has the reason in error.
Edit a dataset
label renames the table in Rippit; its dataset_id and name stay the same. columns relabels or hides columns. conversation_link_column makes that column’s values clickable links to the matching conversations (see Linking to your conversations); setting it moves the link off any other column. The response is the dataset, as in GET /datasets. Unknown column names return 400.
The upload script
This works for any source. Get your rows into a PyArrow table, then callupload(). It creates the dataset from the table’s columns, splits big tables into files under 128 MB and waits for each job.
Example sources
These are common starting points, not a complete list. Anything that can give you rows works: if a library returns a PyArrow table, a pandas DataFrame or a list of dicts, you can turn it into a table withpa.Table.from_pandas(df, preserve_index=False) or pa.Table.from_pylist(rows) and pass it to upload(). Read credentials from environment variables, never from the script.
Postgres
Snowflake
upload() lower-cases them, so use lower case in pkey and updated_at.
BigQuery
A CSV or Excel export
where updated_at > now() - interval '1 day', and run the script on a schedule. Rows with a key that’s already there are updated.
Linking to your conversations
To join a dataset to conversations you’ve uploaded with the bulk conversation upload, add aconversation_id column with the same IDs you used there, stored as string. You can link one row per conversation (for example ticket metadata) or many (for example the orders a customer placed during a chat). Then set it as the link column with PATCH /datasets/{dataset_id} and {"conversation_link_column": "conversation_id"}, so clicking a value opens that conversation.
Limits
Only uploads that were actually completed count toward the limits. If you hit one you get
429 with a Retry-After header. Wait that many seconds and try again.