14 KiB
APIClient - Agent
AI-first API testing desktop client - built with Python + PyQt6. Specialised for the EKIKA Odoo API Framework, but works with any REST, GraphQL, or WebSocket API.
Features
Core API Testing
- Multi-tab request editor - work on multiple requests simultaneously, drag to reorder
- All HTTP methods - GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
- Smart params & headers table - per-row enable/disable checkboxes, 36 px comfortable rows, auto-expanding blank row
- Body editor - raw JSON/XML/text with syntax highlighting, Format JSON button,
application/vnd.api+jsonsupport - Auth panel - Bearer Token, Basic Auth, API Key (header or query)
- Pre-request scripts - Python executed before each request; access
pm.environment.get/set - Test scripts - assertions auto-run after every response;
pm.test(...)/expect(...)DSL - Response viewer - syntax-highlighted body, headers table, test results, search, copy, save
- WebSocket client - connect, send, receive, log messages
- Mock server - local HTTP mock with configurable routes
Collections & Environments
- Collections sidebar - import/export Postman Collection v2.1 JSON, cURL
- Environment variables -
{{base_url}},{{api_key}}, etc. resolved at send time; per-environment values - Collection runner - run all requests in a collection, view pass/fail results
- History - every sent request automatically saved
AI Co-pilot (Claude-powered)
- Persistent AI chat sidebar - toggle with the
✦ AIbutton orCtrl+Shift+A - Full context awareness - AI sees your current request (method, URL, headers, body, params, test scripts) and the last response (status, body, errors); secrets are automatically redacted
- Streaming responses - tokens stream in real time
- One-click Apply - AI suggestions come with Apply Body, Apply Params, Apply Headers, Apply Test Script buttons that set the values directly in the request editor
- Multi-turn conversation - full history maintained per session; Clear to reset
- Quick actions - Analyze, Fix Error, Gen Body, Write Tests, Auth Help, Explain Response
- EKIKA Odoo collection generator - generate complete collections for JSON-API, REST JSON, GraphQL, and Custom REST JSON without spending AI tokens; supports all auth types
EKIKA Odoo API Framework specialisation
- Generates full CRUD + Execute / Export / Report / Fields / Access-Rights endpoints per model
- Auth types: API Key (
x-api-key), Basic Auth, User Credentials, OAuth2, JWT, Public - Correct JSON-API body format out of the box:
{"data": {"type": "sale.order", "attributes": {...}}} - Automatic environment creation with
base_url,api_key, tokens
Installation
Requirements
- Python 3.11+
- Linux, macOS, or Windows
git clone https://git.ekika.co/EKIKA.co/APIClient-Agent.git
cd APIClient-Agent
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
python main.py
requirements.txt
PyQt6>=6.6.0
httpx>=0.27.0
websockets>=12.0
anthropic>=0.25.0
pyyaml>=6.0
pyinstaller>=6.0.0
Quick Start
1 - Send your first request
- Launch the app:
python main.py - Type a URL in the bar, e.g.
https://jsonplaceholder.typicode.com/todos/1 - Press Send (or
Ctrl+Enter) - See the JSON response with syntax highlighting in the bottom panel
2 - Use environment variables
- Click Manage → New Environment → name it
My API - Add variables:
base_url = https://api.example.com api_key = your-secret-key - Select the environment in the top bar
- In the URL bar, type
{{base_url}}/v1/users - In Headers, add
Authorization: Bearer {{api_key}} - Variables are resolved automatically at send time
3 - Import a collection
From Postman export:
File → Import…- Paste Postman Collection v2.1 JSON or drop the file
From cURL:
File → Import… → paste:
curl -X POST https://api.example.com/v1/orders \
-H "Content-Type: application/json" \
-d '{"product_id": 42, "qty": 1}'
From OpenAPI spec:
Tools → AI Assistant → Import from Docs- Paste the OpenAPI JSON/YAML URL - parsed instantly, no AI tokens used
EKIKA Odoo API Framework - Complete Example
Generate a collection in 30 seconds
-
Open Tools → AI Assistant (or click
✦ AI→AI Assistantin the menu) -
Select the EKIKA Odoo API tab
-
Fill in:
Field Example Instance URL https://mycompany.odoo.comAPI Endpoint /user-jsonapi-apikeyAPI Kind JSON-APIAuth Type API KeyAPI Key EwKCljvZoHXsaGlxxvCHt1h4SvWLpuWWModels sale.order, res.partner, account.moveOperations ✓ List, Get, Create, Update, Delete -
Click Generate Collection - preview appears instantly
-
Click Import Both - collection + environment are saved
This generates the following requests for each model with zero AI tokens:
GET {{base_url}}/user-jsonapi-apikey/sale.order
GET {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
POST {{base_url}}/user-jsonapi-apikey/sale.order
PATCH {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
DELETE {{base_url}}/user-jsonapi-apikey/sale.order/{{id}}
Sending a JSON-API request
The generated Create sale.order request body:
{
"data": {
"type": "sale.order",
"attributes": {
"name": "New Order"
}
}
}
Headers sent automatically:
x-api-key: EwKCljvZoHXsaGlxxvCHt1h4SvWLpuWW
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
Filtering and pagination (List endpoint)
The List sale.order request includes query params:
page[number] = 1
page[size] = 10
fields[sale.order] = id,name,display_name,partner_id
sort = -id
To filter by customer, open the AI chat sidebar and ask:
"Add a filter param to get only sale orders for partner ID 7"
AI responds with an apply block you can apply in one click.
GraphQL example
Select API Kind: GraphQL. The generator creates:
List sale.order (GraphQL)
{
"query": "query {\n sale_order(\n filter: \"\"\n pageSize: 10\n pageNumber: 1\n ) {\n id\n name\n display_name\n }\n}"
}
Create sale.order (GraphQL)
{
"query": "mutation {\n create_sale_order(\n attributes: {\n name: \"New Record\"\n }\n ) {\n id\n name\n }\n}"
}
AI Chat Co-pilot - Example Session
Click ✦ AI in the top bar to open the sidebar. The AI automatically knows what request you have open and the last response.
Debugging a 401 error
You: I'm getting 401 Unauthorized on all my Odoo API requests.
AI: A 401 on the EKIKA JSON-API endpoint means the x-api-key header is
missing, empty, or incorrect.
Checklist:
1. Confirm your environment has api_key set (Tools → Environments)
2. Confirm the request Headers tab includes x-api-key: {{api_key}}
3. In Odoo, verify the API key is still active under your user's
API Framework settings
Here are the correct headers to apply:
┌─ apply:headers ──────────────────────────────────┐
│ x-api-key: {{api_key}} │
│ Accept: application/vnd.api+json │
└──────────────────────────────────────────────────┘
[ Apply Headers to Request ]
Click Apply Headers to Request - headers are set immediately and the Headers tab opens.
Generating a body for a complex model
You: Generate a body to create an invoice (account.move) for partner ID 14,
with one line for product ID 7, quantity 3, price 150.
AI: Here is a JSON-API compliant body for creating an account.move:
┌─ apply:body ─────────────────────────────────────┐
│ { │
│ "data": { │
│ "type": "account.move", │
│ "attributes": { │
│ "move_type": "out_invoice", │
│ "partner_id": 14, │
│ "invoice_line_ids": [[0, 0, { │
│ "product_id": 7, │
│ "quantity": 3, │
│ "price_unit": 150.0 │
│ }]] │
│ } │
│ } │
│ } │
└──────────────────────────────────────────────────┘
[ Apply Body to Request ]
Writing test scripts
You: Write tests to verify a successful JSON-API list response.
AI: ┌─ apply:test ─────────────────────────────────────┐
│ pm.test('Status 200', lambda: │
│ pm.response.to_have_status(200)) │
│ pm.test('Has data array', lambda: │
│ expect(pm.response.json()).to_have_key('data'))│
│ pm.test('Data is list', lambda: │
│ expect(pm.response.json()['data']).to_be_list())│
│ pm.test('Response time < 2s', lambda: │
│ expect(pm.response.response_time).to_be_below(2000))│
└──────────────────────────────────────────────────┘
[ Apply Test Script to Request ]
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+Enter |
Send request |
Ctrl+T |
New tab |
Ctrl+W |
Close tab |
Ctrl+S |
Save to collection |
Ctrl+F |
Search requests |
Ctrl+E |
Manage environments |
Ctrl+Shift+A |
Toggle AI chat sidebar |
Ctrl+Shift+F |
Format JSON body |
Escape |
Cancel in-flight request |
Ctrl+Q |
Quit |
Project Structure
APIClient-Agent/
├── main.py # Entry point
├── requirements.txt
├── LICENSE
├── app/
│ ├── models.py # HttpRequest, HttpResponse, Environment
│ ├── core/
│ │ ├── storage.py # SQLite persistence (collections, environments, history)
│ │ ├── http_client.py # httpx-based request engine, variable resolution
│ │ ├── ai_client.py # Claude API - collection generation from docs
│ │ ├── ai_chat.py # Claude API - multi-turn conversational co-pilot
│ │ ├── openapi_parser.py # OpenAPI 3.x / Swagger 2.0 local parser
│ │ ├── ekika_odoo_generator.py# EKIKA Odoo framework collection generator
│ │ ├── test_runner.py # pm.test / expect assertion engine
│ │ ├── mock_server.py # Local HTTP mock server
│ │ ├── code_gen.py # Code generation (curl, Python, JS, etc.)
│ │ ├── exporter.py # Postman Collection v2.1 export
│ │ └── importer.py # Postman Collection / cURL import
│ └── ui/
│ ├── main_window.py # Main window, splitter layout, env bar
│ ├── theme.py # Central QSS stylesheet engine (dark/light)
│ ├── request_panel.py # URL bar, params/headers/body/auth/tests editor
│ ├── response_panel.py # Response viewer with status badge
│ ├── tabs_manager.py # Multi-tab request manager
│ ├── sidebar.py # Collections tree sidebar
│ ├── ai_panel.py # AI Assistant dialog (collection generator)
│ ├── ai_chat_panel.py # AI chat sidebar (co-pilot)
│ ├── environment_dialog.py # Environment manager
│ ├── collection_runner.py # Collection runner
│ ├── websocket_panel.py # WebSocket client
│ ├── mock_server_panel.py # Mock server UI
│ ├── import_dialog.py # Import dialog
│ ├── code_gen_dialog.py # Code generation dialog
│ ├── search_dialog.py # Request search
│ └── highlighter.py # JSON syntax highlighter
Configuration
Settings are stored in an SQLite database at ~/.apiclient_agent/data.db (created automatically).
Anthropic API Key (for AI features)
- Get a key at console.anthropic.com
- In the app:
Tools → AI Assistant → Settings tab - Paste the key and click Save API Key
The key is stored locally in the SQLite database only - never transmitted except to the Anthropic API.
SSL / TLS Notes
Some servers (especially demo/development instances) use self-signed certificates or wildcard certificates that don't match the exact hostname. If you see:
SSL certificate error - could not connect to https://...
Tip: disable SSL verification in the request Settings tab.
Open the Settings tab in the request editor and uncheck Verify SSL certificate.
Building a Standalone Executable
pyinstaller --onefile --windowed \
--name "APIClient-Agent" \
--add-data "app:app" \
main.py
The executable is produced in dist/APIClient-Agent.
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m "Add my feature" - Push and open a pull request
Please keep UI styling in theme.py using setObjectName() selectors - never inline setStyleSheet() for static colors.
License
MIT License - Copyright (c) 2026 EKIKA.co
