# Skill: carousel/story — "סיפור" (Instagram carousel: story)

Your story or a customer's: how it began, what changed, what you learned.

One call turns a short brief into a finished Instagram carousel of this kind: **1080×1080 (1:1) JPEG slides — the
feed's square, the default** — with designed Hebrew or English text, the caption, at most 5 hashtags, alt text per slide
and the source of every picture. `aspect: "4:5"` makes the taller 1080×1350 slide instead (it takes more of the feed). The text
is set by our render engine, never drawn by an image model, so Hebrew, numbers, prices and @handles come out right.

**How the slides are laid out** (`archetype: "story"`): slide 1 the hook (one bold line) · the story: where it started, the turning point, the lesson · the last slide the ask.

Base URL: https://apihub.co.il · every call carries `Authorization: Bearer <API key>`.

## What to ask the user

Only the **brief**: the story in a few sentences, in the first person if it is the owner's: where it started, what changed, what was learned. Years, numbers and names appear only if the brief holds them; and what the last slide should ask for (save, follow, send a message). Facts, prices,
dates and phone numbers are taken only from the brief — nothing is invented — so anything that must appear on a slide
has to be in it.

Optional, only if they have them: brand colours (`primary`, `accent` as #RRGGBB), a logo (`logo_url`: PNG / JPEG /
WebP), the Instagram `handle`, their own pictures (`own_images`: up to 10 URLs, used first, in order).

Do not ask about slide counts, looks or picture levels — this skill presets them.

## 1. The request

The skill's presets are `archetype: "story"`, `look: "card"`, `images: "stock"` and 7 slides — the request
that made the example on /skills. Write the user's own brief (and brand) into it and keep the rest:

```jsonc
POST /v1/carousel
{
  "brief": "הסיפור של נועה, מייסדת סטודיו עפר לקרמיקה ביפו, בגוף ראשון. אחרי 9 שנים בהייטק הרגשתי שאני חיה מול מסך. נרשמתי לחוג קדרות, ערב אחד בשבוע. אחרי שנה כבר מכרתי כלים לחברים. ב-2022 עזבתי את העבודה ופתחתי סטודיו קטן ביפו. השנה הראשונה הייתה קשה: כלים נסדקו בתנור וכמעט לא היו תלמידים. היום יש בסטודיו 6 סדנאות בשבוע. מה שלמדתי: לא חייבים לקפוץ בבת אחת, מספיק להתחיל בערב אחד בשבוע. בסוף: להזמין לסדנת היכרות, בהודעה פרטית.",
  "language": "he",
  "slides": 7,
  "archetype": "story",
  "images": "stock",
  "look": "card",
  "brand": {"handle":"studio.afar","primary":"#F4EFE6","accent":"#2F5D50","font":"Frank Ruhl Libre"}
}
```

- `look: "card"` — brand colour and big type, a picture on the cover only. `images: "stock"` — free photos, picked and checked for each slide (no faces, no brands); a slide with no good photo becomes a brand-colour card, never a paid generation.
- The words carry a story, so the example uses the `card` look: one photo on the cover and brand-colour slides after it — the cheapest carousel. `look: "photo"` puts a picture on every slide.
- The slides are square (1080×1080) — the default, and what the example shows. Only when the user asks for the taller
  post add `"aspect": "4:5"` (1080×1350).
- The user asked for another look, generated or stock pictures, more or fewer slides (5–10), English (`language: "en"`)?
  Change that field only — the general recipe lists every option and what it costs: https://apihub.co.il/skills/carousel.md
- The price before running: `POST /v1/carousel/estimate` with the same body → `estimated_credits`.

The call answers **202** with the execution: `{ "id": "<execution id>", "status": "processing", "output": { "status": "processing", "stage": "planning" } }`.

## 2. Poll

```jsonc
GET /v1/executions/<execution id>      // every 3 seconds; 202 while it runs, 200 when done
```

`output.stage` goes planning → images → rendering. Measured on the real examples: 22–39 s with stock photos,
34 s with one generated picture, 53–54 s with seven. Allow three minutes before giving up. `status: "failed"` carries a
plain reason in `error` (a plan that could not keep the limits, a picture link that cannot be fetched) — nothing or
only what was really spent is charged.

## 3. The result

```jsonc
{
  "status": "completed",
  "output": {
    "slides": [ { "n": 1, "url": "https://…/slide-01.jpg", "alt": "…", "role": "hook", "headline": "…", "body": "…",
                  "image": { "source": "stock", "provider": "pexels", "licence": "Pexels License", "licence_url": "…", "author": "…", "page_url": "…" } } ],
    "caption": "…", "hashtags": ["#…"],          // at most 5
    "plan": { … },                                 // keep it: it is how one slide is fixed
    "look": "card", "archetype": "story", "aspect": "1:1", "size": { "width": 1080, "height": 1080 },
    "images": { "mode": "stock", "stock": 1, "ai": 0, "own": 0, "cards": 6 },
    "expires_at": "…",                             // 24 hours
    "warnings": []
  },
  "usage": { "credits_charged": 32 }       // the example's base API price (the price section below)
}
```

Show the user every slide, in order, with the caption. Read `warnings`: it says which slide got a brand-colour card
instead of a photo, or that a logo could not be read. **Download the slides within 24 hours** — the files expire.

## 4. Fix one slide (no pictures are paid for again)

Change the words (or one picture) in `output.plan` and render again — no model call, no picture search:

