# JellyJelly Genie Listing Tool

Use this tool only when the JellyJelly user explicitly asks Genie to create
Racct marketplace listings from a JellyJelly clip, or explicitly asks Genie to
buy a Racct listing linked to the current JellyJelly video.

`clipUrl` must be the playable JellyJelly clip that shows the item being sold,
not a separate instructions-only clip.

The user should only need to make a normal JellyJelly video that shows the item
and says "Genie, post this on Racct" or similar. Genie must translate that
current JellyJelly context into this API call automatically. Do not ask the user
to provide API fields, endpoint details, or Racct login state.

When handling that current JellyJelly video, use JellyJelly's Firehose API
first. If Genie has a Jelly ID or can extract one from a JellyJelly URL or
`dist.jellyjelly.com/{jelly_id}/...` media URL, call
`GET https://api.jellyjelly.com/v3/jelly/{jelly_id}` and use the returned
`video.hls_master` as `clipUrl` when present. If HLS is unavailable or fails,
fall back to `video.mp4_fallback`, then `video.mp4_preview`, then the current
playable media URL you already had. If Genie can extract clear item stills or
thumbnails from the same video, include them as top-level `imageUrls` or
per-item `items[].imageUrls`. If the video clearly shows or names multiple
items, create one `items[]` entry per item. When Genie can identify a short,
clear, useful segment of the same JellyJelly recording, send the segment bounds
as `items[].clipStartMs` and `items[].clipEndMs`, or send the already-extracted
short clip as `items[].clipUrl` with `items[].keepClip: true`.

Always pass transcript/caption text when available. Racct can use explicit item
words such as "mug" as a fallback when visual detection is uncertain.

## Endpoint

`POST https://jellyjelly-genie-create-listings-mupta2c5da-uc.a.run.app`

Do not open Racct or try to list through the website UI. This endpoint creates
the Racct listing request directly for the linked Racct account and avoids the
normal user auth flow.

Headers:

- `Authorization: Bearer <JELLYJELLY_GENIE_LISTING_SECRET>`
- `Content-Type: application/json`

Temporary public beta fallback:

- If JellyJelly has not provisioned the shared secret yet, omit
  `Authorization` and send `x-jellyjelly-genie-public-beta: true`.
- This fallback is temporary. Use the bearer secret as soon as it is available.

## Buy Linked Listing

When the user replies to a JellyJelly video that has a linked Racct listing and
explicitly tells Genie to buy it on their Racct account, call:

`POST https://jellyjelly-genie-buy-listing-mupta2c5da-uc.a.run.app`

Use the same auth headers. Do not open Racct or drive checkout through the UI.
This endpoint resolves the user's linked Racct account from their JellyJelly
profile and runs the normal backend checkout path.

Required fields:

```json
{
  "jellyJellyUsername": "buyer-jelly-handle",
  "listingId": "linked-racct-listing-id",
  "jellyId": "current-jelly-id",
  "orderMode": "pickup",
  "confirmation": {
    "confirmed": true,
    "source": "jellyjelly",
    "sourceId": "reply-or-jelly-id",
    "summary": "User told Genie to buy this exact linked Racct listing."
  }
}
```

You may send `linkedListing.url` instead of `listingId`. Use `orderMode:
"delivery"` only when the user clearly asks for delivery or the product flow has
already selected delivery terms. If the listing was created by JellyJelly Genie
and the current Jelly ID does not match the stored listing source, Racct rejects
the request.

## Fastest Request

```json
{
  "jellyJellyUsername": "jelly-user-handle",
  "clipUrl": "https://...",
  "imageUrls": ["https://..."],
  "transcript": "optional JellyJelly transcript or post text",
  "caption": "optional JellyJelly title/caption",
  "confirmation": {
    "confirmed": true,
    "source": "jellyjelly",
    "sourceId": "jelly-or-message-id",
    "summary": "User confirmed Genie should create these exact Racct listing drafts."
  }
}
```

For voice-message driven calls, Genie may send `voiceTranscript`,
`messageTranscript`, `title`, `summary`, and nested source media such as
`source.videoUrl` or `jelly.video.mp4_fallback`. The endpoint normalizes these
into the same listing flow.

Genie does not need a Racct browser session and should not ask the user to sign
in just to create the listing request. If Genie has a playable JellyJelly video
URL that shows the item, send it as `clipUrl`; Racct can infer listable items
from video frames plus transcript/caption. Ask for an item-showing clip only
when the current clip is just instructions, does not show the item, or is not
playable.

If Genie can extract item images from JellyJelly, send them as
`imageUrls`, `listingImageUrls`, or per-item `items[].imageUrls` /
`items[].photoUrls` / `items[].thumbnailUrls`. Racct can use supplied images
directly when video frame extraction is unavailable or ambiguous. For multiple
items, send one `items[]` entry per item with that item's own images.

