Async & sync modes
By default, URLpipe processes every request asynchronously — it accepts the request instantly and POSTs the result to your webhook when it's ready. Add sync: true to any request to get the result back inline in the HTTP response instead.
Choosing a mode
Pick the mode per request with the sync parameter. Omit it (or send sync=false) for async — the default, which suits long-running work like /lighthouse and high-volume batches, since you never hold a connection open. Send sync=true for sync — simplest for quick, interactive calls where you want the answer right away.
Typical response times
How long a request takes depends mostly on the target page — its weight, how much JavaScript it runs, and how fast its own server responds. The figures below are drawn from production traffic for non-cached requests: p50 is the median and p90 is the 90th percentile, so 9 in 10 requests finish at or under it.
/lighthouse runs a full audit — the slowest by design, and a natural fit for async.Async requests
Async is the default, so no sync parameter is needed — just include a report_to parameter, the HTTPS URL URLpipe should deliver the result to. The endpoint responds immediately with a token you can use to correlate the eventual webhook.
Request attributes
- Name
url- Type
- string
- Required
- Required
- Description
- The page to process.
- Name
report_to- Type
- string
- Description
- Webhook URL — an
httporhttpsaddress URLpipe POSTs the result to when it's ready. Required for async requests (the default); omit it only when you sendsync=true. A missing or invalid value returns422.
- Name
sync- Type
- boolean
- Description
- Set to
trueto process the request synchronously instead. Defaults tofalse(async). Does not affect the cached result a request maps to.
- Name
max_age- Type
- string | integer
- Description
- How fresh a cached result must be to be accepted. Either an integer number of seconds (
3600) or a duration string of the form"<number> <unit>"— unitss/min/h/d/w(e.g."2 hours","3 days","30m"). Defaults to7 days, clamped to a max of30 days;0always bypasses the cache. See Caching for all accepted units.
curl -X POST https://urlpipe.dev/markdown \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"report_to": "https://your-app.com/webhooks/urlpipe"
}'{
"token": "0Zx3…9aQ",
"status": "accepted"
}The webhook delivery
When processing finishes, URLpipe sends a POST with a JSON body to your report_to URL. The token matches the one from the immediate response, so you can pair it with your original request.
Payload fields
- Name
token- Type
- string
- Description
- Correlates with the token returned when you made the request.
- Name
operation- Type
- string
- Description
- The endpoint that ran, e.g.
markdown.
- Name
success- Type
- boolean
- Description
- Whether the operation succeeded.
- Name
result- Type
- string | object | null
- Description
- The result on success (a string or JSON value, depending on the endpoint);
nullon failure.
- Name
error- Type
- string | null
- Description
- A human-readable message on failure;
nullon success.
{
"token": "0Zx3…9aQ",
"operation": "markdown",
"success": true,
"result": "# Example Domain\n\nThis domain is for use…",
"error": null
}{
"token": "0Zx3…9aQ",
"operation": "markdown",
"success": false,
"result": null,
"error": "The request timed out."
}Delivery guarantees
- Results are delivered as a JSON POST to your report_to URL.
- Webhook delivery uses a 30-second timeout.
- If delivery fails, the result is still stored and remains visible in your project's history in the dashboard, so nothing is lost.
- Each request gets a unique token, so concurrent jobs never collide.
- Prefer to pull instead of receive a webhook? Fetch the result any time with GET /result/:token.
token — treat a repeated token as the same result rather than a new one.Sync mode
Send sync=true to process a request synchronously. report_to is then ignored: the request is processed inline and the result comes straight back in the HTTP response body, in the content type documented for each endpoint. Failures return a 422 with an error field.
Every sync response also carries an X-Result-Token header identifying the request, so you can re-fetch the result later via GET /result/:token.
Sync timeouts
A sync request waits up to 60 seconds for the analysis to finish. If it isn't ready in time, the endpoint returns 504 Gateway Timeout with the token in the body — but the analysis keeps running in the background. Retrieve the result once it completes via GET /result/:token, or use async mode (omit sync) for consistently long-running work.
{
"error": "processing_timeout",
"message": "The analysis is taking longer than expected. Retrieve it later via GET /result/:token, or use async mode for long operations.",
"token": "0Zx3…9aQ"
}