Skip to main content
Version: v0.23.5

Contribute to OpenWA

This guide takes you from a fresh clone to a merged pull request: set up the dev environment on Node 22, find your way around the codebase, and run the same checks CI runs before you push.

Every contribution counts — a typo fix, a new endpoint, a test, a doc clarification. The conventions below keep review fast and keep main releasable.

The canonical repository is github.com/rmyndharis/OpenWA. This page targets OpenWA v0.23.5.

Prerequisites
  • Node.js 22.19 or newer and npm 10+. That minor is the package's engines floor, set by the bundled undici; CI builds and tests on Node 22, so match it locally to avoid surprises.
  • Git and a GitHub account.
  • That's all you need for a default setup — OpenWA defaults to SQLite and local-disk storage, and runs with no cache at all unless you enable Redis, so no Postgres, Redis, or S3 is required to run it.

Set up your fork​

Fork the repository on GitHub, then clone your fork and wire up upstream so you can pull in changes later.

# 1. Clone your fork (replace YOUR_USERNAME)
git clone https://github.com/YOUR_USERNAME/OpenWA.git
cd OpenWA

# 2. Track the canonical repo as "upstream"
git remote add upstream https://github.com/rmyndharis/OpenWA.git

# 3. Install dependencies (this also installs the dashboard's deps)
npm install

npm install runs a postinstall hook that installs the dashboard's dependencies under dashboard/, so you don't install them separately.

Run the dev server​

Start the API and the dashboard together with one command:

npm run dev

This runs the NestJS API (hot-reload) and the React/Vite dashboard concurrently. On first boot the API writes a minimal config to data/.env.generated (SQLite + local storage) and generates a random admin API key in data/.api-key — so the server runs with zero manual configuration.

The API listens on port 2785 behind the global /api prefix. Confirm it's up:

curl http://localhost:2785/api/health -H "X-API-Key: YOUR_API_KEY"
{
"status": "ok",
"timestamp": "2026-06-26T12:00:00.000Z",
"version": "0.23.5"
}

GET /api/health is public — it needs no API key (only its version field, since v0.19.0, is disclosed to key-bearing requests). Every other endpoint requires the X-API-Key: YOUR_API_KEY header, where YOUR_API_KEY is the key in data/.api-key. See Configuration for the full list of environment variables.

Run only the API

If you don't need the dashboard, run npm run start:dev to start just the API in watch mode.

How the project is laid out​

OpenWA is a NestJS API with a React/Vite dashboard and five published client SDKs in one repository.

OpenWA/
├── src/ # NestJS API
│ ├── main.ts # Application entry point
│ ├── common/ # Shared cache, security, storage, errors, utils
│ ├── config/ # Env validation, bootstrap, Swagger
│ ├── core/ # Hook and plugin framework
│ ├── database/ # TypeORM data sources and migrations
│ ├── engine/ # WhatsApp engine abstraction, adapters, and the
│ │ # built-in engine plugins under engine/builtin/
│ └── modules/ # API feature modules (sessions, messages, …)
├── test/ # End-to-end smoke tests
├── dashboard/ # React/Vite dashboard
├── sdk/ # JavaScript, Python, PHP, Java, and Go SDKs
└── docs/ # Repo documentation

Twenty-four of the feature modules under src/modules/ each back one of the API's 24 resource tags (the other seven directories hold no controller) — see the Introduction for the grouped list. The API Reference documents every endpoint these modules expose.

A controller validates the request, calls a capability service, and the service talks to the WhatsApp engine through an adapter. Controllers stay thin: they must not import the engine interface or call getEngine() directly — an ESLint rule enforces this. Engine-specific behavior lives behind the capability services and engine adapters.

Branch and commit​

Create a focused branch off main with a descriptive prefix:

git switch -c feature/add-label-filtering
PrefixUse for
feature/New functionality
bugfix/Bug fixes
hotfix/Urgent production fixes
docs/Documentation only
refactor/Restructuring without behavior change
test/Adding or fixing tests

Conventional Commits​

Commit messages follow Conventional Commits:

<type>(<scope>): <description>

Use one of these types: feat, fix, docs, style, refactor, perf, test, chore. The scope is the affected module or area.

feat(sessions): support multiple proxy configurations
fix(webhooks): retry delivery after a slow-connection timeout
docs(api): clarify the message-status response shape

