# Skill: carousel/before-after — "לפני ואחרי" (Instagram carousel: before and after)

The result of a job: before, what you did, after. Best with your own pictures.

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: "before-after"`): slide 1 the hook (the result) · a "before" slide (the problem) · two or three slides on what changed · an "after" slide (the proof) · 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**: what it was like before, what was done (two or three things) and what it is like after — only what really happened; 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: "before-after"`, `look: "split"`, `images: "ai"` 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": "סדר בבית עם מיכל, מארגנת בתים מקצועית בשרון. לפני ואחרי של ארון בגדים אחד. לפני: ערימות בגדים, אי אפשר למצוא כלום וכל בוקר מתחיל בלחץ. מה עשינו: מיינו הכול ונפרדנו ממה שלא לובשים, קיפלנו בעמידה כך שרואים כל פריט, ונתנו מקום קבוע לכל קטגוריה עם קופסאות ותוויות. אחרי: ארון שרואים בו הכול במבט אחד, ומתארגנים בבוקר בחמש דקות. כל העבודה נמשכה יום אחד. בסוף: לשלוח הודעה לתיאום פגישת היכרות בלי התחייבות.",
  "language": "he",
  "slides": 7,
  "archetype": "before-after",
  "images": "ai",
  "look": "split",
  "brand": {"handle":"michal.seder"}
}
```

- `look: "split"` — the picture on top in a rounded frame, the text below. `images: "ai"` — generated pictures, the cover first and the rest in its style.
- A real before and after is the customer's own pictures: pass them as `own_images` in the slides' order (the cover, the before, the changes, the after) and no picture is generated or paid for. Generated pictures, as in the example, illustrate the story in one consistent style — say so if the user might take them for the real job.
- 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": "ai", "provider": "gemini", "model": "gemini-nano-banana-2.1", "url": "…" } } ],
    "caption": "…", "hashtags": ["#…"],          // at most 5
    "plan": { … },                                 // keep it: it is how one slide is fixed
    "look": "split", "archetype": "before-after", "aspect": "1:1", "size": { "width": 1080, "height": 1080 },
    "images": { "mode": "ai", "stock": 0, "ai": 7, "own": 0, "cards": 0 },
    "expires_at": "…",                             // 24 hours
    "warnings": []
  },
  "usage": { "credits_charged": 223 }       // 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, 7 generated pictures, made in 54 s): **223 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 (a generated picture is about 29 credits and this look has one on every slide; `look: "card"` generates only the cover, `images: "stock"` none).

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.

**Ready in five minutes every morning** ("להתארגן בבוקר בחמש דקות") — `ai` + `split`, 7 slides 1080×1080 (7 generated pictures), 223 credits, 54 s: https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-01.jpg … slide-07.jpg

1. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-01.jpg
2. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-02.jpg
3. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-03.jpg
4. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-04.jpg
5. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-05.jpg
6. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/square/slide-06.jpg
7. https://media.gpt.org.il/lookbook/examples/carousel/organizer-ai-split/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/story`](https://apihub.co.il/skills/carousel-story.md) — Story: Your story or a customer's: how it began, what changed, what you learned.
- [`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
