codai docs
Referință APIGateway

Seif

Seif de credențiale zero-knowledge: sincronizare criptată, broker pentru agenți, aprobări și chei de dispozitiv.

codai 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 /v1/vault/* stochează și sincronizează doar text cifrat. 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.

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

  1. POST /v1/vault/devices/challenge întoarce un nonce de unică folosință (32 de octeți aleatori, base64url), valabil 5 minute.
  2. 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>, unde spki_sha256 este base64url(SHA-256(SubjectPublicKeyInfo DER)).
  3. POST /v1/vault/devices trimite device_id (android-…, wear-… sau desktop-…), kind (android_keystore sau windows_hello), name, surface (phone, wear sau desktop), public_key, nonce, vault_signature, device_signature și, când există, o attestation. Răspunsul este 201 { 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.

Tipuri de atestare

attestationSemnificație
android-strongboxAtestarea Google a cheii verificată, cheia ținută într-un element securizat StrongBox.
android-teeAtestarea Google a cheii verificată, cheia ținută în TEE.
tpmO atestare TPM a cheii Windows Hello, verificată față de rădăcinile TPM Microsoft.
hello-unattestedO cheie Windows Hello fără atestare TPM.

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ă. 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 ca signature.
  • v2 (cheie de dispozitiv sau passkey): codai-vault/approve/v2|<approval_id>|<action_hash>|<decision>|<scope>|<device_id>, trimis ca proof: { 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 cu match_number lângă proof. preview_digest este base64url(SHA-256) al textului canonic al request.preview (codai-vault/preview/v1, apoi title, agent, mode, host, action, purpose, task ca linii cheie=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ă ca proof: { 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 wear pe o aprobare T4 primește 403 wear_t3_only.
  • Potrivirea numărului: fiecare cerere T3/T4 primește un match_number din 2 cifre, întors doar agentului (/vault/use, /vault/http, /vault/resolve). Aprobatorul vede request.preview și trei request.match_choices, niciodată numărul. O aprobare T4 pe o astfel de cerere cere match_number cu o dovadă v3: fără număr primește 403 match_required; un număr greșit refuză imediat cererea și primește 403 match_mismatch. Aprobările T3 și refuzurile acceptă în continuare v1/v2.

Alte erori de dovadă (403): invalid_signature, unknown_device, device_revoked, passkey_invalid.

POST
/v1/vault/devices/challenge

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Corpul răspunsului

OK.

application/json
  1. response
nonce*string

32 de octeți aleatori, base64url. Se folosește o singură dată.

expires_at*string

La 5 minute după emitere.

Formatdate-time
Exemplu de cerere
curl -X POST 'https://ai.codai.ro/v1/vault/devices/challenge'
Exemplu de răspuns
{  "nonce": "string",  "expires_at": "2019-08-24T14:15:22Z"}
POST
/v1/vault/devices

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Corpul cererii

application/json
  1. body
device_id*string
Potrivire^(android|wear|desktop)-[A-Za-z0-9._-]{4,80}$
kind*string
Valoare din"android_keystore""windows_hello"
name*string
Lungime1 <= length <= 80
surface*string
Valoare din"phone""wear""desktop"
public_key*string

SubjectPublicKeyInfo DER al cheii dispozitivului, base64url.

nonce*string

Nonce-ul din POST /v1/vault/devices/challenge.

vault_signature*string

Semnătura Ed25519 a cheii seifului peste codai-vault/device-enroll/v1|<device_id>|<kind>|<spki_sha256>|<nonce>.

device_signature*string

Cheia dispozitivului peste același mesaj (ECDSA P-256 DER pe Android, RSASSA-PKCS1-v1_5 SHA-256 pentru Windows Hello), 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.

Corpul răspunsului

Înrolat.

application/json
  1. response
device*
Exemplu de cerere
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"}'
Exemplu de răspuns
{  "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"  }}
GET
/v1/vault/devices

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Corpul răspunsului

OK.

application/json
  1. response
devices*array<>
Exemplu de cerere
curl -X GET 'https://ai.codai.ro/v1/vault/devices'
Exemplu de răspuns
{  "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"    }  ]}
PATCH
/v1/vault/devices/{id}

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Parametri de cale

id*string

Id-ul dispozitivului.

Potrivire^(android|wear|desktop)-[A-Za-z0-9._-]{4,80}$

Corpul cererii

application/json
  1. body
name*string
Lungime1 <= length <= 80

Corpul răspunsului

OK.

application/json
  1. response
device*
Exemplu de cerere
curl -X PATCH 'https://ai.codai.ro/v1/vault/devices/string' \  -H 'Content-Type: application/json' \  -d '{  "name": "string"}'
Exemplu de răspuns
{  "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"  }}
DELETE
/v1/vault/devices/{id}

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Parametri de cale

id*string

Id-ul dispozitivului.

Potrivire^(android|wear|desktop)-[A-Za-z0-9._-]{4,80}$

Corpul răspunsului

Revocat.

application/json
  1. response
ok*boolean
Exemplu de cerere
curl -X DELETE 'https://ai.codai.ro/v1/vault/devices/string'
Exemplu de răspuns
{  "ok": true}
POST
/v1/vault/approvals/{id}/decide

Autorizare

bearerAuth
headerAutorizareBearer <codai_…>

O cheie API codai (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).

Parametri de cale

id*string

Id-ul resursei (uuid).

Formatuuid

Corpul cererii

application/json
  1. body
decision*string
Valoare din"approve""deny"
scope*string
Valoare din"once""task""1h""8h"
signature?string

Semnă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?stringDepreciat

Ignorat: o confirmare declarată de client nu dovedește nimic. Folosește proof.

via?string
Valoare din"hub""desktop""phone""wear""extension"
match_number?string

Numărul apăsat de utilizator (unul din request.match_choices); cere o dovadă de dispozitiv sau passkey peste mesajul v3.

Potrivire^[0-9]{2}$

Corpul răspunsului

OK.

application/json
  1. response
[key: string]?any
Exemplu de cerere
curl -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"}'
Exemplu de răspuns
{}

Pe această pagină