creating-offers
Installation
SKILL.md
Creating Offers on angebote.lenne.tech
This skill enables Claude Code to create, optimize, and manage business offers on the Offers platform via MCP tools, for whichever company the signed-in account belongs to.
Gotchas
- Content block
ordervalues must be ascending without gaps — Gaps in the sequence (e.g.,1, 3, 5) cause rendering glitches on the offers frontend. When deleting a block, re-normalize remaining orders; when inserting, pick the next consecutive integer. The API does not validate this — the bug only surfaces client-side. global-refblocks point at blocks the platform provides —list_globalsshows which reusable blocks exist andget_globalshows their versions. The MCP catalog has no tool to create one, so reuse your own recurring content through the knowledge base or a template offer instead (see "Reusing content across offers").- OAuth sign-ins are stored per endpoint; a failed refresh needs
/mcp— Claude Code stores theoffers-apiandoffers-api-demosign-ins per endpoint, shared across sessions, so each server is authorized on its own: the first call againstoffers-api-demostarts its own OAuth flow even whenoffers-apiis already signed in. Access tokens expire after an hour; on a 401 Claude Code refreshes the token and retries once. When the refresh fails, open/mcpand authenticate the server again./mcpalso reconnects a server that timed out while connecting. A deploy used to look identical from the client side and is a different problem, now fixed (DEV-3408): the server holds MCP sessions in process memory, so restarting the container invalidates every session id in the wild. It answered that with400 No valid session, on which a client does not recover — so every connected session stayed dead until somebody ran/mcpby hand. It now answers404, and the client sends a freshinitializeby itself. So a400after a deploy is no longer expected; a401is still the authorization case above. - Template offers cannot be published — only duplicated — Offers with
isTemplate: truecannot bemark_sent. Attempting to publish a template silently returns the unchanged offer. To publish, firstcreate_from_templateto produce a regular offer, then send that one. - Hardcoded colors in
custom-htmlbreak in the other color mode — A block styled with inline colors for a light page turns unreadable when the viewer flips the theme toggle: dark headings and dark body text end up on the dark page background.colorMode: 'light'does not prevent this — it only sets the initial preference, the toggle stays available. Everycustom-htmlblock must paint its own background on the outermost element whenever it sets text colors. Seecustom-html-guide.md→ "Readability in both color modes". cta.textis rendered as plain text, not HTML — Passing"<p>…</p>"prints the literal tags on the offer page. The block docs list it next to HTML-bearing fields, which invites the mistake. Pass a bare sentence.textblocks,custom-htmlandfaqanswers are unaffected.- Embedded credentials in links (
https://user:pass@host) are blocked by Chrome — The navigation fails withERR_FAILED, so a "one-click" demo link built that way is dead on arrival for most recipients. Link the plain URL and list the basic-auth credentials next to it so the browser prompt can be answered. - Customer quotes must be verbatim and complete — Shortening a
testimonialorreference.quoteto its "relevant" part, or silently fixing a typo in it, misrepresents a real person. Copying a quote out of an older offer is not safe either: it may already be truncated there. Pull the canonical wording from the company's own published source (the knowledge base, or the references page it links to) and diff it character by character — seebest-practices.md→ "Customer quotes are verbatim, always". - File fields survive an update that omits them, so a new block inherits the old block at the same position —
update_offerreplaces the block array, butOfferService.update()first runsmergeContentBlockFiles(), which pairs stored and incoming blocks by${order}-${type}and then protects every file field:imageFileId,fileId,animationFileId,previewFileId,fileIds,members[].imageFileId,files[].fileId. Omitting the field or sending""means keep what is stored — only an explicitnullclears it. Because the pairing is positional, a brand-newreferenceinserted where anotherreferenceused to sit silently adopts that block'simageFileId, and the offer then shows the wrong screenshot under the new project name. Whenever a block changes identity, send a real file id ornull, never"". Seecontent-blocks.md→ "File fields on update". - A
referenceblock without an image renders an empty placeholder box — The renderer always reserves the image column and falls back to a grey box with an image icon, which reads as broken on a customer-facing page. Everyreferenceneeds a realimageFileId. When no product screenshot exists, a purpose-built diagram is a legitimate substitute; a screenshot of a different project is not.