# Partajare, revizuire și remix (/ro/docs/gateway/sharing)

Linkuri publice doar pentru vizualizare către o creație, linkuri de revizuire cu comentarii ancorate și aprobare, plus remixul unei creații partajate în contul tău.

O creație poate fi partajată printr-un **link**. Un **link de vizualizare** deschide o pagină publică, doar pentru
citire, cu previzualizarea; dacă permiți, oricine are o cheie API codai o poate **remixa** în propriul cont. Un **link de revizuire**
deschide o pagină unde persoane fără cont lasă comentarii fixate pe un nod și pe un moment din videoclip și — dacă
permiți — aprobă creația sau cer modificări.

Tot ce este pe această pagină este **gratuit**: fără apeluri de model, fără randări.

| Metodă | Cale | Rezultat |
| --- | --- | --- |
| `POST` | `/v1/studio/creatives/{id}/shares` | Creează un link de vizualizare sau de revizuire (`201`, tokenul apare o singură dată) |
| `GET` | `/v1/studio/creatives/{id}/shares` | Linkurile active ale unei creații, cele mai noi primele |
| `DELETE` | `/v1/studio/creatives/{id}/shares/{shareId}` | Revocă un link (`204`) |
| `GET` | `/v1/studio/creatives/{id}/review` | Starea revizuirii, versiunea aprobată și numărul de fire |
| `POST` | `/v1/studio/creatives/{id}/review` | `{ action: "request" }` sau `{ action: "reset" }` |
| `GET` | `/v1/studio/creatives/{id}/review/threads?status=` | Firele de comentarii (`open`, `resolved` sau `all`) |
| `POST` | `/v1/studio/creatives/{id}/review/threads` | Fir nou al proprietarului (`201`) |
| `POST` | `/v1/studio/creatives/{id}/review/threads/{threadId}/replies` | Răspuns al proprietarului (`201`) |
| `POST` | `/v1/studio/creatives/{id}/review/threads/{threadId}/resolve` | Marchează un fir ca rezolvat |
| `POST` | `/v1/studio/creatives/{id}/review/threads/{threadId}/reopen` | Redeschide un fir |
| `DELETE` | `/v1/studio/creatives/{id}/review/comments/{commentId}` | Șterge un comentariu (`204`) |
| `POST` | `/v1/studio/shares/{token}/remix` | Copiază o creație partajată în contul tău (`201`) |
| `GET` | `/v1/public/studio/shares/{token}?format=&locale=` | Datele paginii publice (fără autentificare) |
| `POST` | `/v1/public/studio/reviews/{token}/threads` | Comentariu de recenzent (fără autentificare, `201`) |
| `POST` | `/v1/public/studio/reviews/{token}/threads/{threadId}/replies` | Răspuns de recenzent (`201`) |
| `POST` | `/v1/public/studio/reviews/{token}/threads/{threadId}/resolve` | Recenzentul rezolvă un fir |
| `POST` | `/v1/public/studio/reviews/{token}/threads/{threadId}/reopen` | Recenzentul redeschide un fir |
| `POST` | `/v1/public/studio/reviews/{token}/decision` | Aprobă sau cere modificări (doar linkuri de aprobator) |

## Linkuri de vizualizare și de revizuire [#linkuri-de-vizualizare-și-de-revizuire]

```bash
curl https://ai.codai.ro/v1/studio/creatives/<id>/shares \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "review", "label": "Client — Ana", "can_approve": true, "expires_in_days": 14 }'
```

| Câmp | Semnificație |
| --- | --- |
| `kind` | `view` (pagină publică doar pentru citire, `/s/<token>`) sau `review` (comentarii și decizii, `/r/<token>`) |
| `label` | O notă proprie, până la 100 de caractere (de exemplu cine a primit linkul) |
| `expires_in_days` | Între 1 și 365 sau `"never"`; fără el, linkul expiră după 30 de zile |
| `seq` | Doar linkuri de vizualizare: fixează pagina pe această versiune (`400 unknown_seq` dacă nu există); implicit urmează versiunea curentă |
| `allow_remix` | Doar linkuri de vizualizare: dacă vizitatorii pot remixa (implicit `false`; remixul se activează explicit) |
| `can_approve` | Doar linkuri de revizuire: dacă acest link poate aproba sau cere modificări (implicit `false`) |

