Next.js App Router
Create a server-only integration module, mount the allowlisted browser proxy, and keep signed background delivery on a separate webhook route.
Create the integration
import "server-only"
import { createIncld, defineActions } from "@incld/client/next"
export const incld = createIncld({
apiKey: process.env.INCLD_SECRET_KEY!,
webhookSecret: process.env.INCLD_WEBHOOK_SECRET!,
baseUrl: process.env.INCLD_API_URL,
actions: defineActions({
generate_report: {
displayName: "Generate report",
async run({ payload, event }) {
await reports.enqueue(payload, event.idempotencyKey)
},
},
}),
async resolveContext(_request) {
const session = await auth()
return session?.organizationId
? {
user: { id: session.user.id },
organization: { id: session.organizationId },
}
: null
},
async authorize({ context, operation }) {
return canUseIncld(context.user.id, operation)
},
})
Mount the routes
import { incld } from "@/lib/incld"
export const dynamic = "force-dynamic"
export const { GET, POST, PATCH, DELETE } = incld.routes
import { incld } from "@/lib/incld"
export const dynamic = "force-dynamic"
export const POST = incld.webhook
Keep the integration in a server-only module
@incld/react*, never this file.
Add the browser provider
"use client"
import { IncldProvider } from "@incld/react"
export function IncldProviders({ children }) {
return <IncldProvider baseUrl="/api/incld">{children}</IncldProvider>
}
The client appends /v1, so the catch-all route lives beneath /api/incld/v1.
Keep privileged mutations on the server
Browser proxying intentionally excludes action definition and Bulk creation. Perform those operations through
incld.client
after your server authorizes the user. Approval Policy management can use the browser components only when
authorize
explicitly permits the operation. Include the trusted active organization on tenant-bound server writes, then return only safe identifiers to the browser.
import { Incld } from "@incld/client"
export async function POST(request: Request) {
const session = await auth()
if (!session?.organizationId) {
return Response.json({ error: "forbidden" }, { status: 403 })
}
if (!session.permissions.includes("bulk:create")) {
return Response.json({ error: "forbidden" }, { status: 403 })
}
const tenantIncld = new Incld({
apiKey: process.env.INCLD_SECRET_KEY!,
scope: { organizationId: session.organizationId, userId: session.user.id },
})
const operation = await tenantIncld.bulkOperations.create(
{
action: "sync_contacts",
items: await request.json(),
},
{ idempotencyKey: request.headers.get("idempotency-key") ?? crypto.randomUUID() },
)
return Response.json({ operationId: operation.id }, { status: 202 })
}