Integration Guide
This guide explains how to integrate the ShipKit Docs API into your application and receive Webhook notifications.
Authentication
All API requests require an API Key, with two supported methods:
- Query parameter:
?apikey=sdxxxxxxxxxxxxxxxx - Authorization header:
Authorization: Bearer sd_xxxxxxxxxxxxxxxx
Next.js App Router Integration
Embed ShipKit documentation content into your Next.js 14+ application.
1. Create an API Client
// lib/shipkit.ts
const SHIPKITBASE = process.env.SHIPKITAPI_URL || 'https://your-shipkit.vercel.app'
const SHIPKITKEY = process.env.SHIPKITAPI_KEY!
interface DocPage {
path: string
title: string
}
interface SiteIndex {
site_title: string
navigation: unknown[]
pages: DocPage[]
updated_at: string
}
interface PageContent {
title: string
content: string
updated_at: string
}
export async function fetchSiteIndex(siteId: string): Promise<SiteIndex> {
const res = await fetch(
\\${SHIPKITBASE}/api/docs/\${siteId}?apikey=\${SHIPKIT_KEY}\,
{ next: { revalidate: 60 } }
)
if (!res.ok) throw new Error(\Failed to fetch site index: \${res.status}\)
return res.json()
}
export async function fetchPage(siteId: string, path: string): Promise<PageContent> {
const res = await fetch(
\\${SHIPKITBASE}/api/docs/\${siteId}/\${path}?apikey=\${SHIPKIT_KEY}\,
{ next: { revalidate: 60 } }
)
if (!res.ok) throw new Error(\Failed to fetch page: \${res.status}\)
return res.json()
}
2. Documentation List Page
// app/docs/page.tsx
import { fetchSiteIndex } from '@/lib/shipkit'
import Link from 'next/link'
export default async function DocsIndexPage() {
const site = await fetchSiteIndex('my-site-slug')
return (
<div>
<h1>{site.site_title}</h1>
<ul>
{site.pages.map((page) => (
<li key={page.path}>
<Link href={\/docs/\${page.path}\}>{page.title}</Link>
</li>
))}
</ul>
</div>
)
}
3. Documentation Detail Page
// app/docs/[...path]/page.tsx
import { fetchPage, fetchSiteIndex } from '@/lib/shipkit'
import { notFound } from 'next/navigation'
export async function generateStaticParams() {
const site = await fetchSiteIndex('my-site-slug')
return site.pages.map((page) => ({
path: page.path.split('/'),
}))
}
export default async function DocPage({
params,
}: {
params: Promise<{ path: string[] }>
}) {
const { path } = await params
const pagePath = path.join('/')
try {
const page = await fetchPage('my-site-slug', pagePath)
return (
<article>
<h1>{page.title}</h1>
<div dangerouslySetInnerHTML={{ __html: page.content }} />
<p>Last updated: {new Date(page.updated_at).toLocaleString()}</p>
</article>
)
} catch {
notFound()
}
}
Webhook Integration (Next.js revalidatePath)
When ShipKit documentation updates, trigger Incremental Static Regeneration (ISR) via Webhook.
1. Create Webhook Endpoint
// app/api/shipkit-webhook/route.ts
import { NextRequest } from 'next/server'
import { createHmac } from 'crypto'
import { revalidatePath } from 'next/cache'
const WEBHOOKSECRET = process.env.SHIPKITWEBHOOK_SECRET!
function verifySignature(body: string, signature: string): boolean {
const expected = createHmac('sha256', WEBHOOK_SECRET)
.update(body)
.digest('hex')
return expected === signature
}
export async function POST(request: NextRequest) {
const body = await request.text()
const signature = request.headers.get('x-shipkit-signature')
if (!signature || !verifySignature(body, signature)) {
return Response.json({ error: 'Invalid signature' }, { status: 401 })
}
const payload = JSON.parse(body)
if (payload.event === 'page.updated' || payload.event === 'page.created') {
revalidatePath(\/docs/\${payload.data.path}\)
revalidatePath('/docs')
}
if (payload.event === 'site.updated') {
revalidatePath('/docs', 'layout')
}
return Response.json({ received: true })
}
2. Configure Webhook in ShipKit
Add your Webhook URL and Secret in site settings, then test:
curl -X POST https://your-shipkit.vercel.app/api/webhooks/test \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-app.vercel.app/api/shipkit-webhook",
"webhook_secret": "your-secret-here"
}'
Express Integration
1. Install Dependencies
npm install express node-fetch
2. Complete Example
// server.js
const express = require('express')
const crypto = require('crypto')
const app = express()
app.use(express.json({
verify: (req, _res, buf) => { req.rawBody = buf }
}))
const SHIPKITBASE = process.env.SHIPKITAPI_URL
const SHIPKITKEY = process.env.SHIPKITAPI_KEY
const WEBHOOKSECRET = process.env.SHIPKITWEBHOOK_SECRET
// Simple in-memory cache
const cache = new Map()
async function fetchFromShipKit(path) {
const cached = cache.get(path)
if (cached && Date.now() - cached.ts < 60_000) return cached.data
const res = await fetch(\\${SHIPKIT_BASE}\${path}\, {
headers: { Authorization: \Bearer \${SHIPKIT_KEY}\ },
})
if (!res.ok) throw new Error(\ShipKit API error: \${res.status}\)
const data = await res.json()
cache.set(path, { data, ts: Date.now() })
return data
}
// Documentation list
app.get('/docs', async (req, res) => {
try {
const site = await fetchFromShipKit('/api/docs/my-site-slug')
res.json(site)
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// Documentation detail
app.get('/docs/*', async (req, res) => {
const pagePath = req.params[0]
try {
const page = await fetchFromShipKit(
\/api/docs/my-site-slug/\${pagePath}\
)
res.json(page)
} catch (err) {
res.status(500).json({ error: err.message })
}
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => console.log(\Server running on port \${PORT}\))
3. Environment Variables
# .env
SHIPKITAPIURL=https://your-shipkit.vercel.app
SHIPKITAPIKEY=sd_xxxxxxxxxxxxxxxx
SHIPKITWEBHOOKSECRET=your-webhook-secret
API Reference
GET /api/docs/:siteId
Returns site navigation and page list.
Response:{
"site_title": "My Documentation",
"navigation": [
{ "label": "Getting Started", "path": "getting-started" }
],
"pages": [
{ "path": "getting-started", "title": "Getting Started" },
{ "path": "api-reference", "title": "API Reference" }
],
"updated_at": "2026-03-22T10:00:00Z"
}
GET /api/docs/:siteId/:path
Returns specific page content. Includes Cache-Control: public, max-age=60 header.
{
"title": "Getting Started",
"content": "<h2>Introduction</h2><p>Welcome to...</p>",
"updated_at": "2026-03-22T10:00:00Z"
}
POST /api/webhooks/test
Send a test webhook to verify your endpoint configuration.
Request:{
"webhook_url": "https://your-app.com/webhooks/shipkit",
"webhook_secret": "your-secret"
}
Response:
{
"success": true,
"status": 200,
"message": "Test webhook delivered successfully."
}