Public betas live on four platforms

Programmable API client

Ship API tools as JavaScript plugins.

BuildAPlugin is a desktop API client where JavaScript plugins can change the workspace, automate requests, and call app-managed native bridges for Bluetooth, camera, microphone, network, files, clipboard, SMS, phone, Android, and Windows diagnostics.

macOSAvailable now
WindowsAvailable now
LinuxAvailable now
AndroidAvailable now
JSRuntime plugins
APIRequest workspace
OSNative bridge actions
BuildAPlugin light themed API workspace with purple controls

Download

Protected downloads for macOS, Windows, Linux, and Android.

All four builds are delivered through private, rate-limited CloudFront links. No account, email address, or checkout is required.

Apple notarized

macOS desktop app

The free beta expires on 11 August 2026 at 22:00 UTC. A silent browser security check creates a protected link that expires after five minutes. Report bugs through the in-app feedback button.

ZIP SHA256: d9e615a8a39ba480350d603d395c82b2c9c1f83eb96e80926d09983035e8ff31 Developer ID: Melvin Ollewagen · Team KJY5S2ZW8W
Windows installer

Windows desktop app

Version 1.0.0 for 64-bit Windows. The guided setup installs the complete app, adds Start Menu shortcuts, and includes a standard uninstaller. It is not yet code-signed, so SmartScreen may show a warning.

Installer SHA256: 8a171a3c7c2193a4b0043d935163312e154bfa31bb884b079ef550410aa97a0e Package: unsigned per-user installer
Linux package

Linux desktop app

Version 1.0.0 for 64-bit Debian and Ubuntu systems, packaged as a tested .deb with an application launcher and icon.

DEB SHA256: c3ef07867f06463a554db34ad55cf2bd0a30312798821fc75e492fcb62b551b6 Package: amd64 Debian package
Direct Android APK

Android app

Version 1.0.0 for Android 7.0 and newer. This release-compiled beta APK is development-key signed and installed directly, outside the Play Store.

APK SHA256: 8a0722f78cd7aadb7b0e6fd4f64560049cbbe5f4eb26041edae1f6cbbbfc42f4 Package: development-key signed APK

A familiar API client, with a runtime underneath.

Create requests, save collections, edit headers and bodies, inspect responses, then let plugins add the workflow-specific tools your team normally builds as scripts or internal dashboards.

Request and response workspace

Build requests with methods, URLs, headers, bodies, variables, saved names, and a response viewer designed for repeated API work.

Collection import and export

Bring in Postman-style collections with folders, then export organized workflows back out when teams need portable API assets.

Local plugin state

Plugins can store settings, add controls, update the current request, and persist state without changing the Flutter app.

Plugin-first architecture

Turn a one-off API task into a reusable tool.

The app renders a JSON-defined UI. JavaScript plugins can transform that UI, add buttons and panels, run commands, intercept requests, inspect responses, and use a Postman-style pm API.

Change the UI liveAdd cards, tabs, inputs, modals, theme controls, and workflow panels.
Automate request flowRun beforeRequest and afterResponse hooks for auth, validation, logging, and transformations.
Build with AIGenerate plugin scaffolds from natural-language instructions and install them into the workspace.
Reach native capabilitiesPlugins can trigger camera, microphone, Bluetooth, network, files, clipboard, secure storage, mail, SMS, phone, calendar, Android, and Windows bridge actions.
BuildAPlugin with installed plugins and live theme colour picker
Installed plugins can add panels, controls, themes, and workflow shortcuts.

Native plugin bridges

JavaScript plugins can now test real device and OS capabilities.

BuildAPlugin is not limited to HTTP screens. Plugins can request camera and microphone access, record and transcribe voice instructions, test Bluetooth and BLE devices, inspect network interfaces, use OS launchers, work with files, and write native results back into plugin UI.

Bluetooth and BLE testing

Use bluetooth.run actions for permission checks, adapter status, scans, connect/disconnect, service discovery, characteristic reads, and writes. A bundled Bluetooth Test plugin shows live availability, scan counts, devices, RSSI, and raw JSON.

Camera and microphone

Use media actions to request native permissions, render camera preview nodes, start audio recording, stop recording, and store the captured audio result in plugin data.

Platform APIs

Use platform.run for system info, locale, paths, network diagnostics, DNS, HTTP probes, clipboard, secure storage, preferences, file picking, file metadata, text file read/write, Android snapshots, and Windows diagnostics.

Mail, SMS, phone, calendar

