Your team wires a chat assistant to a twenty-year-old ERP. A user types: "Rush three widgets for ACME, bill in dollars." The model returns plausible JSON. Then order_type is "overnight", and the mainframe returns a 500. That enum has not existed since 2008.
Integration teams know this failure mode. The LLM is fluent. The legacy contract is brittle. HTTP 200 from the model is not the same as a payload your API will accept. Chat surfaces hide the gap because users see friendly prose while your integration layer forwards garbage.
This guide covers why NL-to-ERP bridges break, what vendors sell versus what you need, and how schema-gated validation on the LLM path stops bad JSON before your client POSTs.
The Problem: Plausible JSON, Fatal Enums
Legacy order APIs were designed for EDI batches, SOAP clients, and hand-maintained field manuals. They expect rigid shapes: fixed enums, nested line items with non-null quantities, currency codes from a 2003 table, customer IDs that match a regex your intern documented in a wiki page.
Chat assistants promise natural language in and structured action out. The model delivers JSON that parses and looks right.
Invented enum values. Models guess friendly labels (overnight, priority, express) that are not in your order_type list (standard, rush, backorder).
Missing required nested fields. A top-level object passes a quick glance. line_items[].quantity is null. The downstream COBOL parser panics or silently drops the line.
Markdown wrappers and duplicate keys. The assistant returns fenced JSON or repeats keys. Fine for humans. Fatal for strict parsers and some legacy deserializers.
Wrong types that coerce badly. "3" instead of 3, dates as "next Tuesday", SKUs with trailing spaces.
False confidence in prompt-only schemas. Pasting your OpenAPI fragment into the system prompt helps until an edge-case user message, a tool-call handoff, or a model update drifts the output shape.
The user sees "Got it, rushing your order." Your ops channel gets paged at 2 a.m. because the integration retry loop hammered a production endpoint with invalid payloads.
For the same contract discipline on inbound webhooks, read keep API contracts stable. The direction differs; the validator mindset does not.
Why Prompts and Structured Outputs Are Not Enough
OpenAI structured outputs and JSON mode reduce syntax errors. They align the model to a schema at generation time. They do not guarantee your deployed enum list, your tenant-specific required fields, or your legacy quirks that never made it into the public OpenAPI file.
Schema in the prompt decays. Product teams edit prompts without editing the validator. Drift is guaranteed.
Multiple consumers, one model. The same extraction feeds a chat confirmation UI and a POST to ERP. The UI truncates fields the API requires.
Retrieval poisons context. A RAG chunk from an old internal doc mentions deprecated order_type values. The model faithfully reproduces obsolete enums.
Agent loops amplify damage. An agent retries the POST, gets a 500, asks the model to "fix" the JSON, and invents a new invalid value each time. See RAG failure modes for retrieval validation that prevents feeding stale contract text into generation.
Validation belongs on the wire, not in hope. Treat LLM output like an untrusted webhook payload. Parse, then enforce deterministic rules before side effects. The strict JSON schema pillar makes the same argument for refund and billing tools.
What the Market Offers (And the Honest Gap)
Integration platforms with "AI steps." They move data. Few run org-specific enum locks on model output before your credentials hit a legacy URL.
Gateway retries on 429. Provider failover is real and separate. It does not catch HTTP 200 with order_type: overnight.
Embed OpenAPI in the prompt only. Cheap to ship. Expensive to debug when production traffic hits the one field your spec allowed as free text but ERP rejects.
Post-hoc monitoring on API errors. You learn after customers notice. Better than nothing. Not a guardrail.
Manual operator review for every order. Safe at low volume. Collapses when the chat channel succeeds and order volume scales.
ValGuard sits on the LLM response path. It validates structured output before your integration client POSTs to the legacy API. It does not call your mainframe, rewrite your ERP, or guarantee business-rule correctness (credit limits, inventory checks). It guarantees the JSON matches the contract you configured. Guardrail at generation time; integrate on your side.
That distinction belongs in architecture docs and vendor evaluations. Buyers should ask: where does enum enforcement run, and who owns the schema version?
The Desired Model: Parse NL, Enforce Schema, POST or Review
Production NL-to-legacy flows need a short, auditable graph.
user message → parse to draft JSON → schema + enum gate → ready for API client
↓ block
needs review queue
Stage 1: Parse natural language. Loose requests become draft ERP order JSON: customer_id, order_type, currency, line_items[] with sku and quantity. Extraction is probabilistic. That is fine here because the next stage is deterministic.
Stage 2: Enforce legacy schema. The shipped legacy_erp_order_schema_agent template runs five rules:
valid_formatrequires JSON.json_schema_validatechecks the object shape.customer_id,order_type,currency, andline_itemsare required, and each line item needs a stringskuand a numericquantity.no_markdown_fenced_wrapperrejects fenced output.enum_validatorlocksorder_typetostandard,rush, andbackorder.valid_iso_currencycheckscurrencyagainst ISO codes.
We ran drafts through that pack. order_type: "overnight" is blocked by the enum rule. currency: "dollars" is blocked by the ISO rule, which is exactly the "bill in dollars" failure from the opening. A null quantity is blocked by the schema, because null is not a number.
The shipped schema is deliberately light. It does not set a minimum quantity or a pattern for customer IDs, so a quantity of -5 and a customer_id of "???" both pass. Add minimum, pattern, and length constraints to your schema, and you get min/max and ID-format enforcement from the same rule. The extraction template, legacy_erp_order_extract_agent, adds placeholder blocking for "TBD," "N/A," "unknown," "null," and "TODO," plus a 100-item cap on line_items.
Routing.
- Valid payloads → ready for API client (your service POSTs, or a human approves then POSTs).
- Schema or enum failures → needs review with validator errors attached. No silent forward of bad JSON.
Bring your own schema in production. The shipped playbook models a fictional ERP order shape you replace field-for-field with your OpenAPI spec or internal JSON Schema artifact.
On our benchmark hardware the five-rule schema pack evaluates in about 1.5 µs at p50, and the seven-rule extraction pack in about 2.4 µs. A guarded request through the proxy adds about 0.36 ms at p50 with a mocked upstream, excluding the model call. See the latency methodology for what each number includes. That is cheap insurance compared to debugging production 500s from a chat surface or replaying a retry storm against a fragile backend.
The Legacy API Schema Bridge playbook encodes this pattern. Pair it with webhook contract validation thinking for symmetric discipline on inbound and outbound JSON.
For hands-on wiring, follow validate LLM output and test validators in CI. Schema gates belong in the same pipeline as unit tests, not only in production logs.
Benefits You Can Measure
Fewer ERP 500s from chat origin. Track invalid payloads blocked at the gate versus errors returned by the legacy API. The ratio should tilt toward blocked-at-gate as you tune extraction.
Faster debugging. Validator errors name field paths and rule IDs. "Enum violation at order_type" beats grep through chat logs.
Versioned contracts. Pin schema version in request context. Reject payloads generated against an old enum list after ERP deploy.
Safer agent autonomy. Agents may propose orders. They may not POST until validation passes. Combine with agentic tool call validation on the tool boundary.
Provider-agnostic consistency. Same validator runs whether extraction used OpenAI, Anthropic, or a local model. Swap providers without rewriting ERP integration.
Human review on real ambiguity. Reviewers see drafts that failed schema, not every order. Queue depth stays manageable.
CI fixtures for near-misses. "overnight" blocked in tests before it reaches ACME's rush order on a Friday afternoon.
Minimum Production Checklist
-
Authoritative schema artifact. One JSON Schema or OpenAPI-derived file in version control. Not three divergent copies in prompts, wiki, and integration code.
-
Enum locks separate from string types. ERP enums are not "any string."
enum_validatorwith your deployed list, updated on ERP release. -
Nested object validation. Line items, addresses, tax blocks. Top-level pass is insufficient.
-
Reject markdown wrappers. The shipped template blocks fenced JSON outright. Fail if prose or fences surround the payload.
-
Block, do not auto-correct enums. Silent remap of
overnight→rushhides model drift and trains wrong user expectations. -
Idempotency keys on POST. Chat double-submits and webhook retries must not duplicate orders when validation passes twice.
-
Review queue with errors. Human sees draft JSON, field paths, and failed rules. One-click reject or edit-and-resubmit through the same gate.
-
Shadow validation on live traffic. Log would-block before enforcement. Tune extraction prompts from real failures.
-
Agent retry policy. On deterministic schema fail, widen extraction once or escalate. Do not loop identical POSTs. Related: retry logic that made latency worse.
-
Observability. Metrics on pass rate, top failing fields, schema version mismatches. Alert when pass rate drops after a model or prompt change.
Wire the Bridge Before the POST
Chat to legacy ERP is a schema problem wearing an AI costume. Validate enums and nested fields on the model output path. POST only after pass.
Install the Legacy API Schema Bridge playbook, drop in your ERP schema, run shadow mode on production-shaped fixtures, then enforce on the integration path. Browse playbook templates for adjacent gates, or fork from orchestration templates if the chat flow spans multiple validated steps.
Your mainframe was not built for conversation. Your guardrails can be.