The first line is the subject. Add a body for the "why" and a footer to link issues (Closes #123).

Run the checks CI runs​

Run these locally before you open a pull request. They are the gates that fail most often, but they are not the whole of CI.

npm run build # NestJS build (nest build)
npx tsc --noEmit -p tsconfig.json # type-checks the specs `nest build` skips
npm test # unit tests (Jest)
npm run test:docs # repo-file drift gates
npm run test:scripts # node:test specs for scripts/
npm run lint # ESLint
npm run format # Prettier (writes changes in place)
npm run dashboard:build # dashboard type-check + build

CI runs more than this list: the OpenAPI snapshot diff (npm run openapi:check), the SDK route, coverage, event, and doc checks, the version and .dockerignore checks, the dependency audit, a PostgreSQL migration lane, the Helm chart and workflow lint, and the dashboard's own lint, format, type-check, i18n, and unit tests. .github/workflows/ci.yml is the full list.

For changes that cross module boundaries, also run the end-to-end smoke tests:

npm run test:e2e
CommandWhat it does
npm testRuns the unit lane with Jest. Two dozen repo-file drift-gate specs are excluded from it and run in npm run test:docs instead, so run both before you push. It collects no coverage, so the thresholds are not enforced locally; CI runs the same lane with --coverage and does enforce them.
npm run test:docsRuns the excluded drift-gate specs, which check repo files (docs, manifests, Compose files, workflows) against the code they describe. CI runs it as its own step.
npm run test:covRuns the suite with coverage and enforces the thresholds: a global floor (68% lines, 67% statements, 61% branches, 70% functions) plus a separate floor for each of 35 directories, so a change confined to one module is measured against that module's own bar. Security code under src/common/security/ carries one of the strictest (93% lines, 92% statements, 95% functions, 85% branches).
npm run test:e2eBoots the app and runs the end-to-end smoke tests in test/.
npm run lint:fixAuto-fixes lint violations where possible.
npm test -- session.service.spec.tsRuns a single test file.

Add or update tests for any behavior change. Unit tests live next to the code as *.spec.ts; end-to-end smoke tests live in test/.

Code style​

Prettier and ESLint enforce style — run npm run format before committing so review focuses on substance, not whitespace.

AreaConvention
FormattingSingle quotes, 2-space indentation, 120-column width, semicolons.
TypesExplicit types; any is disallowed (noImplicitAny).
Fileskebab-case (send-message.dto.ts); classes PascalCase; functions and variables camelCase; constants UPPER_SNAKE_CASE.
RequestsValidate request bodies with DTOs and class-validator decorators.
Errors & loggingThrow NestJS HTTP exceptions; log through the project Logger (or LoggerService / createLogger), never console.*.

Database changes​

OpenWA uses TypeORM. Any change to a persisted entity needs a migration under src/database/migrations/ — do not rely on schema auto-sync.

# Generate a migration from your entity changes
npm run migration:generate --name=AddLabelColorColumn

# Apply pending migrations
npm run migration:run

Before you open a large PR​

A few rules keep the project stable. Skim these before investing in a big change.

The REST API is the public contract

Response shapes and HTTP status codes are what users depend on. Don't change them without first opening an issue to agree on the approach. The OpenAPI spec is the source of truth.

  • Keep each PR to one logical change. Smaller PRs review faster and are easier to credit and revert.
  • Regenerate the contract when you change a route or a DTO. Run npm run openapi:export and commit the updated openapi.json. CI regenerates the snapshot and diffs it against the committed file, so a route change without a refreshed openapi.json fails the build.
  • Some message types are engine-limited. The default engine is whatsapp-web.js, which doesn't support interactive Buttons or List messages — a PR adding them won't function against the default engine. Confirm engine support before building engine-specific features.
  • Discuss architecture first. For new frameworks, large rewrites, or anything touching the engine abstraction, open an issue to align before writing code.
  • Update the docs and changelog. When a change is user-visible, update the relevant docs/ page and the [Unreleased] section of CHANGELOG.md. Maintainers own version stamping and releases.

A passing CI run and a maintainer approval are required to merge.

Report a bug or request a feature​

Open an issue using the Bug report or Feature request template on GitHub. The structured fields — version, deployment, engine, logs, reproduction steps — make triage far faster. Check Troubleshooting & FAQ first; many common problems are already answered there.

Security issues

Do not open a public issue for a security vulnerability. Follow the private disclosure process in the repository's SECURITY.md.

Open your pull request​

# Push your branch to your fork
git push -u origin feature/add-label-filtering

Then open a pull request against rmyndharis/OpenWA's main branch on GitHub. Fill in the PR template: describe the change, link related issues, and check that tests, lint, and the build pass.

By participating you agree to the project's Community Guidelines and Code of Conduct. Contributions are licensed under the project's MIT License.

Next steps​

  • Quick start — run OpenWA end to end before changing it.
  • API conventions — the auth, error envelope, and status codes your changes must respect.
  • API reference — the generated spec, the contract every endpoint change is measured against.