1 Getting Started
System Requirements
| Platform | Minimum Version | Notes |
|---|---|---|
| macOS | 10.13 (High Sierra) | Apple Silicon and Intel supported |
| Linux | glibc 2.29+ | AppImage works on most distros |
| Windows | Windows 10 | x64 only |
Installation
macOS (recommended) — via Homebrew:
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
- Open CALLSTACK from your Applications folder (or wherever you installed it).
- The app creates a local SQLite database at
~/Library/Application Support/callstack/callstack.db(macOS) or the equivalent on your platform. - 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.
- Create your first project using the + Project button in the sidebar.
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
- Build — Set method, URL, params, headers, body, and scripts.
- Pre-script — JavaScript runs before the request is sent (modify variables, generate data).
- Send — Rust HTTP client sends the request (no CORS, full header control).
- Post-script — JavaScript runs with the response (extract tokens, run assertions).
- 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:
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.
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
- Open a project and click the Environments tab.
- Click + Environment and give it a name (e.g. "Development").
- Add key-value pairs. Mark sensitive values as Secret to mask them in the UI.
- 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.
{{BASE_URL}}/api/v2/users/{{USER_ID}}/profile
Authorization: Bearer {{ACCESS_TOKEN}}
{
"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:
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:
| Token | Output | Example |
|---|---|---|
{{$randomUUID}} | UUID v4 | 550e8400-e29b-41d4-a716-446655440000 |
{{$guid}} | Alias for $randomUUID | |
{{$timestamp}} | Unix timestamp (seconds) | 1713177600 |
{{$isoTimestamp}} | ISO 8601 timestamp | 2024-04-15T12:00:00Z |
{{$randomEmail}} | Email address | john@example.com |
{{$randomFullName}} | Full name | John Doe |
{{$randomInt}} | Integer (0–1000) | 543 |
{{$randomIP}} | IPv4 address | 192.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.
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.method, request.url, request.headers (array), request.params (array), request.body, request.json()response.status, response.statusText, response.headers (array), response.body, response.time, response.json()env.get('KEY') — read a variable. env.set('KEY', value) — write a variable for this execution.secrets.get('KEY') — read a secret. secrets.set('KEY', value) — write a secret for this execution.emitter.emit('key', value) — publish a value for downstream automation steps. emitter.get('key') — read a published value.faker.name(), faker.email(), faker.phone(), faker.address(), faker.uuid() and more — generate realistic test data.test('status is 200', () => { if (response.status !== 200) throw new Error('Expected 200'); })Examples
Extract a JWT from a login response:
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:
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:
// 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:
const userId = response.json().id;
emitter.emit('createdUserId', userId);
// Next step can use {{emitter.createdUserId}} in its URL
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
Building a Workflow
- Open a project and click the Automations tab. Click + Automation.
- Add steps by clicking + in the visual builder. Choose a step type and configure it.
- 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.
- For CSV Iterator steps, select a data file from the project. Each row's columns become variables in nested steps.
- 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).
- 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:
// After creating a user, capture the ID
emitter.emit('userId', response.json().id);
{{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
- Open a project and click the Data tab.
- Click + Data File and give it a name.
- Add columns (e.g.
userId,email,role). - 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:
{{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.
- In Postman, export your collection as Collection v2.1 (recommended).
- In CALLSTACK, click the Import button in the sidebar header.
- Select your
.jsonfile. A preview shows all importable requests. - 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).
- Click the Export button (three dots → Export) on a project.
- Choose what to include: response history, environment variables, inline attachments.
- Save the
.callstack.jsonfile.
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
| Column | Description |
|---|---|
| Timestamp | Date and time the request was sent (YYYY-MM-DD HH:MM:SS) |
| Method | HTTP method with colour-coded badge |
| URL | Full resolved URL (variables substituted) |
| Status | HTTP status code |
| Time | Response time in ms |
| Size | Response 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.
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
| Shortcut | Action |
|---|---|
| ⌘↩ | Send request |
| ⌘N | New request |
| ⌘R | Rename request |
| ⌘D | Duplicate request |
| ⌘S | Save response to file |
| ⌘C | Copy response body (works globally, even inside editors) |
| F1–F12 | Quick-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
- Open Settings (gear icon in the header).
- Click the Shortcuts tab.
- Click the shortcut you want to change and press the new key combination.
- Click Save.
13 Theming
CALLSTACK supports four appearance modes. Toggle via the icon in the top-right header:
| Mode | Description |
|---|---|
| Dark | Deep navy background, teal accents. Easy on the eyes for long coding sessions. |
| Light | Clean white background, darker accents. Great for bright environments. |
| Dim | Softer dark theme with reduced contrast — a middle ground. |
| System | Automatically 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.
| Setting | Description |
|---|---|
| Zoom Level | Scale the UI from 100% to 150%. Useful on high-DPI or small screens. |
| Theme | Dark / Light / Dim / System |
| Shortcuts | Customise key bindings for all actions |
| Reset All Settings | Restore defaults (shortcuts, zoom, theme) |
| Clear All Data | Destructive. Wipes the entire local database. Irreversible. |
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:
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
| Platform | Path |
|---|---|
| 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
curlin 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:
- Locate your database file (see Database Location).
- Open it with any SQLite viewer (e.g. DB Browser for SQLite) to inspect or export data manually.
- 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)