Module 3 of 7 · 56 min

Build Reliable OpenAI Responses API Workflows

Integrate the OpenAI Responses API with environment-based configuration, typed item handling, deliberate conversation state, output validation, bounded recovery, and privacy-aware telemetry.

OpenAI

By the end

You will be able to

  • Explain how Responses API requests and typed output items form an application contract.
  • Choose and document application-managed, response-linked, or conversation-managed state.
  • Use the official SDK with environment-based credentials and a configurable model identifier.
  • Validate terminal status and output items before use, then recover and observe within explicit bounds.
01

Responses are typed items, not one string

The Responses API accepts instructions and input, then returns a response containing status, usage, and typed output items. An item may be a message, function call, tool result, reasoning item, or another supported type. Message content can also contain different content-part types.

Convenience fields such as output_text are useful for simple text-only cases, but production code must inspect the response status and the item types its contract permits. Reject or route unknown types instead of silently flattening them into trusted text.

02

Choose who owns conversation state

A workflow can send the complete history itself, link a request with previous_response_id, or use a provider conversation object where appropriate. Each option changes persistence, retention, deletion, audit, branching, and recovery behavior. Record the chosen state owner in the design.

Do not assume that linking a response automatically satisfies your privacy or retention policy. Decide which inputs, outputs, identifiers, summaries, and audit evidence the application stores; apply minimization and access controls; and verify current provider storage behavior for the selected request settings.

03

Configure the SDK boundary

Load OPENAI_API_KEY from the runtime environment or a managed secret store and fail closed when it is unavailable. Keep the key out of source, prompts, telemetry, browser code, and learner submissions. Scope, rotate, and revoke it through an operational process.

Treat the model identifier, timeout, output limits, retry budget, and storage choice as reviewed configuration. Verify supported values in current official documentation instead of freezing a tutorial model name into reusable code.

Typed Responses API boundary
typescript
import OpenAI from "openai";

const model = process.env.OPENAI_MODEL;
if (!process.env.OPENAI_API_KEY || !model) {
  throw new Error("OpenAI API configuration is incomplete");
}

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await client.responses.create({
  model,
  instructions: "Return a concise, evidence-linked risk summary.",
  input: [{ role: "user", content: approvedInput }],
  store: false,
});

if (response.status !== "completed") {
  throw new Error(`Response did not complete: ${response.status}`);
}

for (const item of response.output) {
  if (item.type !== "message") continue;
  for (const part of item.content) {
    if (part.type === "output_text") await handleValidatedText(part.text);
    else if (part.type === "refusal") await handleRefusal(part.refusal);
    else throw new Error(`Unhandled content part: ${part.type}`);
  }
}
04

Validate status and output

Handle completed, incomplete, failed, cancelled, queued, and in-progress behavior according to the current contract and your execution mode. An incomplete response needs its incomplete details examined; a function call needs tool handling; a refusal needs a user-safe path. Never label every non-empty response as success.

Validate required content, schemas, allowed values, citations, lengths, and business rules before downstream use. Separate provider transport success, model completion, application validation, and external postcondition verification in your state machine.

05

Recover and observe with bounds

Classify failures before retrying. Rate limits and transient service failures may be retried with provider guidance, jitter, a maximum attempt count, and an end-to-end deadline. Authentication, authorization, malformed requests, and validation failures require correction rather than an unchanged retry.

Record correlation identifiers, application and prompt versions, configured model reference, state mode, latency, usage, response status, item types, validation result, retry count, and terminal workflow state. Redact or omit credentials, sensitive inputs, unrestricted outputs, and provider identifiers that are not required by the approved telemetry policy.

Practice activity

Design a production-shaped Responses API client

  1. Define a request contract with environment-based credentials, configurable model, instructions, typed input, storage choice, timeout, retry budget, and correlation identifier.
  2. Choose one conversation-state mode and document persistence, retention, deletion, branching, privacy, and recovery behavior.
  3. Implement or diagram handlers for completed text, refusal, function call, incomplete response, unknown item, invalid output, authentication failure, rate limit, timeout, cancellation, and provider failure.
  4. Create deterministic fixtures and a telemetry allowlist that prove each terminal path without exposing credentials or sensitive prompt content.

What to produce

  • A secret-free client implementation or design with typed item handling, explicit state ownership, validation, bounded retries, and deterministic tests.
  • A state and telemetry record showing configuration versions, correlation, status, item types, usage, validation, retry, and terminal outcome under a documented privacy policy.

Reflect before continuing

Which state-management choice did you make, and what deletion and recovery evidence proves that the application—not an assumption—controls the learner's data?

Evidence

Sources and verification

Knowledge check

Make it stick.

Pass at 80%

Choose the strongest answer for each question. Your attempts become part of your device-local transcript.

01Why should production code inspect response.output instead of trusting only output_text?
02What must accompany the choice to use previous_response_id?
03Where should a reusable client obtain the model identifier?
04A response status is incomplete. What should the application do?
05Which telemetry is appropriate by default?