The Node.js example is a complete pull-first reference client for Node.js 20 or newer and uses only built-in modules. Start with the synthetic sandbox. Never log response bodies, link codes, cursors, random resource IDs, certificate material, or private-key passwords.
Download the complete Node.js source.
Requirements and environment#
Store the BOT certificate chain and locally generated private key outside the application directory with access restricted to the service account.
export BOT_CERT='/secure/path/bot-integration-certificate-chain.pem'
export BOT_KEY='/secure/path/bot-integration-client-key.pem'
export BOT_KEY_PASSWORD='load-this-from-your-secret-manager'
export BOT_EXPECTED_ENVIRONMENT='sandbox'
node bot-integration-client.mjs
Inject the optional password through the process manager or secret store, not a repository, image, shell profile, or command-line argument.
Configure mTLS safely#
An https.Agent presents the client certificate, validates BOT's server certificate and hostname, keeps TLS at 1.2 or newer, and reuses safe connections.
const agent = new https.Agent({
cert: fs.readFileSync(requiredEnvironment('BOT_CERT')),
key: fs.readFileSync(requiredEnvironment('BOT_KEY')),
passphrase: process.env.BOT_KEY_PASSWORD || undefined,
keepAlive: true,
minVersion: 'TLSv1.2',
rejectUnauthorized: true,
});
The request helper pins every URL to api.integration.boringordertracker.com, refuses redirects, limits each response to 8 MiB, and uses explicit connect/read timeouts.
Capabilities and production gate#
Capabilities must be the first request for a new or rotated certificate.
const expectedEnvironment = process.env.BOT_EXPECTED_ENVIRONMENT || 'sandbox';
const capabilities = (await request(
'GET', '/capabilities', null, {accept: 'application/json'},
)).body;
if (capabilities?.environment !== expectedEnvironment) {
throw new Error('Certificate is bound to the wrong environment.');
}
if (expectedEnvironment === 'production'
&& (capabilities.integration_status !== 'active'
|| capabilities.production_data_enabled !== true)) {
throw new Error('Production is not active/data-enabled.');
}
Also compare the returned scopes and quotas with the approved profile. A production certificate never bypasses the separate status and data gates.
Redeem a ten-digit link code#
Keep the code as a string and validate all ten decimal digits before sending it.
const code = requiredEnvironment('BOT_LINK_CODE');
if (!/^[0-9]{10}$/.test(code)) {
throw new Error('The link code must contain exactly ten digits.');
}
const linked = (await request(
'POST',
'/link-codes/redeem',
{code},
{accept: 'application/json'},
)).body;
Do not log the code and do not retry an ambiguous timeout blindly. The returned connection and resource IDs are random and integration-specific.
Initial and delta sync#
The provided synchronize helper follows pages, submits the prior opaque cursor as updated_since, and supports ETag/304.
await synchronize(cursor, etag, async (
items, nextCursor, nextEtag, hasMore,
) => {
// One durable database transaction:
// apply items in order, then persist nextCursor and nextEtag.
});
If the transaction rolls back, retain the previous cursor and ETag and request the same page again. Never parse or create a cursor. A delete tombstone requires immediate deletion of current and derived individual data.
Process the documented fields#
Validate each upsert before persistence and consume BOT's resolved vocabulary:
const projection = projectAllowlistedResource(item.resource.type, item.data);
const {
model,
variant,
delivery_center: deliveryCenter,
option_codes: optionCodes,
configuration: {color, wheels, interior, autopilot, tow_hitch: towHitch},
} = projection;
For orders, delivery_center must exist as a key but may be null. Missing readable configuration stays null. Never classify a real order by inventing a label from a bare option code.
Detail and complete history#
Set a random resource ID and its collection to exercise detail and all history pages:
export BOT_RESOURCE_COLLECTION='orders'
export BOT_RESOURCE_ID='ord_random_integration_specific_id'
node bot-integration-client.mjs
const detail = (await request(
'GET', `/${collection}/${encodeURIComponent(resourceId)}`,
null, {accept: 'application/json'},
)).body;
const projection = projectAllowlistedResource(
collection === 'orders' ? 'order' : 'vehicle',
detail.data,
);
await readCompleteHistory(collection, resourceId, cursor, etag, commitPage);
History pagination has its own cursor and ETag. Preserve event sequence and never claim completeness while history_complete is false.
Read aggregate statistics#
Statistics are fixed preaggregated cells, never individual records.
const statistics = (await request(
'GET', '/statistics/orders', null, {accept: 'application/json'},
)).body;
for (const cell of statistics?.data?.orders_total || []) {
console.log(`${cell.dimensions.country}: ${cell.value} opted-in orders`);
}
Use orders_total for a country total. Do not add surviving by_model_variant_status cells because privacy suppression intentionally omits small and complementary cells. Handle 404 statistics_not_available safely.
Acknowledge deletion#
Only send an acknowledgement after every controlled copy has actually been deleted.
const revocationId = requiredEnvironment('BOT_REVOCATION_ID');
if (process.env.BOT_DELETION_COMPLETED !== '1') {
throw new Error('Deletion has not been confirmed locally.');
}
await acknowledgeDeletion(revocationId);
The helper sends a stable idempotency key. On 429, wait at least the returned Retry-After; quotas apply across all active certificates of the integration.
Expected sandbox run#
With the documented fixture, the client validates Model Y, Long Range AWD, Quicksilver, Induction 20-inch wheels, seven option codes, and Düsseldorf-Holthausen - SANDBOX. The complete static JSON appears below and is rendered without a live request.