Skip to content

API Lab for EspoCRM

Tip

This extension is actively used during day-to-day EspoCRM integration work. Feature requests and bug reports are welcome via GitHub Issues and will be reviewed within 1–3 weeks.

Warning

⚠️ CAUTION: This repository contains code developed with the assistance of Artificial Intelligence (AI). While functional, AI-generated code can introduce hidden bugs, security vulnerabilities, or logic flaws that may not be immediately apparent. Please thoroughly review, audit, and test all files in an isolated development environment before deployment, as this software is provided as-is and used entirely at your own risk.

πŸš€ Introduction

API Lab is a full API testing workbench built as an EspoCRM extension. It is a complete HTTP, GraphQL, SOAP, WebSocket and Server-Sent Events client that lives inside the CRM β€” build a request, sign it with any of twelve auth schemes, send it either from your browser or from the CRM server, assert on the response, and keep every send in a deletable conversation thread.

Everything it stores is an ordinary EspoCRM entity. Requests, collections, environments and history therefore get list views, search, filters, mass update, ACL and audit for free, with no parallel data model to learn.

The point of running it inside the CRM rather than in a desktop client is that the server engine reaches what the CRM host reaches, the browser engine carries your own EspoCRM session, and both share the same saved requests, the same variables and the same recorded history β€” so an integration you debugged by hand can be handed straight to a scheduled monitor.


πŸ”₯ Features

A complete request/response workbench covering building, signing, sending, asserting and scheduling β€” with the safety bounds that sending from a CRM server requires.

πŸ§ͺ Two Engines, One Request

The engine switch in the URL bar decides where the bytes leave from, not how the request is built. Both engines call the same server-side preparation step, so they send the same method, URL, headers and body.

PHP (server) runs libcurl on the CRM host: proxies, TLS verification toggles, client certificates, HTTP/1.0 through HTTP/3, custom DNS resolution, digest and NTLM auth, retries, a cookie jar, per-phase timings and a captured transport log. No CORS.

JavaScript (browser) uses fetch() from your own browser. It reaches hosts the server cannot (your VPN, your localhost), carries your EspoCRM session so you can test the CRM's own API as yourself, and speaks WebSocket and Server-Sent Events. It is subject to CORS, and the browser refuses to set Host, Cookie, User-Agent, Content-Length and friends β€” the viewer says explicitly which headers were dropped.

Assertions are always evaluated on the server, for both engines and for the monitor, so a test cannot pass in one place and fail in another.

πŸ” Authentication

Scheme PHP Browser
Basic, Bearer, API key (header/query/cookie), custom header βœ… βœ…
JWT bearer β€” HS256/384/512 βœ… βœ…
JWT bearer β€” RS256/384/512 βœ… βœ…
OAuth 1.0a β€” HMAC-SHA1, HMAC-SHA256, PLAINTEXT βœ… βœ…
OAuth 2.0 β€” client credentials, password, refresh token, authorization code + PKCE βœ… βœ…
AWS Signature v4 βœ… βœ…
EspoCRM API key / EspoCRM HMAC βœ… βœ…
Digest, NTLM βœ… β€”
TLS client certificates (mTLS) βœ… β€”

Signing always happens on the server, which is why the browser column is nearly full: the browser never receives the secret, it only sends the finished headers. OAuth 2.0 tokens are fetched server-side and cached on the environment, so the scheduled monitor can use them too.

πŸ“¦ Bodies

None Β· JSON Β· Text Β· XML Β· HTML Β· JavaScript Β· YAML Β· form URL-encoded Β· multipart form data (with real file uploads) Β· raw binary file Β· GraphQL (query + variables + operation name) Β· raw with no content type.

SOAP is plain XML plus a SOAPAction header β€” the XPath extractor makes the response usable.

βœ… Assertions & Extractors

Assertions are declarative rows, not code. Pick a source β€” status, status text, response time, size, a header, content type, body text, a JSON path, a cookie, redirect count or transport error β€” and one of 30 operators covering equality, contains, regex, numeric comparison, between, inList, isJson, isXml, hasKeys, countEquals and more.

Extractors pull a value out of a response β€” JSON path, header, cookie, regex, XPath, status or whole body β€” and write it back as a variable, either for this run only or saved into the environment. That is how a login response chains into every following request without scripting.

Pre-request scripts run in your browser before the send, with lab.setVar(), lab.getVar() and lab.draft. They are a convenience for interactive work; the scheduled monitor never runs them, which is why extractors exist.

πŸ—‚οΈ Collections, Environments & Variables

A collection groups requests and holds shared defaults: base URL, headers, query params, auth, transport settings and variables. An environment is a named set of variables, where any value can be marked secret so it is masked in stored history, and which also holds the OAuth 2.0 token cache.

