Skip to content

TypeScript SDK

@trucklinemp/sdk is the official TypeScript and JavaScript toolkit for TrucklineMP integrations. It covers:

  • Public API client (Truckline) with typed models, retries, and pagination helpers
  • OAuth helpers (TrucklineOAuth, PKCE) for user sign-in
  • Webhooks signature verification and delivery handlers (Node.js)

The OpenAPI spec remains the source of truth for every field. The SDK tracks common resources and stays intentionally thin.

Package@trucklinemp/sdk
Version0.2.x
Registrynpmjs.com
Repositorygithub.com/trucklinemp/sdk
LicenseMIT
RuntimeNode.js 18+ (global fetch); browser-capable for the HTTP client
Terminal window
npm install @trucklinemp/sdk
ImportContents
@trucklinemp/sdkFull client, models, errors; OAuth + webhooks re-exported
@trucklinemp/sdk/oauthOAuth / PKCE only
@trucklinemp/sdk/webhooksWebhook verify / handler only (uses Node crypto)

Prefer the subpath imports when you want a smaller surface (for example OAuth in a separate service).

  1. Enable Developer Mode and create a project in the Developer Console.
  2. Create an API key (tlmp_api_...) and store it securely.
  3. Call the API:
import { Truckline, TrucklineError } from "@trucklinemp/sdk";
const tl = new Truckline({
apiKey: process.env.TRUCKLINE_API_KEY,
});
console.log(tl.version); // SDK version string
const { user } = await tl.users.get("some-handle");
console.log(user.webId, user.steamId, user.name);
const bySteam = await tl.users.getBySteam("76561198000000000");
try {
await tl.vtcs.get("missing-vtc");
} catch (err) {
if (err instanceof TrucklineError) {
console.error(err.status, err.code, err.requestId, err.message);
if (err.isRateLimited) console.error("retry after", err.retryAfter);
}
}

Anonymous calls work on many public routes with lower rate limits. Always send a key in production.

new Truckline({
apiKey: "tlmp_api_...",
baseUrl: undefined, // default https://api.trucklinemp.com
timeoutMs: 30_000,
maxRetries: 1, // retries on 429 and 5xx
retryOnServerError: true,
headers: { "X-App": "my-bot" },
userAgent: "my-bot/1.0", // Node only; default includes SDK version
debug: false,
onRequest: ({ method, url, attempt }) => {},
onResponse: ({ status, requestId, durationMs }) => {},
fetch: customFetch, // optional
});
OptionBase URL
Defaulthttps://api.trucklinemp.com
Local Webhttp://localhost:3000/api/v1

Do not append an extra /v1 on api.trucklinemp.com. See Public API base URLs.

After a request, inspect the last parsed rate-limit headers:

await tl.meta.version();
console.log(tl.lastRateLimit);
// { retryAfter, limit, remaining, reset }

The package exports TypeScript types for public payloads (shapes may grow as the API does; optional fields stay optional):

  • Users: PublicUser, PublicUserSearchResult, PublicUserBans, …
  • VTCs / members: VtcListItem, VtcMember, VtcNewsItem, VtcRole
  • Events: PublicEvent, PublicEventAttendee, PublicEventSlot
  • News, bans, partners, badges, game servers, OAuth userinfo, webhook delivery

Dates from the API are typed as ISO strings (IsoDateString).

Example:

import type { PublicUser } from "@trucklinemp/sdk";
const { user } = await tl.users.get("driver");
const profile: PublicUser = user;
await tl.meta.version();
await tl.meta.status();
await tl.meta.stats();
await tl.meta.partners();
await tl.meta.rules();
await tl.meta.session();
await tl.meta.recruitmentOpen();
await tl.users.search({ q: "alex", page: 1, limit: 20 });
await tl.users.get("handle-or-id-or-steamId64");
await tl.users.getBySteam("7656119…");
await tl.users.resolve("handle"); // returns PublicUser
await tl.users.batch(["id1", "id2"]); // auto-chunks at 50
await tl.users.bans(userId);
await tl.users.events(userId, { tab: "upcoming" });
for await (const page of tl.users.iterateSearch({ q: "a", limit: 20 })) {
console.log(page.length);
}
const allMatches = await tl.users.searchAll({ q: "a", maxItems: 100 });

Public user objects include steamId when the account is linked.

