Extract structured data in TypeScript
⚠️
Preview — this feature is being built; the design below is the spec.
The invoice extraction with a Zod schema converted to JSON schema, and a typed result.
import { z } from 'zod'
import { zodToJsonSchema } from 'zod-to-json-schema'
const Invoice = z.object({
supplier: z.string(),
invoice_number: z.string().nullable(),
issue_date: z.string().nullable().describe('YYYY-MM-DD'),
total: z.string().describe('Decimal, two places, no symbol'),
currency: z.enum(['EUR', 'GBP', 'USD', 'AED', 'OTHER']),
line_items: z.array(z.object({ description: z.string(), amount: z.string() })).max(50),
}).strict()
type Invoice = z.infer<typeof Invoice>
export async function extract(text: string): Promise<Invoice> {
const res = await fetch('https://app.syntic.ai/v1/chat/completions', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.SYNTIC_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'Amara Quick',
stream: false,
max_tokens: 1500,
response_format: {
type: 'json_schema',
json_schema: { name: 'invoice', strict: true, schema: zodToJsonSchema(Invoice, { target: 'openApi3', $refStrategy: 'none' }) },
},
messages: [
{ role: 'system', content: 'Extract invoice fields. Use null when a field is not stated. Never compute a total that is not printed.' },
{ role: 'user', content: text },
],
}),
})
const data = await res.json()
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`)
const choice = data.choices[0]
if (choice.finish_reason !== 'stop') throw new Error(`not finished: ${choice.finish_reason}`)
return Invoice.parse(JSON.parse(choice.message.content)) // belt and braces
}The official TypeScript SDK will do the conversion and parsing for you with client.chat.completions.parse; see SDK helpers.
Was this page helpful?