Variables resolve collection β†’ environment β†’ request β†’ pre-request script, later winning. Dynamic helpers need no definition: {{$guid}}, {{$timestamp}}, {{$timestampMs}}, {{$isoTimestamp}}, {{$date}}, {{$randomInt:100}}, {{$randomHex:32}}, {{$randomAlpha:8}}, {{$randomEmail}}, {{$randomBoolean}}, {{$nonce}}.

The β–Ά collection runner sends every request in a collection in order into a single conversation, so extractor chains work end to end.

⏱️ Scheduled Monitors

Tick Monitored on a request, pick an interval, and the API Lab Monitor scheduled job re-runs it and records the result. Users listed under Notify on failure get a notification when a check changes between passing and failing β€” on the transition only, not on every interval.

πŸ’¬ Conversation History

Every send appends to a conversation thread against its request, with the full request, the response, timings, assertion results and the transport log. Deleting a conversation deletes its exchanges β€” bodies and tokens included. Secrets and auth credentials are masked before anything is written; the live response still shows you everything.

πŸ“₯ Import & Export

Paste a curl command straight into the URL bar and it is parsed into the builder β€” "Copy as cURL" from any browser devtools works. The Import dialog additionally accepts OpenAPI 3 / Swagger 2 (every operation becomes a request, with an example body generated from its schema and path parameters turned into variables), Postman v2/v2.1 collections, HAR captures (duplicates collapsed, static assets skipped), and API Lab's own export format.

Collections export as JSON from the sidebar; conversations export from the thread panel.

🧾 Code Generation

The </> button renders the prepared request as curl, HTTPie, raw HTTP, PHP (cURL / Guzzle / an EspoCRM job), JavaScript (fetch / axios), Node, Python, Go, Java, C#, Ruby or PowerShell.

πŸ›‘οΈ Safety Policy

The PHP engine can reach whatever the CRM host can reach. That is the point of it, and it is also the risk, so the bounds are explicit and visible. Sending is admin-only by default; every redirect hop is re-checked against the policy, and Authorization, Cookie and API-key headers are stripped when a redirect crosses to another origin. Response bodies are capped in transit and again in storage.

Config Key Default Meaning
apiLabAllowedSchemes ["http","https"] Schemes the PHP engine may use.
apiLabHostAllowList [] Glob patterns; empty means any host.
apiLabHostDenyList [] Glob patterns, checked first.
apiLabBlockPrivateNetworks false Resolve and refuse private/loopback/link-local addresses. Off by default because testing an internal API is a main use case.
apiLabMaxTimeout 120 Ceiling for the per-request timeout, in seconds.
apiLabMaxResponseSize 8388608 Bytes read from a response.
apiLabMaxStoredBodySize 262144 Bytes kept in the conversation record.
apiLabAllowNonAdminExecution false Let non-admins with record access send.
apiLabExchangeRetentionDays 0 Delete exchanges older than this. 0 keeps everything.

Keys live in data/config.php and are also editable from the workbench settings dialog.


πŸ—’οΈ Requirements

Requirement Value
EspoCRM 8.0.0 or newer (verified end-to-end on 10.0.7)
PHP 8.1 or newer (verified on 8.4)
PHP curl extension Required β€” the PHP engine is libcurl
PHP openssl extension Required only for RS256-signed JWTs
PHP yaml extension or Symfony YAML Required only for importing YAML OpenAPI documents
Administrator account Required to install and, by default, to send requests
Modern browser (Chrome, Firefox, Edge, Safari) Required for the JavaScript engine, WebSocket and SSE

πŸ› οΈ Usage

πŸ“¦ Installation

Download the latest ApiLab-<version>.zip from the _releases folder or from the GitHub Releases page, then go to Administration β†’ Extensions, upload the archive and click Install.

The installer adds an API Lab navigation group, creates the API Lab Monitor scheduled job, and writes the default safety policy into data/config.php so an administrator can see and edit it.

🧭 Opening the Workbench

Open API Lab from the navigation menu, or go to #ApiLab directly. Any API Request record also has an Open in Lab action on its detail view.

πŸ” A First Round Trip

  1. Create an API Collection and give it a base URL.
  2. Create an API Environment with the variables it needs, marking tokens and passwords as secret.
  3. Add an API Request, choose a method, and pick an engine in the URL bar.
  4. Send it. The response lands in a conversation thread with timings, headers and the transport log.
  5. Add an extractor to capture a token, and assertions to describe what "passing" means.
  6. Tick Monitored if the check should keep running on a schedule.

πŸ”Œ Extending & Integrating

Using the HTTP client from your own code

Espo\Modules\ApiLab\Core\HttpClient is usable from any of your own EspoCRM code β€” hooks, jobs, formula-adjacent services β€” with the same transport options the workbench exposes. The </> code generator emits a ready-made snippet for exactly this, so you can prototype a call in the workbench and paste a working version into your module.

REST endpoints

Beyond the standard record endpoints for the five entities:

