1 Getting Started

System Requirements

PlatformMinimum VersionNotes
macOS10.13 (High Sierra)Apple Silicon and Intel supported
Linuxglibc 2.29+AppImage works on most distros
WindowsWindows 10x64 only

Installation

macOS (recommended) — via Homebrew:

Terminal
brew tap kinarix/callstack
brew install --cask callstack

All platforms — download from GitHub Releases:

  • macOS: .dmg — open and drag to Applications
  • Linux: .AppImage — make executable (chmod +x), run directly
  • Windows: .msi — run the installer

First Launch

  1. Open CALLSTACK from your Applications folder (or wherever you installed it).
  2. The app creates a local SQLite database at ~/Library/Application Support/callstack/callstack.db (macOS) or the equivalent on your platform.
  3. Optionally sign in with Google (Settings → Account) to scope your data to an email address — useful if multiple people share one machine. Sign-in is not required.
  4. Create your first project using the + Project button in the sidebar.
💡
No account needed CALLSTACK works entirely offline. Google Sign-In is optional and only used to namespace local data on shared machines.

2 Core Concepts

Data Hierarchy

Everything in CALLSTACK is organised in a three-level tree:

Project
└── Folder (optional, nestable)
    └── Request
  • Projects are top-level containers (e.g. "Payment API", "Auth Service").
  • Folders group related requests within a project. They can be nested.
  • Requests are individual API calls with their own URL, method, headers, body, and scripts.

Deleting a project cascades — all its folders, requests, environments, automations, and data files are removed.

Environments

Each project can have multiple environments (e.g. Development, Staging, Production). An environment holds key-value pairs that can be substituted anywhere in your request using {{variableName}} syntax.

Request Lifecycle

  1. Build — Set method, URL, params, headers, body, and scripts.
  2. Pre-script — JavaScript runs before the request is sent (modify variables, generate data).
  3. Send — Rust HTTP client sends the request (no CORS, full header control).
  4. Post-script — JavaScript runs with the response (extract tokens, run assertions).
  5. View — Inspect the response body, headers, timing, and test results.

3 Request Builder

Method & URL

Select the HTTP method from the dropdown. The badge changes colour to match:

GET POST PUT DELETE PATCH

Type or paste the URL in the URL bar. Use {{variable}} syntax to substitute environment values:

{{BASE_URL}}/api/v1/users/{{USER_ID}}

Query Parameters

Click the Params tab to add URL query parameters as key-value rows. Each row has an enable/disable toggle — disabled rows are excluded from the request. Parameters support {{variable}} substitution.

Headers

The Headers tab lets you add arbitrary HTTP headers. Each row has an enable/disable toggle. CALLSTACK automatically inserts Content-Type based on your body type and an Origin header derived from the URL.

ℹ️
Full header control Because CALLSTACK uses a Rust HTTP client (not a browser), you can set any header — including Host, Origin, and custom headers that browsers normally forbid.

Request Body

The Body tab shows a CodeMirror editor with syntax highlighting for JSON and XML. The editor validates your JSON on-the-fly and shows errors inline. You can also write plain text.

File Attachments

In the Body tab, switch to multipart mode to attach files. Click Add file to open the native file picker. Each attachment shows its name, size, and MIME type. Files are sent as multipart/form-data.

Sending & Cancelling

Click Send (or press ) to execute the request. A spinner appears while the request is in flight. Click Cancel to abort mid-flight. CALLSTACK enforces a 30-second timeout by default.

4 Response Viewer

Metadata Bar

Above the response tabs you'll see:

  • Status — HTTP status code (200, 404, 500…) with colour coding: green for 2xx, amber for 3xx/4xx, red for 5xx.
  • Time — Total round-trip time in milliseconds.
  • Size — Response body size in bytes.

Body Tab

Displays the response body with automatic pretty-printing:

  • JSON — Syntax highlighted with line numbers, collapsible objects.
  • XML / HTML — Indented and highlighted.
  • Plain text — Shown as-is.

Click Copy to copy the formatted body to your clipboard. Click Save to export the body to a file via the native file dialog.

Headers Tab

Lists all response headers as key-value pairs. You can pin this tab to keep it visible alongside the body.

Preview Tab

Renders the response visually:

  • HTML — Renders in an iframe.
  • Images — Displays PNG, JPEG, GIF, SVG, WebP.
  • Video/Audio — Plays back base64-encoded media.

Test Results Tab

If your post-script includes test() assertions, the results appear here after every request. Each test shows its description, status (PASS / FAIL), and any message.

5 Environments & Variables

Creating an Environment

  1. Open a project and click the Environments tab.
  2. Click + Environment and give it a name (e.g. "Development").
  3. Add key-value pairs. Mark sensitive values as Secret to mask them in the UI.
  4. Select the environment from the dropdown in the request builder to activate it.

