---
title: "Create an LLM provider (owner-only) · 0 credits"
method: POST
path: "/api/v1/llm-providers"
tags: ["BYO-LLM"]
---

# Create an LLM provider (owner-only) · 0 credits

`POST /api/v1/llm-providers`

## Request

- Base URL: `https://legal.nexusquantum.legal`
- URL: `https://legal.nexusquantum.legal/api/v1/llm-providers`
- Auth: HTTP bearer

Creates a BYO-LLM configuration. The credential (`api_key`, or `aws:{…}` for kind bedrock) is WRITE-ONLY: it travels in the body, is encrypted server-side (AES-256-GCM) and is NOT returned — the response includes only `key_fingerprint` (non-secret). `base_url` (openai_compatible/anthropic) is validated against SSRF. Limit of 20 providers per firm. Firm-scoped OWNER-ONLY; it NEVER accepts `firm_owner_id` from the client. No charge. Scope: mcp | * (NOT cases).

## Request body

- CreateLlmProviderRequest: The credential is WRITE-ONLY: `api_key` (openai_compatible/anthropic) or `aws` (bedrock). It is encrypted server-side and never returned.
  - `label` string, required
  - `kind` 'openai_compatible' | 'anthropic' | 'bedrock', required
  - `model_default` string, required
  - `base_url` string: Required for openai_compatible; optional for anthropic; ignored for bedrock. Validated against SSRF.
  - `model_map` object: Role→model map, no silent defaults. Recommendation (not a default): A → `claude-fable-5` · B → `claude-opus-4-8` · C → `claude-opus-4-8` or an equally strong reasoning model; any model of the 3 kinds works in any node. `B` ≠ `A` recommended.
  - `extra_headers` object
  - `routing_policy` 'own_only' | 'own_then_platform'
  - `role` 'A' | 'B' | 'C', nullable: Node this engine is assigned to: 'A' (primary analysis), 'B' (adversarial audit) or 'C' (adversarial counterparty). Omit or null = the firm's DEFAULT engine, which serves every node and role (consulta, chat, draft…). Precedence: node engine → default engine → (when the policy forbids platform) Node A engine → platform. Allows a DIFFERENT engine per node: B and C should not share a model with A, or the cross-audit loses its value.
  - `billing_mode` string
  - `api_key` string: Credential (openai_compatible/anthropic). WRITE-ONLY: never returned in responses.
  - `aws` AwsCredentials: AWS credentials for kind bedrock. WRITE-ONLY: `secretAccessKey` is never returned in responses.
    - `accessKeyId` string, required
    - `secretAccessKey` string, required
    - `region` string, required

## Response `201`

Provider created (non-secret projection + `secret_at_rest`).

- LlmProvider: Firm BYO-LLM configuration (your own LLM engine, firm-level). NON-SECRET projection: the credential (`api_key` / `aws.secretAccessKey`) is WRITE-ONLY and NEVER appears here — only `key_fingerprint` is exposed (non-secret). Once `enabled`, the engine applies to ALL of the firm's generative flows (analyze included).
  - `id` string, uuid
  - `label` string: Human-readable name, unique within the firm.
  - `kind` 'openai_compatible' | 'anthropic' | 'bedrock': Adapter family.
  - `base_url` string, nullable: Endpoint (openai_compatible: required; anthropic: optional; bedrock: null, derived from region). Validated against SSRF.
  - `model_default` string: Default model.
  - `model_map` object: Role→model map (e.g. { "A": "claude-opus-4-8", "B": "gpt-4o" }). No silent defaults: each node uses exactly the declared model (or `model_default` when the role is not mapped). Recommendation (not a default): Node A → `claude-fable-5` · Node B → `claude-opus-4-8` · Node C → `claude-opus-4-8` or another equally strong reasoning model; any model of the 3 kinds works in any node. `B` ≠ `A` is recommended to preserve the independence of the audit.
  - `key_fingerprint` string, nullable: NON-secret, NON-reversible fingerprint of the credential (hash, e.g. `sha256:a1b2c3d4e5f6`; older rows may show the legacy format `sk-p…a1b2`). The ONLY representation of the key that leaves the API.
  - `extra_headers` object: Optional extra headers for the provider.
  - `routing_policy` 'own_only' | 'own_then_platform': own_then_platform leaves the platform chain as a fallback if your provider fails recoverably.
  - `role` 'A' | 'B' | 'C', nullable: Node this engine is assigned to: 'A' (primary analysis), 'B' (adversarial audit) or 'C' (adversarial counterparty). Omit or null = the firm's DEFAULT engine, which serves every node and role (consulta, chat, draft…). Precedence: node engine → default engine → (when the policy forbids platform) Node A engine → platform. Allows a DIFFERENT engine per node: B and C should not share a model with A, or the cross-audit loses its value. Additive (per-node BYO, 2026-07-24).
  - `billing_mode` string: Billing mode (default platform).
  - `enabled` boolean: Whether it is active for routing firm traffic.
  - `last_verified_at` string, date-time, nullable: Last successful /test health check.
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `secret_at_rest` 'encrypted_aes_256_gcm' | 'plaintext': Creation response only: at-rest encryption status of the credential.

## Other responses

- `400`: INVALID_JSON | VALIDATION_ERROR (invalid label/kind/model_default/routing_policy/model_map/api_key|aws)
- `409`: PROVIDER_LABEL_TAKEN (duplicate label within the firm)
- `422`: INVALID_PROVIDER_URL (base_url fails the SSRF filter) | PROVIDER_LIMIT_REACHED (>20 per firm)

---

[API](https://skmtc.dev/nexusquantum/apis/nexus-legal-api.md) · [All operations](https://skmtc.dev/nexusquantum/apis/nexus-legal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nexusquantum/apis/nexus-legal-api/revisions/4084d8d4eb0b?raw)
