# Structured outputs in Node via zodTextFormat

Same guarantee as Python, different wiring. Verified against the structured
outputs guide on 2026-09-26.

## The call

```js
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";

const openai = new OpenAI();
const CalendarEvent = z.object({
  name: z.string(),
  date: z.string(),
  participants: z.array(z.string()),
});

const response = await openai.responses.parse({
  model: "...",
  input: "Alice and Bob are going to a science fair on Friday.",
  text: { format: zodTextFormat(CalendarEvent, "event") },
});
const event = response.output_parsed;
```

## The optional-field trap

Strict schemas require every key to be present or explicitly nullable. In zod
that means: do not use `.optional()` and expect it to pass. Use
`z.string().nullable()` for fields the model may omit, or give the field a
`.default()`. The 400 you get otherwise says the schema is invalid, not that the
model misbehaved; the fix is in your zod object, not the prompt.

## The naming trap

`zodTextFormat` takes a name as the second argument. Reuse the same name for the
same shape across deploys; the name becomes part of the schema identity in logs
and traces, and renaming it per request makes debugging harder.

## Check before you ship

- In an Express route, `res.json(response.output_parsed)`; in a Next.js route
  handler, `Response.json(response.output_parsed)`. No manual JSON.parse anywhere.
- Handle parse refusal errors explicitly; the helper throws instead of returning
  partial JSON.