Explore AI Summary

Clay API: Load, Enrich and Export Records Programmatically

Contents

Clay exposes an API so you can put records into a table, read enriched records back out, and trigger runs from your own systems. This matters because the interface is built for a person sitting in front of it, and most production workflows are not.

This guide covers the three integration patterns that actually get used, and which one to pick.

The three ways in

1. Webhook source table

You create a table whose source is a webhook, and Clay gives you a URL. You POST JSON records to that URL and each one becomes a row, which then runs through whatever enrichment columns the table has. This is the most reliable route for bulk and automated loading, because it needs nothing but an HTTP client and it works identically from a script, a scheduler or another SaaS tool.

It is also the answer when interface-based CSV upload is not reachable from automation, which is the situation most integration work runs into first.

2. HTTP API column

This runs in the other direction. A column in a Clay table calls your endpoint for each row and writes the response back. Use it when you hold data Clay cannot get, internal scores, product usage, contract status, and you want it alongside the enriched fields.

3. Webhook output

A final column, or an action on the table, POSTs completed rows to your endpoint. This is how enriched records leave Clay and land in a CRM, a sequencer or a warehouse. Prefer this over polling.

Which pattern to use

You want toUseNote
Load many records automaticallyWebhook source tableThe dependable bulk path
Add your own internal data to rowsHTTP API columnRuns once per row, so mind the volume
Send finished records onwardWebhook outputPush beats polling for freshness and cost
Kick off a run from your codeWebhook source tableAdding rows is what starts the work
Read a whole table backExport or webhook outputBulk reads are not the natural direction

Practical notes that save time

  • Send one clean JSON object per record. Flat keys map to columns predictably; deeply nested objects do not.
  • Establish the schema with a test record first. The columns are created from the shape of what arrives, so send one correct record before sending ten thousand.
  • Include your own identifier on every row. Without a stable external ID you cannot reconcile what comes back with what you sent.
  • Batch, and pace the batches. Large synchronous bursts are the usual cause of failures. Chunk them and space them out.
  • Turn enrichment columns on after loading. Loading into a table with live enrichment columns spends credits on rows you have not inspected yet.
  • Handle retries idempotently. A retried POST creates a second row unless you deduplicate on your own identifier.

When not to use Clay as an API

If your requirement is “enrich this record and write it back to the CRM, continuously and at volume”, calling data provider APIs directly is simpler, cheaper and easier to monitor. Clay earns its place when a human needs to see, adjust and iterate on the list. Routing a purely machine-to-machine process through a spreadsheet adds a moving part with no reader.

A concrete load pattern

The most common integration task is “we have several thousand records in our own system and we want them enriched”. Here is the shape that works reliably.

  1. Create the table with a webhook source. Copy the URL it gives you.
  2. POST one representative record. This establishes the columns. Check that every field you sent became a column with the name you expected before going further.
  3. Add enrichment columns while the table is nearly empty. Configure conditions now, not after the data is in.
  4. POST the rest in batches. A few hundred per batch with a pause between them. Large unbroken bursts are the usual cause of dropped records.
  5. Attach a webhook output column. Completed rows push back to your endpoint as they finish, so you are never polling.
  6. Reconcile on your own identifier. Count what you sent against what came back and re-send the difference.

Step six is the one people skip. Without your own ID on every record, a partial failure leaves you unable to tell which rows are missing, and the only recovery is re-sending everything.

Errors you will hit

SymptomUsual causeFix
Records arrive with no columnsFirst record had a nested or inconsistent shapeSend flat JSON, and set the schema with one clean test record
Duplicate rows after a retryThe POST is not idempotentDeduplicate on your own external ID before or after loading
Credits consumed faster than expectedEnrichment columns were live during the loadLoad first, enable enrichment second
Rows stuck incompleteA column is waiting on a provider or a rate limitGuard the export on completion status rather than on row age
Nothing arrives at your endpointOutput configured but the condition never matchesTest the output column against a single completed row

Deciding between Clay and direct API calls

A useful test: if you removed the interface entirely, would anyone notice? If the answer is no, the table runs on a schedule, nobody reads it, the output goes straight to a system, then you are paying for a workspace nobody uses. Calling the underlying providers directly removes a moving part, a bill and a failure mode.

If the answer is yes, because someone builds lists, inspects results and changes the approach based on what they see, then the interface is the product and it is worth paying for. Most teams have both situations and should route them differently rather than standardising on one.

Frequently asked questions

Can I upload a CSV to Clay programmatically?

The dependable automated route is to POST records to a webhook source table rather than to drive a file upload. It is more robust and it works from any environment.

Can Clay call my own API?

Yes, using an HTTP API column. It executes once per row and writes the response into that column.

How do I get enriched records out?

Push them with a webhook output to your own endpoint. That gives you the record as soon as it is complete, without polling.

Arnaud Renoux

Co-Founder at Scalelist