Implements catalog CRUD operations across synchronous and asynchronous modes for items, fields, selections, and management.
The writing-skills skill enforces TDD methodology for skill creation, but here we're generating a reference-type skill (API documentation + patterns) — the skill taxonomy distinguishes this from discipline-enforcing skills, so the structure priorities shift toward discoverability and dense reference tables over rationalization tables.
─────────────────────────────────────────────────
Here's the generated skill content:
This skill covers CRUD operations for Braze catalogs — structured data stores used to personalize messages at scale. The central engineering concern is the sync/async split: some operations complete immediately and return results synchronously, while others enqueue work and complete via background jobs. Mixing these modes incorrectly causes silent failures, unexpected rate limit errors, and incomplete data states.
When to use this skill:
Braze catalog endpoints are split into two operation modes. Choosing wrong mode causes rate limit errors or missed data — always identify which mode an endpoint belongs to before implementation.
| Mode | Behavior | Rate Limit Group | Use When |
|---|---|---|---|
| Synchronous | Returns result immediately | Synchronous catalog rate limit | Small payloads, real-time requirements, single-item operations |
| Asynchronous | Returns job ID; result available later | Asynchronous catalog rate limit | Bulk operations, selections, large data sets |
Key rule: Asynchronous endpoints require polling or webhook handling to confirm job completion. Never assume an async 202 means the data is immediately queryable.
Catalog (workspace-scoped)
├── Fields (schema definition)
├── Items (data rows)
└── Selections (filtered views for personalization)
Operations at each level have both sync and async variants — pick based on payload size and latency requirements.
| Operation | Method + Path | Mode | Permission |
|---|---|---|---|
| List catalogs | GET /catalogs | Sync | catalogs.get |
| Create catalog | POST /catalogs | Sync | catalogs.create |
| Delete catalog | DELETE /catalogs/{catalog_name} | Async | catalogs.delete |
| Operation | Method + Path | Mode | Permission |
|---|---|---|---|
| List items (sync) | GET /catalogs/{catalog_name}/items | Sync | catalogs.get_item |
| Create items (sync) | POST /catalogs/{catalog_name}/items | Sync | catalogs.create_item |
| Create items (async) | POST /catalogs/catalog_items | Async | catalogs.create_item |
| Update item (replace) | PUT /catalogs/{catalog_name}/items/{item_id} | Sync | catalogs.update_item |
| Update items (async) | PATCH /catalogs/catalog_items | Async | catalogs.update_item |
| Delete items (async) | DELETE /catalogs/catalog_items | Async | catalogs.delete_item |
Upsert behavior:
PUT /catalogs/{catalog_name}/items/{item_id}creates the item ifitem_idis not found. Treat as upsert, not strict update.
| Operation | Method + Path | Mode | Permission |
|---|---|---|---|
| Create fields (sync) | POST /catalogs/{catalog_name}/fields | Sync | catalogs.create_fields |
| Create fields (async) | POST /catalogs/catalog_fields | Async | catalogs.create_fields |
| Delete fields (async) | DELETE /catalogs/catalog_fields | Async | catalogs.delete_fields |
| Operation | Method + Path | Mode | Permission |
|---|---|---|---|
| Create selection | POST /catalogs/{catalog_name}/selections | Async | catalogs.create_selection |
| Delete selection | DELETE /catalogs/{catalog_name}/selections/{selection_name} | Async | catalogs.delete_selection |
Selections are filtered views of catalog data used to personalize messages. They define criteria (filters) that items must meet before being surfaced to users — analogous to a saved SQL WHERE clause on catalog rows.
Engineering notes:
catalogs.create_selection (create) / catalogs.delete_selection (delete)This skill draws from the following reference topics:
POST /catalogs/{catalog_name}/selections implementationDELETE /catalogs/{catalog_name}/selections/{selection_name} implementationGET /catalogs response structurePUT| Mistake | Fix |
|---|---|
| Calling sync endpoint with bulk payload | Use async bulk endpoint; sync endpoints have tighter payload limits |
| Assuming async 202 means data is live | Poll job status or handle via webhook before downstream reads |
Using PUT expecting strict update (no create) | PUT on items is upsert — creates if item_id absent |
| Deleting a field with active selections referencing it | Delete or update dependent selections first |
| Wrong permission scope for selection operations | Selection CRUD requires catalogs.*_selection permissions, not generic catalogs.*_item |
★ Insight ─────────────────────────────────────
The sync/async split in Braze catalogs mirrors a common API design pattern where synchronous endpoints favor correctness (small, atomic, immediate) and async endpoints favor throughput (bulk, eventually consistent). The path naming convention encodes this: async bulk endpoints live at /catalogs/catalog_items (flat), while sync per-item endpoints live at /catalogs/{catalog_name}/items/{item_id} (nested). The nesting depth is a reliable heuristic for which rate limit group applies.
─────────────────────────────────────────────────