Open OS handlers for email drafts, SMS drafts, phone dialer screens, portable calendar .ics files, and contact .vcf files. The bridge opens user-controlled drafts; it does not silently send messages or place calls.

Voice and recorded workflows

Record spoken workflow instructions, transcribe them through the AI bridge, and turn repeatable request interactions into reusable plugin commands. The internal frontend test driver is disabled in public builds.

Developer documentation

Build plugins that feel native.

BuildAPlugin plugins are CommonJS JavaScript files that can add UI, run commands, mutate the live workspace, inspect app values, chain requests, and pass data between plugins through the plugin bus. Use this as the quick-start reference for building reliable plugins by hand or with the AI builder.

1. Minimal plugin file

Every plugin exports a `manifest`, optional `transformApp`, command handlers, and optional request/response hooks. Use stable IDs for every UI node so Inspect, Recorder, and other plugins can target your components.

module.exports = {
  manifest: {
    id: "hello-plugin",
    name: "Hello Plugin",
    version: "1.0.0",
    priority: 100,
    permissions: ["ui.transform", "plugin.storage"]
  },

  transformApp: function(app, api) {
    api.ui.remove(app, "helloPluginCard");
    api.ui.append(app, "rightPanel", {
      type: "card",
      id: "helloPluginCard",
      children: [
        { type: "text", id: "helloPluginTitle", value: "Hello Plugin" },
        { type: "button", id: "helloPluginRun", text: "Run", command: "helloPlugin.run" }
      ]
    });
    return app;
  },

  commands: {
    "helloPlugin.run": function(ctx) {
      return { __action: "showMessage", title: "Hello", message: "Plugin ran." };
    }
  }
};

2. Add UI with `transformApp(app, api)`

Use `api.ui.append`, `api.ui.prepend`, `api.ui.insertBefore`, `api.ui.insertAfter`, and `api.ui.remove` to place plugin UI in the workspace. Common targets include `rightPanel`, `mainPanel`, `pluginList`, `requestTopBar`, `headersEditor`, `bodyEditor`, `responseViewer`, `urlInput`, and `sendButton`.

Common nodes`card`, `panel`, `row`, `column`, `section`, `text`, `selectableText`, `button`, `input`, `textarea`, `dropdown`, `checkbox`, `keyValueEditor`, `tabButton`, `webview`.
Stable targetingSet `id` and `targetId` where possible. Use plugin-prefixed names like `authHelperTokenInput` instead of generic names like `input1`.
State displayRender persisted plugin values from `app.pluginData`, request fields from `app.activeRequest`, and shared values from `app.pluginBus`.

3. Command return actions

Commands return action objects. Use `multi` when you need several operations in order.

return {
  __action: "multi",
  actions: [
    { __action: "ui.setValue", targetId: "urlInput", value: "https://api.example.com/users" },
    { __action: "setFields", fields: { "activeRequest.method": "GET" } },
    { __action: "triggerTarget", targetId: "core.request.sendButton" }
  ]
};
Messages`showMessage`, `showModal`, `showForm`.
Request edits`setFields`, `setRequest`, `request.set`, `saveActiveRequestToCollection`.
Native bridges`platform.run`, `bluetooth.run`, `media.requestCamera`, `media.requestMicrophone`, `media.startAudioRecording`, `media.stopAudioRecording`.
Runtime UI`ui.setText`, `ui.setValue`, `ui.setProps`, `ui.hide`, `ui.show`, `ui.disable`, `ui.enable`.
CRUD UI`ui.append`, `ui.prepend`, `ui.replaceWith`, `ui.empty`, `ui.remove`.
Execution`triggerTarget`, `runCommand`, `sendRequestById`, `request.send`.
Files and debug`pickTextFile`, `saveTextFile`, `debug.log`, `ui.ownership.inspect`.

4. Inspect, Recorder, and `ctx.dollar` selectors

Long-press a visible element in the app and choose Inspect. Copy the exact selector or command body from the inspect panel into your plugin or into the AI builder. Recorder uses the same target model, so recorded workflows can be replayed as plugin commands.

var url = ctx.dollar("#urlInput").val();
ctx.dollar("#requestNameInput").val("Copied from URL");
ctx.dollar("#bodyEditor").val("url=" + url);
return ctx.dollar("#bodyEditor");
Read and write values`.val()`, `.val(value)`, `.text()`, `.text(value)`, `.attr(name)`, `.attr(name, value)`.
Click and state`.click()`, `.hide()`, `.show()`, `.disable()`, `.enable()`.
CRUD`.append(node)`, `.prepend(node)`, `.replaceWith(node)`, `.empty()`, `.remove()`.
Classes and loops`.addClass(name)`, `.removeClass(name)`, `.each(function(index, node) { … })`.

