- Rebrand LoginPage logo to Oliver design system - Move Admin nav link to bottom-left user area - Remove "Ask AI to improve" button from step 2 (VariantsGrid) - Add CharCount component with copy limits across prompt, edit, and export views - Add delete variant with confirmation dialog on step 2 cards - Add theme palette migration (0007_theme_palette.py) - Add copyLimits.ts and themes.ts libs - Remove unused BannerEditor.tsx page and old logo PNG - Add AGENTS.md project entry point - Add docs/ directory Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.8 KiB
API Specification
All endpoints are prefixed with /api. In production the full path is:
https://optical-dev.oliver.solutions/barclays-banner-builder/api/…
Authentication is JWT Bearer token unless marked public.
Interactive docs available at /docs in development only (APP_ENV=development).
Auth — /api/auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/token |
Public | Login — returns JWT access token |
| GET | /api/auth/me |
Bearer | Return current user's id, email, role |
POST /api/auth/token
Request body: application/x-www-form-urlencoded
| Field | Type | Required | Notes |
|---|---|---|---|
username |
string | Yes | User email address |
password |
string | Yes | Plain-text password |
Response 200:
{ "access_token": "eyJ…", "token_type": "bearer" }
Error 401: Invalid credentials.
Health — /api/health
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/health |
Public | Liveness check — returns {"status": "ok"} |
Conversations — /api/conversations
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/conversations |
Bearer | Create conversation (and optionally send first message) |
| GET | /api/conversations |
Bearer | List user's conversations (last 50, newest first) |
| GET | /api/conversations/{id} |
Bearer | Get conversation with full message history |
| POST | /api/conversations/{id}/messages |
Bearer | Send a message — triggers intent classification + async job |
POST /api/conversations
{ "first_message": "string (optional)" }
Response 201:
{ "conversation_id": "uuid", "brief_id": "uuid", "message_id": "uuid|null", "job_id": "uuid|null" }
If first_message is non-empty, an RQ chat_turn job is enqueued. Poll GET /api/jobs/{job_id}.
POST /api/conversations/{id}/messages
{ "text": "string" }
Response 202:
{ "message_id": "uuid", "job_id": "uuid|null", "reply": "string|null" }
If intent is clarify, reply contains the inline response and job_id is null.
If intent is generate or refine, poll the job for the resulting banner_set_id.
Briefs — /api/briefs
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/briefs |
Bearer | List user's briefs (last 50) with associated banner sets |
| POST | /api/briefs |
Bearer | Create brief and enqueue copy generation job |
| GET | /api/briefs/{brief_id} |
Bearer | Get single brief |
POST /api/briefs
{ "text": "string", "n_variants": 4, "aspect_ratios": ["Medium", "Large"] }
Response 202:
{ "job_id": "uuid", "brief_id": "uuid" }
Jobs — /api/jobs
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/jobs/{job_id} |
Public | Poll job status |
Response:
{
"id": "uuid",
"type": "generate_copy|chat_turn|render_pdf|index_icons|ingest_rag",
"status": "pending|running|done|failed",
"result": { "banner_set_id": "uuid", "variant_count": 8 },
"error": "string|null",
"created_at": "ISO 8601",
"finished_at": "ISO 8601|null"
}
Banner Sets — /api/banner-sets
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/banner-sets/{id} |
Bearer | Get banner set with all variants (includes resolved icon URLs) |
| PATCH | /api/banner-sets/{id}/status |
Bearer | Update status: draft, approved, exported |
| POST | /api/banner-sets/{id}/custom-size |
Bearer | Add Custom-format variants at given dimensions |
| POST | /api/banner-sets/{id}/contact-sheet |
Bearer | Enqueue PDF rendering job |
| GET | /api/banner-sets/{id}/contact-sheet.pdf |
Bearer | Download rendered PDF (404 if not yet rendered) |
| GET | /api/banner-sets/{id}/export.csv |
Bearer | Download Workfront CSV (optional ?variant_ids=uuid,uuid) |
GET /api/banner-sets/{id}
Response includes:
{
"id": "uuid", "brief_id": "uuid", "status": "draft",
"variants": [{
"id": "uuid", "aspect_ratio": "SM2|MD1|MD2|MD3|LG1|LG2|Custom",
"pair_id": "uuid", "theme": "navy|sky-blue|yellow|lime|teal",
"short_title": "string", "long_body": "string",
"cta": "string", "cta_secondary": "string|null",
"dam_asset_ref": "string|null", "dam_asset_url": "string|null",
"icon_id": "uuid|null", "icon_url": "string|null",
"edited_by_user": false,
"custom_width": null, "custom_height": null
}]
}
POST /api/banner-sets/{id}/custom-size
{ "width": 640, "height": 200 }
Response 201:
{ "created": 4, "variant_ids": ["uuid", "uuid", "uuid", "uuid"] }
Banner Variants — /api/banner-variants
| Method | Path | Auth | Description |
|---|---|---|---|
| PUT | /api/banner-variants/{id} |
Bearer | Update variant copy, DAM asset, icon, or theme |
| POST | /api/banner-variants/{id}/refine |
Bearer | AI-refine this variant's copy based on feedback text |
PUT /api/banner-variants/{id}
All fields optional:
{
"short_title": "string",
"long_body": "string",
"cta": "string",
"cta_secondary": "string",
"dam_asset_ref": "string",
"dam_asset_url": "string",
"icon_id": "uuid",
"theme": "navy|sky-blue|yellow|lime|teal"
}
Sets edited_by_user = true. Returns updated variant object.
POST /api/banner-variants/{id}/refine
{ "feedback": "Make the title more urgent and mention 0% balance transfer" }
Returns updated variant object with AI-rewritten copy.
Icons — /api/icons
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/icons/categories |
Public | List available illustration categories |
| GET | /api/icons |
Public | Search icons by ?category=Banking&q=card&limit=50 |
Response:
{ "icons": [{ "id": "uuid", "name": "string", "category": "string", "url": "/api/illustrations/…" }] }
Categories: Abstract, Architecture, Banking, Cards, Devices, Documents, Infrastructure, Nature, Objects, World
DAM — /api/dam
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/dam/search |
Bearer | Search DAM assets (?q=…&page=1&page_size=20) |
| GET | /api/dam/assets/{asset_id} |
Bearer | Get single DAM asset by ID |
When ADOBE_DAM_API_BASE_URL is empty, the mock client is used — returns canned Picsum placeholder images.
Admin — /api/admin
All admin endpoints require role = "admin".
System Prompts
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/system-prompts |
List all versions (newest first) |
| GET | /api/admin/system-prompts/active |
Get currently active prompt |
| POST | /api/admin/system-prompts |
Create new version (not yet active) |
| PUT | /api/admin/system-prompts/{id} |
Update — creates new version, deactivates old (immutable audit trail) |
| POST | /api/admin/system-prompts/{id}/activate |
Activate a specific version |
System Prompt body
{
"label": "string",
"system_text": "string",
"tov_text": "string|null",
"tov_banned_phrases": "say hello to,give you peace of mind",
"short_title_max": 32,
"long_body_max": 128,
"cta_max": 50
}
Users
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/users |
List all users |
| POST | /api/admin/users |
Create user (email, password, role) |
| PATCH | /api/admin/users/{id} |
Update email, password, or role |
| DELETE | /api/admin/users/{id} |
Delete user (cannot delete self or last admin) |
Static Assets
| Path | Description |
|---|---|
/api/illustrations/{Category}/{filename}.png |
Served by FastAPI StaticFiles mount — Barclays illustration library |