# Client libraries

Official clients for Python, JavaScript and TypeScript, Ruby and Go. Each is a thin layer over the HTTP API with typed results and errors, and the same behaviour in every language.

You don't need one: every endpoint is a single POST, and the [code recipes](https://urlpipe.dev/code) show it in eight languages with nothing but an HTTP client. A library saves you the parts around that POST — retries, long analyses, error types and webhook signatures.

## Install

| Language | Install | Package | Source | Notes |
| --- | --- | --- | --- | --- |
| Python | `pip install urlpipe` | [PyPI](https://pypi.org/project/urlpipe/) | [GitHub](https://github.com/URLpipe/urlpipe-python) | Python 3.9+, sync and async clients, one dependency (httpx) |
| JavaScript | `npm install @urlpipe/sdk` | [npm](https://www.npmjs.com/package/@urlpipe/sdk) | [GitHub](https://github.com/URLpipe/urlpipe-js) | TypeScript types, no dependencies; Node 18+, Bun, Deno and Cloudflare Workers |
| Ruby | `gem install urlpipe` | [RubyGems](https://rubygems.org/gems/urlpipe) | [GitHub](https://github.com/URLpipe/urlpipe-ruby) | Ruby 3.1+, no dependencies |
| Go | `go get github.com/URLpipe/urlpipe-go` | [pkg.go.dev](https://pkg.go.dev/github.com/URLpipe/urlpipe-go) | [GitHub](https://github.com/URLpipe/urlpipe-go) | Go 1.21+, standard library only |

## Your first call

Each client reads the project API key from `URLPIPE_API_KEY` (or takes it as an argument) and waits for the result, so a call returns the page:

```
import urlpipe

client = urlpipe.Client()  # reads URLPIPE_API_KEY

page = client.markdown("https://example.com")
print(page.data)
```

## What every client does

- **Waits for the result.** Calls send `sync: true` by default. When a page outlives the 60-second sync window, the API answers `504` with a token and the client polls [GET /result/:token](https://urlpipe.dev/docs/results) until the result lands, so your code sees one call. Pass `sync: false` for a token straight away, and `wait(token)` to collect it.
- **Retries without paying twice.** Connection errors, 5xx answers, `rate_limited` and `concurrency_limit` are retried with backoff, and every retried request carries an [Idempotency-Key](https://urlpipe.dev/docs/retries#idempotency-key), so a retry can never run or bill the work twice.
- **Types every error.** Each [documented error](https://urlpipe.dev/docs/errors) — invalid key, unconfirmed email, invalid request, failed analysis, out of credits, too many in parallel, rate limited, not found, expired — is its own type, with the API's code, message and fields.
- **Reads the metadata.** The [response headers](https://urlpipe.dev/docs/response-headers) — cache status and age, processing time, credits spent and left — come back parsed on every response.
- **Verifies webhooks.** A helper checks a delivery's [HMAC signature](https://urlpipe.dev/docs/async#signature) against the raw body, accepts either secret during a rotation, and refuses stale timestamps.

Every option the API takes can be passed, including ones newer than your client version: each client has an `extra` map that is merged into the request body as it is.

## From an AI agent

Agents don't need a library at all: the hosted [MCP server](https://urlpipe.dev/docs/mcp) gives Claude, Cursor, VS Code and other clients the same operations as tools, with one token.

Source: https://urlpipe.dev/docs/client-libraries