```jsonc
POST /v1/carousel/render
{ "plan": <output.plan with your edit>, "only": [3] }      // only: the slides to render (1-based); leave it out for all
```

- a word, a headline, a body: edit `plan.slides[2].headline` / `.body` — within the limits of the carousel's shape
  (square: headline ≤ 6 words and 44 characters, body ≤ 18 words and 120 characters; 4:5: headline ≤ 8 words, body ≤ 25);
- another picture: set `plan.slides[2].image_url` to the user's own picture URL; remove the field for a brand-colour card;
- a picture whose subject is cut by the crop: set `plan.slides[2].focus_y` (0 = keep the picture's top, 1 = its bottom)
  or `focus_x` (0 = its left, 1 = its right);
- colours or font for the whole carousel: edit `plan.brand` and render without `only`;
- the other shape: send `"aspect": "4:5"` (or `"1:1"`) next to the plan, without `only` — the whole carousel is rendered
  again in that shape from the same pictures (a carousel has one shape; the plan keeps its `aspect`, so a plain
  re-render never changes it).

Poll the same way. A re-rendered slide keeps its place: its marker still says 3/7 and its layout matches the others.
The charge is the render only (base price: 7 slides 21 credits, one slide 3).

## 5. Publish (optional)

Publishing needs the account's social plan (connected networks; 1,500 credits per 30 days). Check it first, it is free:

```jsonc
GET /v1/social/plan
// → { "active": true|false, "active_until": "…", "monthly_credits": 1500, "period_days": 30, "how_to_activate": "…" }
```

If `active` is false, tell the user the price and ask before turning it on: `POST /v1/social/plan { "confirm": true }`
charges the 1,500 credits once (`charged_credits` is 0 when the plan is already on). Without the plan the publish call
answers `402 social_plan_inactive` with the price and charges nothing. A user who only wants the files needs no plan:
give them the slide links and the caption.

```jsonc
POST /v1/social/publish
{ "text": "<caption>\n\n<hashtags joined by spaces>", "media": [ "<slide 1 url>", "<slide 2 url>", … ], "profiles": ["instagram"] }
```

The slide URLs go in `media` in order (Instagram takes 2–10 pictures in a carousel; ours are JPEG, square 1080×1080 —
or 1080×1350 when made with `aspect: "4:5"` — under 8 MB, all one size). **Publishing a carousel through this endpoint has not been verified live by us yet** — if the post
comes back as something other than a carousel, give the user the files and the caption to post by hand, and say so.

## Price

**The example on /skills** (7 slides, one stock photo (the cover), made in 29 s): **32 credits**. A carousel of this kind with the
same presets costs about the same: the planner and the render change little, the pictures are the price (stock photos are free; `images: "ai"` adds about 29 credits a generated picture).

Every number here is the **base API price**: the real cost of what ran — the planner, the photo check or each generated
picture, the render — × 3, in credits, rounded up to a whole credit. An account that bought its credits
at a package discount pays the same money and therefore more credits per call. **`POST /v1/carousel/estimate` with the
same body answers with the price for the account that calls it**: `estimated_credits` is the ceiling (what is reserved);
the charge is what really ran — on these runs about half of it.

## Output rules

- Post the slides in order, all of them — slide 1 is the hook, slide 2 stands on its own, the last one is the ask.
- Never put text into the pictures yourself and never ask an image model to: every word on a slide comes from the plan.
- At most 5 hashtags (Instagram's limit); the caption stays under 2,200 characters. Use `slides[].alt` as the alt text.
- Stock pictures need no credit on the slide; `slides[].image` holds each one's source, author and licence — keep it.
- A carousel is 2–10 pictures of one size. Do not mix these slides with pictures of another shape, and never mix
  square and 4:5 slides in one post: Instagram crops every picture of a carousel to the shape of the first.

## The example (a real run)

The slides are square, 1080×1080 — what the call makes by default. Each example is one real run; its slides are shown
as the run's own plan and pictures rendered in the square (`POST /v1/carousel/render` with `"aspect": "1:1"`), and its
price and time are the full run's (planner, pictures, render) — the same in both shapes.

**How I left tech for ceramics** ("איך עזבתי הייטק לטובת קרמיקה") — `stock` + `card`, 7 slides 1080×1080 (one stock photo (the cover)), 32 credits, 29 s: https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-01.jpg … slide-07.jpg

1. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-01.jpg
2. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-02.jpg
3. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-03.jpg
4. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-04.jpg
5. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-05.jpg
6. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-06.jpg
7. https://media.gpt.org.il/lookbook/examples/carousel/ceramics-stock-card/square/slide-07.jpg

## The other kinds

- [`carousel/tips`](https://apihub.co.il/skills/carousel-tips.md) — Tips: A short list of tips, one per slide. The post people save.
- [`carousel/myths`](https://apihub.co.il/skills/carousel-myths.md) — Myths vs. facts: What everyone believes and what is true: a myth, then its truth.
- [`carousel/steps`](https://apihub.co.il/skills/carousel-steps.md) — Step-by-step guide: A process in order, one step per slide. For how-tos and questions that keep coming.
- [`carousel/before-after`](https://apihub.co.il/skills/carousel-before-after.md) — Before and after: The result of a job: before, what you did, after. Best with your own pictures.
- [`carousel/product`](https://apihub.co.il/skills/carousel-product.md) — Products: A product or service on every slide, and how to order at the end.
- The general recipe (every field and option): https://apihub.co.il/skills/carousel.md
