@xenterprises/fastify-xwhatconverts
v1.3.0
Published
Fastify plugin for WhatConverts lead tracking API integration
Readme
@xenterprises/fastify-xwhatconverts
Fastify plugin for the WhatConverts lead tracking API. It gives consuming applications a single fastify.xWhatConverts namespace with lead, account, profile, and call-recording operations — no SDK, just a thin authenticated wrapper over the WhatConverts REST API.
Installation
npm install @xenterprises/fastify-xwhatconverts fastify@5Minimal example
import Fastify from "fastify";
import xWhatConverts from "@xenterprises/fastify-xwhatconverts";
const fastify = Fastify({ logger: true });
await fastify.register(xWhatConverts, {
token: process.env.WHATCONVERTS_TOKEN, // consumer owns env access
secret: process.env.WHATCONVERTS_SECRET,
});
const result = await fastify.xWhatConverts.leads.list({ leadType: "phone_call" });Options
All configuration arrives via app.register(xWhatConverts, options). The plugin never reads process.env — pass credentials in from your own config layer.
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| token | string | Yes | — | WhatConverts API token |
| secret | string | Yes | — | WhatConverts API secret |
| baseUrl | string | No | https://app.whatconverts.com/api/v1 | API base URL override |
| active | boolean | No | true | Set false to disable the plugin (no decorators added) |
Generate API keys in your WhatConverts dashboard:
- Profile API Key: Account Profile → Tracking → Integrations (1,000 requests/day)
- Master API Key: Master Integrations — Agency plan required (10,000 requests/day)
Decorators
The plugin decorates the Fastify instance with a single namespace, fastify.xWhatConverts, containing four services. Credentials are held in closure scope and are never exposed on the decorator.
| Property | Description |
|----------|-------------|
| fastify.xWhatConverts.leads | Lead CRUD operations and constants |
| fastify.xWhatConverts.accounts | Account CRUD operations (Agency Key required) |
| fastify.xWhatConverts.profiles | Profile CRUD operations |
| fastify.xWhatConverts.recordings | Call recording retrieval |
Leads service
leads.list(params?)
List leads with optional filtering.
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| leadsPerPage | number | 25 | Results per page (max 250) |
| pageNumber | number | 1 | Page number |
| accountId | string | — | Filter by account |
| profileId | string | — | Filter by profile |
| leadType | string | — | phone_call, form, chat, transaction |
| leadStatus | string | — | unique, repeat |
| startDate | string | — | Start date (YYYY-MM-DD) |
| endDate | string | — | End date (YYYY-MM-DD) |
| order | string | — | asc or desc |
| quotable | boolean | — | Filter quotable leads |
| spam | boolean | — | Filter spam leads |
| duplicate | boolean | — | Filter duplicate leads |
leads.get(leadId, params?)
Get a single lead by ID. params.customerJourney (boolean) includes the customer journey (Elite plans only).
leads.create(params)
Create a new lead. profileId and leadType are required; optional fields: sendNotification, dateTime (YYYY-MM-DD HH:MM:SS), quotable, quoteValue, salesValue, leadSource, leadMedium, leadCampaign, leadContent, leadKeyword, contactName, contactEmail, contactPhone, leadUrl, additionalFields.
const newLead = await fastify.xWhatConverts.leads.create({
profileId: "your-profile-id",
sendNotification: true,
leadType: "form",
contactName: "John Doe",
contactEmail: "[email protected]",
});leads.update(leadId, params)
Update an existing lead. Optional fields: quotable, quoteValue, salesValue, leadUrl, additionalFields.
leads.delete(leadId) / leads.remove(leadId)
Delete a lead by ID (delete is an alias of remove).
Lead constants
const { leadTypes, leadStatuses } = fastify.xWhatConverts.leads;
leadTypes.PHONE_CALL // "phone_call"
leadTypes.FORM // "form"
leadTypes.CHAT // "chat"
leadTypes.TRANSACTION // "transaction"
leadStatuses.UNIQUE // "unique"
leadStatuses.REPEAT // "repeat"Accounts service
Requires Agency Key (Master API Key) for all operations.
accounts.list(params?)
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| accountsPerPage | number | 25 | Results per page (max 250) |
| pageNumber | number | 1 | Page number |
| startDate | string | — | Start date (ISO 8601) |
| endDate | string | — | End date (ISO 8601) |
| order | string | — | asc or desc |
accounts.get(accountId)
Get a single account by ID.
accounts.create(params)
accountName (string) is required; createProfile (boolean) optionally creates a default profile.
accounts.update(accountId, params)
Update an existing account (accountName).
accounts.delete(accountId) / accounts.remove(accountId)
Delete an account. Warning: removes all profiles, numbers, leads, and settings.
Profiles service
profiles.list(params?)
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| profilesPerPage | number | 25 | Results per page (max 250) |
| pageNumber | number | 1 | Page number |
| accountId | string | — | Filter by account |
| startDate | string | — | Start date (ISO 8601) |
| endDate | string | — | End date (ISO 8601) |
| order | string | — | asc or desc |
profiles.get(profileId)
Get a single profile by ID.
profiles.create(params)
accountId and profileName (strings) are required; profileUrl is optional.
profiles.update(profileId, params)
Update profileName and/or profileUrl.
profiles.delete(profileId) / profiles.remove(profileId)
Delete a profile by ID.
Recordings service
recordings.get(leadId)
Get the MP3 recording for a lead as an ArrayBuffer.
recordings.getBuffer(leadId)
Get the MP3 recording for a lead as a Node.js Buffer.
import { writeFile } from "node:fs/promises";
const buffer = await fastify.xWhatConverts.recordings.getBuffer("123456");
await writeFile("recording.mp3", buffer);recordings.getUrl(leadId)
Get the API URL for a recording (does not make a request).
Exported constants
import { LEAD_TYPES, LEAD_STATUSES, SORT_ORDERS } from "@xenterprises/fastify-xwhatconverts";
LEAD_TYPES // ["phone_call", "form", "chat", "transaction"]
LEAD_STATUSES // ["unique", "repeat"]
SORT_ORDERS // ["asc", "desc"]Routes
None. The plugin only decorates the Fastify instance; it adds no routes.
Error behavior
Registration fails fast when required options are missing or invalid:
xwhatconverts: missing required option `token` (string), e.g. `app.register(xWhatConverts, { token: 'wc-token', secret: 'wc-secret' })`
xwhatconverts: missing required option `secret` (string), e.g. `app.register(xWhatConverts, { token: 'wc-token', secret: 'wc-secret' })`
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' })`Method-level validation errors throw standard Errors with an [xWhatConverts] prefix, e.g. [xWhatConverts] leads.get: leadId is required.
API call failures throw Errors with a code property:
| Code | Description |
|------|-------------|
| XWHATCONVERTS_API_ERROR | WhatConverts API returned a non-2xx status. Error includes statusCode and whatConvertsError properties. |
| XWHATCONVERTS_NETWORK_ERROR | Network-level failure (DNS, timeout, connection refused). |
try {
await fastify.xWhatConverts.leads.get("bad-id");
} catch (err) {
if (err.code === "XWHATCONVERTS_API_ERROR") {
console.error(err.statusCode); // 404
console.error(err.whatConvertsError); // { message: "Lead not found" }
}
}API errors are logged via fastify.log with the endpoint, status, and error message only — credentials and raw response payloads are never logged.
Rate limits
- Profile API key: 1,000 requests per day
- Master API key: 10,000 requests per day
- Maximum: 1 request per millisecond, 20 concurrent requests
Requirements
- Node.js >= 20
- Fastify >= 5 (peer dependency)
License
All Rights Reserved — X Enterprises. See LICENSE.
