Quickstart
Enrich individual rows or perform row-based actions.
Create rows by searching for people, companies, or data.
const res = await pipe0.pipes.run({ pipes: [ { pipe_id: "people:workemail@1" }, ], input: [{ name: "John Doe" }],});Public API endpoints.
pipe0 is a data enrichment API. You send records (people, companies) and get them back with new fields: email addresses, phone numbers, LinkedIn profiles. Searches create records, pipes enrich them.
If all you need is an email or a phone number, this page is enough. Browse the pipe catalog or search catalog, copy a request, and go.
You need an API key to run the examples. Create one in the dashboard, see Authentication. All examples run in sandbox mode: mock data, zero credits, no subscription required.
Find a work email
Send one record and one pipe. The person:workemail:waterfall@1 pipe reads name and company_domain and adds a work_email field. You don't configure anything; the pipe knows its inputs and uses the default provider order.
import { Pipe0 } from "@pipe0/client";
const pipe0 = new Pipe0({ apiKey: process.env.PIPE0_API_KEY });
const result = await pipe0.pipes.pipe({
config: {
environment: "sandbox",
},
pipes: [
{
pipe_id: "person:workemail:waterfall@1",
},
],
input: [
{
id: "1",
name: "Jane Doe",
company_domain: "pipe0.com",
},
],
});
console.log(result);import requests
response = requests.post(
"https://api.pipe0.com/v1/pipes/run/sync",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"config": {
"environment": "sandbox",
},
"pipes": [
{
"pipe_id": "person:workemail:waterfall@1",
},
],
"input": [
{
"id": "1",
"name": "Jane Doe",
"company_domain": "pipe0.com",
},
],
},
)
print(response.json())curl -X POST "https://api.pipe0.com/v1/pipes/run/sync" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"config": {
"environment": "sandbox"
},
"pipes": [
{
"pipe_id": "person:workemail:waterfall@1"
}
],
"input": [
{
"id": "1",
"name": "Jane Doe",
"company_domain": "pipe0.com"
}
]
}'The response contains your record with the new field:
{
"id": "xgvxuqk2771d8t17n60vphu9",
"status": "completed",
"records": {
"1": {
"id": "1",
"fields": {
"work_email": {
"type": "string",
"value": "jane@pipe0.com",
"status": "completed"
// ...
}
// ...
}
}
}
// ...
}Sandbox values are mock data. Remove config.environment (or set it to "production") to run real providers and get real results.
Search for people
While pipes add fields to records you already have, search creates the records. Use it when you start from a filter ("software engineers in Berlin") instead of a list.
import { Pipe0 } from "@pipe0/client";
const pipe0 = new Pipe0({ apiKey: process.env.PIPE0_API_KEY });
const result = await pipe0.searches.search({
config: {
environment: "sandbox",
},
search: {
search_id: "people:profiles:crustdata@2",
config: {
limit: 25,
filters: {
current_job_titles: {
include: [
"Software Engineer",
],
},
},
},
},
});
console.log(result);import requests
response = requests.post(
"https://api.pipe0.com/v1/search/run/sync",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"config": {
"environment": "sandbox",
},
"search": {
"search_id": "people:profiles:crustdata@2",
"config": {
"limit": 25,
"filters": {
"current_job_titles": {
"include": [
"Software Engineer",
],
},
},
},
},
},
)
print(response.json())curl -X POST "https://api.pipe0.com/v1/search/run/sync" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"config": {
"environment": "sandbox"
},
"search": {
"search_id": "people:profiles:crustdata@2",
"config": {
"limit": 25,
"filters": {
"current_job_titles": {
"include": [
"Software Engineer"
]
}
}
}
}
}'The results array of a search response is a valid input for a pipes request, so you can search for people and enrich them in two calls. See Search then enrich.
Compose pipes
Stack pipes in one request. Each pipe reads the output of the pipes before it:
import { Pipe0 } from "@pipe0/client";
const pipe0 = new Pipe0({ apiKey: process.env.PIPE0_API_KEY });
const result = await pipe0.pipes.pipe({
config: {
environment: "sandbox",
},
pipes: [
{
pipe_id: "person:name:join@1",
},
{
pipe_id: "person:workemail:waterfall@1",
},
],
input: [
{
id: "1",
first_name: "Jane",
last_name: "Doe",
company_name: "Pipe0",
},
],
});
console.log(result);import requests
response = requests.post(
"https://api.pipe0.com/v1/pipes/run/sync",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"config": {
"environment": "sandbox",
},
"pipes": [
{
"pipe_id": "person:name:join@1",
},
{
"pipe_id": "person:workemail:waterfall@1",
},
],
"input": [
{
"id": "1",
"first_name": "Jane",
"last_name": "Doe",
"company_name": "Pipe0",
},
],
},
)
print(response.json())curl -X POST "https://api.pipe0.com/v1/pipes/run/sync" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"config": {
"environment": "sandbox"
},
"pipes": [
{
"pipe_id": "person:name:join@1"
},
{
"pipe_id": "person:workemail:waterfall@1"
}
],
"input": [
{
"id": "1",
"first_name": "Jane",
"last_name": "Doe",
"company_name": "Pipe0"
}
]
}'The second pipe read name even though your input never contained it: person:name:join@1 created it from first_name and last_name. Pipes see each other's output. Two pipes can do what one can't.
Motivation
When Ivan Zhao explains the idea behind Notion he compares it to paper:
Paper is simple enough for a 3-year-old to take out of the drawer and paint on it. Yet it's versatile enough that the bureaucracies of entire countries can run on it.
pipe0's philosophy is similar. One request finds an email address, and the same primitives are enough to build a Clay-like product. The Data tables example is an interactive enrichment table built in about 400 lines of code.