API client · macOS, Windows, Linux

The developer's HTTP client.

REST, SOAP, GraphQL, sockets, and a capture proxy in one application.

It sends the request and shows you the DNS lookup, the TCP connect, the TLS handshake, the certificate chain and every byte in both directions — so when a request misbehaves, you can see why.

Free · No account · Local-first

Sendwire's main request/response view: a POST to echo.sendwire.dev/mirror with a small JSON body in the top pane, and below it the 200 OK response — the same JSON returned verbatim and syntax-highlighted.

REST is the easy half.

Most clients treat anything that isn't JSON over HTTP as someone else's problem. Sendwire treats SOAP, GraphQL, WebSocket and raw sockets as first-class — one client instead of SoapUI, a GraphQL IDE, a WebSocket tool and netcat.

REST & HTTP

Every method, every body type, every auth scheme — plus the handshake underneath.

  • Bodies: JSON, form, multipart, raw, file upload
  • Auth: OAuth 2 (PKCE), mTLS, AWS SigV4, JWT, bearer
  • Underneath: DNS, TCP, the TLS handshake, the cert chain
Sendwire sending a POST to echo.sendwire.dev/mirror: the JSON request body on top and the same JSON echoed back in the response pane below.

SOAP & WSDL

Point it at a WSDL. Every operation becomes a request with the envelope scaffolded.

  • Import a WSDL — operations, types and SOAPAction filled in
  • 1.1 and 1.2 handled properly, not guessed
  • Faults parsed — code, string and detail, not XML soup
Sendwire sending a SOAP 1.1 Echo request to soap.sendwire.dev: the request envelope on top and the syntax-highlighted response envelope, returning

GraphQL

Schema-aware editing — completion and inline docs from introspection.

  • Autocomplete fields, arguments and types as you type
  • Variables pane kept beside the query
  • Errors surfaced with their path, next to the data
Sendwire running a GraphQL query against graph.sendwire.dev: the UsersAndRoles query and its variables on top, and the JSON response listing three users with their roles below.

WebSocket

The upgrade, then a live frame log — send and receive, with close codes.

  • 101 Switching Protocols shown, headers and all
  • Every frame timestamped, in and out
  • Close codes named, not left as a number
Sendwire connected to wss://echo.sendwire.dev/ws: the log shows the TLS connection, the 101 Switching Protocols upgrade with its headers, and a subscribe frame sent and echoed back.

Raw sockets

A plain TCP (or TLS) socket, bytes shown both ways — where netcat used to live.

  • TCP or TLS — connect, then send raw bytes
  • Hex + text for everything received
  • Line or binary framing, your call
Sendwire on a raw TCP socket to socket.sendwire.dev:80: a hand-written GET / HTTP/1.1 request sent as raw bytes, and the HTTP/1.1 200 OK response with its headers and JSON body returning byte for byte.

The whole exchange, not just the response body.

The raw HTTP exchange, all of it — the handshake, the certificate chain, every header in both directions. When an API call or an integration misbehaves, this is the one place that tells you why.

