Seif
Seif de credențiale, zero-knowledge în mod implicit: sincronizare criptată, broker pentru agenți, aprobări și chei de dispozitiv.
Kodwen Vault îți păstrează credențialele criptate pe propriile dispozitive: clienții sigilează fiecare element (XChaCha20-Poly1305, chei împachetate cu hibridul post-cuantic X-Wing) înainte de încărcare, deci în mod implicit /v1/vault/* stochează și sincronizează text cifrat pe care Kodwen nu îl poate citi. Seiful este zero-knowledge în mod implicit, cu o singură excepție, dezactivată implicit și setată pentru fiecare element: proprietarul unui seif poate marca un element ca utilizabil în cloud (PUT /v1/vault/items/{id}/cloud). Clientul trimite atunci elementul decriptat, iar gateway-ul păstrează o a doua copie, sigilată cu o cheie KMS Kodwen, pe care o poate deschide ca să servească cererile agenților (/v1/vault/http, /v1/vault/resolve, /v1/vault/derive) cât timp dispozitivele tale sunt offline. Doar proprietarul seifului o poate activa sau dezactiva; dezactivarea, modificarea elementului sau ștergerea lui elimină acea copie. Agenții nu primesc niciodată valori secrete. Ei văd un catalog de handle-uri ({{vault:<slug>}}), cer o decizie de politică (niveluri t0-t4 sau deny), așteaptă aprobarea ta când nivelul o cere și apelează endpoint-uri HTTPS intermediate al căror răspuns este redactat.
SDK-urile expun toată suprafața ca codai.vault (TypeScript și Python), iar cheile de dispozitiv sub codai.vault.devices.
Elemente: sincronizare, scriere și roluri
Citirea și sincronizarea elementelor
GET /v1/vault/items răspunde { items, server_time, has_more }. Fiecare element este rândul stocat: id, vault_id, revision, wrapped_key, ciphertext, kind, slug, agent_meta, honeytoken, cloud_usable, deleted_at, last_used_at, created_at, updated_at.
- Lista completă (fără
since): doar elementele active, cele mai recent modificate primele, cel mult 5000.has_moreeste adevărat când există peste 5000 de elemente active. - Modificări (
?since=<dată și oră ISO 8601>): fiecare element modificat dupăsince, inclusiv cele șterse (deleted_ateste setat: elimină elementul local), cele mai vechi primele, cel mult 1000 pe apel. - Elemente șterse: un element șters de mai mult de 30 de zile păstrează doar un rând de marcaj, iar
wrapped_keyșiciphertextale lui sunt șiruri goale, deci un client nu trebuie să decripteze niciodată un rând care aredeleted_at. has_more: true: apelează din nou imediat cusince=server_timeprimit, care este atunciupdated_atal ultimului element întors. Bazează-te pehas_more, nu pe numărul de elemente: o pagină nu este tăiată niciodată în interiorul unei milisecunde, deci poate avea mai puțin de 1000 de elemente și are peste 1000 doar când mai mult de 1000 de elemente s-au modificat în aceeași milisecundă.has_more: false: ești la zi.server_timeeste ceasul bazei de date, citit înaintea elementelor, minus 5 secunde; păstrează-l casinceal următoarei sincronizări. Poate fi mai devreme decâtsince-ul trimis de tine. Un element modificat în acele ultime secunde poate sosi din nou: înlocuiește copia ta a aceluiid.- Un
sincecare nu poate fi citit ca dată și oră, inclusiv o valoare goală, răspunde 400invalid_since. Momentele se compară la milisecundă.
Scrierea elementelor
PUT /v1/vault/items/{id} { vault_id, revision, wrapped_key, ciphertext, kind, slug?, agent_meta?, honeytoken? } răspunde 201 { id, revision } pentru un element nou și 200 { id, revision } pentru o actualizare. Corpul nu are id: calea numește elementul, iar o cheie pe care ruta nu o cunoaște răspunde 400.
- Un element nou trimite
revision: 1; o actualizare trimite revizia stocată + 1. Orice altceva răspunde 409{ error: { code: 'revision_conflict' }, revision }cu revizia stocată: reîncarcă elementul și reîncearcă. - 409
item_deleted: elementul a fost șters pe alt dispozitiv și rămâne șters. Elimină-l local; ca să îi păstrezi conținutul, creează un element nou cu un id nou. kindși seiful unui element sunt fixate la creare; o schimbare răspunde 400.- Expunerea către agenți (
slugșiagent_meta, trimise mereu împreună) șihoneytokensunt decizii ale proprietarului sau ale unui manager al seifului. Un editor care creează un element cu ele sau le schimbă primește 403. Fiecare actualizare trimite înapoi neschimbateslug,agent_metașihoneytokenstocate; omiterea lor contează ca schimbare. - Un
slugdeja folosit în același seif răspunde 400. O schimbare de conținut elimină copia pentru cloud a elementului.
DELETE /v1/vault/items/{id} păstrează rândul ca element șters pentru sincronizare, revocă toate permisiunile pe el și îi elimină copia pentru cloud. Ștergerea unui element deja șters răspunde același 200 { deleted: true } și nu schimbă nimic.
Înregistrarea unei folosiri locale
POST /v1/vault/items/{id}/used { via } înregistrează că un passkey sau o autentificare a fost folosită pe un dispozitiv (via: windows_plugin, android_provider, ios_provider, desktop sau phone) și răspunde { id, last_used_at }. Se stochează doar momentul, niciodată conținutul. Ruta păstrează o singură marcare pe element la 60 de secunde: o repetare în acest interval răspunde 200 cu last_used_at stocat, nu scrie nimic și nu înregistrează niciun eveniment item.used. Nu răspunde niciodată 429. Un element necunoscut, șters sau inaccesibil răspunde 404.
Ce poate face fiecare rol pe elemente
| Acțiune | viewer | editor | manager | owner |
|---|---|---|---|---|
Citește și sincronizează elementele (GET /v1/vault/items) | da | da | da | da |
Înregistrează o folosire locală (POST /v1/vault/items/{id}/used) | da | da | da | da |
| Creează, modifică și șterge elemente; setează limitele și programul de rotire | nu | da | da | da |
Setează sau schimbă expunerea către agenți (slug, agent_meta) și honeytoken | nu | nu | da | da |
Activează sau dezactivează utilizarea în cloud (PUT /v1/vault/items/{id}/cloud); setează sau elimină un derivator | nu | nu | nu | da |
Un apelant care nu este membru al seifului primește 404, același răspuns ca pentru un seif care nu există.
Răspunsuri 429
Fiecare 429 are corpul { error: { message, type: 'rate_limit_error', code } } și un antet Retry-After în secunde.
code | Rute | Când | Retry-After |
|---|---|---|---|
vault_rate_limited | POST /v1/vault/use, /v1/vault/http, /v1/vault/resolve, /v1/vault/derive | a fost atinsă o limită per handle a elementului | 60 pentru limita pe minut, 3600 pentru limitele zilnice |
rate_limit_exceeded | GET /v1/vault/hibp/range/{prefix} | peste 300 de apeluri pe utilizator într-o oră | 600 |
rate_limit_exceeded | POST /v1/vault/add-requests | există deja 20 de cereri de adăugare în așteptare | 60 |
Chei de dispozitiv și confirmare dovedită
O aprobare dovedește cine a decis. Pe lângă semnătura v1 a cheii seifului, o decizie poate purta o dovadă v2 de la o cheie de dispozitiv protejată hardware (Android Keystore pe telefon și ceas, Windows Hello pe desktop) sau de la un passkey. Cheile de dispozitiv sunt doar chei publice; cheia privată nu părăsește niciodată hardware-ul securizat al dispozitivului.
Înrolarea
POST /v1/vault/devices/challengeîntoarce unnoncede unică folosință (32 de octeți aleatori, base64url), valabil 5 minute.- Dispozitivul își creează cheia, iar cheia seifului și cheia dispozitivului semnează amândouă mesajul de înrolare:
codai-vault/device-enroll/v1|<device_id>|<kind>|<spki_sha256>|<nonce>, undespki_sha256este base64url(SHA-256(SubjectPublicKeyInfo DER)). POST /v1/vault/devicestrimitedevice_id(android-…,wear-…,desktop-…,ios-…saucli-…),kind(android_keystore,windows_hello,ios_secure_enclavesaucli_ed25519),name,surface(phone,wear,desktopsaucli),public_key,nonce,vault_signature,device_signatureși, când există, oattestation. Răspunsul este201 { device }.
Reînrolarea aceluiași device_id îi înlocuiește cheia. GET /v1/vault/devices listează cheile tale (inclusiv cele revocate), PATCH /v1/vault/devices/{id} redenumește una, iar DELETE /v1/vault/devices/{id} o revocă imediat: următoarea ei dovadă primește 403 device_revoked.
Toate valorile binare sunt base64url fără padding. Android semnează cu ECDSA P-256 SHA-256 (DER); Windows Hello semnează cu RSASSA-PKCS1-v1_5 SHA-256; cli_ed25519 (cheia software creată de codaid vault enroll) semnează cu Ed25519 (semnătură brută de 64 de octeți, public_key = SubjectPublicKeyInfo DER Ed25519).
Tipuri de atestare
attestation | Semnificație |
|---|---|
android-strongbox | Atestarea Google a cheii verificată, cheia ținută într-un element securizat StrongBox. |
android-tee | Atestarea Google a cheii verificată, cheia ținută în TEE. |
tpm | O atestare TPM a cheii Windows Hello, verificată față de rădăcinile TPM Microsoft. |
hello-unattested | O cheie Windows Hello fără atestare TPM. |
ios-unattested | O cheie P-256 din Secure Enclave pe iPhone (ios_secure_enclave, suprafața phone, Face ID la fiecare semnătură). Încă fără atestare, deci aprobă doar cereri T3; o aprobare T4 primește 403 step_up_required. |
software | O cheie cli_ed25519 ținută într-un fișier pe calculator. Poate dovedi doar apeluri /v1/vault/resolve; nu poate aproba și nu poate debloca niciodată (403 device_not_allowed). |
Cheile Android trebuie să trimită attestation: { android_chain: [...] } (frunza prima); provocarea de atestare este formată din octeții nonce-ului, iar cheia atestată trebuie să fie egală cu public_key. Cheile Windows Hello pot trimite attestation: { tpm: { attestation, cert_chain } }; fără ea cheia este hello-unattested, cu una invalidă înrolarea eșuează. Cheile de iPhone (ios_secure_enclave) nu trimit deloc attestation (cu una, înrolarea eșuează cu attestation_invalid); semnătura este ECDSA P-256 SHA-256 în DER, ca la Android. Erori: 400 invalid_nonce, possession_failed, attestation_required, attestation_invalid; 403 invalid_signature; 409 device_id_taken; 503 revocation_unavailable (lista de revocare Google nu a putut fi verificată, reîncearcă mai târziu).
Mesajele de aprobare
- v1 (cheia seifului):
codai-vault/approve/v1|<approval_id>|<action_hash>|<decision>|<scope>, trimis casignature. - v2 (cheie de dispozitiv sau passkey):
codai-vault/approve/v2|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>, trimis caproof: { type: 'device', device_id, signature }. - v3 (cheie de dispozitiv sau passkey + potrivirea numărului):
codai-vault/approve/v3|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>|<preview_digest>|<match_number>, trimis cumatch_numberlângăproof.preview_digesteste base64url(SHA-256) al textului canonic alrequest.preview(codai-vault/preview/v1, apoititle,agent,mode,host,action,purpose,taskca liniicheie=valoare, cu\, linie nouă și CR escapate), deci semnătura acoperă exact ce a văzut aprobatorul. - passkey: provocarea WebAuthn este base64url(SHA-256(mesajul v2 cu id-ul de dispozitiv
passkey)), trimisă caproof: { type: 'passkey', response }.
Trimite cel mult unul dintre signature și proof. step_up_acr este încă acceptat, dar ignorat: o confirmare declarată de client nu dovedește nimic.
Reguli pe niveluri
- Refuzul nu cere dovadă (butonul Refuză din notificare este suficient).
- Aprobarea T3 acceptă o semnătură v1 validă, o dovadă de dispozitiv sau o dovadă passkey.
- Aprobarea T4 cere o dovadă de dispozitiv sau passkey; o semnătură v1 primește 403
step_up_required. Toate tipurile de atestare de mai sus sunt acceptate astăzi. - Ceasul Wear aprobă doar T3: o cheie de ceas nu poate fi atestată ca legată de biometrie, deci o dovadă de la un dispozitiv
wearpe o aprobare T4 primește 403wear_t3_only. - Potrivirea numărului: fiecare cerere T3/T4 primește un
match_numberdin 2 cifre, întors doar agentului (/vault/use,/vault/http,/vault/resolve). Aprobatorul vederequest.previewși treirequest.match_choices, niciodată numărul. O aprobare T4 pe o astfel de cerere cerematch_numbercu o dovadă v3: fără număr primește 403match_required; un număr greșit refuză imediat cererea și primește 403match_mismatch. Aprobările T3 și refuzurile acceptă în continuare v1/v2.
Alte erori de dovadă (403): invalid_signature, unknown_device, device_revoked, passkey_invalid.
Dovada pentru resolve (brokeri locali)
POST /v1/vault/resolve întoarce valori unui broker local (codaid, desktop) care le injectează într-un proces copil și îi redactează ieșirea. Brokerul trebuie să dovedească faptul că deține o cheie de dispozitiv înrolată; antetul x-codai-agent singur nu este de încredere.
POST /v1/vault/resolve/challengeîntoarce unchallengede unică folosință, valabil 120 s.- Brokerul semnează
codai-vault/resolve/v1|<challenge>|<device_id>|<digest>cu cheia dispozitivului, undedigest= base64url(SHA-256(handlesunite cu\n, apoi\n\n, apoiaction)), cu handle-urile exact cum sunt trimise și în aceeași ordine. - Corpul cererii resolve poartă
proof: { device_id, challenge, signature }.
Erori: 400 proof_required (fără dovadă), 400 invalid_challenge (necunoscut, folosit sau expirat), 403 invalid_device_proof (cheie care nu e a ta, revocată sau semnătură greșită), 403 broker_only (nu este un broker Kodwen). Evenimentul de audit use.resolved înregistrează device_id.
Protecții la anomalii
Fiecare utilizare de către un agent este verificată și față de protecțiile tale la anomalii, citite din GET /v1/vault/account (guards) și schimbate cu PATCH /v1/vault/settings { default_tier?, guards? } (trimite cel puțin unul; guards este parțial și se combină cu valorile curente, iar răspunsul este { default_tier, guards } efectiv).
| Protecție | Implicit | Se declanșează când | Motiv |
|---|---|---|---|
new_host | true | nicio utilizare permisă sau permisiune pentru acest element și host în ultimele 30 de zile | anomaly:new_host |
burst_max / burst_window_s | 5 / 60 | cel puțin burst_max cereri ale agenților pentru element în fereastră (burst_max: 0 = dezactivat) | anomaly:burst |
hour_start / hour_end / tz | 7 / 23 / Europe/Bucharest | utilizarea cade în afara [hour_start, hour_end) în tz (ambele ore null = dezactivat) | anomaly:hour |
O anomalie forțează decizia la t4: utilizatorul aprobă cu o cheie de dispozitiv sau un passkey (inclusiv potrivirea numărului), iar permisiunile existente care nu au fost aprobate la t4 sunt ignorate pentru acea utilizare. Un deny rămâne deny.
Blocare de urgență și deblocare
POST /v1/vault/lock (corp opțional, { via? }) este butonul de panică: revocă toate permisiunile active, refuză toate aprobările în așteptare și blochează seiful, răspunzând { locked_at, grants_revoked, approvals_denied }. Cheile dispozitivelor rămân înrolate ca să poți debloca. Apelul este idempotent. Cât timp e blocat, GET /v1/vault/account arată locked_at și lock_reason (panic sau honeytoken), iar orice utilizare de către agenți este refuzată cu motivul vault_locked (/v1/vault/http și /v1/vault/resolve răspund 403 vault_denied).
Deblocarea cere o dovadă protejată hardware peste o provocare de unică folosință:
POST /v1/vault/unlock/challengeîntoarce{ challenge, expires_at, message_template }(32 de octeți aleatori, base64url, valabilă 5 minute).- Construiește mesajul
codai-vault/unlock/v1|<challenge>|<device_id|passkey>:- cheie de dispozitiv (telefon, desktop): cheia semnează mesajul UTF-8 cu id-ul dispozitivului tău, trimis ca
proof: { type: 'device', device_id, signature }. Cheile de ceas sunt refuzate (wear_t3_only). - passkey (hub): provocarea WebAuthn este base64url(SHA-256(mesajul cu
passkeyîn locul id-ului de dispozitiv)), trimisă caproof: { type: 'passkey', response }.
- cheie de dispozitiv (telefon, desktop): cheia semnează mesajul UTF-8 cu id-ul dispozitivului tău, trimis ca
POST /v1/vault/unlock { challenge, proof, via? }răspunde{ unlocked: true }. Erori (403):challenge_invalid,unknown_device,device_revoked,wear_t3_only,invalid_signature,passkey_invalid.
Jurnalul de audit înregistrează vault.locked, vault.unlocked, vault.unlock_failed și use.locked.
Momeli (honeytokens)
Un element marcat honeytoken este o momeală pe care niciun agent legitim nu ar trebui să o atingă. O utilizare a lui este refuzată și declanșează o alarmă, iar acum blochează și seiful (lock_reason: 'honeytoken') și trimite o notificare de date fiecărui dispozitiv activ: { kind: 'vault.alarm', reason: 'honeytoken', locked: '1', title?, agent?, host? } (o blocare de urgență trimite aceeași alarmă cu reason: 'panic'). Deblochează ca mai sus după ce știi ce s-a întâmplat.
Limite per handle
Limitează cât de des pot agenții folosi un element. GET /v1/vault/limits listează { limits: [{ item_id, per_minute, per_day, units_per_day }] }; PUT /v1/vault/items/{id}/limits { per_minute, per_day, units_per_day } le setează (toate cele trei chei sunt obligatorii, null elimină o limită, toate null elimină limitele; rol de editor sau mai mare pe seiful elementului).
Se numără doar utilizările permise. O utilizare http costă 2 unități, orice alt mod 1. Peste o limită, /v1/vault/use, /v1/vault/http și /v1/vault/resolve răspund 429 { error: { code: 'vault_rate_limited', type: 'rate_limit_error', message } } cu Retry-After (60 s pentru limita pe minut, 3600 s pentru limitele zilnice), iar jurnalul de audit înregistrează use.limited.
Permisiunile se încheie odată cu sarcina
O permisiune creată pentru o sarcină (scope task sau orice permisiune care poartă task-ul trimis la /v1/vault/use) este revocată când sarcina se încheie: la POST /v1/tasks/{id}/confirm, la DELETE /v1/sessions/{id} și de un proces de curățare la fiecare 5 minute pentru sarcinile închise. Agenții și brokerii le pot încheia explicit cu POST /v1/vault/grants/revoke-task { task }, care răspunde { revoked: n }. GET /v1/vault/grants rămâne neschimbat; clienții grupează rândurile după task ca să arate permisiunile active.
Cereri de adăugare
Când un agent are nevoie de o credențială pe care seiful nu o are, nu trebuie niciodată să-ți ceară s-o lipești în chat. În schimb creează o cerere de adăugare, iar tu introduci valoarea într-o pagină Kodwen unde este criptată în browser (sau în aplicația desktop) înainte de salvare.
POST /v1/vault/add-requests { kind, title, slug?, hosts?, env_var?, fields?, purpose, task? }răspunde201 { id, url, status, expires_at }.urlestehttps://hub.codai.ro/vault/add?req=<token>; tokenul apare doar în acest răspuns.fieldssunt numele câmpurilor cerute (cel mult 10), niciodată valori. O cerere trăiește 10 minute; pot fi cel mult 20 de cereri în așteptare per utilizator.GET /v1/vault/add-requests/{id}răspunde{ id, status, slug, handle, item_id, expires_at }, undestatusestepending,completed,cancelledsauexpired, iarhandleeste{{vault:<slug>}}după finalizare.DELETE /v1/vault/add-requests/{id}o anulează.POST /v1/vault/add-requests/lookup { token }întoarce cererea doar utilizatorului autentificat căruia îi aparține (linkuri directe pe desktop și telefon); oricine altcineva primește 404.POST /v1/vault/add-requests/{id}/complete { item_id }o marchează finalizată; elementul trebuie să fie într-unul dintre seifurile tale. Repetarea apelului cu același element nu mai schimbă nimic.
Aplicația desktop deschide codai://vault/add?req=<token> când este instalată; telefonul deschide pagina din hub într-un Custom Tab. Jurnalul de audit înregistrează add.requested, add.completed și add.cancelled.
Din terminal, codaid vault add --title <t> [--kind api_key] [--slug s] [--host h]… [--env-var NAME] [--field f]… [--purpose p] [--json] creează aceeași cerere și afișează linkul de deschis.
Din MCP: elicitare prin URL
Setul de unelte MCP vault (în gateway și în codaid vault mcp) are două unelte pentru asta: vault_add_secret (aceleași intrări ca apelul REST) și vault_add_status { id }.
initializerăspunde cu un antetMcp-Session-Idcare reține dacă clientul tău a declaratcapabilities.elicitation.url. Antetul este semnat și fără stare pe server (v1.<payload>.<HMAC-SHA256>, valabil 30 de zile); trimite-l înapoi la apelurile următoare.- Dacă elicitarea prin URL este declarată,
tools/call vault_add_secretrăspunde cu eroarea JSON-RPC-32042șidata.elicitations = [{ mode: 'url', elicitationId, url, message }], așa cum o definește specificația MCP (2025-11-25). Clientul afișează linkul; după ce adaugi secretul, agentul apeleazăvault_add_status(sau din nouvault_add_secretcu același slug sau titlu în 10 minute, ceea ce refolosește cererea) și primește handle-ul. - Alternativă: fără această capabilitate (sau fără id de sesiune), unealta întoarce un rezultat obișnuit cu linkul și instrucțiunea „deschide-l, apoi apelează vault_add_status”.
Securitate
- URL-ul conține doar un token de unică folosință de 32 de octeți; serverul păstrează SHA-256 al lui, niciodată tokenul însuși.
- Linkul nu este preautentificat: pagina din hub cere autentificare și arată cererea doar utilizatorului pentru care a fost creată. Oricine altcineva vede „nu a fost găsită”.
- Pagina nu primește nimic secret de la server. Sigilează elementul în browser cu cheile seifului tău și îl salvează pe calea obișnuită pentru elemente; agentul vede doar handle-ul.
Acces de urgență
Numește un alt utilizator Kodwen care poate citi seifurile alese dacă tu nu mai poți, după o perioadă de așteptare pe care o controlezi.
| Stare | Înțeles | Pasul următor |
|---|---|---|
invited | Invitație trimisă pe email (valabilă 14 zile). | Contactul acceptă din hub-ul său. |
accepted | Contactul a acceptat; nicio cheie partajată încă. | Clientul tău sigilează cheile seifurilor pentru contact. |
sealed | Cheile seifurilor sunt sigilate pentru cheia X-Wing a contactului. | Contactul poate cere acces. |
requested | Contactul a cerut; release_at = acum + delay_hours. | Refuzi sau aprobi, ori trece perioada de așteptare. |
granted | Contactul poate citi seifurile alese. | Revoci. |
revoked | Încheiat de oricare parte; cheile sigilate sunt șterse. | — |
GET /v1/vault/emergencyrăspunde{ outgoing, incoming }.POST /v1/vault/emergency { email, delay_hours, vault_ids? }răspunde mereu202 { id }, cu aceeași formă indiferent dacă adresa are sau nu cont Kodwen, deci nu poate fi folosit pentru a descoperi conturi.delay_hourseste 24, 48 sau 72;vault_idseste implicit seiful tău personal. Cel mult 5 contacte.POST /v1/vault/emergency/accept { token }(contactul): are nevoie de un cont de seif (404vault_not_setup) și nu poate fi propria ta invitație.PUT /v1/vault/emergency/{id}/seal { grantee_fingerprint, sealed_keys }(tu):sealed_keystrebuie să acopere exactvault_ids. Dacă amprenta cheii contactului nu este cea pe care ai verificat-o, răspunsul este 409fingerprint_changed. Compară amprenta afișată pe ambele dispozitive înainte de sigilare.PATCH /v1/vault/emergency/{id} { delay_hours?, vault_ids? }(tu): schimbarea seifurilor șterge cheile sigilate și readuce contactul înaccepted.DELETE /v1/vault/emergency/{id}: tu revoci sau contactul refuză.POST /v1/vault/emergency/{id}/request { reason? }(contactul, staresealed), apoiPOST /v1/vault/emergency/{id}/denysau/approve(tu, starerequested). Un proces de curățare acordă accesul după ce a trecutrelease_at.GET /v1/vault/emergency/{id}/vault-data(contactul, staregranted) întoarce textul cifrat al seifurilor alese și cheile sigilate; contactul decriptează local. Accesul este doar pentru citire și nu se extinde niciodată la agenți; fiecare citire apare caemergency.accessedîn jurnalul tău de audit.
Fiecare tranziție anunță cealaltă parte: notificare FCM de date { kind: 'vault.emergency', contact_id, event, other_name, release_at } pe telefon, Web Push în hub și un email. Jurnalul de audit înregistrează emergency.invited|accepted|sealed|requested|denied|approved|granted|revoked|accessed.
Rotire și monitorizarea scurgerilor
Verificarea scurgerilor (HIBP)
GET /v1/vault/hibp/range/{prefix} intermediază API-ul de intervale Pwned Passwords cu k-anonimitate: clientul calculează local SHA-1 pentru fiecare parolă, trimite doar primele 5 caractere hex și compară singur sufixul în răspuns. Gateway-ul nu vede niciodată o parolă sau un hash complet. Răspunsurile folosesc Add-Padding: true, ca mărimea lor să nu dezvăluie prefixul, sunt păstrate în cache 24 de ore și sunt limitate la 300 de apeluri per utilizator pe oră (429 peste limită, 503 hibp_unavailable când serviciul extern nu răspunde). Clientul raportează apoi POST /v1/vault/rotation/breach-report { results: [{ item_id, count }] } (cel mult 500); un element nou compromis trimite o notificare vault.breach.
Coada de rotire
GET /v1/vault/rotationlistează{ items: [{ item_id, slug, title, kind, interval_days, rotated_at, due_at, overdue, breached, breach_count, breach_checked_at, snoozed_until, provider, create_url }] }: întâi cele compromise, apoi cele întârziate, apoi cele cu termenul cel mai apropiat.PUT /v1/vault/items/{id}/rotation { interval_days?, provider?, snoozed_until? }setează programul (1–730 de zile) și furnizorul;POST /v1/vault/items/{id}/rotatedînregistrează o rotire și șterge marcajul de compromis.- Valori implicite: 90 de zile pentru elementele
api_key,oauth_tokenșienv; autentificările sunt doar verificate pentru scurgeri; elementele cu derivator sunt omise (credențialele lor sunt de scurtă durată). - Un proces de curățare la fiecare 6 ore trimite câte o notificare
vault.rotationper element întârziat per ciclu (nu cât timp este amânat). - Cheile care nu pot fi rotite printr-un API rămân statice, iar lista trimite la pagina unde creezi una nouă:
provider | create_url |
|---|---|
stripe (chei restricționate) | https://dashboard.stripe.com/apikeys |
github_pat (PAT cu permisiuni granulare) | https://github.com/settings/personal-access-tokens/new |
openai | https://platform.openai.com/api-keys |
google_api_key | https://console.cloud.google.com/apis/credentials |
Credențiale JIT
Un derivator transformă o credențială rădăcină într-una de scurtă durată, cu drepturi restrânse, la fiecare utilizare, astfel încât secretul de lungă durată nu ajunge niciodată la comandă.
GET /v1/vault/derivers,PUT /v1/vault/items/{id}/deriver { provider, config, max_ttl_s }(300–43200 s),DELETE /v1/vault/items/{id}/deriver.confignu conține secrete.
provider | config | Câmpurile elementului rădăcină | Câmpuri derivate → env |
|---|---|---|---|
aws_sts | role_arn, region (implicit us-east-1), session_policy? (≤ 2048 caractere), external_id?, duration_s 900–43200 | access_key_id, secret_access_key | access_key_id, secret_access_key, session_token → AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
gcp_sa | mode key | impersonate, target_service_account?, scopes (implicit cloud-platform), lifetime_s 300–3600 | json (cheie de cont de serviciu) | token → CLOUDSDK_AUTH_ACCESS_TOKEN, GOOGLE_OAUTH_ACCESS_TOKEN |
cloudflare | account_id?, policies, ttl_s 300–86400 | token (cu drept de a crea tokenuri) | token → CLOUDFLARE_API_TOKEN |
github_app | app_id, installation_id, repositories?, permissions? | private_key (PEM) | token → GH_TOKEN, GITHUB_TOKEN |
{{vault:slug}} pe un element derivat este primul câmp derivat; {{vault:slug.<câmp>}} alege unul anume.
POST /v1/vault/derive este doar pentru brokerii Kodwen (codaid, desktop): corpul { handle, action, purpose?, provenance?, task?, ttl_s?, proof }, cu aceeași dovadă de dispozitiv ca la /v1/vault/resolve, peste handles = [handle]. Dovada este verificată înaintea oricărei decizii de politică; fără ea răspunsul este 400 proof_required, iar un apelant care nu este broker primește 403 broker_only. După politica obișnuită (modul env, inclusiv aprobările), elementul trebuie să fie utilizabil în cloud (409 not_cloud_usable) și să aibă un derivator (409 no_deriver). Răspunsul este { provider, values, env, expires_at } cu Cache-Control: no-store; o eroare a furnizorului răspunde 502 derive_failed, cu mesajul curățat de orice seamănă cu un token. Jurnalul de audit înregistrează derive.issued { provider, expires_at, device_id }, niciodată valoarea.
Elementele care nu sunt utilizabile în cloud sunt derivate în brokerul local (codaid vault run, desktop), cu aceiași furnizori; brokerul injectează variabilele de mediu în procesul copil și redactează orice valoare derivată din ieșirea lui.
/v1/vault/http pe un element cu derivator gcp_sa, cloudflare sau github_app injectează tokenul bearer derivat în locul secretului rădăcină. Tokenul este păstrat în memoria gateway-ului până cu 60 de secunde înainte să expire.
Completare automată de către agent
Browserul agentului din desktop se poate autentifica pe site-uri fără ca modelul să vadă parola. În browser_type, scrie {{vault:slug.câmp}} (username, password, totp sau orice alt câmp). Aplicația desktop apoi:
- citește originea paginii prin CDP și verifică hosturile legate ale elementului (
agent_meta.hosts); un host nelegat eșuează cuvault_host_mismatch; - cere o decizie de politică în modul
autofill, cuhost= hostul paginii (aprobare pe dispozitivul tău când nivelul o cere); - decriptează local, verifică dacă pagina este încă pe aceeași origine și injectează valoarea; unealta răspunde
{ ok, filled: true }fără valoare.
Instantaneele nu arată niciodată valoarea unui câmp de parolă, iar ieșirea browser_eval și a clicurilor este redactată pentru fiecare valoare completată în acea sesiune de browser ([vault:<slug>]).
Extensia de browser acceptă și cereri agent_fill de la aplicația desktop prin native messaging și completează doar când fila activă este exact pe originea cerută.
Extensia de browser și passkey-uri în Windows
Kodwen Vault pentru Chrome și Edge (Manifest V3, distribuită nelistată în Chrome Web Store și ascunsă în Edge Add-ons):
- Funcționează singură: criptografia seifului este inclusă ca WASM (fără cod de la distanță). Deblochezi cu parola și Secret Key; sesiunea deblocată trăiește doar în memoria service worker-ului și se blochează implicit după 10 minute de inactivitate.
- Completează doar pe originea legată de autentificare: service worker-ul verifică originea filei, iar scriptul de conținut verifică din nou
location.originînainte să scrie un câmp. - Native messaging opțional către aplicația desktop (host
ro.codai.vault): deblocare cu Windows Hello pe desktop, completare din seiful desktop (candidates,fill) și completări cerute de agent.allowed_originsdin manifestul hostului conține doar id-urile extensiei din magazine, iar aplicația desktop verifică din nou id-ul extensiei și originea paginii la fiecare cerere. - Permisiuni:
storage,scripting,activeTab,contextMenus,alarms,nativeMessaging,idle; accesul la toate site-urile este opțional și cerut la rulare pentru completarea în pagină. Apelurile către gateway folosescvia: 'extension'.
Furnizor de passkey-uri în Windows 11: versiunea din Microsoft Store (MSIX) a aplicației desktop se înregistrează ca furnizor de passkey-uri, astfel încât Windows poate crea și folosi passkey-uri păstrate ca elemente passkey în seiful tău, după Windows Hello. Fiecare cerere de la Windows este verificată cu cheia de semnare a operațiilor pe care Windows a înregistrat-o pentru plugin. Instalările NSIS nu îl înregistrează și afișează „disponibil în versiunea din Microsoft Store”.
Android: parole și passkey-uri pentru alte aplicații
Aplicația Kodwen pentru Android descărcată de pe GitHub (nu versiunea din Play) este furnizor Credential Manager pe Android 14+ și serviciu de completare automată pe Android 11–13. Îl activezi din Setări › Parole și conturi (sau Serviciu de completare automată).
- Completare: autentificările potrivite (
androidapp://<pachet>sau domeniul site-ului și subdomeniile lui) sunt oferite cât timp seiful e deblocat; fiecare completare cere o confirmare biometrică. - Salvare: când îți creezi un cont sau schimbi parola într-o altă aplicație sau într-un browser, telefonul îți propune să o salvezi în seif: implicit în primul seif personal, sau în orice seif în care ești owner, manager sau editor. Dacă există deja o autentificare cu același nume de utilizator și aceeași adresă, îți propune să o actualizezi. Elementul este sigilat pe telefon și urcat doar ca text cifrat (
PUT /v1/vault/items/:id); nu este niciodată vizibil agenților (fără handle). - Passkey-uri: site-urile și aplicațiile pot crea și folosi passkey-uri (ES256) păstrate ca elemente
passkeyîn seif, în același format ca furnizorul din Windows, deci un passkey creat pe telefon funcționează și pe desktop. Cheia privată rămâne în elementul din seif; semnarea are loc în nucleul seifului de pe dispozitiv după confirmarea biometrică, iar contorul de semnături este salvat înapoi în element. Cererile din browser sunt acceptate doar de la browserele din lista Google de browsere privilegiate și doar când id-ul relying party se potrivește cu originea paginii. - Nucleul CTAP / WebAuthn (authenticator data, cheie COSE, atestare
none, aserțiune) este comun pentru furnizorul din desktop și telefon (crates/codai-vault, funcționalitateapasskey).
Seifurile organizației
Un proprietar sau administrator al organizației creează un seif partajat cu POST /v1/vault/vaults { id, encrypted_meta, sealed_key, org_id } (kind: shared). GET /v1/vault/vaults arată apoi, pentru fiecare seif, org_id, role-ul tău (owner, manager, editor, viewer), quorum, rotation_needed_at și key_epoch. Serverul nu vede niciodată o cheie de seif: fiecare membru primește propria copie, sigilată pentru cheia lui publică X-Wing de clientul unui proprietar sau manager.
GET /v1/vault/vaults/{id}/members(orice membru):{ members: [{ user_id, email, name, role, fingerprint, key_epoch, added_at }] }.GET /v1/vault/vaults/{id}/candidates(proprietar/manager): membrii organizației care au cont de seif și nu sunt încă în seif, cupublic_keysșifingerprint.PUT /v1/vault/vaults/{id}/members/{userId} { role, sealed_key, fingerprint }(proprietar/manager): arată amprenta candidatului, cere confirmarea ei (pe alt canal, ca la contactele de urgență), sigilează cheia seifului pentrupublic_keysși încarc-o. Dacă cheile membrului s-au schimbat de când a fost citită amprenta, răspunsul este 409fingerprint_changed; un utilizator din afara organizației primește 403. Rândul proprietarului nu poate fi modificat.PATCH /v1/vault/vaults/{id}/members/{userId} { role }schimbă rolul (manager,editorsauviewer).DELETE /v1/vault/vaults/{id}/members/{userId}(proprietar/manager sau membrul care pleacă) șterge imediat rândul și seteazărotation_needed_at. Eliminarea cuiva din organizație face același lucru pe toate seifurile acelei organizații.
Rotirea cheii
Un membru eliminat poate avea încă o copie veche a cheii seifului, așa că după orice eliminare seiful afișează un banner până când un proprietar sau manager îl rotește. Clientul generează o cheie nouă de seif, o resigilează pentru fiecare membru rămas, reîmpachetează cheia fiecărui element și trimite totul într-un singur apel:
POST /v1/vault/vaults/{id}/rotate { key_epoch, encrypted_meta, members: [{ user_id, sealed_key }], items: [{ id, revision, wrapped_key, ciphertext }] }
key_epoch este epoca curentă + 1, iar revision al fiecărui element este revizia lui curentă + 1. Cererea trebuie să acopere fiecare membru actual și fiecare element activ (cel mult 2000): altfel răspunsul este 409 rotation_incomplete cu id-urile lipsă și nu se schimbă nimic. Totul rulează într-o singură tranzacție și șterge rotation_needed_at.
Aprobări cu cvorum
Pe un seif al organizației, proprietarul poate cere ca mai multe persoane să aprobe utilizările sensibile: PUT /v1/vault/vaults/{id}/quorum { m, scope }, cu m între 2 și 9 și scope critical (doar elementele critice) sau high (ridicate și critice); { m: null } dezactivează cvorumul. m nu poate depăși numărul de membri proprietari/manageri (400).
Când un agent cere o utilizare t3 sau t4 a unui element potrivit, aprobarea este creată cu quorum_m = m și expiră după 24 de ore. Dacă există mai puțin de m aprobatori eligibili (proprietari și manageri, alții decât solicitantul, cu cont de seif), utilizarea este refuzată imediat cu motivul quorum_unavailable. Fiecare aprobator eligibil primește o notificare, iar GET /v1/vault/approvals listează cererea cu quorum: { m, approvals, needed, voted }.
- Votezi cu
POST /v1/vault/approvals/{id}/vote { decision, proof }. Fiecare vot are propria dovadă peste approve/v4:codai-vault/approve/v4|<approval_id>|<action_hash>|<decision>|once|<approver_user_id>|<device_id>|<preview_digest>semnată de una dintre cheile de dispozitiv ale aprobatorului (proof: { type: 'device', device_id, signature }) sau ca passkey a cărui provocare WebAuthn este base64url(SHA-256(mesajul cu id-ul de dispozitivpasskey)). Id-ul utilizatorului care aprobă face parte din mesaj, deci dovada unui aprobator nu poate fi refolosită ca a altuia. Cheile software sunt refuzate; t4 cere un dispozitiv atestat sau un passkey. Nu există număr de potrivire: aprobatorii nu sunt lângă agent. - Orice refuz încheie cererea (
denied). Am-a aprobare distinctă o marcheazăapprovedși creează o singură permisiuneoncepentru solicitant; evenimentul de auditapproval.approvedlistează dispozitivul fiecărui votant. Fiecare vot apare caapproval.vote. - Erori: 409
already_voted, 409not_pending, 403 pentru o dovadă greșită sau un aprobator neeligibil.POST /v1/vault/approvals/{id}/decidepe o aprobare cu cvorum răspunde 409quorum_required.
Ce semnează aprobatorul (previzualizare v2)
Previzualizarea aprobării include acum lanțul de delegare al agentului (cine pe cine a rugat, cel mai exterior primul, unit prin >, tăiat la 300 de caractere). Textul canonic este codai-vault/preview/v2, urmat de title, agent, mode, host, action, purpose, task, chain ca linii key=value, cu aceeași escapare ca la v1. Un obiect de previzualizare al cărui chain este un șir folosește v2; altfel v1. Hub-ul, desktopul și telefonul arată lanțul lângă cerere, iar fiecare eveniment de utilizare îl stochează.
Tranziție: până la următoarea versiune de desktop și telefon, gateway-ul stochează și rezumatul v1 al aceleiași previzualizări (fără chain). O dovadă v3 este verificată întâi cu rezumatul v2, apoi cu cel v1; o dovadă v4 trebuie să folosească rezumatul v2.
Aprobări offline prin cod QR
Când telefonul nu are rețea, desktopul poate transporta aprobarea în ambele sensuri prin coduri QR:
- Desktopul afișează un QR de cerere (JSON compact, UTF-8, corecție de erori M):
{ "v": "codai-vault-qr/1", "t": "req", "id", "h": "<action_hash>", "tier": "t3|t4", "u": "<id-ul solicitantului>", "p": { ...previzualizare... }, "c": ["47","12","83"] }. - Telefonul refuză un QR al cărui
unu este utilizatorul autentificat, recalculează singur rezumatul previzualizării dinp(nu are încredere în niciun rezumat din QR), afișeazăpși îți cere să apeși numărul pe care ți-l arată agentul (unul dintrec; numărul nu apare în QR). - Telefonul semnează approve/v3 (v2 când nu există număr) cu cheia de dispozitiv și afișează un QR de răspuns:
{ "v": "codai-vault-qr/1", "t": "res", "id", "d": "approve|deny", "s": "once|task|1h|8h", "dev": "<id-ul dispozitivului>", "m": "<număr sau gol>", "sig": "<base64url>" }. - Desktopul îl citește cu camera web și trimite
POST /v1/vault/approvals/{id}/decide { decision, scope, via: 'qr', match_number, proof: { type: 'device', device_id, signature } }. Gateway-ul verifică dovada dispozitivului exact ca și cum ar fi trimis-o telefonul.
Simulatorul de politici
Înainte să-ți schimbi regulile, vezi ce ar fi făcut. POST /v1/vault/policy/simulate { rules?, default_tier?, since?, limit? } reevaluează utilizările trecute ale agenților tăi sub o politică propusă: rules înlocuiește regulile actuale, default_tier nivelul implicit; since este implicit acum 30 de zile, iar limit implicit 200 (cel mult 500). Este doar pentru citire și răspunde:
{ evaluated, changed, grants: 'none', rows: [{ event_id, at, item_id, title, agent, chain, mode, host, current_tier, simulated_tier, reasons, source }] }
Sursele sunt evenimentele use.allowed, use.denied și approval.requested (care stochează de acum chain, mode, host, action_hash, purpose, task și provenance, niciodată acțiunea brută), plus cererile stocate ale aprobărilor t3/t4 mai vechi (source: 'approval'). Sensibilitatea și hosturile legate provin din metadatele actuale ale fiecărui element. Permisiunile și protecțiile la anomalii nu sunt reevaluate. Aceeași verificare este disponibilă agenților prin unealta MCP doar pentru citire vault_policy_simulate.
Chitanțe semnate
Evenimentele relevante pentru securitate sunt semnate: use.allowed, use.denied, approval.approved, approval.denied, approval.vote și honeytoken. Fiecare are un plic DSSE la payload.receipt în jurnalul de audit:
payloadType:application/vnd.codai.vault-receipt+json;- conținut:
{ v: 1, event, user_id, item_id, agent, tier, action_hash, reasons, device_id, approval_id, at }(doar metadate, niciodată o valoare); signatures: [{ keyid, sig }], ECDSA P-256 SHA-256 cu o cheie Cloud KMS.
Pentru verificare, citește GET /v1/vault/receipts/keys ({ keys: [{ kid, alg: 'ES256', pem }] }, păstrat în cache 1 oră), alege cheia al cărei kid este egal cu keyid și verifică semnătura peste codificarea de preautentificare DSSE DSSEv1 <len(type)> <type> <len(payload)> <payload>. Hub-ul face asta în browser și afișează un ecuson „semnat”. Dacă semnarea nu este disponibilă, evenimentul este stocat totuși, nesemnat; verificarea nu acceptă niciodată o chitanță nesemnată sau modificată.
Rezumatul săptămânal
În fiecare luni la 07:10 (ora României), utilizatorii cu activitate în seif în acea săptămână primesc un email prin poșta Kodwen: utilizări, refuzuri, aprobări, dispozitive noi, elemente scadente pentru rotire. Îl oprești din linkul de dezabonare, din setarea din hub sau cu PATCH /v1/vault/settings { digest_opt_out: true }; GET /v1/vault/account arată digest_opt_out.
Chei API cu scopuri
O cheie API poate avea scopes; null (orice cheie existentă) înseamnă cheie completă. O cheie cu scopuri poate apela doar:
| Scop | Rute |
|---|---|
vault.read | GET /v1/vault/account, GET /v1/vault/vaults, GET /v1/vault/items, GET /v1/vault/catalog, GET /v1/vault/receipts/keys |
vault.add | POST /v1/vault/add-requests, GET /v1/vault/add-requests/{id}, DELETE /v1/vault/add-requests/{id} |
Orice altceva răspunde 403 key_scope_forbidden. Conectează extensia de browser din pagina de chei a hub-ului emite o cheie cu vault.read + vault.add, valabilă 180 de zile, după o autentificare recentă, și o afișează o singură dată. Extensia o păstrează criptată cu o cheie AES-GCM neexportabilă ținută în IndexedDB, niciodată în clar. GET /v1/vault/account întoarce key_scopes pentru cheia care apelează, iar extensia avertizează când rulează cu o cheie completă.
Momeli în depozite
codaid vault import --apply plantează și 2 elemente-momeală pentru fiecare depozit importat (numite după --repo sau după folder): elemente api_key vizibile agenților și marcate honeytoken, precum aws-prod-legacy, stripe-live-old, github-deploy-old sau openai-prod-old, legate de hostul real al furnizorului și completate cu valori aleatoare în formatul furnizorului (niciodată reale). Alegerea este deterministă pentru fiecare depozit și sare peste slug-urile pe care le ai deja; o rulare de probă le listează ca decoy. Fișierele din depozit nu sunt atinse niciodată. Orice utilizare declanșează calea de momeală de mai sus (refuz, blocare, notificare vault.alarm). Folosește --no-honeytokens ca să le omiți.
bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
bundle*Pachetul contului: chei publice, chei private sigilate cu cheia contului, sloturi de deblocare (chei împachetate + parametri KDF). Fără text clar.
fingerprint*stringAmprenta cheii publice, de comparat între dispozitive.
default_tier*string"t1""t2""t3""t4"revision*integerlocked_at?stringMomentul blocării seifului (panică sau momeală); null când e deblocat. Cât timp e blocat, orice utilizare de către agenți este refuzată cu motivul vault_locked.
date-timelock_reason?stringDe ce este blocat seiful.
"panic""honeytoken"guards?key_scopes?array<>Scopurile cheii API care a făcut acest apel; null = cheie completă (fără scopuri). Extensia de browser avertizează când rulează cu o cheie completă.
digest_opt_out?booleanAdevărat când ai dezactivat emailul săptămânal cu rezumatul seifului.
curl -X GET 'https://ai.codai.ro/v1/vault/account'{ "bundle": {}, "fingerprint": "string", "default_tier": "t1", "revision": 0, "locked_at": "2019-08-24T14:15:22Z", "lock_reason": "panic", "guards": { "new_host": true, "burst_max": 0, "burst_window_s": 10, "hour_start": 0, "hour_end": 1, "tz": "string" }, "key_scopes": [ "vault.read" ], "digest_opt_out": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
bundle*revision?integerActualizat.
application/json- response
[key: string]?anycurl -X PUT 'https://ai.codai.ro/v1/vault/account' \ -H 'Content-Type: application/json' \ -d '{ "bundle": {}}'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
default_tier?string"t1""t2""t3""t4"guards?Orice submulțime din VaultGuards; hour_start și hour_end sunt ambele null (dezactivat) sau ambele setate.
digest_opt_out?booleanAdevărat oprește emailul săptămânal cu rezumatul (luni, 07:10, ora României).
Setările efective.
application/json- response
default_tier*string"t1""t2""t3""t4"guards*digest_opt_out?booleancurl -X PATCH 'https://ai.codai.ro/v1/vault/settings' \ -H 'Content-Type: application/json' \ -d '{}'{ "default_tier": "t1", "guards": { "new_host": true, "burst_max": 0, "burst_window_s": 10, "hour_start": 0, "hour_end": 1, "tz": "string" }, "digest_opt_out": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
via?string"hub""desktop""phone""wear""extension"Blocat.
application/json- response
locked_at*stringdate-timegrants_revoked*integerPermisiunile active revocate de această blocare.
approvals_denied*integerAprobările în așteptare refuzate de această blocare.
curl -X POST 'https://ai.codai.ro/v1/vault/lock' \ -H 'Content-Type: application/json' \ -d '{}'{ "locked_at": "2019-08-24T14:15:22Z", "grants_revoked": 0, "approvals_denied": 0}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
challenge*string32 de octeți aleatori, base64url. Se folosește o singură dată.
expires_at*stringLa 5 minute după emitere.
date-timemessage_template*stringcodai-vault/unlock/v1|<challenge>|<device_id or passkey>: mesajul UTF-8 acoperit de dovadă.
curl -X POST 'https://ai.codai.ro/v1/vault/unlock/challenge'{ "challenge": "string", "expires_at": "2019-08-24T14:15:22Z", "message_template": "string"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
challenge*stringProvocarea din POST /v1/vault/unlock/challenge.
proof*|Confirmare dovedită pentru o decizie. device: o cheie de dispozitiv înrolată semnează codai-vault/approve/v2|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>. passkey: o aserțiune WebAuthn a cărei provocare este base64url(SHA-256(același mesaj cu id-ul de dispozitiv passkey)). Cu match_number mesajul este v3: codai-vault/approve/v3|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>|<preview_digest>|<match_number>, unde preview_digest = base64url(SHA-256(textul canonic al request.preview)).
via?string"hub""desktop""phone""wear""extension"Deblocat.
application/json- response
unlocked*booleancurl -X POST 'https://ai.codai.ro/v1/vault/unlock' \ -H 'Content-Type: application/json' \ -d '{ "challenge": "string", "proof": { "type": "device", "device_id": "string", "signature": "string" }}'{ "unlocked": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
limits*array<>curl -X GET 'https://ai.codai.ro/v1/vault/limits'{ "limits": [ { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "per_minute": 1, "per_day": 1, "units_per_day": 1 } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
per_minute*integer1 <= value <= 10000per_day*integer1 <= value <= 1000000units_per_day*integer1 <= value <= 1000000OK; limits este null când au fost eliminate.
application/json- response
limits*curl -X PUT 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/limits' \ -H 'Content-Type: application/json' \ -d '{ "per_minute": 1, "per_day": 1, "units_per_day": 1}'{ "limits": { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "per_minute": 1, "per_day": 1, "units_per_day": 1 }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
vaults*array<>curl -X GET 'https://ai.codai.ro/v1/vault/vaults'{ "vaults": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "kind": "personal", "owner_user_id": "65139110-7c3c-4777-b692-80c218be3b9d", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "encrypted_meta": "string", "role": "owner", "sealed_key": {}, "quorum": { "m": 2, "scope": "critical" }, "rotation_needed_at": "2019-08-24T14:15:22Z", "key_epoch": 1, "updated_at": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
id*stringuuidencrypted_meta*stringsealed_key*org_id?stringCreează un seif al organizației în această organizație.
uuidCreat.
application/json- response
[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/vaults' \ -H 'Content-Type: application/json' \ -d '{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "encrypted_meta": "string", "sealed_key": {}}'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
since?stringDoar modificările de după acest moment. Trimite o dată și oră ISO 8601 cu fus orar, de exemplu 2026-11-10T12:00:00Z.
date-timeOK.
application/json- response
items*array<>server_time*stringsince-ul următorului tău apel (vezi descrierea operației).
date-timehas_more*booleanAdevărat: apelează din nou imediat cu since = server_time.
curl -X GET 'https://ai.codai.ro/v1/vault/items'{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "vault_id": "432b199b-1f71-42bf-ba0b-33d512afa9de", "revision": 1, "wrapped_key": "string", "ciphertext": "string", "kind": "login", "slug": "string", "agent_meta": {}, "honeytoken": true, "cloud_usable": true, "deleted_at": "2019-08-24T14:15:22Z", "last_used_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } ], "server_time": "2019-08-24T14:15:22Z", "has_more": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
vault_id*stringuuidrevision*integer1 <= valuewrapped_key*stringCheia elementului împachetată cu cheia seifului (v1.<nonce>.<ciphertext>).
ciphertext*stringElementul sigilat cu cheia lui.
kind*string"login""api_key""env""ssh_key""oauth_token""note""card""identity""passkey"slug?stringSlug-ul handle-ului când elementul este expus agenților.
agent_meta?Intrarea publică din catalog pentru agenți (titlu, sensibilitate, hosturi, variabilă de mediu). Niciodată valori secrete.
honeytoken?booleanMarcaj de momeală. Doar proprietarul sau managerul; o actualizare trebuie să trimită înapoi valoarea stocată.
Actualizat.
application/json- response
id*stringuuidrevision*integer1 <= valuecurl -X PUT 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "vault_id": "432b199b-1f71-42bf-ba0b-33d512afa9de", "revision": 1, "wrapped_key": "string", "ciphertext": "string", "kind": "login"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "revision": 1}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidȘters.
application/json- response
deleted*booleancurl -X DELETE 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "deleted": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
item*OK.
application/json- response
cloud_usable*booleancurl -X PUT 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/cloud' \ -H 'Content-Type: application/json' \ -d '{ "item": {}}'{ "cloud_usable": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
rules*array<>curl -X GET 'https://ai.codai.ro/v1/vault/rules'{ "rules": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "itemId": "f11b669d-7201-4c21-88af-d85092f0c005", "agent": "string", "mode": "env", "tier": "t0", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
item_id?stringuuidagent?stringmode?string"env""http""autofill""ssh_sign""reveal"tier*string"t0""t1""t2""t3""t4""deny"Creat.
application/json- response
rule*Rândul stocat, așa cum este: cheile acestui obiect sunt camelCase.
curl -X POST 'https://ai.codai.ro/v1/vault/rules' \ -H 'Content-Type: application/json' \ -d '{ "tier": "t0"}'{ "rule": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "itemId": "f11b669d-7201-4c21-88af-d85092f0c005", "agent": "string", "mode": "env", "tier": "t0", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidȘters.
application/json- response
[key: string]?anycurl -X DELETE 'https://ai.codai.ro/v1/vault/rules/497f6eca-6276-4993-bfeb-53cbbbba6f08'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
grants*array<>curl -X GET 'https://ai.codai.ro/v1/vault/grants'{ "grants": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "itemId": "f11b669d-7201-4c21-88af-d85092f0c005", "agent": "string", "mode": "env", "host": "string", "task": "string", "usesLeft": 0, "expiresAt": "2019-08-24T14:15:22Z", "revokedAt": "2019-08-24T14:15:22Z", "approvalId": "23bbe807-dea1-4601-b208-07fd1aaad2b6", "createdAt": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
task*string1 <= length <= 120OK.
application/json- response
revoked*integercurl -X POST 'https://ai.codai.ro/v1/vault/grants/revoke-task' \ -H 'Content-Type: application/json' \ -d '{ "task": "string"}'{ "revoked": 0}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidRevocat.
application/json- response
[key: string]?anycurl -X DELETE 'https://ai.codai.ro/v1/vault/grants/497f6eca-6276-4993-bfeb-53cbbbba6f08'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
limit?integer1-500, implicit 100.
OK.
application/json- response
events*array<>curl -X GET 'https://ai.codai.ro/v1/vault/events'{ "events": [ { "id": 0, "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "kind": "string", "itemId": "f11b669d-7201-4c21-88af-d85092f0c005", "agent": "string", "tier": "string", "payload": {}, "createdAt": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
approvals*array<>curl -X GET 'https://ai.codai.ro/v1/vault/approvals'{ "approvals": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "quorum": { "m": 2, "approvals": 0, "needed": 0, "voted": true }, "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "itemId": "f11b669d-7201-4c21-88af-d85092f0c005", "agent": "string", "tier": "t3", "request": {}, "actionHash": "string", "reasons": [ "string" ], "status": "pending", "expiresAt": "2019-08-24T14:15:22Z", "createdAt": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
id*stringuuidstatus*string"pending""approved""denied""expired""cancelled"tier*string"t3""t4"expiresAt*stringdate-timegrantScope?stringDurata aleasă la aprobare: once, task, 1h sau 8h.
decidedDeviceId?stringCheia de dispozitiv, sau passkey, care a dovedit decizia.
quorum?vault_id?stringSeiful elementului; prezent la aprobările de cvorum.
uuid[key: string]?anycurl -X GET 'https://ai.codai.ro/v1/vault/approvals/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "pending", "tier": "t3", "expiresAt": "2019-08-24T14:15:22Z", "grantScope": "string", "decidedDeviceId": "string", "quorum": { "m": 2, "approvals": 0, "needed": 0, "voted": true }, "vault_id": "432b199b-1f71-42bf-ba0b-33d512afa9de"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
decision*string"approve""deny"scope*string"once""task""1h""8h"signature?stringSemnătura Ed25519 v1 a cheii seifului, base64url.
proof?|Confirmare dovedită pentru o decizie. device: o cheie de dispozitiv înrolată semnează codai-vault/approve/v2|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>. passkey: o aserțiune WebAuthn a cărei provocare este base64url(SHA-256(același mesaj cu id-ul de dispozitiv passkey)). Cu match_number mesajul este v3: codai-vault/approve/v3|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>|<preview_digest>|<match_number>, unde preview_digest = base64url(SHA-256(textul canonic al request.preview)).
step_up_acr?stringDepreciatIgnorat: o confirmare declarată de client nu dovedește nimic. Folosește proof.
via?stringqr: un telefon offline a semnat decizia, iar desktopul a citit codul QR de răspuns.
"hub""desktop""phone""wear""extension""qr"match_number?stringNumărul apăsat de utilizator (unul din request.match_choices); cere o dovadă de dispozitiv sau passkey peste mesajul v3.
^[0-9]{2}$OK.
application/json- response
[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/approvals/497f6eca-6276-4993-bfeb-53cbbbba6f08/decide' \ -H 'Content-Type: application/json' \ -d '{ "decision": "approve", "scope": "once"}'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
nonce*string32 de octeți aleatori, base64url. Se folosește o singură dată.
expires_at*stringLa 5 minute după emitere.
date-timecurl -X POST 'https://ai.codai.ro/v1/vault/devices/challenge'{ "nonce": "string", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
devices*array<>curl -X GET 'https://ai.codai.ro/v1/vault/devices'{ "devices": [ { "id": "string", "kind": "android_keystore", "name": "string", "surface": "phone", "public_key": "string", "attestation": "android-strongbox", "attestation_info": {}, "created_at": "2019-08-24T14:15:22Z", "last_used_at": "2019-08-24T14:15:22Z", "revoked_at": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
device_id*string^(android|wear|desktop|ios|cli)-[A-Za-z0-9._-]{4,80}$kind*string"android_keystore""windows_hello""cli_ed25519""ios_secure_enclave"name*string1 <= length <= 80surface*string"phone""wear""desktop""cli"public_key*stringSubjectPublicKeyInfo DER al cheii dispozitivului, base64url.
nonce*stringNonce-ul din POST /v1/vault/devices/challenge.
vault_signature*stringSemnătura Ed25519 a cheii seifului peste codai-vault/device-enroll/v1|<device_id>|<kind>|<spki_sha256>|<nonce>.
device_signature*stringCheia dispozitivului peste același mesaj (ECDSA P-256 DER pe Android și pentru ios_secure_enclave, RSASSA-PKCS1-v1_5 SHA-256 pentru Windows Hello, Ed25519 brut de 64 de octeți pentru cli_ed25519), base64url.
attestation?|Obligatorie pentru android_keystore (lanț de certificate, frunza prima, provocarea de atestare = octeții nonce-ului). Opțională pentru windows_hello: o atestare TPM dă tpm, lipsa ei dă hello-unattested. Trebuie să lipsească pentru cli_ed25519 (suprafața cli, stocată ca software) și pentru ios_secure_enclave (suprafața phone, stocată ca ios-unattested).
Înrolat.
application/json- response
device*curl -X POST 'https://ai.codai.ro/v1/vault/devices' \ -H 'Content-Type: application/json' \ -d '{ "device_id": "string", "kind": "android_keystore", "name": "string", "surface": "phone", "public_key": "string", "nonce": "string", "vault_signature": "string", "device_signature": "string"}'{ "device": { "id": "string", "kind": "android_keystore", "name": "string", "surface": "phone", "public_key": "string", "attestation": "android-strongbox", "attestation_info": {}, "created_at": "2019-08-24T14:15:22Z", "last_used_at": "2019-08-24T14:15:22Z", "revoked_at": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul dispozitivului.
^(android|wear|desktop|ios|cli)-[A-Za-z0-9._-]{4,80}$application/json- body
name*string1 <= length <= 80OK.
application/json- response
device*curl -X PATCH 'https://ai.codai.ro/v1/vault/devices/string' \ -H 'Content-Type: application/json' \ -d '{ "name": "string"}'{ "device": { "id": "string", "kind": "android_keystore", "name": "string", "surface": "phone", "public_key": "string", "attestation": "android-strongbox", "attestation_info": {}, "created_at": "2019-08-24T14:15:22Z", "last_used_at": "2019-08-24T14:15:22Z", "revoked_at": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul dispozitivului.
^(android|wear|desktop|ios|cli)-[A-Za-z0-9._-]{4,80}$Revocat.
application/json- response
ok*booleancurl -X DELETE 'https://ai.codai.ro/v1/vault/devices/string'{ "ok": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
[key: string]?anycurl -X GET 'https://ai.codai.ro/v1/vault/catalog'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
handle*stringmode*string"env""http""autofill""ssh_sign""reveal"host?stringaction*stringpurpose?stringprovenance?string"user""agent""untrusted"chain?array<string>task?stringDecizia.
application/json- response
tier*string"t0""t1""t2""t3""t4""deny"allowed*booleanreasons*array<string>De ce acest nivel. Motive de protecție: vault_locked (seiful este blocat, nivel deny), anomaly:new_host, anomaly:burst, anomaly:hour (nivel forțat la t4; permisiunile neaprobate la t4 sunt ignorate).
approval_id?stringuuidmatch_number?stringDouă cifre de arătat utilizatorului împreună cu cererea de aprobare; utilizatorul apasă același număr pe dispozitivul care aprobă (potrivirea numărului). Null când nu e nevoie de aprobare.
^[0-9]{2}$action_hash?stringHash-ul cererii exacte pe care o semnează aprobatorul.
cloud_usable?booleancurl -X POST 'https://ai.codai.ro/v1/vault/use' \ -H 'Content-Type: application/json' \ -d '{ "handle": "string", "mode": "env", "action": "string"}'{ "tier": "t0", "allowed": true, "reasons": [ "string" ], "approval_id": "15af2260-72db-4fc4-b587-6b841d6a3d55", "match_number": "string", "action_hash": "string", "cloud_usable": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
handle*stringurl*stringurimethod?string"GET""POST""PUT""PATCH""DELETE""HEAD"headers?body?stringpurpose?stringprovenance?string"user""agent""untrusted"chain?array<string>task?stringRăspunsul serverului (redactat).
application/json- response
[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/http' \ -H 'Content-Type: application/json' \ -d '{ "handle": "string", "url": "http://example.com"}'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
challenge*string32 de octeți aleatori, base64url. Se folosește o singură dată; semnează-l în dovada următorului POST /v1/vault/resolve.
expires_at*stringLa 120 de secunde după emitere.
date-timecurl -X POST 'https://ai.codai.ro/v1/vault/resolve/challenge'{ "challenge": "string", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
handles*array<string>action*stringpurpose?stringprovenance?string"user""agent""untrusted"chain?array<string>task?stringproof*Elementele decriptate, după handle.
application/json- response
[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/resolve' \ -H 'Content-Type: application/json' \ -d '{ "handles": [ "string" ], "action": "string", "proof": { "device_id": "string", "challenge": "string", "signature": "string" }}'{}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
kind*string"login""api_key""env""ssh_key""oauth_token""note""card""identity""passkey"title*string1 <= length <= 120slug?stringSlug-ul sugerat pentru handle (utilizatorul îl poate schimba).
hosts?array<>Hosturile de care ar trebui legat secretul.
items <= 10env_var?string^[A-Z_][A-Z0-9_]{0,63}$fields?array<>Numele câmpurilor pe care utilizatorul ar trebui să le completeze.
items <= 10purpose*stringDe ce are agentul nevoie de acest secret; afișat utilizatorului.
1 <= length <= 500task?string1 <= length <= 120Creată sau refolosită.
application/json- response
id*stringuuidurl*stringLinkul din hub pe care utilizatorul îl deschide ca să adauge secretul. Null când a fost refolosită o cerere echivalentă în așteptare (tokenul linkului nu este stocat).
status*stringO cerere în așteptare trecută de expirare apare ca expired.
"pending""completed""cancelled""expired"expires_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/add-requests' \ -H 'Content-Type: application/json' \ -d '{ "kind": "login", "title": "string", "purpose": "string"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "url": "string", "status": "pending", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
token*string^[A-Za-z0-9_-]{43}$OK.
application/json- response
id*stringuuidstatus*stringO cerere în așteptare trecută de expirare apare ca expired.
"pending""completed""cancelled""expired"agent*stringkind*string"login""api_key""env""ssh_key""oauth_token""note""card""identity""passkey"title*stringslug*stringhosts*array<string>env_var*stringfields*array<string>purpose*stringtask*stringhandle*stringitem_id*stringuuidexpires_at*stringdate-timecompleted_at*stringdate-timecreated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/add-requests/lookup' \ -H 'Content-Type: application/json' \ -d '{ "token": "string"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "pending", "agent": "string", "kind": "login", "title": "string", "slug": "string", "hosts": [ "string" ], "env_var": "string", "fields": [ "string" ], "purpose": "string", "task": "string", "handle": "string", "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "expires_at": "2019-08-24T14:15:22Z", "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
id*stringuuidstatus*stringO cerere în așteptare trecută de expirare apare ca expired.
"pending""completed""cancelled""expired"slug*stringhandle*string{{vault:<slug>}} după finalizare.
item_id*stringuuidexpires_at*stringdate-timecurl -X GET 'https://ai.codai.ro/v1/vault/add-requests/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "pending", "slug": "string", "handle": "string", "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidAnulată.
application/json- response
id*stringuuidstatus*stringO cerere în așteptare trecută de expirare apare ca expired.
"pending""completed""cancelled""expired"slug*stringhandle*string{{vault:<slug>}} după finalizare.
item_id*stringuuidexpires_at*stringdate-timecurl -X DELETE 'https://ai.codai.ro/v1/vault/add-requests/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "pending", "slug": "string", "handle": "string", "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
item_id*stringuuidFinalizată.
application/json- response
id*stringuuidstatus*stringO cerere în așteptare trecută de expirare apare ca expired.
"pending""completed""cancelled""expired"slug*stringhandle*string{{vault:<slug>}} după finalizare.
item_id*stringuuidexpires_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/add-requests/497f6eca-6276-4993-bfeb-53cbbbba6f08/complete' \ -H 'Content-Type: application/json' \ -d '{ "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "pending", "slug": "string", "handle": "string", "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
outgoing*array<>incoming*array<>curl -X GET 'https://ai.codai.ro/v1/vault/emergency'{ "outgoing": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z" } ], "incoming": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
email*stringemaillength <= 320delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids?array<>Seifurile acoperite; omis = toate seifurile pe care le deții.
1 <= items <= 20Invitat.
application/json- response
id*stringuuidcurl -X POST 'https://ai.codai.ro/v1/vault/emergency' \ -H 'Content-Type: application/json' \ -d '{ "email": "user@example.com", "delay_hours": 24}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
token*string^[A-Za-z0-9_-]{43}$Acceptat.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/emergency/accept' \ -H 'Content-Type: application/json' \ -d '{ "token": "string"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
grantee_fingerprint*string8 <= length <= 200sealed_keys*Id-ul seifului → cheia seifului sigilată pentru contact.
1 <= properties <= 20Sigilat.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X PUT 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08/seal' \ -H 'Content-Type: application/json' \ -d '{ "grantee_fingerprint": "stringst", "sealed_keys": { "property1": { "alg": "xwing-hkdf-xchacha20poly1305", "ct": "string", "wrapped": "string" }, "property2": { "alg": "xwing-hkdf-xchacha20poly1305", "ct": "string", "wrapped": "string" } }}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
delay_hours?integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids?array<>Seifurile acoperite; omis = toate seifurile pe care le deții.
1 <= items <= 20Actualizat.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X PATCH 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidRevocat.
application/json- response
id*stringuuidstatus*"revoked""revoked"curl -X DELETE 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "status": "revoked"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
reason?stringlength <= 500Cerut.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08/request' \ -H 'Content-Type: application/json' \ -d '{}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidRefuzat.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08/deny'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidAcordat.
application/json- response
id*stringuuidrole*stringPartea ta în relație.
"grantor""grantee"email*stringAdresa de email invitată (vederea titularului).
other_name*stringNumele afișat al celeilalte părți.
status*stringinvited → accepted (contactul are cont de seif) → sealed (titularul a sigilat cheile seifurilor pentru contact) → requested → granted (aprobat sau perioada de așteptare a trecut fără refuz). Un refuz readuce starea la sealed.
"invited""accepted""sealed""requested""granted""revoked"delay_hours*integerOrele dintre o cerere de acces și eliberarea automată, dacă titularul nu o refuză.
244872vault_ids*array<>grantee_fingerprint*stringAmprenta cheilor publice ale contactului pentru care a sigilat titularul.
grantee_public_keys*Cheile publice ale contactului (vederea titularului, după acceptare) pentru care se sigilează cheile seifurilor.
request_reason*stringrequested_at*stringdate-timerelease_at*stringMomentul în care o cerere în așteptare este eliberată automat.
date-timegranted_at*stringdate-timedenied_at*stringdate-timecreated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08/approve'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "role": "grantor", "email": "string", "other_name": "string", "status": "invited", "delay_hours": 24, "vault_ids": [ "ce59860b-d4b4-4beb-86e8-1b6dbe13411f" ], "grantee_fingerprint": "string", "grantee_public_keys": {}, "request_reason": "string", "requested_at": "2019-08-24T14:15:22Z", "release_at": "2019-08-24T14:15:22Z", "granted_at": "2019-08-24T14:15:22Z", "denied_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
vaults*array<>items*array<>curl -X GET 'https://ai.codai.ro/v1/vault/emergency/497f6eca-6276-4993-bfeb-53cbbbba6f08/vault-data'{ "vaults": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "encrypted_meta": "string", "sealed_key": {} } ], "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "vault_id": "432b199b-1f71-42bf-ba0b-33d512afa9de", "revision": 0, "wrapped_key": "string", "ciphertext": "string", "kind": "string", "slug": "string", "agent_meta": null } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
prefix*stringPrimele 5 caractere hex ale SHA-1 al parolei (k-anonimat).
^[0-9A-Fa-f]{5}$Linii SUFFIX:COUNT (cu umplutură).
response?stringtext/plaincurl -X GET 'https://ai.codai.ro/v1/vault/hibp/range/string'"string"bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
items*array<>curl -X GET 'https://ai.codai.ro/v1/vault/rotation'{ "items": [ { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "slug": "string", "title": "string", "kind": "string", "interval_days": 0, "rotated_at": "2019-08-24T14:15:22Z", "due_at": "2019-08-24T14:15:22Z", "overdue": true, "breached": true, "breach_count": 0, "breach_checked_at": "2019-08-24T14:15:22Z", "snoozed_until": "2019-08-24T14:15:22Z", "provider": "stripe", "create_url": "string" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
interval_days?integer1 <= value <= 730provider?string"stripe""github_pat""openai""google_api_key""other"snoozed_until?stringdate-timeOK.
application/json- response
item_id*stringuuidinterval_days*integerprovider*string"stripe""github_pat""openai""google_api_key""other"snoozed_until*stringdate-timecurl -X PUT 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/rotation' \ -H 'Content-Type: application/json' \ -d '{}'{ "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "interval_days": 0, "provider": "stripe", "snoozed_until": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
item_id*stringuuidrotated_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/rotated'{ "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "rotated_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
via*stringUnde a fost folosit elementul.
"windows_plugin""android_provider""ios_provider""desktop""phone"OK.
application/json- response
id*stringuuidlast_used_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/used' \ -H 'Content-Type: application/json' \ -d '{ "via": "windows_plugin"}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "last_used_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
results*array<>items <= 500OK.
application/json- response
recorded*integernewly_breached*integercurl -X POST 'https://ai.codai.ro/v1/vault/rotation/breach-report' \ -H 'Content-Type: application/json' \ -d '{ "results": [ { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "count": 0 } ]}'{ "recorded": 0, "newly_breached": 0}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
OK.
application/json- response
derivers*array<>curl -X GET 'https://ai.codai.ro/v1/vault/derivers'{ "derivers": [ { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "provider": "aws_sts", "config": {}, "max_ttl_s": 300, "updated_at": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
provider*string"aws_sts""gcp_sa""cloudflare""github_app"config*max_ttl_s*integer300 <= value <= 43200OK.
application/json- response
deriver*curl -X PUT 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/deriver' \ -H 'Content-Type: application/json' \ -d '{ "provider": "aws_sts", "config": {}, "max_ttl_s": 300}'{ "deriver": { "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "provider": "aws_sts", "config": {}, "max_ttl_s": 300, "updated_at": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidȘters.
application/json- response
deleted*booleancurl -X DELETE 'https://ai.codai.ro/v1/vault/items/497f6eca-6276-4993-bfeb-53cbbbba6f08/deriver'{ "deleted": true}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
handle*string1 <= length <= 80action*string1 <= length <= 4000purpose?stringlength <= 500provenance?string"user""agent""untrusted"chain?array<string>items <= 16task?stringttl_s?integer300 <= value <= 43200proof*Credențiala.
application/json- response
provider*string"aws_sts""gcp_sa""cloudflare""github_app"values*Câmpurile credențialei de scurtă durată. Doar pentru broker: se injectează și se redactează, nu se transmit niciodată unui model.
env*Aceleași valori, indexate după numele variabilei de mediu.
expires_at*stringdate-timecurl -X POST 'https://ai.codai.ro/v1/vault/derive' \ -H 'Content-Type: application/json' \ -d '{ "handle": "string", "action": "string", "proof": { "device_id": "string", "challenge": "string", "signature": "string" }}'{ "provider": "aws_sts", "values": { "property1": "string", "property2": "string" }, "env": { "property1": "string", "property2": "string" }, "expires_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
members*array<>curl -X GET 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/members'{ "members": [ { "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "email": "string", "name": "string", "role": "owner", "fingerprint": "string", "key_epoch": 1, "added_at": "2019-08-24T14:15:22Z" } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidOK.
application/json- response
candidates*array<>curl -X GET 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/candidates'{ "candidates": [ { "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "email": "string", "name": "string", "fingerprint": "string", "public_keys": { "kem": "string", "sign": "string" } } ]}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuiduserId*stringId-ul utilizatorului membru (uuid).
uuidapplication/json- body
role*stringowner nu se atribuie niciodată prin această rută.
"manager""editor""viewer"sealed_key*fingerprint*string8 <= length <= 200Adăugat sau resigilat.
application/json- response
member*[key: string]?anycurl -X PUT 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/members/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "role": "manager", "sealed_key": { "alg": "xwing-hkdf-xchacha20poly1305", "ct": "stringstringstri", "wrapped": "string" }, "fingerprint": "stringst"}'{ "member": { "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "email": "string", "name": "string", "role": "owner", "fingerprint": "string", "key_epoch": 1, "added_at": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuiduserId*stringId-ul utilizatorului membru (uuid).
uuidapplication/json- body
role*stringowner nu se atribuie niciodată prin această rută.
"manager""editor""viewer"Actualizat.
application/json- response
member*[key: string]?anycurl -X PATCH 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/members/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "role": "manager"}'{ "member": { "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "email": "string", "name": "string", "role": "owner", "fingerprint": "string", "key_epoch": 1, "added_at": "2019-08-24T14:15:22Z" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuiduserId*stringId-ul utilizatorului membru (uuid).
uuidEliminat.
application/json- response
removed*booleanrotation_needed_at?stringdate-time[key: string]?anycurl -X DELETE 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/members/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "removed": true, "rotation_needed_at": "2019-08-24T14:15:22Z"}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
key_epoch*integer2 <= valueencrypted_meta*stringmembers*array<>1 <= itemsitems*array<>items <= 2000Rotită.
application/json- response
key_epoch*integer[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/rotate' \ -H 'Content-Type: application/json' \ -d '{ "key_epoch": 2, "encrypted_meta": "string", "members": [ { "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "sealed_key": { "alg": "xwing-hkdf-xchacha20poly1305", "ct": "stringstringstri", "wrapped": "string" } } ], "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "revision": 2, "wrapped_key": "string", "ciphertext": "string" } ]}'{ "key_epoch": 0}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
m*integer2 <= value <= 9scope?stringObligatoriu când m este setat.
"critical""high"Politica efectivă.
application/json- response
quorum*[key: string]?anycurl -X PUT 'https://ai.codai.ro/v1/vault/vaults/497f6eca-6276-4993-bfeb-53cbbbba6f08/quorum' \ -H 'Content-Type: application/json' \ -d '{ "m": 2}'{ "quorum": { "m": 2, "scope": "critical" }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringId-ul resursei (uuid).
uuidapplication/json- body
decision*string"approve""deny"proof*|Dovada pentru un vot de cvorum, peste approve/v4: codai-vault/approve/v4|<approval_id>|<action_hash>|<decision>|once|<approver_user_id>|<device_id>|<preview_digest>. device: una dintre cheile TALE de dispozitiv înrolate semnează mesajul (cheile software cli_ed25519 sunt refuzate; t4 cere un dispozitiv atestat). passkey: o aserțiune WebAuthn a cărei provocare este base64url(SHA-256(același mesaj cu id-ul de dispozitiv passkey)). Fără număr de potrivire: aprobatorii nu sunt lângă agent.
Vot înregistrat.
application/json- response
status*string"pending""approved""denied"quorum*[key: string]?anycurl -X POST 'https://ai.codai.ro/v1/vault/approvals/497f6eca-6276-4993-bfeb-53cbbbba6f08/vote' \ -H 'Content-Type: application/json' \ -d '{ "decision": "approve", "proof": { "type": "device", "device_id": "string", "signature": "string" }}'{ "status": "pending", "quorum": { "m": 2, "approvals": 0, "needed": 0, "voted": true }}bearerAuthAutorizareBearer <codai_…>O cheie API Kodwen (prefix codai_). Tokenurile efemere de la POST /v1/tokens sunt acceptate doar de suprafețele media potrivite scope-ului lor (/v1/realtime, /v1/audio/*, /v1/embeddings).
application/json- body
rules?array<>Regulile propuse; omis = regulile tale actuale.
items <= 200default_tier?string"t1""t2""t3""t4"since?stringCea mai veche utilizare de reevaluat (ISO).
date-timelimit?integer1 <= value <= 500Simularea.
application/json- response
evaluated*integerUtilizările trecute reevaluate.
changed*integerRândurile al căror nivel diferă sub politica propusă.
grants*"none"Permisiunile și protecțiile la anomalii nu sunt reevaluate.
"none"rows*array<>curl -X POST 'https://ai.codai.ro/v1/vault/policy/simulate' \ -H 'Content-Type: application/json' \ -d '{}'{ "evaluated": 0, "changed": 0, "grants": "none", "rows": [ { "event_id": "string", "at": "2019-08-24T14:15:22Z", "item_id": "4d8cd62e-a579-4dae-af8c-3172f96f8f7c", "title": "string", "agent": "string", "chain": [ "string" ], "mode": "string", "host": "string", "current_tier": "t0", "simulated_tier": "t0", "reasons": [ "string" ], "source": "event" } ]}OK.
application/json- response
keys*array<>curl -X GET 'https://ai.codai.ro/v1/vault/receipts/keys'{ "keys": [ { "kid": "string", "alg": "ES256", "pem": "string" } ]}