Extending the API
apps/api is your own NestJS app. It imports MarketlumCoreModule for all built-in functionality, but you can register additional modules alongside it for custom endpoints, background jobs, webhooks, and integrations.
Add a new module
The scaffold's apps/api/src/app.module.ts looks like this:
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, envFilePath: '../.env' }),
MarketlumCoreModule,
],
})
export class AppModule {}
To add a custom feature, create a NestJS module and import it. For example, a webhook endpoint that fires when an invoice is paid:
import { Module } from '@nestjs/common';
import { WebhooksController } from './webhooks.controller';
import { WebhooksService } from './webhooks.service';
@Module({
controllers: [WebhooksController],
providers: [WebhooksService],
})
export class WebhooksModule {}
import { WebhooksModule } from './webhooks/webhooks.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, envFilePath: '../.env' }),
MarketlumCoreModule,
WebhooksModule,
],
})
export class AppModule {}
Inject core services
Any service exported from @marketlum/core can be injected into your own providers. The core module is global, so you don't need to re-import it.
import { Injectable } from '@nestjs/common';
import { InvoicesService } from '@marketlum/core';
@Injectable()
export class WebhooksService {
constructor(private readonly invoices: InvoicesService) {}
async onInvoicePaid(invoiceId: string) {
const invoice = await this.invoices.findOne(invoiceId);
// forward to Stripe, Slack, etc.
}
}
See the Project Structure page for the list of exported services.
Add custom entities
You can register your own TypeORM entities without touching core:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity('webhook_events')
export class WebhookEvent {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column()
type!: string;
@Column('jsonb')
payload!: Record<string, unknown>;
}
Add it to apps/api/src/data-source.ts alongside the core entities:
import { ALL_ENTITIES, ALL_MIGRATIONS } from '@marketlum/core';
import { WebhookEvent } from './webhooks/webhook-event.entity';
export default new DataSource({
// ...
entities: [...ALL_ENTITIES, WebhookEvent],
migrations: [...ALL_MIGRATIONS, /* your migrations */],
});
Generate a migration for the new table:
pnpm --filter @my/api typeorm migration:generate src/migrations/AddWebhookEvents -d src/data-source.ts
Reference your custom entity via TypeOrmModule.forFeature([WebhookEvent]) in your module's imports.
Background jobs
For scheduled work, install @nestjs/schedule:
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { ReminderJob } from './reminder.job';
@Module({
imports: [ScheduleModule.forRoot()],
providers: [ReminderJob],
})
export class JobsModule {}
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { AgreementsService } from '@marketlum/core';
@Injectable()
export class ReminderJob {
constructor(private readonly agreements: AgreementsService) {}
@Cron(CronExpression.EVERY_DAY_AT_9AM)
async sendExpiryReminders() {
// ...
}
}
Don't modify core
If you find yourself wanting to change how a core service behaves, prefer one of:
- Compose around it — call the core service from your own service and add behavior before/after.
- Replace a provider — if core exposes a DI token (e.g.
STORAGE_PROVIDER), bind your own implementation inapp.module.ts. - Open an issue — if neither works, the framework is missing an extension point. That's worth reporting.
Forking @marketlum/core is always an option but it forfeits the upgrade path.