Supported selectors are `#id`, `.className`, type names, role names, exact `id` or `targetId`, and exact label text. Prefer Inspect-provided IDs such as `#urlInput`, `#bodyEditor`, `#response.body.line.2`, `#kvTable.Headers.add.key`, and `#core.headers.addButton`.

5. Request and response hooks

Use hooks to prepare requests, validate data, store results, or chain follow-up requests. Hooks can return a request, a response, or an action.

module.exports = {
  manifest: { id: "response-tools", name: "Response Tools", version: "1.0.0" },

  hooks: {
    beforeRequest: function(ctx) {
      ctx.request.headers["X-From-Plugin"] = "yes";
      return ctx.request;
    },

    afterResponse: function(ctx) {
      return {
        __action: "multi",
        actions: [
          { __action: "setPluginData", key: "responseTools.lastBody", value: ctx.responseBody },
          { __action: "pluginBus.output", name: "response.lastBody", value: ctx.responseBody }
        ]
      };
    }
  }
};

To send and then show the response, call `core.request.send` with an explicit `afterSendCommand`, then read `ctx.responseBody`, `ctx.response`, or `ctx.payload.response` in that command.

6. Plugin bus: pass data between plugins

The plugin bus is the shared lane for plugin-to-plugin data. Use it when another plugin, request interpolation, or the inspector should be able to see an output.

commands: {
  "authTools.publishToken": function(ctx) {
    return {
      __action: "multi",
      actions: [
        { __action: "pluginBus.output", name: "auth.token", value: "abc123" },
        { __action: "pluginBus.publish", channel: "auth.token.changed", data: { source: "authTools" } }
      ]
    };
  },

  "authTools.useToken": function(ctx) {
    var token = ctx.bus.input("auth.token", "");
    return { __action: "setFields", fields: { "activeRequest.headers": { "Authorization": "Bearer " + token } } };
  }
}
Read`ctx.bus.input(name, fallback)` or `ctx.bus.read(name, fallback)`.
Write`ctx.bus.output(name, value)` or return `pluginBus.output`.
Publish`ctx.bus.publish(channel, data)` or return `pluginBus.publish`.
InterpolatePublic bus variables are available in requests as `{{auth.token}}`.

Private bus names start with `_` or contain `.private.`, `:private:`, or `/private/`. Use clear public names like `auth.token`, `customer.selected`, `response.cleaned`, or `pluginId.outputName`.

7. Performance pattern: make hot interactions native-speed

The request tabs became dramatically faster by moving the hot path out of plugin storage and full app rebuilds. Normal tab clicks now update request/tab state in RAM, repaint a tiny native tab strip, and avoid JavaScript execution, disk saves, and app-definition rebuilds.

Slow pathJS command → `setPluginData` → save → rebuild every plugin → relayout the page.
Fast pathUpdate in-memory state → notify the small widget that changed → keep the rest of the workspace still.

Plugin authors should use this principle too: use full `transformApp` rebuilds for structure, and lightweight runtime mutations for frequent interactions like tab switching, accordions, typing, selection, filters, hover state, and temporary workflow state.

// Good for frequent UI changes:
return { __action: "ui.setValue", targetId: "requestNameInput", value: "Fast update" };

// Good for durable settings:
return { __action: "setPluginData", key: "myPlugin.settings", value: { enabled: true } };

// Avoid this for every click or keystroke:
return { __action: "refresh" };

Rule of thumb: persist what must survive restart; keep temporary UI state in runtime memory; use `ui.*` mutations and `ctx.dollar` for immediate effects; rebuild only when the plugin’s structure actually changes.

Built for real API work.

These screenshots are from the current desktop app: a request editor, plugin manager, variable tools, live theme controls, modal editors, and upgrade activation flow.

Add header modal inside the BuildAPlugin request editor
Fast request editing with focused modal controls.
BuildAPlugin red theme showing request editor and plugin panels
Runtime theme changes prove the UI can be plugin-driven.
BuildAPlugin installed plugin list and API workspace
Installed plugins sit beside collections and request tools.
BuildAPlugin variable panel for API environments
Variables and environment panels support repeatable API workflows.

Launch with the local client. Upgrade when the workspace becomes your toolchain.

Use the WooCommerce store for Pro access, license activation, and account management. The download page is now the public entry point; shop and account stay available for purchases and activation.

BuildAPlugin Programmable API workflows for humans and AI agents.