---
title: "ai.credential-put@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/ai.credential-put@1"
updated: null
---

# ai.credential-put@1 · OpenVibe.Services

HTML: [ai.credential-put@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/ai.credential-put@1)

# AiCredentialPut `ai.credential-put@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

An older major, still in the catalog. The current one is [`ai.credential-put@2`](/docs/contracts/ai.credential-put).

- Version: 1.0.0
- Owner: ai
- Visibility: first-party
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/ai/credential-put.v1.json`](/docs/contracts/ai.credential-put@1.json)

ai.credential-put@1 (OpenVibe.AI; roadmap WS-O task 2): a person's own provider key, stored by the service that holds their consent (Live, for a streamer's AI viewers), PUT /api/v1/credentials/{subject} with capability ai.credential.manage. OpenVibe.AI encrypts the key at rest and never returns it; runs that name the credential call that provider with it, never a shared key, and are limited by \`budget\_usd\_per\_day\`. \`base\_url\` is any https endpoint (OpenAI-compatible or Anthropic); OpenVibe.AI connects only to public addresses. Provider \`node\` (contracts 0.220.0) is the person's own machine instead: \`machine\` names it, there is no key or base\_url, and a run reaches it only through OpenVibe.Bot (capability bot.machine.ai), only for that person, where they turned on "Let my AI use this computer's models".

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `provider` | enum | yes | openai = any OpenAI-compatible endpoint. node = the person's own machine: a model on their own model server, through their OpenVibe Link and OpenVibe.Bot (no key, no base\_url, no cost). | - `one of "openai", "anthropic", "link"` |
| `machine` | string |  | provider link: the person's own machine (openvibe.link/machines) whose OpenVibe Link runs the model (the ai plugin, contracts 0.219.0), or \`any\` (contracts 0.221.0): whichever of their machines is on, lets their AI use its models and offers the model, the fastest first, the next one when it is busy or away. Never anyone else's machine. | - `pattern ^(dev_[0-9A-HJKMNP-TV-Z]{26}\|any)$` |
| `base_url` | string |  |  | - `pattern ^https://[^\s/?#@]+(/[^\s?#]*)?$`<br>- `maxLength 300` |
| `api_key` | string |  | Required the first time, and whenever provider or base\_url changes (a key is never sent to a new endpoint without being entered again); otherwise the stored key is kept. | - `minLength 8`<br>- `maxLength 400` |
| `models` | object |  | Model per Live role; \`chat\` is the default for the others. | - `no other fields` |
| `models.chat` | string |  |  | - `minLength 1`<br>- `maxLength 120` |
| `models.vision` | string |  |  | - `minLength 1`<br>- `maxLength 120` |
| `models.director` | string |  |  | - `minLength 1`<br>- `maxLength 120` |
| `models.summary` | string |  |  | - `minLength 1`<br>- `maxLength 120` |
| `models.legacy` | string |  |  | - `minLength 1`<br>- `maxLength 120` |
| `budget_usd_per_day` | number |  | The person's own daily cap on estimated spend with this key; 0 or absent = no cap. | - `minimum 0`<br>- `maximum 1000` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

The fixtures that ship with the package are the current major's.

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('ai.credential-put@1', value);   // { valid, errors: [{ path, message }] }
~~~~
