# HTTP API Integration ## Scope This document defines the implemented inbound HTTP contract for Scriptorium. Current scope is only: - `POST /v1/runs` For CLI behavior, see the [CLI reference](../cli.md). ## Endpoint - Method: `POST` - Path: `/v1/runs` - Content type: JSON request/response Route behavior: - unknown path: `404 not_found` - unsupported method on `/v1/runs`: `405 method_not_allowed` Copyable request example file: - `examples/http-run.json` ## Request Body ```json { "prompt_id": "generic.structured_events", "profile_id": "local-quality", "prompt_version": "1.0.0", "inputs": { "transcript": {"type": "file", "uri": "./examples/fixtures/transcript.md"}, "glossary": {"type": "inline", "body": "party:\n - Rin"} }, "vars": { "session_date": "2026-05-04" }, "model": { "endpoint": "http://localhost:8000/v1", "model": "gpt-4o-mini", "temperature": 0.0, "max_tokens": 800, "top_p": 1.0, "timeout_seconds": 120, "service_tier": "priority", "reasoning_effort": "medium", "api_key_env": "SCRIPTORIUM_API_KEY", "extra_params": { "route": "primary", "provider_options": { "retry_budget": 2 } } }, "include_raw_output": false } ``` Required fields: - `prompt_id` - `inputs` (must contain at least one named input) Input reference types currently supported by runtime artifact loading: - `file` - `inline` Model override notes: - Numeric model override fields distinguish omitted values from explicit zero values. For example, omitting `temperature` preserves the selected profile/default value, while `"temperature": 0` explicitly sets the effective temperature to zero. - `extra_params` accepts JSON-compatible values: strings, numbers, booleans, objects, and arrays. - `extra_params` are passed through effective model metadata and flattened into top-level provider request fields by the OpenAI-compatible client. - `extra_params` keys must not be empty and must not collide with reserved outbound fields: `model`, `session_id`, `messages`, `temperature`, `max_tokens`, `top_p`, `service_tier`, `reasoning_effort`, or `response_format`. - Raw API-key values are not accepted. Use `api_key_env` to name an environment variable. ## Strict JSON Rules Request decoding uses strict JSON field checks: - unknown request fields are rejected with `400 invalid_json` - unknown `model` fields are rejected with `400 invalid_json` - raw API-key payload fields such as `api_key` are rejected as unknown fields ## Success Response Status: `200 OK` Response shape: ```json { "artifact": { "name": "output", "content_type": "application/json", "body": "{\"summary\":\"...\"}", "uri": "", "size": 123, "hash": "..." }, "validation": { "status": "passed", "mode": "json_schema", "errors": [], "schema_path": "structured_events.schema.json", "repair_attempts": 0, "is_valid": true }, "metadata": { "run_id": "...", "prompt_id": "generic.structured_events", "prompt_version": "1.0.0", "prompt_hash": "...", "rendered_prompt_hash": "...", "selected_profile_id": "local-quality", "model_name": "gpt-4o-mini", "endpoint": "http://localhost:8000/v1", "model_params": { "endpoint": "http://localhost:8000/v1", "model": "gpt-4o-mini", "temperature": 0, "max_tokens": 800, "top_p": 1, "timeout_seconds": 120, "service_tier": "priority", "reasoning_effort": "medium", "api_key_env": "SCRIPTORIUM_API_KEY", "extra_params": { "route": "primary", "provider_options": { "retry_budget": 2 } } }, "input_hashes": { "transcript": "..." }, "usage": { "prompt_tokens": 11, "completion_tokens": 22, "total_tokens": 33, "cached_tokens": 0, "cache_write_tokens": 0 }, "start_time": "2026-05-04T12:00:00Z", "end_time": "2026-05-04T12:00:01Z", "duration_ms": 1000, "validation_mode": "json_schema", "validation_status": "passed", "repair_attempts_used": 0 } } ``` `raw_model_output` is omitted by default. `metadata.usage.cached_tokens` and `metadata.usage.cache_write_tokens` are always present as numbers. They are `0` when the provider omits compatible cache usage fields or reports no cache activity. To include it, send: - `"include_raw_output": true` ## Validation Failure Behavior Validation content failures do not map to HTTP error status. Behavior: - status remains `200 OK` - `validation.status` is `failed` - validation errors are returned in `validation.errors` ## Error Responses Error body shape: ```json { "error": { "code": "invalid_request", "message": "prompt_id is required" } } ``` Current error mapping (non-exhaustive): - `400 invalid_json`: malformed JSON or unknown JSON fields - `400 invalid_request`: missing/invalid request fields - `400 profile_required`: no explicit `profile_id` and prompt has no `default_profile` - `400 prompt_load_failed`: prompt definition invalid/unloadable - `400 profile_load_failed`: profile invalid/unloadable - `400 artifact_read_failed`: input artifact loading failed - `400 prompt_render_failed`: template render failed - `400 api_key_env_missing`: named API-key environment variable is missing - `404 prompt_not_found` - `404 profile_not_found` - `502 llm_failed`: outbound model request failed - `500 validation_runtime_failed`: validator runtime/schema-load failure - `500 internal_error` ## Security And Deployment Note The HTTP adapter has no built-in authentication or authorization. Deploy behind trusted controls (for example authenticated gateway/reverse proxy and network boundaries).