Exchange · GET api.github.com/repos/nodejs/node
    0.3  * Resolving hostname api.github.com
   40.5  *   api.github.com → 140.82.116.5 (IPv4)
   80.2  * Connected to api.github.com (140.82.116.5) port 443
   80.2  * ALPN: offering http/1.1
  127.6  * TLS handshake complete
  127.6  *   version: TLSv1.3
  127.6  *   cipher:  TLS_AES_128_GCM_SHA256
  127.6  *   key exchange: X25519 253 bits
  127.6  * Server certificate:
  127.6  *   subject:     CN=*.github.com
  127.6  *   issuer:      CN=Sectigo Public Server Authentication CA DV E36
  127.6  *   expire date: Sep 29 23:59:59 2026 GMT (59 days remaining)
  127.6  *   certificate verify ok.
  127.6  *   chain depth: 4
  127.6  > GET /repos/nodejs/node HTTP/1.1
  127.6  > Accept: */*
  127.6  > Host: api.github.com
  377.1  < HTTP/1.1 200 OK
  377.1  < Content-Type: application/json; charset=utf-8
  377.1  < Strict-Transport-Security: max-age=31536000
  • Where the time actually went

    A waterfall splitting DNS, TCP, TLS, time-to-first-byte and download. When a call is slow, this is the difference between a slow server and a slow handshake.

  • The certificate chain, in full

    Subject, issuer, validity, SANs and chain depth for every hop. Expiry is counted in days, because that is the number you actually needed.

  • Connection reuse, made visible

    Whether keep-alive held, which IP answered, which ALPN protocol was agreed. A benchmark that silently reconnects every time is measuring the wrong thing.

  • Redirects you can inspect

    Every hop is kept, with the method rewrites and the credential drops that RFC 9110 requires — rather than one opaque final answer.

Sendwire's Timing tab for a GET to api.github.com, drawn as a waterfall: DNS lookup, TCP connect, the TLS handshake, waiting for the first byte and content download, each timed, with the total across the top.
One GET, split into its five phases: DNS, TCP connect, TLS handshake, waiting, and download. A client that reports one number can't tell you which of them was slow.

Capture the traffic you didn't send.

A built-in capture proxy: point a browser, an app, or a phone at it and watch real requests flow through. Hold any one at a breakpoint to rewrite it before it goes, turn on HTTPS decryption when you need the bodies, and open a capture straight into the editor to replay it. Bring a HAR someone sent you and it reads the same way.

Capture proxy · live
Sendwire's capture proxy listening on 127.0.0.1:8899: a live list of requests that passed through it — GET, POST, PUT and DELETE to echo.sendwire.dev and api.sendwire.dev, 200s alongside a 401, a 404 and a 500, each row showing status, method, host, path, time and duration — and a POST to api.sendwire.dev/rest/charges held at the breakpoint with Edit, Forward and Drop.
Real requests captured as they pass through, newest first — a POST to /rest/charges held at the breakpoint to rewrite before it goes, and a 401, a 404 and a 500 called out among the 200s. Click any row to open it in the editor with the response it got.
  • Real traffic, live

    Start the proxy and every request that passes through appears as it happens. Click one to open it in the editor with its recorded response, then replay it, save it to a collection, or export it as code.

  • Stop a request mid-flight

    A breakpoint holds a request in the air so you can rewrite its method, URL, headers or body and forward it — or drop it. HTTP, and HTTPS once decryption is on — the same intercept-and-edit you'd reach for Burp or Charles to do, in the client you already send from.

  • HTTPS, decrypted only when you say so

    Off by default. Turn it on and a local CA opens HTTPS bodies in full; a browser Sendwire launches trusts it automatically, or install the certificate on a phone. Nothing is decrypted until you opt in.

  • A throwaway browser, or your phone

    Launch a Chrome pointed at the proxy in a disposable profile — no system settings touched, nothing to clean up — or flip one toggle to let a phone on the same Wi-Fi route through the computer.

HAR browser
Sendwire's HAR viewer: a browsed HAR export shown as a Chrome-style network waterfall — filter tabs (All, XHR, JS, CSS, Img, Media, Other, Errors), a phase legend for DNS, connection, SSL/TLS, waiting and download, and one row per request with status, type, start time, URL and a phase-segmented timing bar against a shared axis; a POST returns 201, one request 404s, another is still pending.
Drop in a browser's HAR export (DevTools → Save all as HAR) and it opens as the same waterfall — one row per request, phase-segmented bars on a shared axis, filtered by type — and any row opens into the editor with its recorded response.

Coming from Postman? Bring all of it, in one file.

Postman’s Settings → Data → Export Data writes every collection and every environment into a single file. Sendwire reads that file — folders, variables and, the part that usually does not survive a move, your scripts, rewritten rather than dropped. It also writes it, so leaving is the same one file.

Postman collections

v2 collections, with pre-request and post-response scripts rewritten from pm to sw on the way in — and back again on the way out, so a collection you export runs in Postman rather than throwing on every request. Anything with no equivalent either side is named before the file is written, not discovered afterwards. Individually, or the whole data export at once. Environments and globals come with it; globals arrive as an environment named for what they were, because we have no wider scope to put them in.

OpenAPI 3

JSON or YAML, grouped by tag, with parameters and body examples filled in.

WSDL

Every operation as a request, envelope scaffolded and SOAPAction set.

cURL

Paste a command — or whatever your browser's “Copy as cURL” gave you.

HAR

A browser's network export, browsable. Click any request to open it exactly as it was sent, with the recorded response already on screen.

Swagger 2.0

Translated to OpenAPI 3 on the way in, so host, basePath, body parameters and formData arrive as the requests they describe rather than as something approximate.

Ask Claude. It opens in Sendwire.

Point Claude at a curl command, a request in your logs, or a proxy capture — it reads the call (and the response it got) and opens it in Sendwire for you, built and ready to re-send. No file to find, no double-click. It imports whole OpenAPI specs and Postman collections too, and exports everything back out. One small Skill, or File → Add Claude Skill in the app.

Claude
you  add this HTTP call to Sendwire — it's in our
     server logs at ~/logs/export.txt

Claude  Found the POST to /v1/orders and its 201 response.
     Done — opening it in Sendwire.

     ↳ Sendwire comes to the front, the request built and
       its response already beside it.

Scripts are JavaScript. All of it.

Not a template language, not a subset, not a builder UI with an escape hatch. If it runs in JavaScript, it runs here — and the editor colours it with VS Code's own grammar and themes.

Post-response
// Capture the session token for the next request.
const data = sw.response.json().data;
sw.environment.set("token", data.token);

// Sign the next call with an HMAC of the user object.
sw.environment.set("sig", sw.crypto.hmacSha256(
  sw.environment.get("apiSecret"),
  JSON.stringify(data.user)
));

for (const key of Object.keys(data)) {
  if (/^user_/.test(key)) sw.console.log(key);
}

sw.test("session is active", () => {
  sw.expect(sw.response.code).to.equal(200);
});
  • Autocomplete from the real response

    Type response.json(). and the fields offered are the ones the last response actually returned — with their types and their current values, not a guess from a schema.

  • One namespace, and it's sw

    Importing a Postman collection rewrites pm automatically. Type it anyway and the editor underlines it before you ever hit send.

  • Export it and run it anywhere

    A suite exports to a standalone Node script that carries your scripts across verbatim — because it runs the same JavaScript, rather than trying to reconstruct your intent.

Sendwire's post-response script editor with a JavaScript test coloured by VS Code's grammar, and an open completion list after typing sw.response.json().f — offering full_name, fork, forks_url, forks_count and forks, each with its type and the value the last response returned.
That list is not a schema and not a guess. Those are the fields the last response actually carried, with the values it carried them with — read straight back out of the nodejs/node GET this page opens with.

Test suites, built in — and load testing from the same steps.

Chain requests into a suite so a value captured in one is spent by the next, and assert on every response — a pass or fail you can gate a build on. Then point a load test at that same suite when you need to know it holds up. No second tool, no exporting, no writing a k6 script.

A Sendwire suite run for 'Checkout flow': three chained steps — Sign in (POST), Create order (POST), Fetch order (GET) — with the run modal open on a PASSED verdict: 3 passed, 0 failed, 3/3 assertions, each step green with a 200 and a 1/1 checks badge.
A three-step Checkout flow: sign in, create an order, fetch it — each step spending the id captured by the one before, each asserted, all green. That is the functional test; the load run below is the same steps under pressure.
A Sendwire load test result: total requests and throughput per second at a 0% error rate, latency percentiles from p50 to p99, the status-code distribution, a breakdown of where the time went, and throughput over time.
  • Steps that pass state along

    Each step is a real request, and a value captured in one — a token, an id — is spent by the next. A log-in-then-call flow is a single suite that asserts as it goes, not a fixture you maintain by hand.

  • Checks, not just status codes

    Assert on the body of every response. A service under load will happily answer 200 with an error page, and a run that only counted status codes would call that a pass.

  • Where the time actually went

    DNS, TCP, TLS, time-to-first-byte and download, broken out across the whole run — so "it got slow" becomes "the handshake got slow".

p50 · p95 · p99 Nearest-rank, never interpolated — an interpolated p99 is a latency nobody experienced.
Checks Assert on every response, not just the status. A 200 carrying an error page is a failure.
Thresholds Set a bar for error rate and latency, and let the run pass or fail against it.
No fleet Measured at ~23,000 req/s on one laptop. A second machine buys nothing until you exceed that.

Export it — to twelve languages, or a script that runs anywhere.

A request becomes cURL, Python, Go or any of ten others. A whole suite becomes a standalone Node script. A collection becomes one file. And the workspace was a readable JSON document the entire time.

Sendwire's Code snippet panel showing thirteen targets — cURL, HTTP, JavaScript, Python, Go, C#, Java, Ruby, Rust, PHP, PowerShell, Dart and Claude — with Go selected and the generated net/http program for a POST with a JSON body.
  • The request on screen, as code

    cURL, HTTP, JavaScript, Python, Go, C#, Java, Ruby, Rust, PHP, PowerShell and Dart — plus a written brief for Claude. Variables resolved so it runs as-is, or left as {{name}} so it stays a template. Copy it, or save it.

  • A suite becomes a Node script

    Steps in order, values captured from one response and spent in the next, and your own JavaScript emitted verbatim rather than reconstructed. It runs the same code because it is the same language.

  • Collections travel as one file

    A bundle carries its environments with it, so what arrives at the other end is not full of unresolved {{variables}} — and what goes into it is chosen explicitly, so a secret never rides along by accident.

  • And the workspace was always yours

    One JSON file on your disk. If Sendwire vanished tomorrow you would still be able to read every request you ever wrote, in any text editor.

Built like the tool it is.

An HTTP client is where you go when something is wrong. It should be the one piece of software that never makes you wonder whether it is the problem.

  • Zero native dependencies

    The whole engine is Node's own http, tls and net. Nothing to compile, nothing to break on upgrade, no binary blobs in the package.

  • Your workspace is a JSON file

    On your disk, at a path the app will tell you, saved as you type. No account, no sync, no cloud that can go down or change its pricing.

  • No nag screens

    No account, no sync, no “rate us,” no feedback prompts. It opens, it does its job, and it gets out of the way.

Take a light to the deep end.

Every byte, every layer — the parts other clients leave in the dark. Free, no account.

One command on macOS & Linux, or pick a build — on the download page. ⌘P jumps to any request in the app.