Variable Substitution

Use {{variableName}} anywhere in your request — URL, params, headers, or body. CALLSTACK resolves variables at send time against the active environment.

URL example
{{BASE_URL}}/api/v2/users/{{USER_ID}}/profile
Header example
Authorization: Bearer {{ACCESS_TOKEN}}
Body example
{
  "email": "{{TEST_EMAIL}}",
  "org_id": {{ORG_ID}}
}

Secrets

Variables marked as Secret are shown as masked (●●●●) in the UI. Hold the reveal button to peek at the value. Secrets are stored in plain text in the local SQLite database — they are not encrypted at rest.

Runtime Variable Changes

Pre/post scripts can read and write environment variables at runtime using env.get() and env.set(). Runtime changes are not persisted back to the saved environment — they apply only for the current request execution.

Recursive Variables

Environment variables can reference other variables in the same environment using {{variableName}} syntax. CALLSTACK resolves them recursively at send time:

Environment variables
BASE_URL   = https://api.example.com
API_V2     = {{BASE_URL}}/v2
USERS_URL  = {{API_V2}}/users   → resolves to https://api.example.com/v2/users

Circular references are detected and left unresolved. Resolved values are cached per send, so each unique key is resolved only once.

Dynamic Tokens

Use built-in $-prefixed tokens anywhere you use {{…}} — URL, headers, body, params — to inject randomly-generated or time-based values without writing scripts:

TokenOutputExample
{{$randomUUID}}UUID v4550e8400-e29b-41d4-a716-446655440000
{{$guid}}Alias for $randomUUID
{{$timestamp}}Unix timestamp (seconds)1713177600
{{$isoTimestamp}}ISO 8601 timestamp2024-04-15T12:00:00Z
{{$randomEmail}}Email addressjohn@example.com
{{$randomFullName}}Full nameJohn Doe
{{$randomInt}}Integer (0–1000)543
{{$randomIP}}IPv4 address192.168.1.1

