# Banners API Dynamic banners for the homepage carousel/slider. Banners can be scheduled to appear at specific times. ## Client API ### Get active banners ``` GET /client/v1/banners/ ``` Returns a list of all currently active banners, ordered by `displayOrder` (ascending). Use this to render the homepage banner carousel. **Response** `200 OK` ```json [ { "id": "xYz123", "name": "Summer Campaign", "image": "https://example.com/banner-desktop.jpg", "mobileImage": "https://example.com/banner-mobile.jpg", "link": "https://example.com/promo" } ] ``` | Field | Type | Description | |---------------|----------|--------------------------------------------------| | `id` | string | Banner ID | | `name` | string | Banner name (for display or accessibility) | | `image` | string | Desktop/web banner image URL | | `mobileImage` | string | Mobile banner image URL | | `link` | string? | Click-through URL. `null` if no action on click | **Notes:** - The response is an array. Render all items in a carousel/slider, in the order returned. - If `link` is not null, the banner should be clickable and navigate to that URL. - If the array is empty, hide the banner section. - The API handles scheduling server-side; the client always receives only the banners that should be visible right now. --- ## Admin API All admin endpoints require the admin authorization header. ### Create a banner ``` POST /admin/v1/banners ``` **Request body:** ```json { "name": "Summer Campaign", "image": "https://example.com/banner-desktop.jpg", "mobileImage": "https://example.com/banner-mobile.jpg", "link": "https://example.com/promo", "isActive": true, "activeFrom": "2026-06-01T00:00:00Z", "activeUntil": "2026-06-30T23:59:59Z", "displayOrder": 1 } ``` | Field | Type | Required | Description | |----------------|-----------|----------|--------------------------------------------------------------| | `name` | string | yes | Banner name | | `image` | string | yes | Desktop image URL | | `mobileImage` | string | yes | Mobile image URL | | `link` | string? | no | Click-through URL | | `isActive` | boolean | yes | Whether this banner is enabled | | `activeFrom` | datetime? | no | Schedule start (UTC). `null` = no start restriction | | `activeUntil` | datetime? | no | Schedule end (UTC). `null` = no end restriction | | `displayOrder` | integer | yes | Sort order in the carousel. Lower number = shown first | **Response:** `200 OK` with `AdminBannerDto` (see below). ### List all banners ``` GET /admin/v1/banners?page=1&pageSize=20 ``` **Response:** `200 OK` ```json { "items": [ /* AdminBannerDto[] */ ], "totalCount": 5 } ``` ### Get a single banner ``` GET /admin/v1/banners/{id} ``` **Response:** `200 OK` with `AdminBannerDto`. ### Update a banner ``` PUT /admin/v1/banners/{id} ``` Same body as create, plus `id` in the body matching the URL param. ### Delete a banner ``` DELETE /admin/v1/banners/{id} ``` **Response:** `200 OK` with `true`/`false`. ### AdminBannerDto ```json { "id": "xYz123", "name": "Summer Campaign", "image": "https://example.com/banner-desktop.jpg", "mobileImage": "https://example.com/banner-mobile.jpg", "link": "https://example.com/promo", "isActive": true, "activeFrom": "2026-06-01T00:00:00Z", "activeUntil": "2026-06-30T23:59:59Z", "displayOrder": 1, "createdAt": "2026-04-01T10:00:00Z", "updatedAt": "2026-04-01T10:00:00Z", "createdBy": null, "updatedBy": null } ``` --- ## Scheduling logic A banner appears in the client response when **all** of the following are true: 1. `isActive` is `true` 2. `activeFrom` is `null` **or** current time >= `activeFrom` 3. `activeUntil` is `null` **or** current time < `activeUntil` | Scenario | `isActive` | `activeFrom` | `activeUntil` | |-----------------------|------------|--------------------|--------------------| | Always visible | `true` | `null` | `null` | | Visible after a date | `true` | `2026-06-01T00:00Z`| `null` | | Visible until a date | `true` | `null` | `2026-06-30T23:59Z`| | Scheduled window | `true` | `2026-06-01T00:00Z`| `2026-06-30T23:59Z`| | Manually disabled | `false` | any | any |