Promotions API
Endpoints for managing promotional banners and deals. Banners display in the hub's customer-facing interface. Deals apply automatic discounts at checkout.
Banners
List promotional banners configured for a hub.
Example Request
curl -X GET \ "https://tina-api.venhub.com/api/v1/owners/owner/banners?hub_id=123" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
hub_id | Integer | Query | Required | Hub ID to retrieve banners for |
Response
[
{
"id": 1,
"name": "Summer Sale",
"image_url": "https://storage.example.com/banners/summer.jpg",
"order_by": 1
},
{
"id": 2,
"name": "New Products",
"image_url": "https://storage.example.com/banners/new.jpg",
"order_by": 2
}
]
Create a new promotional banner with image upload.
hub_id as a query parameter.Example Request
curl -X POST \ "https://tina-api.venhub.com/api/v1/owners/owner/banners?hub_id=123" \ --header "X-API-Key: vh_abc123..." \ --form 'name=Summer Sale' \ --form 'order_by=1' \ --form '[email protected]'
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
hub_id | Integer | Query | Required | Hub ID to create the banner for |
name | String | Form | Required | Banner display name |
order_by | Integer | Form | Required | Display order position |
file | File | Form | Required | Banner image file |
Response
{
"id": 3,
"name": "Summer Sale",
"image_url": "https://storage.example.com/banners/abc123.jpg",
"order_by": 1
}
Delete a promotional banner from the hub.
Example Request
curl -X DELETE \ "https://tina-api.venhub.com/api/v1/owners/owner/banners/3?hub_id=123" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
banner_id | Integer | Path | Required | ID of the banner to delete |
hub_id | Integer | Query | Required | Hub ID the banner belongs to |
Response
{success: true} or any other JSON — check the status code to confirm the delete succeeded.Deals
Get currently active deals for a hub.
Example Request
curl -X GET \ "https://tina-api.venhub.com/api/v1/deals/active/123" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
hub_id | Integer | Path | Required | Hub ID to retrieve active deals for |
Response
[
{
"id": 1,
"name": "Buy 2 Get 1 Free",
"description": "Buy any 2 snacks, get the cheapest one free",
"display_text": "Buy any 2 snacks, get 1 free!",
"display_image": "https://storage.example.com/deals/bogo.jpg",
"priority": 1
}
]
Get detailed information about a specific deal.
Example Request
curl -X GET \ "https://tina-api.venhub.com/api/v1/deals/1" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
deal_id | Integer | Path | Required | ID of the deal to retrieve |
Response
{
"id": 1,
"name": "Buy 2 Get 1 Free",
"description": "Buy any 2 snacks, get the cheapest one free",
"is_deal_active": true,
"start": "2026-02-01",
"end": "2026-02-28",
"triggers": [
{ "type": "QUANTITY", "quantity": 2, "category": "Snacks", "category_id": 14, "product_id": null }
],
"rewards": [
{ "type": "FREE_ITEM", "quantity": 1, "product_id": 456, "discount_pct_or_price": null }
],
"constraints": [
{ "type": "SALEAMT", "value": 100 }
]
}
Get all deals (active and inactive) for a hub.
Example Request
curl -X GET \ "https://tina-api.venhub.com/api/v1/deals/hub/123" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
hub_id | Integer | Path | Required | Hub ID to retrieve all deals for |
Response
[
{
"id": 1,
"name": "Buy 2 Get 1 Free",
"description": "Buy any 2 snacks, get the cheapest one free",
"is_deal_active": true,
"start": "2026-02-01",
"end": "2026-02-28",
"triggers": [
{ "type": "QUANTITY", "quantity": 2, "category": "Snacks", "category_id": 14, "product_id": null }
],
"rewards": [
{ "type": "FREE_ITEM", "quantity": 1, "product_id": 456, "discount_pct_or_price": null }
],
"constraints": [
{ "type": "SALEAMT", "value": 100 }
]
}
]
Create a new promotional deal with banner image upload.
dealData field.Example Request
curl -X POST \ "https://tina-api.venhub.com/api/v1/deals/create-from-owner" \ --header "X-API-Key: vh_abc123..." \ --form 'dealData={"deal":{"name":"Summer Sale","hub_id":123},"trigger":{"type":"QUANTITY"},"reward":{"type":"PERCENT_OFF"}}' \ --form '[email protected]'
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
dealData | JSON String | Form | Required | JSON-encoded deal configuration |
file | File | Form | Required* | Banner image. *Required on vencart-service, optional on vh-tina-service |
dealData Fields
| Field | Type | Required | Description |
|---|---|---|---|
deal.name | String | Required | Display name for the deal |
deal.hub_id | Integer | Required | Hub to associate the deal with |
deal.start | Date | Optional | Deal start date (YYYY-MM-DD) |
deal.end | Date | Optional | Deal end date (YYYY-MM-DD) |
trigger | Object | Required | Trigger configuration |
reward | Object | Required | Reward configuration |
Response
{
"id": 3,
"name": "Summer Sale",
"is_deal_active": true,
"display_image": "https://storage.example.com/deals/abc123.jpg"
}
Update an existing deal's configuration.
Example Request
curl -X PUT \ "https://tina-api.venhub.com/api/v1/deals/1" \ --header "X-API-Key: vh_abc123..." \ --header "Content-Type: application/json" \ --data '{"name": "Updated Deal Name", "is_deal_active": false}'
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
deal_id | Integer | Path | Required | ID of the deal to update |
name | String | Body | Optional | Updated display name for the deal |
is_deal_active | Boolean | Body | Optional | Enable or disable the deal |
start | Date | Body | Optional | Updated start date (YYYY-MM-DD) |
end | Date | Body | Optional | Updated end date (YYYY-MM-DD) |
Response
{
"id": 1,
"name": "Updated Deal Name",
"description": "Buy any 2 snacks, get the cheapest one free",
"is_deal_active": false,
"start": "2026-02-01",
"end": "2026-02-28",
"triggers": [
{ "type": "QUANTITY", "quantity": 2, "category": "Snacks", "category_id": 14, "product_id": null }
],
"rewards": [
{ "type": "FREE_ITEM", "quantity": 1, "product_id": 456, "discount_pct_or_price": null }
],
"constraints": [
{ "type": "SALEAMT", "value": 100 }
]
}
Delete a deal and all associated triggers and rewards.
Example Request
curl -X DELETE \ "https://tina-api.venhub.com/api/v1/deals/1" \ --header "X-API-Key: vh_abc123..."
Parameters
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
deal_id | Integer | Path | Required | ID of the deal to delete |
Response
{
"success": true,
"message": "Deal 1 deleted successfully"
}
Errors
| Error Code | Description |
|---|---|
| deal_not_found | The specified deal does not exist |
Additional Deal Routes
Create a deal directly with a JSON body, as an alternative to /deals/create-from-owner's multipart upload — use this when there's no banner image to attach.
Example Request
curl -X POST \ "https://tina-api.venhub.com/api/v1/deals/" \ --header "X-API-Key: vh_abc123..." \ --header "Content-Type: application/json" \ --data '{"name":"Buy 2 Get 1 Free","hub_id":123,"description":"Buy any 2 snacks, get the cheapest one free","start":"2026-02-01","end":"2026-02-28","triggers":[{"type":"QUANTITY","quantity":2,"category":"Snacks","category_id":14}],"rewards":[{"type":"FREE_ITEM","quantity":1,"product_id":456}],"constraints":[{"type":"SALEAMT","value":100}]}'
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | String | Required | Display name for the deal |
hub_id | Integer | Required | Hub to associate the deal with |
description | String | Optional | Internal description |
start | Date | Optional | Deal start date (YYYY-MM-DD) |
end | Date | Optional | Deal end date (YYYY-MM-DD) |
triggers | Array | Required | Trigger definitions — same fields as GET /deals/{deal_id}'s triggers, minus id (not yet assigned) |
rewards | Array | Required | Reward definitions — same shape as above, minus id |
constraints | Array | Optional | Constraint definitions — same shape as above, minus id |
Response
{
"id": 4,
"name": "Buy 2 Get 1 Free",
"description": "Buy any 2 snacks, get the cheapest one free",
"is_deal_active": true,
"start": "2026-02-01",
"end": "2026-02-28",
"triggers": [
{ "id": 10, "type": "QUANTITY", "quantity": 2, "category": "Snacks", "category_id": 14 }
],
"rewards": [
{ "id": 11, "type": "FREE_ITEM", "quantity": 1, "product_id": 456 }
],
"constraints": [
{ "id": 12, "type": "SALEAMT", "value": 100 }
]
}
Check which active deals a cart qualifies for, before applying any reward.
Example Request
curl -X POST \ "https://tina-api.venhub.com/api/v1/deals/check-eligibility" \ --header "X-API-Key: vh_abc123..." \ --header "Content-Type: application/json" \ --data '{"hub_id":123,"cart_items":[{"product_id":456,"category_id":14,"quantity":2,"unit_price":299}],"cart_total":598}'
Body
| Field | Type | Required | Description |
|---|---|---|---|
hub_id | Integer | Required | Hub the cart belongs to |
user_id | Integer | Optional | Customer placing the order |
cart_items | Array | Required | Each item: product_id, category_id (optional), subcategory_id (optional), quantity, unit_price |
cart_total | Integer | Required | Cart total in cents |
user_order_count | Integer | Optional | Customer's prior order count, for first-time-buyer style deals |
device_uuid | String | Optional | Device identifier |
Response
{
"eligible_deals": [
{
"deal_id": 1,
"deal_name": "Buy 2 Get 1 Free",
"description": "Buy any 2 snacks, get the cheapest one free",
"display_text": "Buy any 2 snacks, get 1 free!",
"reward_description": "1 free item",
"potential_savings": 299,
"start": "2026-02-01",
"end": "2026-02-28",
"stackable": false
}
]
}
description and display_text are optional and may be absent. This is a preview only — nothing is applied to the cart until you call apply-reward.Apply one or more deals' rewards to a cart, after check-eligibility has confirmed they qualify.
Example Request
curl -X POST \ "https://tina-api.venhub.com/api/v1/deals/apply-reward" \ --header "X-API-Key: vh_abc123..." \ --header "Content-Type: application/json" \ --data '{"deal_ids":[1],"hub_id":123,"cart_items":[{"product_id":456,"category_id":14,"quantity":2,"unit_price":299}]}'
Body
| Field | Type | Required | Description |
|---|---|---|---|
deal_ids | Array<Integer> | Required | Deals to apply |
hub_id | Integer | Required | Hub the cart belongs to |
user_id | Integer | Optional | Customer placing the order |
cart_items | Array | Required | Same shape as check-eligibility's cart_items |
device_uuid | String | Optional | Device identifier |
Response
{
"success": true,
"deal_applied": true,
"modified_cart_items": [
{
"product_id": 456,
"category_id": 14,
"quantity": 2,
"original_unit_price": 299,
"discounted_unit_price": 0,
"discount_applied": 299,
"quantity_discounted": 1
}
],
"original_cart_total": 598,
"discounted_cart_total": 299,
"total_savings": 299,
"message": "Deal applied successfully"
}
Check redemption status/history for a specific deal.
List product IDs currently attached to any active deal for a hub (union of every reward and trigger product ID across the hub's active deals).
Example Request
curl -X GET \ "https://tina-api.venhub.com/api/v1/deals/promo-products/123" \ --header "X-API-Key: vh_abc123..."
Response
[456, 789]