The response includes `listings[].url` Racct links when processing completes.
If `pending` is true, keep `processingListingId` and check again later through
Racct support tooling.

Every response includes `requestId`. Failed responses include `blocker`,
`genieMessage`, and diagnostics. Include the `requestId` when reporting a
failure so Racct can inspect the matching logs.

For `blocker: "no_items_identified"` or `blocker: "item_clip_required"`, do
not assume the user recorded the wrong video. Retry once with the same current
JellyJelly media, add extracted item stills/thumbnails as `imageUrls` when
possible, and pass transcript/caption or `items[]` details you can derive from
the JellyJelly context. Only ask the user to record another clip after you have
verified the submitted media was actually missing the item or not playable.

If the response has `blocker: "linked_racct_account_required"`, tell the user
to create or sign in to Racct and link their JellyJelly profile, then retry with
the same clip and `auditReceiptId` as context. Failed requests are recorded so a
later Genie request can reference what already happened.

## Optional Items

Send `items` when Genie already knows the exact listing details. Omit `price`
unless the user explicitly mentioned one; Racct will use the same suggested
price that the app normally fills after item details are generated.

```json
{
  "jellyJellyUsername": "jelly-user-handle",
  "clipUrl": "https://...",
  "items": [
    {
      "title": "Brand new linen shirt",
      "description": "Sealed in packaging.",
      "price": 18,
      "priceMentioned": true,
      "category": "Clothing",
      "imageUrls": ["https://cdn.example.com/shirt-front.jpg"],
      "isUnopened": true,
      "size": "M",
      "sizeKind": "shirt",
      "keepClip": true,
      "clipStartMs": 1200,
      "clipEndMs": 8400
    },
    {
      "title": "Desk lamp",
      "description": "Small desk lamp.",
      "priceMentioned": false,
      "category": "Home Goods"
    }
  ],
  "confirmation": {
    "confirmed": true,
    "source": "jellyjelly",
    "sourceId": "jelly-or-message-id"
  }
}
```

## Item Fields

- `title`: Required if `items` is sent.
- `description`: Use only facts from the clip or user.
- `price`: Include only when explicitly mentioned by the user.
- `priceMentioned`: Set `true` only for explicit user price mentions.
- `category`: One of Furniture, Electronics, Toys/Games, Clothing, Home Goods,
  Sporting Goods, Entertainment, Family, Garden/Outdoor, Hobbies, Pet Supplies,
  Instruments, Office Supplies, Food, Automotive.
- `isUnopened`: Set `true` for brand new, sealed, new in box, or never opened.
- `size` and `sizeKind`: Use `shirt`, `pant`, `shoe`, or `dress` for clothing
  sizes.
- `priceDropMentioned`: Set `true` only when the user asks for auto-adjust.
- `priceDropTargetPrice`: Optional. Use the user's minimum price when one is
  given. If omitted, Racct uses the default lower price.
- `priceDropDurationMs`: Optional. If omitted and no deadline is given, Racct
  uses the default period.
- `priceDropDeadlineMs`: Optional deadline timestamp. Send it when the user
  gives a deadline such as "drop to $20 by Friday".
- `clipStartMs` and `clipEndMs`: Optional per-item video segment boundaries.
- `keepClip`: Set `true` only when a short JellyJelly segment is interesting,
  clearly shows the item, and helps the listing. Include `clipStartMs` and
  `clipEndMs` with it, or include `clipUrl` if Genie already extracted the
  short clip from the same JellyJelly recording. Otherwise omit it or set
  `false`.
- `clipUrl`: Optional short item clip. Use only for a clear, good-looking clip
  extracted from the same JellyJelly video that was recorded for this listing.
- `imageUrls`, `photoUrls`, `thumbnailUrls`: Optional per-item listing photos.
  Use these when Genie has already extracted clear item images from JellyJelly.

## Media Quality

Racct extracts listing photos from the clip and ranks frames for sharpness,
exposure, and low grain. Genie should still help by providing per-item
`clipStartMs` and `clipEndMs` when it knows where the item is clearly visible.
Avoid timestamps where the item is moving fast, hidden, dark, tiny, cropped, or
out of focus. Listing thumbnails should show the item clearly and should not be
grainy screenshots.

## Confirmation Rule

Genie may draft, extract, compare, and prepare listings. Genie must not call the
endpoint unless the user has explicitly confirmed publishing the Racct listing
request for the exact item(s) and clip.

## JellyJelly Source

If Genie has only a Jelly ID, use JellyJelly's Firehose API at
`https://jellyjelly.com/firehose`:

- `GET https://api.jellyjelly.com/v3/jelly/{jelly_id}`
- Prefer `jelly.video.hls_master` for the best source video.
- Fall back to `jelly.video.mp4_fallback`, then `jelly.video.mp4_preview`, then
  the current playable JellyJelly media URL.
- Pass `title`, `summary`, and `transcript_overlay` text as `caption`, `notes`,
  or `transcript` when present.