Răspunsul este **201** `{ "id", "object": "studio.share", "kind", "token", "url", "label", "pinned_seq", "allow_remix",
"can_approve", "expires_at", "created_at" }`. `token` și `url` complet sunt returnate **o singură dată**: codai
păstrează doar un hash SHA-256 al tokenului de 256 de biți, așa că un link pierdut nu mai poate fi afișat — îl revoci și
creezi altul. Listarea întoarce aceleași câmpuri cu `url: null`, fără `token` și cu `last_used_at`.

`DELETE …/shares/{shareId}` revocă imediat un link (`404` dacă este necunoscut sau deja revocat). Un link expirat,
revocat sau a cărui creație a fost ștearsă răspunde peste tot cu `404 Share link not found or expired` — același
răspuns ca pentru un token care nu a existat niciodată.

## Pagina publică [#pagina-publică]

`https://hub.codai.ro/s/<token>` afișează titlul, previzualizarea (videoclipurile și documentele rulează într-un cadru
izolat), un selector de format și de limbă și, dacă este permis, butonul **Remixează în codai**. Un link de vizualizare
arată versiunea fixată sau versiunea curentă; un link de revizuire arată mereu versiunea curentă. Aceleași date vin din
`GET /v1/public/studio/shares/{token}`: `kind`, `title`, `creative_kind`, `seq`, `doc_hash`, `allow_remix`,
`can_approve`, `formats`, `default_format`, `locales`, `compiled` (`{ format, width, height, duration_ms, html }` sau
`null` pentru imagini) și, pentru linkurile de revizuire, `review` și `threads`. Adresele resurselor din
previzualizare sunt semnate pentru o oră. Răspunsurile publice nu sunt niciodată puse în cache sau indexate
(`cache-control: private, no-store`, `x-robots-tag: noindex, nofollow`, `referrer-policy: no-referrer`).

## Remix [#remix]

`POST /v1/studio/shares/{token}/remix` (orice cheie API codai, opțional `{ "title" }`) copiază versiunea partajată în
contul **tău** și răspunde **201** cu creația nouă plus `remixed_from: { share_id, seq }`:

- resursele gata ale proprietarului folosite în document sunt copiate în biblioteca ta Studio (cel mult 200 de
  resurse și 1 GiB, altfel `413 remix_too_large`); resursele lipsă sau neterminate rămân ca referințe și apar în
  `warnings`;
- legătura cu kitul de brand este eliminată (kitul aparține altcuiva) — culorile și fonturile deja prezente în document
  rămân;
