import { env } from '@/lib/env'; import { logger } from '@/lib/logger'; const BASE_URL = env.DOCUMENSO_API_URL; const API_KEY = env.DOCUMENSO_API_KEY; async function documensoFetch(path: string, options?: RequestInit): Promise { const res = await fetch(`${BASE_URL}${path}`, { ...options, headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json', ...options?.headers, }, }); if (!res.ok) { const err = await res.text(); logger.error({ path, status: res.status, err }, 'Documenso API error'); throw new Error(`Documenso API error: ${res.status}`); } return res.json(); } // Documenso 2.x renamed top-level `id` → `documentId` and recipient `id` → // `recipientId`; v1.13 still uses `id`. Normalize both shapes to the legacy // `id` form that this codebase consumes everywhere downstream. function normalizeDocument(raw: unknown): DocumensoDocument { const r = (raw ?? {}) as Record; const id = String(r.documentId ?? r.id ?? ''); const status = String(r.status ?? 'PENDING'); const recipientsRaw = (r.recipients as Array> | undefined) ?? []; const recipients = recipientsRaw.map((rec) => ({ id: String(rec.recipientId ?? rec.id ?? ''), name: String(rec.name ?? ''), email: String(rec.email ?? ''), role: String(rec.role ?? ''), signingOrder: Number(rec.signingOrder ?? 0), status: String(rec.signingStatus ?? rec.status ?? 'PENDING'), signingUrl: typeof rec.signingUrl === 'string' ? rec.signingUrl : undefined, embeddedUrl: typeof rec.embeddedUrl === 'string' ? rec.embeddedUrl : undefined, })); return { id, status, recipients }; } export interface DocumensoRecipient { name: string; email: string; role: string; signingOrder: number; } export interface DocumensoDocument { id: string; status: string; recipients: Array<{ id: string; name: string; email: string; role: string; signingOrder: number; status: string; signingUrl?: string; embeddedUrl?: string; }>; } export async function createDocument( title: string, pdfBase64: string, recipients: DocumensoRecipient[], ): Promise { return documensoFetch('/api/v1/documents', { method: 'POST', body: JSON.stringify({ title, document: pdfBase64, recipients }), }).then(normalizeDocument); } export async function generateDocumentFromTemplate( templateId: number, payload: Record, ): Promise { return documensoFetch(`/api/v1/templates/${templateId}/generate-document`, { method: 'POST', body: JSON.stringify(payload), }).then(normalizeDocument); } export async function sendDocument(docId: string): Promise { return documensoFetch(`/api/v1/documents/${docId}/send`, { method: 'POST', }).then(normalizeDocument); } export async function getDocument(docId: string): Promise { return documensoFetch(`/api/v1/documents/${docId}`).then(normalizeDocument); } export async function sendReminder(docId: string, signerId: string): Promise { await documensoFetch(`/api/v1/documents/${docId}/recipients/${signerId}/remind`, { method: 'POST', }); } export async function downloadSignedPdf(docId: string): Promise { const res = await fetch(`${BASE_URL}/api/v1/documents/${docId}/download`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); if (!res.ok) { const err = await res.text(); logger.error({ docId, status: res.status, err }, 'Documenso download error'); throw new Error(`Documenso download error: ${res.status}`); } const arrayBuffer = await res.arrayBuffer(); return Buffer.from(arrayBuffer); }