# טרנדים

> עיון בקטלוג הטרנדים של Nodaro, מילוי המשבצות של טרנד בתמונות שלכם, אומדן מחיר בחינם והרצה ב-REST API, ב-SDK, ב-CLI או ב-MCP.

Source: https://nodaro.ai/he/docs/developers/api/trends

**ה-API של הטרנדים** מריץ מתכונים מוכנים של [Nodaro Motion](https://nodaro.ai/docs/developers/api/cast-swap). טרנד הוא קליפ קצר עם משבצות: האנשים, חיות המחמד, המוצרים והמקום שאפשר להחליף. מלאו את המשבצות בתמונות שלכם והריצו את הטרנד, כדי לקבל בחזרה את הקליפ, כשמה שבתמונות שלכם מופיע בו.

הטרנדים הם חלק מ-Nodaro Cloud. בהתקנה באירוח עצמי, כל נתיב מחזיר `404`. הקטלוג, התגיות שלו והדף של טרנד עונים גם לאורח, בלי פרטי גישה: ראו את הסעיף [גישת אורחים לקטלוג](#guests). כל נתיב אחר דורש אסימון Bearer. ראו את דף ה-API [אימות](https://nodaro.ai/docs/developers/api/authentication).

ב-API הזה קיימים רק טרנדים **שפורסמו**. כל נתיב מחזיר `404` על slug של טרנד בטיוטה, של טרנד שלא פורסם או שבארכיון, או על slug לא מוכר.

## נקודות קצה
| שיטה | נתיב | מה היא עושה |
| --- | --- | --- |
| `GET` | `/v1/trends` | הקטלוג, בסדר שנקבע לו: `{ data: TrendCard[], next }`. פרמטרי שאילתה: `q` (חיפוש), `tag`, `favorites=1` (רק המועדפים שלכם), `locale`, `cursor`, `limit` (1–60, ברירת המחדל: 30). |
| `GET` | `/v1/trends/:slug` | טרנד אחד: `{ data: TrendDetail }`, עם הקליפ המקורי, המשבצות, הדוגמאות, אורך התצוגה המקדימה, המנוע והרזולוציות שלו. פרמטר שאילתה: `locale`. |
| `POST` | `/v1/trends/:slug/estimate` | אומדן מחיר להרצה, בחינם. התגובה היא `{ data: { expectedCredits, holdCredits, engine, engineName, breakdown, privacyCredits? } }`. |
| `POST` | `/v1/trends/:slug/runs` | התחלת הרצה. התגובה היא `202 { data: { jobId } }`. בדקו את מצב המשימה עם `GET /v1/jobs/:id`. |
| `GET` | `/v1/trends/runs` | הרצות הטרנדים שלכם, מהחדש לישן: `{ data: TrendRun[], next }`. פרמטרי שאילתה: `trend` (slug), `cursor`, `limit` (1–60, ברירת המחדל: 30). |
| `GET` | `/v1/trends/runs/:jobId` | אחת מהרצות הטרנדים שלכם, באותו מבנה: `{ data: TrendRun }`. על משימה שהיא לא הרצת טרנד שלכם, נקודת הקצה מחזירה `404`, למשל משימה של משתמש אחר, שלב בתוך משימה אחרת או כל סוג אחר של משימה. |
| `GET` | `/v1/trends/tags` | התגיות שבשימוש בטרנדים שפורסמו, לפי מספר השימושים, מהגבוה לנמוך: `{ data: [{ tag, label, count }] }`. השדה `label` מגיע בשפה של `?locale=`, כמו שמוסבר בהמשך, ואם אין תווית בשפה הזו, באנגלית, ואם גם באנגלית אין, התווית היא התגית עצמה. העבירו את `tag` ל-`GET /v1/trends?tag=`. |
| `PUT` | `/v1/trends/:slug/favorite` | הוספת הטרנד למועדפים שלכם. התגובה היא `204`. |
| `DELETE` | `/v1/trends/:slug/favorite` | הסרת הטרנד מהמועדפים שלכם. התגובה היא `204`. |

השמות, התיאורים, התוויות של המשבצות והרמזים מגיעים בשפה של `?locale=`, כשזו אחת משפות הפלטפורמה. אחרת הם מגיעים בשפת הפרופיל שלכם, ואם גם בה אין, באנגלית. אצל אורח, במקום שפת הפרופיל באה שפת הפלטפורמה הראשונה שהכותרת `Accept-Language` של הבקשה מבקשת, לפי המשקלים שלה. הערכים `pt` ו-`pt-br` נחשבים ל-`pt-BR`.

הרצה נשארת זמינה לקריאה ב-`GET /v1/trends/runs` גם אחרי שהטרנד שלה עובר לגרסה חדשה, יורד מהפרסום או עובר לארכיון. המילים `runs` ו-`tags` אף פעם לא משמשות כ-slug של טרנד. תגית היא מחרוזת פשוטה שמופיעה בטרנדים שלה. לתגית שאין לה תווית בשפה מסוימת, התווית היא התגית עצמה.

## גישת אורחים לקטלוג
הנתיבים `GET /v1/trends`, `GET /v1/trends/tags` ו-`GET /v1/trends/:slug` לא דורשים פרטי גישה. אפליקציה יכולה להציג למבקר כל טרנד שפורסם, ולבקש ממנו להתחבר רק כדי להריץ טרנד.

- אורח מקבל את אותם נתונים שפורסמו, עם `isFavorite: false`.
- הפרמטר `favorites=1` קורא את המועדפים של חשבון, ולכן אצל אורח הוא נדחה עם `401`.
- בקשה עם אסימון לא תקין או שפג תוקפו מקבלת את התשובה שאורח מקבל.
- כל אחד משלושת הנתיבים מאפשר 60 בקשות לדקה לכל כתובת IP אצל אורח, ולכל חשבון אצל משתמש מחובר. מעבר לזה, הנתיב מחזיר `429 rate_limit_exceeded`.

השרת שומר את התשובה שאורח קיבל בשביל האורח הבא, עד שהקטלוג משתנה, ולכן שינוי מופיע בתוך שניות. חיפוש (`q`) אף פעם לא נשמר. התשובות כוללות את כותרות המטמון האלה:

| מי קורא | `Cache-Control` |
| --- | --- |
| אורח שהשפה שלו נקבעה לפי `Accept-Language` | `private, max-age=60`, עם `Vary: Accept-Language, Authorization`. רק הדפדפן שומר את התשובה, כי מטמון משותף שהמפתח שלו הוא כתובת ה-URL היה מגיש שפה אחת לכולם. |
| אורח שמציין את השפה עם `?locale=` | `public, max-age=60`, עם `Vary: Authorization`, ולכן מטמון משותף רשאי לשמור את התשובה. פריסה שמנקה את מטמון הקצה שלה בכל שינוי בקטלוג שולחת `public, max-age=60, s-maxage=86400`, ואז מטמון הקצה שומר את התשובה למשך יום. |
| משתמש מחובר | `private, no-store`. |

בבקשות של אורחים, שלחו את `locale`.

## מה יש בטרנד
הנתיב `GET /v1/trends/:slug` מחזיר:

- `original`: הקליפ שכל הרצה מתחילה ממנו, כפי שמותר להציג אותו: `{ videoUrl, posterUrl?, width, height, durationSec, previewStartSec? }`. זה עותק MP4 ב-H.264 שכל דפדפן יכול לנגן. השדה `previewStartSec`, שיכול להיות גם `0`, הוא הנקודה שבה מתחילה התצוגה המקדימה של 4 שניות, כשלטרנד יש תצוגה מקדימה.
- `slots`: לכל משבצת, `key`, `label`, `kind` (`person`, `pet`, `product` או `location`), `required`, `hint` אופציונלי, `hintImageUrl` אופציונלי, `chips` ו-`defaults`. השדה `hintImageUrl` הוא תמונה של מי או מה שהמשבצת מייצגת בקליפ המקורי. השדה `chips` מפרט את התגיות שאפשר להגדיר במשבצת הזו, לפי הסדר של הסוג. רשימה ריקה פירושה שאין כאלה, ולכן אל תציגו שורת תגיות. ב-`defaults` נמצאים ערכי ההתחלה של התגיות האלה.
- `examples`: לכל דוגמה, סרטון התוצאה שלה והתמונות שכל משבצת השתמשה בהן. הרשימה יכולה להיות ריקה, בטרנד שיש לו רק את הקליפ המקורי. ה-`cover` של הכרטיס הוא אז הקליפ המקורי. למשבצת אופציונלית שהדוגמה השאירה כמו במקור אין מפתח ב-`slots` של הדוגמה הזו.
- `previewSec`: הערך `4` כשהטרנד מציע הרצת תצוגה מקדימה של 4 שניות, ואחרת `null`.
- `engine`: המנוע שכל הרצה של הטרנד משתמשת בו, `"motion-prism"` או `"motion-pulse"`. הטרנד קובע אותו, ואף פעם לא מי שמריץ אותו. כשהשדה חסר, המנוע הוא Nodaro Motion Prism.
- `engineName`: השם של המנוע, `"Nodaro Motion Prism"` או `"Nodaro Motion Pulse"`.
- `resolutions`: הרזולוציות שהרצה יכולה לבקש, כשברירת המחדל ראשונה. טרנד של Nodaro Motion Prism מציע `["480p", "720p", "1080p"]`, ו-480p היא הטיוטה. טרנד של Nodaro Motion Pulse מציע `["720p", "1080p"]`, ואין לו טיוטה.

בכרטיס בקטלוג של `GET /v1/trends` נמצאים ה-slug, השם, התגיות, `cover`, `original`, `examples`, `needs` (כמה משבצות יש מכל סוג), האורך בשניות ו-`isFavorite`. השדה `cover` הוא הדוגמה הראשונה, או הקליפ המקורי כשאין דוגמה. השדה `original` הוא עותק התצוגה של הקליפ המקורי, `{ videoUrl, posterUrl?, width, height }`, באותה כתובת כמו ה-`original` בדף הטרנד. השדה `examples` מפרט את הסרטון של כל דוגמה, לפי הסדר, בתור `{ videoUrl, posterUrl?, width, height }`, בלי התמונות שהמשבצות שלה השתמשו בהן. התמונות האלה נמצאות בדף הטרנד. בטרנד שיש לו רק קליפ מקורי, השדה `examples` הוא `[]`.

בכל סרטון יכולים להופיע גם השדות `webUrl` ו-`webSizeBytes`. זה נכון ל-`cover`, ל-`original` ולכל אחד מה-`examples` של הכרטיס, ול-`original` ול-`examples` של דף הטרנד. השדה `webUrl` הוא עותק קל שהפלטפורמה הכינה לניגון (H.264 בקצב של כ-2.5 Mbit/s, AAC ב-160 kbit/s): נגנו אותו כמו שהוא, בלי עיבוד ב-CDN. השדה `webSizeBytes` הוא הגודל של הקובץ הזה בבייטים. שני השדות חסרים עד שהעותק נוצר, למשל בגרסה שפורסמה לפני כן. במקרה כזה, נגנו את `videoUrl`.

### טרנד שמסתיר את הקליפ המקורי שלו
טרנד יכול להסתיר את הקליפ המקורי שלו. ה-`original` שלו, בכרטיס ובדף הטרנד, הוא אז הדוגמה הראשונה שלו: הסרטון, תמונת הפוסטר, הגודל והאורך של הדוגמה הזו, עם ה-`previewStartSec` של הטרנד עצמו. רשימת ה-`examples` שלו מתחילה מהדוגמה השנייה. הקליפ המקורי אף פעם לא נשלח.

## גוף הבקשה של ההרצה
הנתיבים `POST /v1/trends/:slug/estimate` ו-`POST /v1/trends/:slug/runs` מקבלים את אותו גוף בקשה: `{ slots, example?, details?, preview?, resolution?, draft?, sessionId?, projectId?, origin?, previewJobId? }`.

| שדה | מה הוא עושה |
| --- | --- |
| `slots` | נדרש. אובייקט שהמפתחות שלו הם מפתחות המשבצות, וכל ערך בו הוא `{ images?, …chips }`, עם 1–3 תמונות של נושא אחד בכל משבצת. כל משבצת נדרשת צריכה תמונות. |
| `example` | אופציונלי. מספר של דוגמה. המספור מתחיל ב-1, לפי הסדר שבו דף הטרנד מפרט את ה-`examples` שלו. התמונות של הדוגמה ממלאות את המשבצות האופציונליות שלא שלחתם. ברירת המחדל היא 1. כשלדוגמה הזו אין תמונות למשבצת, המשבצת נשארת כמו במקור (`fromExample: false`). בטרנד בלי דוגמאות, השמיטו את השדה: משבצת אופציונלית שלא נשלחה נשארת אז כמו במקור, ובהרצה נרשם `example: 0`. בטרנד שמסתיר את המקור שלו, כשמשמיטים את `example`, המשבצות מתמלאות מהדוגמה שמוצגת כקליפ המקורי. טרנד בעומק מלא לא משתמש בדוגמאות: משבצת אופציונלית שלא נשלחה מקבלת את תמונת ברירת המחדל של הטרנד לתפקיד הזה, אם הוגדרה כזו, ואחרת את המראה של המקור. במשבצת כזו נרשם `fromDefault: true`, ובהרצה נרשם `example: 0`. |
| `details` | אופציונלי. טקסט משלכם, עד 1,000 תווים. הזכירו משבצת כ-`{slot:<key>}`. |
| `preview` | אופציונלי. הערך `true` מריץ 4 שניות, כשה-`previewSec` של הטרנד הוא 4. |
| `resolution` | אופציונלי. אחת מהרזולוציות ב-`resolutions` של הטרנד. ברירת המחדל היא הראשונה: `"480p"`, או `"720p"` בטרנד של Nodaro Motion Pulse. ערך אחר נדחה עם `resolution_unsupported`. |
| `draft` | אופציונלי. ברירת המחדל היא `true`. טיוטה זמינה רק ב-480p, בטרנד של Nodaro Motion Prism. הערך `draft: true` בטרנד של Nodaro Motion Pulse נדחה עם `draft_unsupported`. |
| `sessionId` | אופציונלי. מתקבל ונבדק, אבל עדיין לא מוחל: הרצות טרנד עדיין לא מתויקות בסשנים. |
| `projectId` | אופציונלי. מתקבל, אבל כרגע ההרצה לא משתמשת בו. |
| `origin` | אופציונלי. ה-slug של האפליקציה שלכם, באותיות קטנות, ספרות ומקפים. המשימה של ההרצה שומרת אותו ב-`input_data.origin`, ו-`GET /v1/jobs?origin=` מסנן לפיו. ערך שהוא לא slug נדחה עם `400 validation_error`. בלי השדה, אין להרצה מקור. |
| `previewJobId` | אופציונלי. בהרצה מלאה, ה-`jobId` של הרצת תצוגה מקדימה שהושלמה של הטרנד הזה, מהחשבון שלכם. כשהתצוגה המקדימה הראתה שהקליפ צריך את הניסיון החוזר של הטרנד, ההרצה המלאה נעשית כך כבר מההתחלה, ואומדן המחיר מציין זאת. כל משימה אחרת לא נלקחת בחשבון, בלי שגיאה. |

משבצת מקבלת את התגיות שרשימת ה-`chips` שלה מציינת, מתוך התכונות של הסוג שלה. הערך של כל תגית הוא `"new"`, שנלקח מהתמונות שלכם, או `"original"`, שנשאר כמו בקליפ:

| סוג המשבצת | תגיות |
| --- | --- |
| `person` | `body`, `outfit`, `hair` |
| `pet` | `body`, `coat` |
| `product` | `shape`, `finish` |
| `location` | אין |

תגית ששייכת לסוג של המשבצת, אבל המשבצת לא מפרטת אותה, מקבלת ערך קבוע מהטרנד: ברירת המחדל שלה, ואם אין, `"new"`. שליחה של תגית כזו נדחית עם `chip_not_offered`.

```json
{
"slots": {
"dancer": { "images": ["https://example.com/me.jpg"], "outfit": "original" }
},
"preview": true,
"resolution": "480p"
}
```

## אומדן המחיר
האומדן מחזיר את `expectedCredits`, החיוב הצפוי על ההרצה, ואת `holdCredits`, הסכום שמשוריין כשההרצה מתחילה. השדה `engine` הוא המנוע שהמחיר חושב לפיו, המנוע של הטרנד עצמו (`"motion-prism"` או `"motion-pulse"`, כמו בדף שלו), ו-`engineName` הוא השם שלו. השדה `breakdown` מפרט את החלקים של אומדן המחיר, לתצוגה בלבד. חלק מהחלקים לא כלולים בסכומים הכוללים, ולכן השתמשו בסכומים הכוללים, ולעולם אל תחברו את החלקים של הפירוט.

חלק מהטרנדים מנסים שוב קליפ שמודל הווידאו דוחה. בטרנדים כאלה, האומדן מחזיר גם את `privacyCredits`: החיוב הנוסף אם הניסיון החוזר הזה רץ. השדה `privacyCredits` לא כלול ב-`expectedCredits` ולא ב-`holdCredits`. הערך שלו 0 בטרנד שהקליפ שלו הוכן מראש.

## הרצות באיכות מלאה
כברירת מחדל, הרצת טרנד היא טיוטה. בתוך 7 ימים מסיום ההרצה, אפשר להשלים אותה ב-1080p עם [האיכות המלאה של Nodaro Motion](https://nodaro.ai/docs/developers/api/cast-swap#full-quality). העבירו את ה-`jobId` של הרצת הטרנד ל-`POST /v1/cast-swap/:jobId/full-quality`.

בכל הרצה מופיעים ה-`engine` שלה, `"motion-prism"` או `"motion-pulse"`, וה-`engineName` שלה. לטיוטה של Nodaro Motion Prism שהושלמה, או להרצה של Nodaro Motion Pulse ב-720p שהושלמה, יש `fullQualityUntil`, המועד שבו 7 הימים שלה נגמרים. ב-Nodaro Motion Pulse, גרסת האיכות המלאה היא טייק חדש ב-1080p, שנוצר מחדש מגרסת הטרנד שההרצה השתמשה בה.

גרסת איכות מלאה היא הרצה בפני עצמה ב-`GET /v1/trends/runs` וב-`GET /v1/trends/runs/:jobId`. יש לה `jobId`, `status`, `videoUrl` ו-`creditsCharged` משלה, עם `resolution: "1080p"` ו-`draft: false`. ה-`fullQualityOf` שלה הוא מזהה המשימה של הטיוטה, ובכל הרצה אחרת הערך שלו `null`. היא נשארת ברשימה גם אחרי שהטיוטה שלה נמחקת.

- ברשימה מופיע הניסיון האחרון של איכות מלאה לכל טיוטה: ניסיון שרץ, ניסיון שהסתיים או הכשל האחרון. כשניסיון נכשל או בוטל ואז ניסו שוב להשלים את הטיוטה, הניסיונות הקודמים לא מופיעים ב-`GET /v1/trends/runs`. הנתיב `GET /v1/trends/runs/:jobId` עדיין מחזיר כל אחד מהם לפי המזהה שלו.
- בגרסת איכות מלאה שהספק דחה, או חסם בגלל זכויות יוצרים או דמיון לאדם אמיתי, מופיע גם `refused: true`. ניסיון נוסף ייכשל באותו אופן. כשמוחקים את הגרסה הזו, אפשר שוב לבקש איכות מלאה.
- ה-`fullQuality` של הטיוטה הוא רק מצביע לניסיון האחרון הזה: `{ jobId, status }`, עם `refused: true` כשהספק דחה או חסם אותו, או `null` כשלא התחיל אף ניסיון. קבלו את הסרטון ואת החיוב של הניסיון מההרצה שלו עצמה, ולעולם לא מהטיוטה.

## קליפ הקלט של התצוגה המקדימה
טרנד שמציע תצוגה מקדימה שומר קליפ קלט מוכן לתצוגה המקדימה. זה חלון התצוגה המקדימה של 4 שניות, ועוד עד שנייה אחת של הסרטון האמיתי שאחריו. Nodaro חותך את הקליפ הזה פעם אחת מהקליפ של הטרנד כשהטרנד נשמר או מתפרסם, ושומר אותו כקובץ נפרד, עם גיבוב.

- הרצת תצוגה מקדימה עורכת את הקליפ השמור הזה כמו שהוא. כך כל תצוגה מקדימה של גרסת טרנד שפורסמה מתחילה בדיוק מאותו סרטון.
- הרצה מלאה עורכת את הקליפ כולו.
- המשימה רושמת איזה קליפ היא ערכה, ב-`GET /v1/jobs/:id`, בשדה `input_data.sourceAsset`: `{ kind: "preview" | "full", sha256?, startSec?, durationSec?, recipe? }`. השדה `sha256` הוא הגיבוב של הקובץ. השדות `startSec`, `durationSec` ו-`recipe` מציינים איפה ואיך נחתך קליפ של תצוגה מקדימה.
- בתצוגה מקדימה שערכה את הקליפ השמור מופיע גם `input_data.preparedPreview: true`. כשההרצה מסתיימת, השדה `sourceAsset` מועתק ל-`output_data.sourceAsset`.

השדה `sourceAsset` לא כולל כתובת URL. הוא רישום של הקליפ שההרצה התחילה ממנו, והוא לא חלק מהמבנה `TrendRun` ב-`GET /v1/trends/runs`. בגרסת פלטפורמה שהמנוע שלה לא מקבל קליפ מוכן, התצוגה המקדימה נחתכת מהקליפ כולו כשהיא רצה, ובמשימה אין `sourceAsset`.

## בקשות חוזרות
הנתיב `POST /v1/trends/:slug/runs` מקבל כותרת `Idempotency-Key` באורך 8–200 תווים. בקשה חוזרת עם אותו מפתח מקבלת את המשימה של ההרצה הראשונה. שום הרצה חדשה לא מתחילה, ולא נגבים קרדיטים.

## הרשאות
אפליקציית OAuth צריכה:

- את `jobs:read` כדי לקרוא את הקטלוג, טרנד מסוים ואת ההרצות שלכם;
- את `workflows:execute` כדי לקבל אומדן מחיר או להתחיל הרצה, ובנוסף את `assets:write` כדי לשלוח `sessionId`;
- את `assets:write` למועדפים.

## שגיאות
גוף התגובה של דחייה הוא `{ error: { code, message } }`. שגיאות המשבצות מציינות גם את המפתח של המשבצת ב-`slot`, והשגיאה `chip_not_offered` מציינת את התגית ב-`chip`. דחיות `400` של נתיבי האומדן וההרצה קורות לפני שנגבים קרדיטים.

| סטטוס | `code` | מתי |
| --- | --- | --- |
| `400` | `validation_error` | גוף הבקשה או פרמטר שאילתה לא תקינים, ה-`cursor` לא הגיע מהרשימה הזו, אורך הכותרת `Idempotency-Key` הוא לא בין 8 ל-200 תווים, או שהשדה `origin` הוא לא slug. |
| `400` | `missing_slot` | למשבצת נדרשת אין תמונות. משבצת אופציונלית שנשארה ריקה, ושלדוגמה שנבחרה אין תמונות בשבילה, לא נדחית: היא נשארת כמו במקור. |
| `400` | `unknown_slot` | השדה `slots` מציין מפתח שאין לטרנד. |
| `400` | `invalid_choice` | תגית שהסוג של המשבצת לא מקבל, למשל `coat` באדם או כל תגית במיקום. |
| `400` | `draft_unsupported` | הערך `draft: true` בטרנד שלמנוע שלו אין טיוטה, כלומר Nodaro Motion Pulse. |
| `400` | `resolution_unsupported` | ערך ב-`resolution` שהטרנד לא מציע, למשל 480p בטרנד של Nodaro Motion Pulse. |
| `400` | `too_many_images` | הרצה בטרנד של Nodaro Motion Pulse הייתה שולחת יותר מ-10 תמונות: שלכם, של הדוגמה למשבצות שהשארתם ריקות (תמונת ברירת המחדל, בטרנד בעומק מלא) ושל הטרנד עצמו. שלחו פחות תמונות בכל משבצת. |
| `400` | `chip_not_offered` | תגית מהסוג של המשבצת שהטרנד לא מציע במשבצת הזו, כי היא לא מופיעה ב-`chips` של המשבצת. הטרנד קובע את הערך שלה. השגיאה מציינת את `slot` ואת `chip`. |
| `400` | `example_out_of_range` | השדה `example` מציין דוגמה שדף הטרנד לא מפרט. בטרנד בלי דוגמאות, כל `example` נדחה. בטרנד שמסתיר את המקור שלו, מספר שגדול מהאורך של ה-`examples` שלו נדחה. |
| `400` | `preview_unavailable` | הערך `preview: true` בטרנד שלא מציע תצוגה מקדימה. |
| `400` | `invalid_slot_mention` | השדה `details` מזכיר `{slot:<key>}` עם מפתח שאין לטרנד. |
| `400` | `prompt_too_long` | השדה `details` ארוך מדי לטרנד הזה. קצרו אותו. |
| `401` | `unauthorized` | אין משתמש מאומת, בכל נתיב חוץ מהקטלוג, התגיות שלו והדף של טרנד. גם `GET /v1/trends?favorites=1` דורש משתמש מחובר. |
| `404` | `not_found` | הטרנד לא פורסם, או ש-`sessionId` מציין סשן שאין לכם גישה אליו. |
| `429` | `rate_limit_exceeded` | יותר מ-60 קריאות של הקטלוג, של התגיות או של דף טרנד בדקה, מכתובת IP אחת (אורח) או מחשבון אחד. |
| `409` | `trend_unavailable` | אומדן או הרצה של טרנד שההגדרה שלו לא עדכנית. אי אפשר להריץ את הטרנד עד שהוא מתעדכן, ולכן ניסיון חוזר יקבל את אותה תשובה. |
| `502` | `engine_error` | Nodaro Motion החזיר תשובה לא צפויה. |
| `503` | `engine_unsupported` | גרסת הפלטפורמה הזו עדיין לא יכולה להריץ טרנדים. |
| `503` | `trend_unavailable` | כרגע אי אפשר להריץ את הטרנד. |
| `503` | `not_available` | בשרת הזה עדיין אין קטלוג טרנדים. בכל נתיב חוץ מ-`GET /v1/trends/runs` ומ-`GET /v1/trends/runs/:jobId`. |

כש-Nodaro Motion דוחה אומדן או הרצה, נתיבי הטרנדים מחזירים קודים משלהם והודעות קבועות:

| סטטוס | `code` | מתי |
| --- | --- | --- |
| `400` | `trend_run_rejected` | המנוע דחה את הקלטים האלה, מסיבה שלא מופיעה בהמשך. |
| `400` | `clip_out_of_range`, `preview_out_of_range`, `video_unreadable` | אי אפשר להריץ את הקליפ של הטרנד עצמו כמו שהוא. |
| `400` | `unsafe_url` | אחת התמונות היא לא כתובת http או https ציבורית. |
| `400` | `raw_reference_token` | השדה `details` כולל `{image:`, `{video:` או `{audio:`. |
| `402` | `insufficient_credits` | אין לכם מספיק קרדיטים להרצה. בסביבת עבודה, במקום הקוד הזה יכול לחזור קוד המגבלה שדחתה את ההרצה: `budget_exceeded`, `member_cap_exceeded` או `user_allowance_exceeded`. |
| `413` | `storage_limit_exceeded` | נפח האחסון שלכם מלא. |
| `422` | `job_blocked` | מדיניות המשימות של הפריסה חסמה את ההרצה. |
| `429` | `rate_limited` | יותר מדי בקשות. נסו שוב בעוד רגע. |
| `503` | `engine_unsupported`, `estimate_unavailable` | כרגע אי אפשר להתחיל את ההרצה או לתת לה אומדן מחיר. נסו שוב בעוד רגע. |
| `502` | `engine_error` | כל מקרה אחר. |

## הרצות שלא הסתיימו
להרצה ב-`GET /v1/trends/runs` שלא הסתיימה יש `error: { code, message }`. ההודעה היא תמיד אותו משפט קבוע, ולכן פעלו לפי הקוד:

| `code` | משמעות |
| --- | --- |
| `safety-block`, `policy-block` | המשימה נחסמה. |
| `credits` | הקרדיטים נגמרו באמצע ההרצה. הקרדיטים על ההרצה הוחזרו. טענו קרדיטים והריצו אותה שוב. |
| `input-refused` | מודל הווידאו דחה את הקליפ של הטרנד עצמו. |
| `request-refused` | מודל הווידאו דחה את ההרצה כפי שהיא נשלחה. אותה הרצה תידחה שוב, ולכן שנו את התמונות או את ההגדרות. |
| `cancelled` | ההרצה בוטלה. |
| `failed` | כל כשל אחר. |

להרצה שלא נכשלה ולא בוטלה יש `error: null`. בהרצה שהושלמה מופיעים `videoUrl` ו-`posterUrl`.

## כמה נגבה על הרצה
ה-`creditsCharged` של הרצה הוא כמה עלתה ההרצה כולה אחרי החיוב הסופי. זה החיוב של ההרצה עצמה, ועוד כל שלב שהיא הריצה: הכנת הייחוסים, המסכה והסרטון. כל שלב מתווסף אחרי החיוב הסופי שלו. השדה `creditsCharged` הוא `null` עד החיוב הסופי של השריון של ההרצה עצמה.

- השדה `creditsHeld` הוא השריון של ההרצה: השריון שלה עצמה ועוד השריונות של השלבים שלה.
- השדה `creditsReleased` הוא מה שחזר מתוך `creditsHeld` אחרי החיוב הסופי של כל השריונות בהרצה. עד אז הערך שלו `null`. כל משבצת בהרצה מציינת אם התמונות שלה הגיעו מהדוגמה (`fromExample`) או מתמונת ברירת המחדל של הטרנד (`fromDefault: true`).

ה-`example` של הרצה הוא הדוגמה שהתמונות שלה מילאו את המשבצות האופציונליות הריקות של ההרצה, לפי המספור של הדוגמאות בדף הטרנד בגרסה שההרצה רצה עליה (`trend.version`). הערך `0` פירושו שההרצה לא השתמשה באף דוגמה. בגרסת טרנד שמסתירה את הקליפ המקורי, להרצה שהשתמשה בדוגמה שמוצגת כקליפ המקורי אין מפתח `example`.

## דרך ה-SDK
המשאב `client.trends` עוטף את הנתיבים. אפשר גם לייבא אותו מ-`@nodaro/sdk/trends`.

```ts
list(params?: ListTrendsParams): Promise<TrendPage<TrendCard>>
get(slug: string, params?: { locale?: string }): Promise<TrendDetail>
estimate(slug: string, request: TrendRunRequest): Promise<TrendEstimate>
run(slug: string, request: TrendRunRequest, options?: { idempotencyKey?: string }): Promise<{ jobId: string }>
runs(params?: ListTrendRunsParams): Promise<TrendPage<TrendRun>>
getRun(jobId: string): Promise<TrendRun>
tags(params?: { locale?: string }): Promise<TrendTag[]>
favorite(slug: string): Promise<void>
unfavorite(slug: string): Promise<void>
```

**בלי התחברות:** המתודות `list()`, `tags()` ו-`get()` עובדות בלי פרטי גישה. אובייקט `Auth` שהמתודה `getToken()` שלו מחזירה `null` לא שולח כותרת `Authorization`. אורח מקבל את אותם טרנדים שפורסמו, עם `isFavorite: false`, והטקסט מגיע בשפה של `locale`, ואם אין, בשפה של `Accept-Language` של הבקשה, ואם גם היא חסרה, באנגלית. אצל אורח, הקריאה `list({ favorites: true })` זורקת `UnauthorizedError` (401). כל שאר המתודות דורשות משתמש מחובר.

המתודות `list()` ו-`runs()` מחזירות את העמוד כמו שהוא מגיע, `{ data, next }`. שלחו את `next` בחזרה בתור `cursor`; בעמוד האחרון הערך שלו `null`. המתודות `get()`, `estimate()`, `run()`, `getRun()` ו-`tags()` מחזירות את המטען עצמו, בלי המעטפת `{ data }`. המחרוזות `"runs"` ו-`"tags"` אף פעם לא משמשות כ-slug: המתודות שמקבלות slug זורקות עליהם `TypeError` עוד לפני ששולחים בקשה.

- המתודה `getRun(jobId)` מחזירה אחת מהרצות הטרנדים שלכם. על משימה שהיא לא הרצת טרנד שלכם, המתודה זורקת `NotFoundError`.
- המתודה `tags()` מחזירה את התגיות שבשימוש בטרנדים שפורסמו, לפי מספר השימושים, מהגבוה לנמוך. הטיפוס `TrendTag` הוא `{ tag, label, count }`, והשדה `label` מגיע בשפה שנקבעה לבקשה. העבירו את `tag` ל-`list({ tag })`.
- הטיפוס `TrendRun` כולל את `fullQualityOf`, הטיוטה שגרסת איכות מלאה נוצרה ממנה, ואת `fullQuality`, המצביע של טיוטה לניסיון האחרון שלה של איכות מלאה (`{ jobId, status }` או `null`). קבלו את הניסיון הזה עם `getRun(fullQuality.jobId)`.
- הטיפוס `TrendEstimate` כולל את `privacyCredits` האופציונלי, ואת `engine` ו-`engineName` האופציונליים, המנוע שהאומדן מתייחס אליו. שרת ישן יותר משמיט אותם.
- הטיפוס `TrendCard` כולל את `original` ואת `examples`, ששניהם אופציונליים. שרת ישן יותר משמיט את `examples`.
- משבצת ב-`TrendRun` כוללת את `fromDefault` האופציונלי, וגם ה-`example` של ההרצה אופציונלי.
- הטיפוסים `TrendDetail` ו-`TrendRun` כוללים את `engine` האופציונלי, מהטיפוס `TrendEngine`, ואת `engineName`. כשהשדה `engine` חסר, המנוע הוא Nodaro Motion Prism.
- הטיפוס `TrendRun` כולל את `creditsCharged`, עם כל שלבי ההרצה, ואת `creditsHeld` ו-`creditsReleased` האופציונליים.

```ts

const { data: cards } = await client.trends.list({ q: "dance" })
const trend = await client.trends.get(cards[0].slug)

const request: TrendRunRequest = {
// Every required slot needs 1–3 pictures; optional slots left out take the example's (or stay as in the original where it has none).
slots: Object.fromEntries(
trend.slots.filter((s) => s.required).map((s) => [s.key, { images: [myPhotoUrl] }]),
),
}
const quote = await client.trends.estimate(trend.slug, request)
console.log(`about ${quote.expectedCredits} credits, ${quote.holdCredits} held while it runs`)

const { jobId } = await client.trends.run(trend.slug, request, { idempotencyKey: crypto.randomUUID() })
const job = await client.jobs.get(jobId)
```

## דרך ה-CLI
```bash
nodaro trends list --search dance
nodaro trends get <slug>
nodaro trends estimate <slug> --slot dancer=https://example.com/me.jpg --choice dancer.outfit=original
nodaro trends run <slug> --slot dancer=https://example.com/me.jpg --idempotency-key <key>
nodaro trends runs --trend <slug>
nodaro trends favorite <slug>
```

אפשר לחזור על `--slot` כמה פעמים, עם 1–3 תמונות לכל משבצת. הפקודה `trends run` מוציאה קרדיטים, ולכן הריצו קודם את `trends estimate`. ראו את הדף [פקודות ה-CLI](https://nodaro.ai/docs/developers/cli/commands).

## דרך MCP
ארבעה כלי MCP מטפלים בטרנדים: `list_trends`, `get_trend`, `estimate_trend` ו-`run_trend`. ראו בדף [MCP › וידאו](https://nodaro.ai/docs/mcp/tools/video#trends). בלי `confirm`, הכלי `run_trend` מחזיר את אומדן המחיר ולא גובה כלום. עם `confirm: true`, אחרי שהמחיר אושר, הכלי מתחיל את ההרצה ומחזיר מזהה משימה.

## שאלות נפוצות

### מה זה טרנד ב-Nodaro?

טרנד הוא מתכון מוכן של Nodaro Motion. הטרנד הוא קליפ קצר עם משבצות לאנשים, לחיות המחמד, למוצרים ולמקום שאפשר להחליף. ממלאים את המשבצות בתמונות שלכם ומקבלים בחזרה את הקליפ, כשמה שבתמונות שלכם מופיע בו.

### איך יודעים כמה תעלה הרצה של טרנד?

קראו ל-POST /v1/trends/:slug/estimate עם אותו גוף בקשה שתשלחו להרצה. הקריאה הזו חינמית. היא מחזירה את expectedCredits, החיוב הצפוי על ההרצה, ואת holdCredits, הסכום שמשוריין בזמן שההרצה רצה.

### האם צריך למלא כל משבצת?

לא. כל משבצת נדרשת צריכה בין תמונה אחת לשלוש. משבצת אופציונלית שלא שולחים מקבלת את התמונות של דוגמה מהטרנד — כברירת מחדל, הדוגמה הראשונה. כשלדוגמה הזו אין תמונות למשבצת, או כשלטרנד אין דוגמה, המשבצת נשארת כמו בקליפ המקורי. טרנד בעומק מלא משתמש במקום זאת בתמונת ברירת המחדל שלו לתפקיד, כשיש לו כזו.

### האם אפשר לנסות שוב הרצת טרנד בבטחה?

כן. שלחו את אותה כותרת Idempotency-Key, באורך 8–200 תווים. בקשה חוזרת עם אותו מפתח מקבלת את המשימה של ההרצה הראשונה, ושום הרצה חדשה לא מתחילה ולא נגבים קרדיטים.

### האם אפשר להשלים הרצת טרנד באיכות מלאה?

כן, בתוך 7 ימים מסיום ההרצה. הנתיב POST /v1/cast-swap/:jobId/full-quality מרנדר מחדש הרצת טיוטה ב-1080p, או יוצר טייק חדש ב-1080p להרצה של Nodaro Motion Pulse ב-720p, כמשימה חדשה. המשימה הזו מופיעה אז כהרצה בפני עצמה ב-GET /v1/trends/runs, והשדה fullQualityOf שלה מציין את הטיוטה.

### האם טרנדים עובדים בהתקנה באירוח עצמי?

לא. הטרנדים הם חלק מ-Nodaro Cloud. בהתקנה באירוח עצמי, כל נתיב של הטרנדים מחזיר 404.
