fastify-xwhatconverts
fastify-xwhatconverts
WhatConverts lead tracking integration for Fastify v5. Decorates fastify.xWhatConverts with four service namespaces: leads (CRUD + constants), accounts (Agency Key required), profiles, and recordings. All methods validate inputs, attach the original WhatConverts error object on API failure, and expose structured error codes.
Installation
npm install @xenterprises/fastify-xwhatconverts
Quick Start
import Fastify from "fastify";
import xWhatConverts from "@xenterprises/fastify-xwhatconverts";
const fastify = Fastify({ logger: true });
await fastify.register(xWhatConverts, {
token: process.env.WHATCONVERTS_TOKEN,
secret: process.env.WHATCONVERTS_SECRET,
});
// List recent phone call leads
const result = await fastify.xWhatConverts.leads.list({
leadType: "phone_call",
leadsPerPage: 50,
});
await fastify.listen({ port: 3000 });
Options
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
token | string | — | Yes | WhatConverts API token. |
secret | string | — | Yes | WhatConverts API secret. |
baseUrl | string | "https://app.whatconverts.com/api/v1" | No | API base URL override. |
active | boolean | true | No | Set false to skip plugin registration. |
Methods
Leads (fastify.xWhatConverts.leads)
- leads.list(params?) — List leads with optional filters.
- leads.get(leadId, params?) — Get a single lead by ID.
- leads.create(params) — Create a new lead.
- leads.update(leadId, params) — Update an existing lead.
- leads.delete(leadId) — Delete a lead by ID.
Accounts (fastify.xWhatConverts.accounts) — Agency Key required
- accounts.list(params?) — List accounts with optional filters.
- accounts.get(accountId) — Get a single account by ID.
- accounts.create(params) — Create a new account.
- accounts.update(accountId, params) — Update an existing account.
- accounts.delete(accountId) — Delete an account (removes all profiles, leads, and numbers).
Profiles (fastify.xWhatConverts.profiles)
- profiles.list(params?) — List profiles with optional filters.
- profiles.get(profileId) — Get a single profile by ID.
- profiles.create(params) — Create a new profile.
- profiles.update(profileId, params) — Update an existing profile.
- profiles.delete(profileId) — Delete a profile by ID.
Recordings (fastify.xWhatConverts.recordings)
- recordings.get(leadId) — Get the call recording as an
ArrayBuffer. - recordings.getBuffer(leadId) — Get the call recording as a Node.js
Buffer. - recordings.getUrl(leadId) — Construct the recording API URL without a network request.
Error Reference
| Error | Cause |
|---|---|
xwhatconverts: missing required option `token` (string), e.g. `app.register(xWhatConverts, { token: 'wc-token', secret: 'wc-secret' })` | Missing or non-string token at registration |
xwhatconverts: missing required option `secret` (string), e.g. `app.register(xWhatConverts, { token: 'wc-token', secret: 'wc-secret' })` | Missing or non-string secret at registration |
xwhatconverts: option `baseUrl` must be a string, e.g. `app.register(xWhatConverts, { token: 'wc-token', secret: 'wc-secret', baseUrl: 'https://app.whatconverts.com/api/v1' })` | Non-string baseUrl at registration |
[xWhatConverts] leads.get: leadId is required | leads.get() called without leadId |
[xWhatConverts] leads.create: params object is required | leads.create() called without a params object |
[xWhatConverts] leads.create: profileId is required | leads.create() missing profileId |
[xWhatConverts] leads.create: leadType is required | leads.create() missing leadType |
[xWhatConverts] leads.update: leadId is required | leads.update() called without leadId |
[xWhatConverts] leads.update: params object is required | leads.update() called without a params object |
[xWhatConverts] leads.delete: leadId is required | leads.delete() called without leadId |
[xWhatConverts] accounts.get: accountId is required | accounts.get() called without accountId |
[xWhatConverts] accounts.create: params object is required | accounts.create() called without a params object |
[xWhatConverts] accounts.create: accountName is required | accounts.create() missing accountName |
[xWhatConverts] accounts.update: accountId is required | accounts.update() called without accountId |
[xWhatConverts] accounts.update: params object is required | accounts.update() called without a params object |
[xWhatConverts] accounts.delete: accountId is required | accounts.delete() called without accountId |
[xWhatConverts] profiles.get: profileId is required | profiles.get() called without profileId |
[xWhatConverts] profiles.create: params object is required | profiles.create() called without a params object |
[xWhatConverts] profiles.create: accountId is required | profiles.create() missing accountId |
[xWhatConverts] profiles.create: profileName is required | profiles.create() missing profileName |
[xWhatConverts] profiles.update: profileId is required | profiles.update() called without profileId |
[xWhatConverts] profiles.update: params object is required | profiles.update() called without a params object |
[xWhatConverts] profiles.delete: profileId is required | profiles.delete() called without profileId |
[xWhatConverts] recordings.get: leadId is required | recordings.get() called without leadId |
[xWhatConverts] recordings.getBuffer: leadId is required | recordings.getBuffer() called without leadId |
[xWhatConverts] recordings.getUrl: leadId is required | recordings.getUrl() called without leadId |
[xWhatConverts] Network error: <message> | Network-level failure (DNS, timeout, connection refused); error has code: "XWHATCONVERTS_NETWORK_ERROR" |
[xWhatConverts] API error: <status> | Non-2xx response from WhatConverts API; error has code: "XWHATCONVERTS_API_ERROR" plus statusCode and whatConvertsError |
Environment Variables
The plugin never reads process.env. All configuration arrives via app.register(xWhatConverts, options). These variables are a consumer-side convention — your app owns env access and passes the values in as options:
| Variable | Passed as | Description |
|---|---|---|
WHATCONVERTS_TOKEN | token | API token from the WhatConverts dashboard. |
WHATCONVERTS_SECRET | secret | API secret from the WhatConverts dashboard. |
await fastify.register(xWhatConverts, {
token: process.env.WHATCONVERTS_TOKEN,
secret: process.env.WHATCONVERTS_SECRET,
});
How It Works
On registration the plugin validates token and secret, builds a Basic Auth header from them, then decorates fastify.xWhatConverts with four service namespaces (leads, accounts, profiles, recordings). All JSON service methods share a common apiRequest helper that sets Authorization and Content-Type, handles both JSON and empty responses, and wraps failures as structured errors with code, statusCode, and whatConvertsError. The recordings service uses apiBinaryRequest which returns the raw response body as an ArrayBuffer. API credentials are held in closure scope and are never exposed on the decorator.
AI Context
package: "@xenterprises/fastify-xwhatconverts"
type: fastify-plugin
use-when: WhatConverts lead tracking — lead CRUD, account management (Agency Key), profile management, call recording retrieval
decorator: fastify.xWhatConverts (leads, accounts, profiles, recordings)
env: WHATCONVERTS_TOKEN, WHATCONVERTS_SECRET
accounts: requires Agency Key (token/secret from agency account)
error-shape: { code, statusCode, whatConvertsError } on API failures
