API client · macOS, Windows, Linux

The developer's HTTP client.

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 — because when a request misbehaves, the body is the last place the answer is.

Free while in beta · No account · No telemetry

Sendwire showing the timeline of a GET to api.github.com — DNS resolution, TCP connect, the TLS 1.3 handshake with its cipher and certificate chain, the request headers, and the 200 OK response.
  • REST & HTTPEvery method, body type and auth scheme
  • GraphQLSchema-aware completion and docs
  • SOAPWSDL import, envelopes, faults
  • WebSocketUpgrade, frames, close codes
  • Raw socketsTCP with the bytes shown
  • Load testingConcurrency and percentiles

A request is a conversation, not a return value.

This is genuine output from Sendwire's engine — not a mock-up, not a redraw. It is what the Wire tab prints for a single GET.

Wire · 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: DNS Lookup 12 ms, TCP Connect 40 ms, TLS Handshake 46 ms, Waiting for the first byte 42 ms, Content Download 4 ms, and a total of 144 ms.
One GET, 144 ms. The server accounted for forty-two of them. The rest went on finding the host and shaking hands with it — which is the difference between a slow API and a cold connection, and it is invisible in any client that reports one number.
Sendwire's Certificate tab: the leaf certificate CN=*.github.com marked 59 days remaining, with its issuer, validity dates, EC P-256 key, SANs, serial number and SHA-256 fingerprint, and the Sectigo intermediate that signed it below.
Every certificate the server presented, leaf first — four deep on this call. The badge counts days, because Sep 29 23:59:59 2026 GMT is not a number anyone can act on while looking at it.

Coming from Postman? Your collections come with you.

Folders, variables and — the part that usually does not survive a move — your scripts, rewritten rather than dropped. Postman exports one collection per file, so it is one import each.

Postman collections

v2 collections, with pre-request and post-response scripts rewritten from pm to sw on the way in. If one slips through, the editor underlines it and offers to convert it — you never find out at send time. Environments export separately from Postman, and import separately here.

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.

Not yet: Swagger 2.0

Detected and refused rather than half-read — host, basePath and body parameters differ enough that guessing would send quietly wrong requests. Convert to OpenAPI 3 first.

REST is the easy half.

Most clients treat anything that isn't JSON over HTTP as somebody else's problem. Sendwire was built by someone who still has to call SOAP services.

SOAP & WSDL

Point it at a WSDL and every operation arrives as a request with the envelope scaffolded, SOAPAction set and 1.1/1.2 handled properly. Faults are parsed, not printed as XML soup.

OpenAPI & cURL

Import an OpenAPI 3 document and get a collection grouped by tag. Paste a cURL command and get a request. Export any request back out as cURL, or as code in thirteen languages.

WebSocket & raw sockets

The upgrade exchange in full, then frames in both directions with opcodes and payloads. Send text or binary from hex. Close with a code the server actually sees.

Auth that works

OAuth 2 with PKCE, mutual TLS with a client certificate, AWS SigV4, JWT, bearer, basic and API keys — plus an HTTP proxy when you need to sit behind one.

A real command line

Run a suite, a collection or a folder from CI. JSON and JUnit reporters, CSV or JSON data files, and a non-zero exit when anything fails — so it can gate a build.

Bring your collections

Postman collections import with their scripts translated, not discarded. Point it at a browser's HAR export too, and pick the handful of calls you care about out of the network trace.

Sendwire sending a SOAP 1.1 request to the public CountryInfoService: the envelope in the request pane with its namespaces and a country code, and below it a 200 OK whose response envelope is syntax-highlighted, showing the Netherlands, Amsterdam, phone code 31 and the currency EUR.
A real call to a public SOAP service. The envelope was not typed: importing the service's WSDL listed forty-two operations and turned this one into a request with its namespaces, its parameter and its SOAP version already in place. The reply comes back parsed and coloured rather than as one long line of angle brackets.
A Sendwire WebSocket session against Coinbase's public market-data feed: the HTTP/1.1 101 Switching Protocols upgrade response with its headers, the connection line showing TLSv1.3 and the negotiated cipher, an outbound subscribe frame, and inbound heartbeat frames each with its opcode and byte count.
The upgrade in full — the 101 and every header that came back with it — then frames in both directions, each with its opcode and its size. The payloads are heartbeats off a public market-data feed, a second apart. The next message sits in the composer above, unsent.

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 — no declarative form could express this.
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 — nodejs/node, and 36,286 forks — read straight back out of the GET this page opens with.

Load testing, built in.

Chain requests into a suite so a value captured in one is spent by the next — then point a load test at that same suite. No second tool, no exporting to something else, no writing a k6 script to find out whether it holds up.

A Sendwire load test result: 32,775 requests at 3,277 per second with 0% errors, latency percentiles from p50 to p99, status code distribution, a breakdown of where the time went, and throughput over time.
  • Real concurrency, real numbers

    Fifty virtual users, or a fixed arrival rate if you want to know whether a service sustains one. Whatever cannot be dispatched on schedule is reported as a shortfall rather than quietly absorbed.

  • 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.

  • Nothing phones home

    No telemetry, no analytics, no crash reporting you did not ask for. The only requests Sendwire makes are the ones you tell it to.

sendwire — command line
$ sendwire run "Checkout flow" --env staging --reporter junit

  ok   Log in                      142 ms
  ok     login worked
  ok   Create order                211 ms
  ok     order id captured
  ok   List orders                  88 ms
  ok     status is active
  ok     matches the schema

  3 steps · 4 assertions · 441 ms · all passed

Get Sendwire

Free while in beta. No account, no licence key, no strings.

Not shipping yet. These buttons are live and the download path works end to end, but the builds behind them are placeholders. Follow one and you will get a text file that says so.

Also available in the app: ⌘K opens the command palette.