From raw, chaotic CSVs to production-ready APIs in minutes
Transform, join and serve data with familiar SQL queries and documented, secured APIs.
Tap into the value of data. Go from:
Data locked away
Valuable datasets trapped in static files, unusable by applications
Weeks of development
Building data pipelines and APIs traditionally takes extensive engineering resources
Isolated datasets
No easy way to combine, enrich, or transform data from multiple sources
To unleashing the value from any data file, all spreadsheet exports, and every public dataset in your applications within minutes.
No backend development required.
See the transformation
Watch messy data become a production-ready API
1. Start with raw data
PostcodeUtf8 | AddressLine1Utf8 | AddressLine2Utf8 |
---|---|---|
"KA278LF" | "Lamlash " | "Isle of Arran" |
"KA128SS" | " Kilwinning Road" | " Irvine" |
"KA280HF" | "College St " | "Millport" |
"KA2 0BE" | " Kilmarnock Road" | "Kilmarnock" |
"KA120DP" | " Warrix Avenue" | "Irvine" |
"KA6 6AB" | "Dalmellington Road " | "Ayr" |
"KA9 2HQ" | "Biggart Road " | "Prestwick" |
"KA6 6DX" | " Dalmellington Road" | "Ayr" |
"KA7 4DW" | "10 Doonfoot Road " | "Ayr" |
"KA215RF" | "Nelson Road" | "Saltcoats" |
2. Clean and transform with SQL
SELECT
regexp_replace("Postcode", '\s*(.3$)', ' \1', 'g') AS "Postcode",
trim("AddressLine1") AS "AddressLine1",
trim("AddressLine2") AS "AddressLine2"
FROM data.example
PostcodeUtf8 | AddressLine1Utf8 | AddressLine2Utf8 |
---|---|---|
"KA27 8LF" | "Lamlash" | "Isle of Arran" |
"KA12 8SS" | "Kilwinning Road" | "Irvine" |
"KA28 0HF" | "College St" | "Millport" |
"KA2 0BE" | "Kilmarnock Road" | "Kilmarnock" |
"KA12 0DP" | "Warrix Avenue" | "Irvine" |
"KA6 6AB" | "Dalmellington Road" | "Ayr" |
"KA9 2HQ" | "Biggart Road" | "Prestwick" |
"KA6 6DX" | "Dalmellington Road" | "Ayr" |
"KA7 4DW" | "10 Doonfoot Road" | "Ayr" |
"KA21 5RF" | "Nelson Road" | "Saltcoats" |
3. Join with other datasets
SELECT model.example_cleaned.*,
data.uk_postcode_lookup.latitude AS "Latitude",
data.uk_postcode_lookup.longitude AS "Longitude"
FROM model.example_cleaned
JOIN data.uk_postcode_lookup ON "Postcode" = postcode
PostcodeUtf8 | LatitudeFloat64 | LongitudeFloat64 | AddressLine1Utf8 | AddressLine2Utf8 |
---|---|---|---|---|
"KA27 8LF" | 55.54312 | -5.115521 | "Lamlash" | "Isle of Arran" |
"KA12 8SS" | 55.635056 | -4.676106 | "Kilwinning Road" | "Irvine" |
"KA28 0HF" | 55.761296 | -4.922755 | "College St" | "Millport" |
"KA2 0BE" | 55.61394 | -4.539409 | "Kilmarnock Road" | "Kilmarnock" |
"KA12 0DP" | 55.611863 | -4.660189 | "Warrix Avenue" | "Irvine" |
"KA6 6AB" | 55.434174 | -4.593108 | "Dalmellington Road" | "Ayr" |
"KA9 2HQ" | 55.492576 | -4.604862 | "Biggart Road" | "Prestwick" |
"KA6 6DX" | 55.430332 | -4.595538 | "Dalmellington Road" | "Ayr" |
"KA7 4DW" | 55.449149 | -4.639765 | "10 Doonfoot Road" | "Ayr" |
"KA21 5RF" | 55.63957 | -4.772409 | "Nelson Road" | "Saltcoats" |
4. Enrich with H3 geospatial indexing
SELECT
model.example_joined.*,
h3_latlng_to_cell("Latitude", "Longitude", 15::INT) AS "H3Res15"
FROM model.example_joined
PostcodeUtf8 | H3Res15Utf8 | LatitudeFloat64 | LongitudeFloat64 | AddressLine1Utf8 | AddressLine2Utf8 |
---|---|---|---|---|---|
"KA27 8LF" | "8f19569a8c5c648" | 55.54312 | -5.115521 | "Lamlash" | "Isle of Arran" |
"KA12 8SS" | "8f19092e6775410" | 55.635056 | -4.676106 | "Kilwinning Road" | "Irvine" |
"KA28 0HF" | "8f19092b0d119ad" | 55.761296 | -4.922755 | "College St" | "Millport" |
"KA2 0BE" | "8f190925084439b" | 55.61394 | -4.539409 | "Kilmarnock Road" | "Kilmarnock" |
"KA12 0DP" | "8f19092e3d467a6" | 55.611863 | -4.660189 | "Warrix Avenue" | "Irvine" |
"KA6 6AB" | "8f1954598d46a49" | 55.434174 | -4.593108 | "Dalmellington Road" | "Ayr" |
"KA9 2HQ" | "8f1954598c58ac3" | 55.492576 | -4.604862 | "Biggart Road" | "Prestwick" |
"KA6 6DX" | "8f1954598c58ac3" | 55.430332 | -4.595538 | "Dalmellington Road" | "Ayr" |
"KA7 4DW" | "8f19545932d3a66" | 55.449149 | -4.639765 | "10 Doonfoot Road" | "Ayr" |
"KA21 5RF" | "8f19092f28342c1" | 55.63957 | -4.772409 | "Nelson Road" | "Saltcoats" |
5. Download or serve via a documented, secure and monitored API:
https://example.com/test?Within=[-5.205964198095899,55.50214416203221,-5.079052659295115,55.57395814779818]
{ "data": [ { "Postcode": "KA27 8LF", "H3Res15": "8f19569a8c5c648", "Latitude": 55.54312, "Longitude": -5.115521, "AddressLine1": "Lamlash", "AddressLine2": "Isle of Arran" } ], "_meta": { "cursor": null, "elapsed": 35 } }
Everything you need, nothing you don't
Focus on your data and use-case, not infrastructure
Large files of various formats
Upload CSV, JSONL, Parquet and other files of any size.
Full power of SQL
Clean, join, enrich your data using familiar SQL queries.
No infrastructure setup
Zero backend configuration. No servers to manage.
Auto-generated docs
OpenAPI documentation created automatically.
Built-in security
Secure your endpoints with API keys on a unique domain and separate storage.
Geospatial filters
Custom API filters, including location-based via H3 indexing.
Usage monitoring
Track API usage metrics.
High performance
Fast, optimised queries.
No lock-in
Download the transformed data at any point.
Case study: Scottish Energy Performance Certificate (EPC) data
Scotland publishes energy performance certificate data as CSV files only. So we used tap to transform those CSVs into the API behind epcdata.scot.
Raw government data
From a zip of 41 CSV files totalling 3 GB
Beyond ELT
We cleaned, transformed and enriched it with geospatial indexes
Enabled live applications
Our API is used in numerous applications providing real value

Ready to tap into your data?
Transform your CSV files into production APIs in minutes. No backend experience required.
Try tap nowStart building immediately • No credit card required