Pipedream sits between the no-code platforms and writing a service yourself: workflows are triggers and steps like anywhere else, but a step is Node.js you write. There is no dynamic endpoint dropdown here — you write the request — and in exchange you get retries, concurrency and error handling exactly as you want them.
A first step
Add a Node.js code step and call the endpoint directly.
import { axios } from "@pipedream/platform";
export default defineComponent({
props: {
apiverve: { type: "app", app: "apiverve" },
},
async run({ steps, $ }) {
return await axios($, {
url: "https://api.apiverve.com/v1/emailvalidator",
headers: { "x-api-key": this.apiverve.$auth.api_key },
params: { email: "test@example.com" },
});
},
});The apiverve prop is a connected account: Pipedream stores the key and exposes it as
this.apiverve.$auth.api_key, so the key never appears in the code or in the workflow's saved
version. Use it rather than an environment variable — an account is revocable and shareable
across workspace members, and it keeps the key out of anything you export.
Use your primary key. Sub-keys work fine on direct API calls, and this is a direct API call, so a sub-key is a legitimate choice here — unlike on the built connectors, where it is rejected. If the workflow only ever calls one endpoint, a sub-key scoped to it is the better credential.
Taking input
Declare props to make the step configurable from the Pipedream UI instead of hardcoding values:
import { axios } from "@pipedream/platform";
export default defineComponent({
props: {
apiverve: { type: "app", app: "apiverve" },
email: {
type: "string",
label: "Email address",
description: "The address to validate",
},
},
async run({ steps, $ }) {
const res = await axios($, {
url: "https://api.apiverve.com/v1/emailvalidator",
headers: { "x-api-key": this.apiverve.$auth.api_key },
params: { email: this.email },
});
return { email: this.email, valid: res.data?.valid, raw: res };
},
});Returning a narrow object rather than the whole response makes later steps easier to read, and keeps the workflow's execution log small enough to actually scan.
POST endpoints
Some endpoints take a body rather than query parameters — the reference page for each one says
which. Same call, data instead of params:
await axios($, {
method: "POST",
url: "https://api.apiverve.com/v1/texttoemoji",
headers: {
"x-api-key": this.apiverve.$auth.api_key,
"Content-Type": "application/json",
},
data: { text: this.text },
});Handling failure yourself
This is the reason to be on Pipedream rather than a connector, so it is worth doing properly.
axios from @pipedream/platform throws on a non-2xx, and the status is what you branch on:
try {
return await axios($, { /* ... */ });
} catch (e) {
const status = e.response?.status;
if (status === 429) {
$.flow.rerun(60_000, null, 3); // back off and retry up to 3 times
return;
}
if (status === 400) {
$.flow.exit("Bad input, not retrying"); // retrying will not help
return;
}
throw e;
}The distinction that matters: a 429 is worth retrying and a 400 never is. A blanket retry on
every failure spends calls re-sending a request that was malformed the first time. See
error handling for what each status means, and note that 401 is the only
authentication verdict — a 403 is a key restriction, not a bad key.
Concurrency is yours to manage
Pipedream will happily run a workflow concurrently across many events, and nothing throttles the calls for you. Two things follow.
Fan-out hits the rate limit before it hits your balance. A queue that suddenly delivers 500 events will fire 500 calls as fast as the platform can start them. Set the workflow's concurrency limit, or batch inside a single step and pace it yourself.
One call per item, always. Iterating 1,000 rows in a code step is 1,000 calls. Cache what repeats — Pipedream's data stores are the obvious place — and check the store before calling.
For genuinely bulk work, POST /v1/<endpoint>/batch takes many inputs in one request; see
batch requests.
When to choose Pipedream over a connector
The built connectors are faster to set up and need no code, so the honest question is when writing the request yourself is worth it. Four cases where it clearly is.
The logic is conditional in a way a connector cannot express. Call one endpoint, look at the
result, and decide which of three others to call next. On a linear platform that is three
workflows and a lot of duplicated setup; here it is an if.
You need a file-upload endpoint. Image conversion, OCR, QR reading and the rest are excluded from every connector dropdown because those platforms cannot send multipart form data. From a code step they are ordinary requests.
Retry policy matters. A connector retries — or does not — on the platform's terms. Here you decide per status code, which is the difference between a workflow that recovers from a rate limit and one that burns its balance retrying a malformed request.
You want to cache. Any workflow that looks up the same domains, addresses or IPs repeatedly should check a store before calling. That is a few lines in a code step and impossible in most connector dropdowns.
If none of those apply, use a connector. Code you maintain is a cost, and a Zap that does the job is cheaper than a step that does it slightly better.
Patterns worth copying
Poll with a high-water mark. A scheduled workflow that processes "everything new since last time" needs to remember when last time was. Keep the timestamp in a Pipedream data store, read it at the start of the run, write it at the end. Without it, every run reprocesses the whole source and every run costs a full sweep of calls.
Deduplicate before you call. If the trigger can deliver the same record twice — most queues and webhooks can — check a store for the id first. A workflow that is called twice for one signup should validate that address once.
Enrich, then branch, then act. Put the API call early and everything irreversible after it, so a failed lookup stops the run before it has written anything. The reverse order leaves you reconciling half-finished records.
Return narrowly. Pipedream stores every step's return value in the execution record. Handing back a large response body on a high-volume workflow makes the log unusable and the run slower; return the two fields you need and drop the rest.
What it costs
One call per request at the endpoint's rate, exactly as if you had run curl. Pipedream's own
credit model counts separately and is unrelated.
Because the number of calls is whatever your code does, this is the integration where a bug is most expensive. Test with a small event first, then check analytics before enabling the trigger properly, and turn on the 80% usage alert in settings.
Next
Making requests covers the request shape in full, and SDKs offer a typed client if you would rather not hand-write the call. Zapier is the no-code alternative when a step does not need real code, and integrations compares every platform side by side.