NestJS

Set up Pingback in your NestJS app with the @usepingback/nestjs adapter.

Installation

npm install @usepingback/nestjs

Module Setup

Import PingbackModule and call register() in your root module. The module auto-registers a POST endpoint and scans your providers for decorated handlers on startup:

import { PingbackModule } from '@usepingback/nestjs';

@Module({
  imports: [
    PingbackModule.register({
      apiKey: process.env.PINGBACK_API_KEY,
      cronSecret: process.env.PINGBACK_CRON_SECRET,
      baseUrl: process.env.APP_URL,
    }),
  ],
})
export class AppModule {}

Defining Functions

Use the @Cron and @Task decorators on methods in any injectable service. They are automatically discovered at startup:

import { Injectable } from '@nestjs/common';
import { Cron, Task, PingbackContext } from '@usepingback/nestjs';

@Injectable()
export class EmailService {
  @Cron('send-emails', '*/15 * * * *', { retries: 3, timeout: '60s' })
  async sendEmails(ctx: PingbackContext) {
    const pending = await getPendingEmails();
    for (const email of pending) {
      await ctx.task('send-email', { id: email.id });
    }
    ctx.log(`Dispatched ${pending.length} emails`);
  }

  @Task('send-email', { retries: 2, timeout: '15s' })
  async sendEmail(ctx: PingbackContext, payload: { id: string }) {
    const email = await getEmail(payload.id);
    await deliver(email);
    ctx.log('Sent email', { id: payload.id });
  }
}

Structured Logging

The ctx object provides structured logging at multiple levels. All log entries are captured and returned to the platform with the execution result:

ctx.log('message');                          // info
ctx.log('message', { key: 'value' });        // info with metadata
ctx.log.warn('slow query', { ms: 2500 });    // warning
ctx.log.error('failed', { code: 'E001' });   // error
ctx.log.debug('cache stats', { hits: 847 }); // debug

Fan-Out

Dispatch background tasks from within a cron handler using ctx.task(). Each task runs independently with its own retries and timeout:

@Cron('process-orders', '0 * * * *', { retries: 3, timeout: '120s' })
async processOrders(ctx: PingbackContext) {
  const orders = await getUnprocessedOrders();
  for (const order of orders) {
    await ctx.task('fulfill-order', { orderId: order.id });
  }
  ctx.log(`Dispatched ${orders.length} orders for fulfillment`);
}

Configuration

The full set of options accepted by PingbackModule.register():

PingbackModule.register({
  apiKey: string;          // Required — your project API key
  cronSecret: string;      // Required — request signing secret
  baseUrl?: string;        // Your app's public URL
  routePath?: string;      // default: /api/pingback
  platformUrl?: string;    // default: https://api.pingback.lol
})

Environment Variables

Add these to your .env file:

PINGBACK_API_KEY=pb_live_your_api_key_here
PINGBACK_CRON_SECRET=your_cron_secret_here
VariableDescription
PINGBACK_API_KEYYour project API key. Found in the dashboard under API Keys.
PINGBACK_CRON_SECRETRequest signing secret. Found in the dashboard under project Settings.

Local Development

Use npx pingback-nest dev [port] to test your cron jobs and tasks locally against the production Pingback platform. The CLI creates a secure tunnel to your local NestJS dev server so the platform can invoke your endpoint:

# Start your NestJS dev server, then in another terminal:
npx pingback-nest dev 3000

Executions triggered from the dashboard or by schedule will be routed to your local machine, letting you debug with full access to local logs and breakpoints.

How It Works

1. On startup, the module scans all providers for @Cron and @Task decorators.

2. Discovered functions are registered with the Pingback platform via the API.

3. A POST endpoint is auto-registered at /api/pingback (configurable).

4. The platform sends signed execution requests to your endpoint on schedule.

5. The controller verifies the HMAC signature, executes the handler, and returns results with logs.