await tl.vtcs.list({ limit: 20, q: "logistics" });
await tl.vtcs.get("handle-or-id");
await tl.vtcs.batch([1, 2, 3]);
await tl.vtcs.members("handle");
await tl.vtcs.news(vtcId);
await tl.vtcs.events(vtcId);
await tl.vtcs.roles(vtcId);
await tl.vtcs.gallery(vtcId);
await tl.vtcs.tier(vtcId);
await tl.vtcs.liveEvents(vtcId);
await tl.vtcs.upcomingEvents(vtcId);
for await (const members of tl.vtcs.iterateMembers("my-vtc", { limit: 50 })) {
for (const m of members) console.log(m.name, m.steamId);
}
const everyVtc = await tl.vtcs.listAll({ maxPages: 10 });
await tl.events.list();
await tl.events.get(eventId);
await tl.events.attendees(eventId);
await tl.events.slots(eventId);
await tl.news.list();
await tl.news.get(newsId);
await tl.bans.list({ page: 1, pageSize: 25, q: "cheat" });
await tl.bans.get(banId);
for await (const page of tl.bans.iterate({ pageSize: 50 })) { /* … */ }
await tl.programs.badge("bug-hunter");
await tl.programs.recognition();
await tl.game.servers();
await tl.get("/version");
await tl.request("GET", "/vtcs", { query: { limit: 5 } });
await tl.post("/path", { body: { … } }); // if a future write route is documented

Failed HTTP responses throw TrucklineError:

Field / flagMeaning
statusHTTP status (0 for network / timeout / abort)
codeAPI or client code (NOT_FOUND, TIMEOUT, ABORTED, …)
requestIdCorrelation id for support
retryAfterSeconds from Retry-After when present
detailsExtra API payload
isRateLimited / isNotFound / isUnauthorized / isForbiddenHelpers
isTimeout / isNetworkError / isServerError / isValidationErrorHelpers

Default retries: up to maxRetries (default 1) on 429 and 5xx, with jitter. Set maxRetries: 0 to disable. Network failures also retry when maxRetries > 0.

Platform limit tables: Rate limits.

Use OAuth when you need data as a signed-in user (not with an API key alone). Full product flow: OAuth Apps.

import { TrucklineOAuth, generatePkce } from "@trucklinemp/sdk/oauth";
const oauth = new TrucklineOAuth({
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET, // omit for public + PKCE clients
redirectUri: "https://myapp.com/callback",
// siteUrl: "https://trucklinemp.com",
});
const pkce = generatePkce();
const url = oauth.getAuthorizeUrl({
scope: ["profile", "vtc:read", "presence:read"],
state: "csrf-token",
codeChallenge: pkce.codeChallenge,
});
// After redirect:
const tokens = await oauth.exchangeCode(code, {
codeVerifier: pkce.codeVerifier,
});
const me = await oauth.userinfo(tokens.access_token);
console.log(me.sub, me.steam_id, me.handle);
const refreshed = await oauth.refresh(tokens.refresh_token!);
await oauth.revoke(tokens.access_token, "access_token");

Redirect URI rules (localhost / private LAN / https): OAuth Apps — redirect URIs.

userinfo with profile includes steam_id when linked.

Deliveries are signed with HMAC-SHA256 over the raw body:

X-TrucklineMP-Signature: sha256=<hex>
X-TrucklineMP-Event: user.banned
X-TrucklineMP-Delivery: <id>
import {
createWebhookHandler,
verifyWebhookSignature,
WEBHOOK_SIGNATURE_HEADER,
} from "@trucklinemp/sdk/webhooks";
const handle = createWebhookHandler({
secret: process.env.WEBHOOK_SECRET!,
onEvent: async (event, meta) => {
console.log(meta.type, meta.deliveryId, event);
},
});
// Express: use express.raw() so body is not re-parsed first
app.post("/hooks/truckline", express.raw({ type: "*/*" }), async (req, res) => {
const result = await handle({ rawBody: req.body, headers: req.headers });
res.status(result.ok ? 200 : 401).json(result);
});

Low-level:

verifyWebhookSignature(rawBody, req.headers[WEBHOOK_SIGNATURE_HEADER], secret);

Event catalog and retries: Webhooks.

In the SDK repository (after npm run build):

FilePurpose
examples/basic.mjsVersion + user search
examples/oauth-pkce.mjsPrint authorize URL + verifier
examples/webhook-express.mjsMinimal Express receiver
  • SDK methods, options, and error class follow semver (Truckline.VERSION / package version).
  • Server JSON fields can evolve; treat new optional fields as optional.
  • Breaking client changes ship as major versions. See the package CHANGELOG.

API traffic with your key is subject to the same logging and rate limiting as raw HTTP. See the Privacy Policy and Public API telemetry notes.

Package layout, PRs, and adding methods: Contributing to the TypeScript SDK.

GuideTopics
Platform OverviewDeveloper Mode, integration types
Public APIAuth, base URLs, rate limits, endpoint map
OAuth AppsAuthorize, tokens, scopes, redirect URIs
WebhooksEvents, signatures, retries
Developer ConsoleProjects, keys, playground
Contributing to the SDKLocal setup and PRs
Leaked API Keys & SecretsRotation after exposure