Optional typed client parsing
The first request needs only an HTTP client. If your application already uses Pydantic or Zod, you can also parse the returned value into local types. Install Pydantic 2 or Zod 4 before running the matching example.
The example below uses a conditional output: accepted requests have reason none, and rejected requests have reason missing_details. It illustrates why a local parser and the server schema are different responsibilities.
Keep advanced rules in a JSON Schema file. Your Python or TypeScript code loads that file unchanged, sends the request and parses the response into a small output model.
- Python
- TypeScript
- cURL
These optional typed Python examples use Pydantic for response parsing and HTTPX for requests.
python -m pip install "pydantic>=2.13,<3" "httpx>=0.28,<1"
Use Python 3.10 or later. Save an example as example.py and run python example.py.
These optional typed TypeScript examples use Zod for response parsing and Node’s built-in fetch.
npm install zod@4
Use Node.js 24 or later. Save an example as example.ts and run node example.ts, or use your TypeScript setup.
Use curl to send JSON Schema directly. No Python or JavaScript libraries are required.
The registration and file-based schema examples also use jq to construct JSON bodies.
1. Save the schema
Save this as conditional.schema.json. An accepted request must have reason none; a rejected request must have reason missing_details.
{
"type": "object",
"properties": {
"status": {
"enum": [
"accepted",
"rejected"
],
"description": "Whether the supplied request is complete enough to accept.",
"type": "string"
},
"reason": {
"enum": [
"none",
"missing_details"
],
"description": "The reason for the decision.",
"type": "string"
}
},
"required": [
"status",
"reason"
],
"additionalProperties": false,
"if": {
"properties": {
"status": {
"const": "accepted"
}
},
"required": [
"status"
]
},
"then": {
"properties": {
"reason": {
"const": "none"
}
}
},
"else": {
"properties": {
"reason": {
"const": "missing_details"
}
}
}
}
The required in the condition makes its treatment of absent fields explicit. In this example both fields are also required at the root.
2. Load it and send a request
Set your API key and run the example from the directory containing the schema file. Connection prerequisites are included below; the additional parser dependencies are shown above.
Before you run this example
Call https://api.blatent.ai from your server. Set your API key in the same terminal where you run the example:
export BLATENT_API_KEY='YOUR_SERVICE_KEY'
Python requires Python 3.10+ and HTTPX:
python -m pip install "httpx>=0.28,<1"
TypeScript requires Node.js 24+ and uses its built-in fetch. The cURL examples require curl and jq.
Save the displayed files and the selected client in one directory. Run the client there with python example.py, node example.ts or bash example.sh. Downloads use the example's name in place of example.
- Python
- TypeScript
- cURL
import json
import os
from pathlib import Path
import httpx
from typing import Literal
from pydantic import BaseModel
class Decision(BaseModel, extra="forbid"):
status: Literal["accepted", "rejected"]
reason: Literal["none", "missing_details"]
schema = json.loads(Path("conditional.schema.json").read_text())
response = httpx.post(
"https://api.blatent.ai" + "/v1/resolve",
headers={"Authorization": f"Bearer {os.environ['BLATENT_API_KEY']}"},
json={
"input": "All required request details have been supplied.",
"schema": schema,
},
timeout=195,
)
response.raise_for_status()
result = Decision.model_validate(response.json()["output"], strict=True)
print(result.model_dump_json(indent=2))
import { readFileSync } from "node:fs";
import { z } from "zod";
const Decision = z.strictObject({
status: z.enum(["accepted","rejected"]),
reason: z.enum(["none","missing_details"]),
});
const schema = JSON.parse(readFileSync("conditional.schema.json", "utf8"));
const response = await fetch(
"https://api.blatent.ai" + "/v1/resolve",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLATENT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
input: "All required request details have been supplied.",
schema: schema,
}),
signal: AbortSignal.timeout(195_000),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const body = await response.json();
const result = Decision.parse(body.output);
console.log(JSON.stringify(result));
set -eu
body=$(jq -n --slurpfile schema 'conditional.schema.json' \
--arg input 'All required request details have been supplied.' \
'{input: $input, schema: $schema[0]}')
curl --fail-with-body --silent --show-error \
"https://api.blatent.ai/v1/resolve" \
-H "Authorization: Bearer $BLATENT_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary "$body"
Also download conditional.schema.json and run the example from that directory.
3. Use the result
Python and TypeScript provide result.status and result.reason. The local Decision definition checks those fields and their allowed values. It does not repeat the descriptions or conditional rules, and is never exported as the request schema.
Illustrative value of output:
{"status":"accepted","reason":"none"}
Struct receives the full JSON Schema and uses its supported constraints for generation. The local model checks only the response shape: on its own, it would accept accepted with missing_details. If your application also needs independent validation of every constraint, validate against the original JSON Schema before parsing the result.
To reuse this schema, register it once using the loaded schema value and send the returned schema_id on later requests. Keep the same local output model to parse responses.
Related: conditions and dependencies or schema composition.