- dacă tu deții creația partajată, remixul este o [bifurcare](./creatives.mdx#versiuni) obișnuită.

Doar linkurile de vizualizare cu `allow_remix` pot fi remixate; orice alt link răspunde cu `404`. Remixul este gratuit
și limitat la 20 pe minut pentru fiecare cheie.

## Revizuire [#revizuire]

O revizuire are o **stare**: `draft` → `in_review` → `approved` sau `changes_requested`.

- `POST …/review` cu `{ "action": "request" }` deschide revizuirea pentru versiunea curentă (`requested_seq`) și șterge
  o decizie anterioară; `{ "action": "reset" }` revine la `draft`.
- Doar un recenzent cu un link creat cu `can_approve: true` poate decide, prin
  `POST /v1/public/studio/reviews/{token}/decision` `{ "name", "decision": "approve" | "request_changes", "seq", "note"? }`.
  Erori: `403 not_an_approver`, `409 review_not_open` (starea nu este `in_review`) și `409 stale` cu `head_seq` când
  `seq` nu este versiunea curentă — recenzentul reîncarcă pagina și decide pe ce vezi acum.
- O aprobare **fixează versiunea**: `approved_seq` și `approved_doc_hash`. `GET …/review` întoarce `approved_is_head`,
  ca să știi când creația s-a schimbat după aprobare. Fiecare decizie apare și în fire ca un comentariu rezolvat de tip
  `decision`, împreună cu nota.

`GET …/review` răspunde cu `{ "object": "studio.review", "creative_id", "status", "head_seq", "requested_seq",
"requested_at", "approved_seq", "approved_doc_hash", "approved_is_head", "decided_by", "decided_at", "decision_note",
"threads": { "open", "total" } }`.

## Comentarii și ancore [#comentarii-și-ancore]

Un fir este un comentariu rădăcină plus răspunsurile lui. Fiecare fir poate fi ancorat cu `node_id`, `scene_id` și
`t_ms` (între 0 și 3 600 000 ms), verificate față de versiunea curentă: `400 unknown_node` sau `400 unknown_scene`.
Dacă trimiți doar `node_id`, scena se deduce din nod; dacă trimiți doar `t_ms` pentru un videoclip, se folosește scena
care rulează în acel moment. Textul unui comentariu are între 1 și 2000 de caractere.

Un fir este `{ "id", "node_id", "scene_id", "t_ms", "seq", "status": "open" | "resolved", "resolved_by",
"resolved_at", "created_at", "comments" }`; fiecare comentariu este `{ "id", "kind", "decision", "author": { "kind":
"owner" | "reviewer", "name" }, "body", "created_at" }`, primul fiind rădăcina. Numele proprietarului este mereu `null`
(aplicațiile afișează „Proprietar”). Recenzenții trimit un `name` (între 1 și 80 de caractere, altfel `400
invalid_name`) la fiecare comentariu, răspuns, rezolvare sau redeschidere. Proprietarul poate rezolva, redeschide și
șterge orice comentariu; ștergerea unei rădăcini ascunde tot firul.

## Limite [#limite]

| Limită | Valoare |
| --- | --- |
| Linkuri active pe creație | 20 (`409 too_many_shares`) |
| Fire pe creație | 500 (`409 too_many_comments`) |
| Răspunsuri pe fir | 100 (`409 too_many_comments`) |
| Comentariu / notă | 2000 de caractere |
| Numele recenzentului | 80 de caractere |
| Citiri publice | 60 pe minut pe IP, 300 pe minut pe link |
| Scrieri publice | 10 pe minut pe IP și link |
| Remix | 20 pe minut pe cheie; 200 de resurse, 1 GiB |

## Confidențialitate [#confidențialitate]

Numele și comentariile recenzenților sunt vizibile proprietarului și tuturor celor care au un link de revizuire al
aceleiași creații. Sunt stocate împreună cu creația și sunt **șterse odată cu ea** (și odată cu contul proprietarului).
Numele proprietarului nu este afișat niciodată. Tokenurile sunt stocate doar ca hash-uri; codai nu înregistrează
niciodată în jurnale tokenuri, adrese semnate, textul comentariilor sau numele recenzenților.

## SDK-uri și unelte de agent [#sdk-uri-și-unelte-de-agent]

```ts
const link = await codai.creatives.createShare(creative.id, { kind: 'review', can_approve: true, expires_in_days: 14 });
console.log(link.url); // apare o singură dată
await codai.creatives.requestReview(creative.id);
const threads = await codai.creatives.reviewThreads(creative.id, { status: 'open' });
const copy = await codai.shares.remix('https://hub.codai.ro/s/<token>', { title: 'Versiunea mea' });
```

```python
link = client.creatives.create_share(creative["id"], kind="review", can_approve=True, expires_in_days=14)
print(link["url"])  # apare o singură dată
client.creatives.request_review(creative["id"])
threads = client.creatives.review_threads(creative["id"], status="open")
copy = client.shares.remix("https://hub.codai.ro/s/<token>", title="Versiunea mea")
```

SDK-urile mai au `listShares` / `list_shares`, `revokeShare` / `revoke_share`, `review`, `resetReview` /
`reset_review`, metodele pentru fire și, pe `shares`, `get`, `comment`, `reply`, `resolve`, `reopen` și `decide` pentru
fluxul public de revizuire. Acceptă un token simplu sau o adresă completă `/s/…` ori `/r/…`.

Agenții de pe desktop, telefon și VS Code folosesc `creative_share` (`creative_id`, `kind`, `can_approve`,
`allow_remix`, `expires_in_days`, `label`), `creative_review` (`action`: `status`, `request` sau `reset`; `threads`),
`creative_review_comment` (`action`: `comment`, `reply`, `resolve` sau `reopen`; `body`, `thread_id`, `node_id`,
`t_ms`) și `creative_remix` (`share`, `title`).

## Hub (intern) [#hub-intern]

Hub-ul apelează rutele proprietarului sub `/internal/studio/creatives/:id/shares…` și
`/internal/studio/creatives/:id/review…`, iar remixul sub `/internal/studio/shares/:token/remix`, cu un token de
serviciu și un `user_id`; corpurile și erorile sunt identice. Paginile publice apelează direct rutele publice.
