v1.2.0

Node + Hook Company Export

Export Bitrix24 companies into a CSV file from a pure Node.js script using B24Hook.

A typical batch / cron-style job: export companies into a CSV with one webhook. Stays under the rate limits and uses fetchList so memory stays flat regardless of dataset size.

Project Layout

my-export-job/
├── dist/
├── src/
│   └── process-company-list.ts
├── out/                            # generated *.csv files
├── .env.local                      # B24_HOOK=...
├── package.json
└── tsconfig.json

package.json

{
  "name": "my-export-job",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node --env-file=.env.local dist/process-company-list.js"
  },
  "devDependencies": {
    "@types/node": "^22",
    "typescript": "^5.6"
  },
  "dependencies": {
    "@bitrix24/b24jssdk": "latest",
    "chalk": "^5"
  }
}

src/process-company-list.ts

// @check-ignore: node:fs not available in docs typecheck context

import { writeFileSync } from 'node:fs'
import {
  B24Hook,
  EnumCrmEntityTypeId,
  LoggerFactory,
  Text,
  type ISODate
} from '@bitrix24/b24jssdk'

const $logger = LoggerFactory.createForBrowser('export', process.env.NODE_ENV === 'development')

if (!process.env.B24_HOOK) {
  $logger.error('B24_HOOK is not set in .env.local')
  process.exit(1)
}

const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
$logger.info(`Portal: ${$b24.getTargetOrigin()}`)

type Company = { id: number, title: string, createdTime: ISODate }

async function main() {
  const generator = $b24.actions.v2.fetchList.make<Company>({
    method: 'crm.item.list',
    params: {
      entityTypeId: EnumCrmEntityTypeId.company,
      select: ['id', 'title', 'createdTime']
    },
    idKey: 'id',
    requestId: 'export:companies'
  })

  const rows: string[] = ['id,title,createdTime']
  for await (const chunk of generator) {
    for (const c of chunk) {
      rows.push([
        c.id,
        JSON.stringify(c.title ?? ''),
        Text.toDateTime(c.createdTime).toFormat('yyyy-LL-dd HH:mm:ss')
      ].join(','))
    }
    $logger.info(`Loaded ${chunk.length} (total ${rows.length - 1})`)
  }

  const out = `out/companies-${Date.now()}.csv`
  writeFileSync(out, rows.join('\n'), 'utf8')
  $logger.notice(`Wrote ${out}`)

  $b24.destroy()
}

main().catch((error) => {
  $logger.error('export failed', { error })
  process.exit(1)
})

Why fetchList?

  • Memory-flat: each for await iteration yields a 50-item chunk, so a 50 000-row dataset never materialises in RAM.
  • Built-in pagination: don't roll your own start: nextStart loop.
  • Gracefully handles the SDK rate / operating limiters between pages.

For full-blown bulk operations (delete-then-create, bulk imports), pair the export with actions.v2.batchByChunk.

Full Source

bitrix24/b24sdk-examples → js/05-node-hook.