FNLB Devs

Developer Portal

SDK

HTTP Client

fnlb.api is created inside start(), using the same token. It calls https://api.fnlb.net/v1. Set apiBaseUrl on the FNLB constructor to point somewhere else. OAuth tokens still need the scope each route requires. See OAuth2 and the API reference for the route list. Limits are the same per-route limits as a direct HTTP call. See Rate limits. A non-2xx response throws ApiError. status is the HTTP status, path is the route, and body is the parsed error payload.

import FNLB, { ApiError } from 'fnlb';

const fnlb = new FNLB();
await fnlb.start({ token: 'FNLB_...', categories: ['your-category-id'] });

try {
  const user = await fnlb.api.user.get({ includeEmail: true });
  const bots = await fnlb.api.bots.list();
  console.log(user.username, bots.length);
} catch (error) {
  if (error instanceof ApiError) console.error(error.status, error.body);
}

Account

CallWhat it does
api.user.get()The account that owns the token. includeEmail: true adds the email when the token may read it.
api.bots.list() / get(id)Every bot on the account, including ones this process is not running.
api.bots.create / update / deleteChange bots.
api.bots.stats()Counts for the account.
api.bots.bulkExport / bulkImportMove device auth in bulk. Same limits as the bulk guide.
api.categories.list / get / create / update / deleteCategories. delete(id, { includeBots: true }) also deletes bots in that category.
api.presets.list / get / create / update / deleteCosmetic presets. Creating and listing presets requires a VIP account, or staff.

Commands and chat

Cloud commands work for a bot that is not running in this process. Local bot.runCommand does not round-trip through the API.

const bots = await fnlb.api.bots.list();
const id = bots[0].id;

await fnlb.api.bots.commands.run(id, { command: 'outfit', args: ['renegade'] });
await fnlb.api.bots.chat.send(id, { content: 'hello from the api' });

chat.send sends one line and waits for the bot's reply text. It is not party meta and it is not the local Message event.

Friends and party snapshot

These routes read a bot that is connected to FNLB. They are not the local IPC friends list.

await fnlb.api.bots.friends.list(botId);
await fnlb.api.bots.friends.pending(botId);
await fnlb.api.bots.users.search(botId, 'name');
await fnlb.api.bots.users.blocked(botId);
await fnlb.api.bots.party.member(botId, memberId);

party.member is the cosmetic snapshot from the API, not bot.party.me.meta.

Creating a bot

create stores Epic device auth. All three device fields are required. parent is the category id.

const created = await fnlb.api.bots.create({
  nickname: 'Alpha',
  parent: 'category-id',
  deviceAuth: {
    accountId: 'epic-account-id',
    deviceId: 'device-id',
    secret: 'device-secret'
  }
});

await fnlb.api.bots.update(created.id, { disabled: false });

update accepts nickname, email, parent (null removes the category), disabled, and a replacement deviceAuth. delete removes that bot. categories.delete(id, { includeBots: true }) also deletes the bots in the category. bulkExport({ deleteAfterExport: false }) returns device auth for the account. bulkImport writes a list back. Both follow the bulk operations limits. Treat the secret as a credential.

Scopes

An API token can call the routes that token is allowed to call. An OAuth access token needs the scope on the route. The usual ones for this client:

WorkScopes
start()bots.run, categories.read, bots.read
List and edit botsbots.read, bots.write
Categoriescategories.read, categories.write
Cloud command or chatThe bots scope that route documents in the API reference

A missing scope is ApiError with status 401 or 403. body is the API error payload.

Reference

TopicWhere
ClientRestClient
Thrown errorApiError
Bot recordApiBot
Command replyApiCommandResult
Route list and scopesAPI reference
Local equivalent of commands and chatChat and commands