25+ tokens are available covering names, addresses, network values, colours, and lorem text. All tokens are listed in the autocomplete dropdown when you type {{$ in any field.

💡
Quick tip Use the Variable Inspector (accessible from the URL bar) to see all variables currently in scope and their resolved values.

6 Pre/Post Scripts

Scripts are JavaScript that runs in a sandboxed environment — no filesystem access, no fetch, no Node APIs. Two hooks are available per request: Pre-request (before send) and Post-response (after response received).

Available APIs

request
The outgoing request: request.method, request.url, request.headers (array), request.params (array), request.body, request.json()
response
The incoming response: response.status, response.statusText, response.headers (array), response.body, response.time, response.json()
env
env.get('KEY') — read a variable. env.set('KEY', value) — write a variable for this execution.
secrets
secrets.get('KEY') — read a secret. secrets.set('KEY', value) — write a secret for this execution.
emitter
emitter.emit('key', value) — publish a value for downstream automation steps. emitter.get('key') — read a published value.
faker
faker.name(), faker.email(), faker.phone(), faker.address(), faker.uuid() and more — generate realistic test data.
test(desc, fn)
Assert conditions. test('status is 200', () => { if (response.status !== 200) throw new Error('Expected 200'); })

Examples

Extract a JWT from a login response:

Post-response script
const body = response.json();
if (body && body.token) {
  env.set('ACCESS_TOKEN', body.token);
  console.log('Token saved:', body.token.substring(0, 20) + '...');
}

Assert a successful response:

Post-response script
test('Status is 200', () => {
  if (response.status !== 200) throw new Error(`Expected 200, got ${response.status}`);
});

test('Response has user ID', () => {
  const body = response.json();
  if (!body.id) throw new Error('Missing user ID in response');
});

Generate fake data before sending:

Pre-request script
// Inject a random email into the request body
const email = faker.email();
const body = request.json();
body.email = email;
// Note: use env.set to pass data to the body via {{variables}}

Pass a value to the next automation step:

Post-response script
const userId = response.json().id;
emitter.emit('createdUserId', userId);
// Next step can use {{emitter.createdUserId}} in its URL
ℹ️
Script errors If a script throws an uncaught error, it is shown in the Request Log footer. The request still sends — scripts don't block execution unless they are in a pre-request hook with an explicit throw.

7 Automations

Automations let you build multi-step request workflows visually. Think of them as a flowchart of API calls — with loops, branching, parallel lanes, and CSV-driven data iteration.

Step Types

📡
RequestExecute a saved request
⏱️
DelayWait N milliseconds
🔁
RepeatLoop N times
📄
CSV IteratorLoop over data file rows
Set EnvSwitch active environment mid-run
🔀
BranchConditional if/else
FanoutParallel execution lanes
🛑
StopHalt the workflow
📝
LogEmit a message to the run log

Building a Workflow

  1. Open a project and click the Automations tab. Click + Automation.
  2. Add steps by clicking + in the visual builder. Choose a step type and configure it.
  3. For Request steps, select a saved request from the dropdown. You can pin an environment to each individual Request step — it overrides the automation's global environment for that step only.
  4. For CSV Iterator steps, select a data file from the project. Each row's columns become variables in nested steps.
  5. For Set Env steps, choose the environment to activate from that point forward in the run. Useful for workflows that cross environment boundaries (e.g. create in dev, verify in staging).
  6. Click Run to execute. Watch the progress indicator and collect test results.

Branch Conditions

A Branch step evaluates a condition and takes the "if" or "else" path:

  • Last request passed / failed (test results)
  • Last status code >= or < a threshold
  • Emitted variable equals, exists, or is truthy

Passing Data Between Steps

Use the emitter API in post-response scripts to pass values between steps:

Step 1 post-script
// After creating a user, capture the ID
emitter.emit('userId', response.json().id);
Step 2 URL
{{BASE_URL}}/api/users/{{emitter.userId}}/activate

Run History

Every automation run is saved with its start time, duration, overall status (PASS / FAIL / PARTIAL / ERROR), and a breakdown of each step's result. Access run history from the History tab in the automation editor.

8 Data Files

Data Files are CSV tables stored per-project. They power the CSV Iterator automation step, letting you run the same request against multiple rows of data.

Creating a Data File

  1. Open a project and click the Data tab.
  2. Click + Data File and give it a name.
  3. Add columns (e.g. userId, email, role).
  4. Add rows and fill in values. You can also import an existing CSV file.

Using in Automations

Add a CSV Iterator step to an automation and select the data file. Each row's column values are injected as template variables with the column name as the key:

URL in nested Request step
{{BASE_URL}}/api/users/{{userId}}

This will execute once per row, substituting {{userId}} with each row's userId value.

CSV Editor

The built-in grid editor supports:

  • Adding/removing rows and columns inline
  • Renaming columns by double-clicking the header
  • Filtering rows by column value
  • Sorting ascending/descending per column
  • Importing and exporting CSV files

9 Organisation & Navigation

Sidebar

The left sidebar lists all your projects. Click the chevron to expand a project and see its folders and requests. Click again to collapse. The expansion state is saved across sessions.

Folders

Create folders inside a project to group related requests. Folders can be nested. Drag a folder to a different position or into another project.

Drag-and-Drop Reordering

Grab any request, folder, or project by its drag handle and drop it to a new position. Reordering is persisted immediately.

Collapsing the Sidebar

Click the collapse button (at the bottom of the sidebar) to hide it entirely, giving your request and response panels more space. Click again to restore it. You can also resize the sidebar by dragging the border between the sidebar and main content.

Renaming & Cloning

  • Rename a request: double-click its name in the sidebar, or press R.
  • Clone a request: right-click in the sidebar and choose Duplicate, or press D.

10 Import & Export

Import from Postman

CALLSTACK can import Postman Collection v2.1 JSON files.

  1. In Postman, export your collection as Collection v2.1 (recommended).
  2. In CALLSTACK, click the Import button in the sidebar header.
  3. Select your .json file. A preview shows all importable requests.
  4. Check/uncheck items, then click Import Selected.

CALLSTACK preserves folder structure, headers, query params, and body from Postman collections.

Export to Callstack Format

Export one or more projects with the native Callstack format (JSON with optional response history and file attachments).

  1. Click the Export button (three dots → Export) on a project.
  2. Choose what to include: response history, environment variables, inline attachments.
  3. Save the .callstack.json file.

Curl Export

Any request in the Request Log can be exported as a curl command. Click on a log entry, then click Copy curl.

Export to Postman Format

Export your projects back to Postman v2.1 format for sharing with teammates who use Postman. Use Export → Postman from the project menu.

11 Request Log

The Request Log is a collapsible footer panel that records every request sent in the current session. It's useful for debugging, auditing, and generating curl commands.

Log Columns

ColumnDescription
TimestampDate and time the request was sent (YYYY-MM-DD HH:MM:SS)
MethodHTTP method with colour-coded badge
URLFull resolved URL (variables substituted)
StatusHTTP status code
TimeResponse time in ms
SizeResponse body size in bytes

Curl Export

Click any log entry to expand it. Click Copy curl to copy the equivalent curl command for the request, including all headers and body. Useful for sharing requests with teammates or reproducing issues in CI/CD.

Example curl output
curl -X POST https://api.example.com/v1/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGci..." \
  -d '{"email":"user@example.com","role":"admin"}'

Clear Log

Click Clear in the log header to wipe the current session's log. This does not affect saved responses in the database.

12 Keyboard Shortcuts

Default Shortcuts

ShortcutAction
Send request
NNew request
RRename request
DDuplicate request
SSave response to file
CCopy response body (works globally, even inside editors)
F1F12Quick-launch assigned requests

On Windows and Linux, use Ctrl instead of .

F-Key Quick Launch

Assign any request to an F1–F12 key for instant access. Right-click a request in the sidebar and choose Assign shortcut. Press that F-key from anywhere in the app to jump directly to that request and trigger a send.

Customising Shortcuts

  1. Open Settings (gear icon in the header).
  2. Click the Shortcuts tab.
  3. Click the shortcut you want to change and press the new key combination.
  4. Click Save.

13 Theming

CALLSTACK supports four appearance modes. Toggle via the icon in the top-right header:

ModeDescription
DarkDeep navy background, teal accents. Easy on the eyes for long coding sessions.
LightClean white background, darker accents. Great for bright environments.
DimSofter dark theme with reduced contrast — a middle ground.
SystemAutomatically follows your OS dark/light preference.

Your theme preference is saved locally and persists across sessions.

14 Settings

Open Settings via the gear icon in the top-right of the header.

SettingDescription
Zoom LevelScale the UI from 100% to 150%. Useful on high-DPI or small screens.
ThemeDark / Light / Dim / System
ShortcutsCustomise key bindings for all actions
Reset All SettingsRestore defaults (shortcuts, zoom, theme)
Clear All DataDestructive. Wipes the entire local database. Irreversible.
⚠️
Backup before clearing data Use Export on each project before using Clear All Data. This action cannot be undone.

15 Advanced Features

JWT Decoder

Quickly inspect any JSON Web Token without leaving CALLSTACK. Click the JWT button in the toolbar, paste your token, and the decoded header and payload are displayed as formatted JSON.

Template Variable Inspector

While building a request, click the { } inspector icon near the URL bar to see all {{variables}} currently in scope — from the active environment and emitter — along with their resolved values. Useful for debugging substitution issues.

Faker in Scripts

The faker object is available in all scripts:

Pre-request script
faker.name()          // "Alice Johnson"
faker.email()         // "alice.johnson@example.com"
faker.phone()         // "+1-555-123-4567"
faker.address()       // "123 Main St, Springfield"
faker.uuid()          // "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
faker.number(1, 100)  // 42

Multi-User Support

If multiple developers share one machine, each can sign in with their Google account (optional). Data — projects, requests, responses — is scoped to the signed-in user's email. Sign out to switch users. All data lives in the same local SQLite file but is namespaced by email.

Database Location

PlatformPath
macOS~/Library/Application Support/callstack/callstack.db
Linux~/.local/share/callstack/callstack.db
Windows%APPDATA%\callstack\callstack.db

You can back up this file at any time with a regular file copy. No special tool required.

16 Troubleshooting

Request times out

CALLSTACK enforces a 30-second timeout. If your server is slow to respond:

  • Check that the URL is reachable from your machine (try curl in a terminal).
  • Verify there are no OS-level firewall rules blocking outbound connections.
  • If using a VPN, ensure it allows traffic to the target host.

Variables not substituting

  • Ensure an environment is selected in the request builder (dropdown near the Send button).
  • Verify the variable key matches exactly — names are case-sensitive.
  • Use the Variable Inspector to see the list of available variables and their values.
  • Check there are no extra spaces inside the {{ }} braces.

Scripts not running / errors

  • Open the Request Log footer and expand the relevant log entry to see script error messages.
  • Ensure your JavaScript syntax is valid — the editor highlights syntax errors.
  • Check that you are reading response.json() only in post-response scripts (it is undefined in pre-request scripts).

Automation stopped early

  • Check branch conditions — a branch that evaluates to the "else" path may hit a Stop step unexpectedly.
  • If using CSV Iterator, verify the data file has rows and the row limit is not set too low.
  • Check the run history panel for the step that failed and its error message.

Postman import fails

  • CALLSTACK only supports Postman Collection v2.1 format. Export with "Collection v2.1 (recommended)" in Postman.
  • Very large collections (>1,000 requests) may take a few seconds to parse.

Data recovery

If the app crashes or the database becomes corrupted:

  1. Locate your database file (see Database Location).
  2. Open it with any SQLite viewer (e.g. DB Browser for SQLite) to inspect or export data manually.
  3. Replace the file with a previous backup if available.

Reporting bugs

Open an issue on GitHub Issues with:

  • Steps to reproduce
  • Expected vs. actual behaviour
  • Your platform and CALLSTACK version (visible in Settings → About)