Method Endpoint Purpose
GET ApiLab/action/bootstrap Everything the workspace needs, in one call.
GET ApiLab/action/conversations Conversation list, optionally per request.
GET ApiLab/action/exchanges The exchanges of one conversation.
POST ApiLab/action/prepare Resolve a request without sending it.
POST ApiLab/action/execute Send with the PHP engine and record it.
POST ApiLab/action/record Verify and record a browser-engine result.
POST ApiLab/action/oauthToken Fetch an OAuth 2.0 token.
POST ApiLab/action/oauthAuthorizeUrl Build an authorization URL with PKCE.
POST ApiLab/action/import curl / OpenAPI / Postman / HAR / native.
GET ApiLab/action/export Export a collection.
GET/POST ApiLab/action/settings Read or write the safety policy (admin).
GET ApiLab/action/systemInfo What this server's libcurl can actually do.

Known limits

  • WebSocket and SSE are browser-only; the PHP engine reports that rather than pretending.
  • gRPC is out of scope β€” it needs proto compilation.
  • The browser engine cannot report cookies or disable TLS verification; the browser owns both. Use the PHP engine.
  • HTTP/2 and HTTP/3 depend on how libcurl was built. The workbench reads the real capability list from the server and shows it under Settings.

πŸ“ Repository Structure

Path Description
.git/ Internal file, can be ignored.
.github/ Internal file, can be ignored.
_changelogs/ HTML changelogs for each released version.
_licenses/ Licenses of third-party components used by this project.
_licenses/THIRD-PARTY-LICENSES.md Full third-party library and license listing.
_releases/ Installable extension packages, one ZIP per release.
_source/ Unpacked extension source β€” manifest.json, files/, scripts/.
_source/README.md Technical documentation of the extension internals.
github_reset.bat / github_update.bat Internal file, can be ignored.
README.md This readme file.
CHANGELOG.md Pointer to the detailed changelogs.
CONTRIBUTING.md Contribution policy.
SECURITY.md Security policy and disclosure process.
PRIVACY.md Privacy notice.
LICENSE.md License file.

πŸ’¬ Support Channels

If you encounter any issues or have questions while using this software, feel free to contact us:


πŸ“’ Spread the Word

Help us grow by sharing this project with others! You can:

  • Tweet about it – Share your thoughts on Twitter/X and link us!
  • Post on LinkedIn – Let your professional network know about this project on LinkedIn.
  • Share on Reddit – Talk about it in relevant subreddits like r/selfhosted or r/opensource.
  • Tell Your Community – Spread the word in Discord servers, Slack groups, and forums.

🌱 Contributing to the Project

Thank you for your interest in this project.

At this time, this repository is not open for external contributions. Please do not submit pull requests or patches.

  • Pull requests from external contributors are not accepted.
  • Any unsolicited pull requests will be closed without review.
  • All code in this repository is maintained by the project owner.
  • By design, no third‑party code will be merged into this project via GitHub.

If you encounter a bug or have an enhancement suggestion, please check the "Issues" section of our GitHub repository or visit our official website for guidance before beginning any work on it.


🀝 Community Guidelines

We're focused on developing innovative solutions and advancing technology. By being part of this, you contribute to our progress.

Positive guidelines include being kind, empathetic, and respectful in all interactions. It is important to engage thoughtfully and offer constructive, solution-oriented feedback. Fostering an environment of collaboration, support, and mutual respect is essential.

Unacceptable behaviors include harassment, hate speech, or offensive language. Personal attacks, discrimination, or any form of bullying are not tolerated. Sharing private or sensitive information without explicit consent is strictly prohibited.

Together, we can partner to achieve common goals by following guidelines designed to promote effective collaboration and positive teamwork.


πŸ›‘οΈ Security Policy

I take security seriously and appreciate responsible disclosure. If you discover a vulnerability, please follow these steps:

  • Do not report it via public GitHub issues or discussions. Instead, please contact the security@bugfish.eu email address directly.
  • Provide as much detail as possible, including a description of the issue, steps to reproduce it, and its potential impact.

I aim to acknowledge reports within 2–4 weeks and will update you on our progress once the issue is verified and addressed.

This software is provided as-is, without any guarantees of security, reliability, or fitness for any particular purpose. We do not take responsibility for any damage, data loss, security breaches, or other issues that may arise from using this software. By using this software, you agree that We are not liable for any direct, indirect, incidental, or consequential damages. Use it at your own risk.


πŸ“œ License Information

The license for this software can be found in the LICENSE.md file. As an EspoCRM extension, this project is distributed under the GNU General Public License v3.0. The software may also include or depend on additional licensed software or libraries β€” these are documented in _licenses/THIRD-PARTY-LICENSES.md.

🐟 Bugfish

About

πŸ’Ό EspoCRM πŸš€ API Lab is a full API testing workbench built as an EspoCRM extension. It is a complete HTTP, GraphQL, SOAP, WebSocket and Server-Sent Events client that lives inside the CRM β€” build a request, sign it with any of twelve auth schemes, send it either from your browser or from the CRM server.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages