Vouchers
A voucher is a discount offer — a percentage or a fixed amount off the basket, with an optional minimum amount and validity period — together with the codes your customers type at checkout to use it. When you move from another tool, import your running vouchers and the codes you have already sent so that they keep working in your shop, then read each voucher back to check it.
Both endpoints need a key holding the promotion:read (read) or promotion:write (import) scope.
Endpoints
| Method | Path | Scope | Batch limit |
|---|---|---|---|
| POST | /v1/voucher/import | promotion:write | 50 vouchers and 500 codes per request |
| GET | /v1/voucher/import | promotion:read | One voucher |
The voucher object
| Field | Type | Description |
|---|---|---|
id | string | The voucher's identifier in your shop, prefixed prom_. |
object | string | Always promotion. |
external_id | string | The voucher's reference in your former system. |
project | string | Your shop's identifier. |
status | string | draft, scheduled, activated, paused, expired or archived; deleted once deleted in your workspace. |
name | string | The voucher's name. |
type | string | percentage or fixed_amount. |
value | string | The discount: a percentage or an amount, as a decimal string such as "15.00". |
currency | string | The currency code of a fixed amount, such as EUR. |
min_amount | string | The minimum basket amount, as a decimal string. "0.00" for none. |
audience | string | all, segment or consumer. |
starts_at | integer | Start of validity, in Unix seconds. 0 for none. |
ends_at | integer | End of validity, in Unix seconds. 0 for none. |
created_at | integer | Creation time, in Unix seconds. |
updated_at | integer | Last change, in Unix seconds. |
codes | array | Every code of the voucher, sorted by code. |
Each entry of codes:
| Field | Type | Description |
|---|---|---|
id | string | The code's identifier in your shop, prefixed prco_. |
object | string | Always promotion_code. |
external_id | string | The code's reference in your former system; empty for a code created in your workspace. |
status | string | activated, or deleted once deleted in your workspace. |
code | string | The code the customer types. |
customer | string | The identifier in your shop of the customer the code is reserved for (cust_…); empty for a public code. |
usage_limit | integer | How many times the code can be used. 0 means unlimited. |
usage_count | integer | How many times the code has been used. |
starts_at | integer | Start of validity, in Unix seconds. 0 for none. |
expires_at | integer | Expiry, in Unix seconds. 0 for none. |
created_at | integer | Creation time, in Unix seconds. |
updated_at | integer | Last change, in Unix seconds. |
Import vouchers
POST /v1/voucher/import creates or updates up to 50 vouchers per request, each with its codes. It follows the shared import contract described in Your first API call: items, dry_run, a line-by-line report.
Voucher fields
| Field | Type | Required | Description |
|---|---|---|---|
external_id | string | Yes | Your reference for the voucher, up to 50 characters, unique in the batch. The voucher is recognised by it on every later import. |
name | string | No | Up to 190 characters. |
type | string | No | percentage or fixed_amount. |
value | number or string | No | The discount, zero or more, with up to 2 decimals. At most 100 for a percentage voucher. |
min_amount | number or string | No | The minimum basket amount, zero or more. |
currency | string | No | A currency code of 3 to 10 letters, such as EUR. |
starts_at | integer | No | Start of validity, in Unix seconds. |
ends_at | integer | No | End of validity, in Unix seconds. |
audience | string | No | all, segment or consumer. |
status | string | No | draft, scheduled, activated, paused, expired or archived. A new voucher without a status is created as draft; an existing one keeps its status. |
created_at | integer | No | The original creation time, in Unix seconds. Kept as sent and never changed by a later import. |
codes | array | No | The voucher's codes (see below). |
Code fields
| Field | Type | Required | Description |
|---|---|---|---|
external_id | string | Yes | Your reference for the code, up to 50 characters, unique in the whole batch. |
code | string | Yes | The code the customer types, 1 to 190 characters. A code is unique across the shop, without regard to case or accents. |
customer_external_id | string | No | The external_id of an already imported customer, to reserve the code for that customer. Leave it out for a public code. |
usage_limit | integer | No | How many times the code can be used; 0 (the default) means unlimited. |
usage_count | integer | No | How many times the code has already been used. Left unchanged when you leave it out. |
starts_at | integer | No | Start of validity, in Unix seconds. |
expires_at | integer | No | Expiry, in Unix seconds. |
status | string | No | Only activated is accepted. |
created_at | integer | No | The original creation time, in Unix seconds. |
An invalid code refuses its whole voucher, and a voucher is saved together with all its codes or not at all. Codes you leave out of a later import are never removed: to send a voucher with more than 500 codes, split its codes over several requests that repeat the voucher's external_id.
Important — Import the customers first: a code whose
customer_external_idmatches no customer of your shop is refused withImport the customers first.See Orders & logistics.
The import report
Each accepted entry of data adds two fields to the shared report:
| Field | Type | Description |
|---|---|---|
codes | object | The number of the voucher's codes created, updated and unchanged. |
codes_detail | array | One entry per code: its external_id, its action and its id (null for a creation in a dry run). |
A refused entry carries only the eight shared fields. A code already held by another code of the shop refuses its voucher with code 409. A voucher whose codes changed is reported as updated, even if its own fields did not.
Example
curl https://api.ultineo.com/v1/voucher/import \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"dry_run": false,
"items": [
{
"external_id": "SPRING-2026",
"name": "Spring sale",
"type": "percentage",
"value": 15,
"min_amount": "50.00",
"currency": "EUR",
"audience": "all",
"status": "activated",
"starts_at": 1774998000,
"ends_at": 1777590000,
"codes": [
{ "external_id": "SPRING-2026-PUBLIC", "code": "SPRING15", "usage_limit": 0, "usage_count": 42 },
{ "external_id": "SPRING-2026-C1001", "code": "SPRING15-MARTIN", "customer_external_id": "C1001", "usage_limit": 1 }
]
}
]
}' {
"code": 200,
"title": "OK",
"response": {
"object": "list",
"resource": "promotion",
"dry_run": false,
"data": [
{
"index": 0,
"external_id": "SPRING-2026",
"action": "created",
"id": "prom_8d2c5e41a0b7f39e6c14",
"code": null,
"title": null,
"reason": null,
"notice": [],
"codes": { "created": 2, "updated": 0, "unchanged": 0 },
"codes_detail": [
{ "external_id": "SPRING-2026-PUBLIC", "action": "created", "id": "prco_1f6a93c0d4e8b2a75e31" },
{ "external_id": "SPRING-2026-C1001", "action": "created", "id": "prco_7b04e2d9a6c1f835b0d2" }
]
}
],
"created": 1,
"updated": 0,
"unchanged": 0,
"refused": 0,
"total": 1
}
} Read a voucher
GET /v1/voucher/import returns one voucher with all its codes, including how many times each code has been used.
| Parameter | In | Description |
|---|---|---|
external_id | query | The voucher's reference in your former system. Takes precedence over id. |
id | query | The voucher's identifier in your shop, prefixed prom_. |
Give one of the two; with neither, the call answers 400 Missing required parameter: external_id. A voucher that is not in your shop answers 404 Promotion not found.
curl "https://api.ultineo.com/v1/voucher/import?external_id=SPRING-2026" \
-H "Authorization: Bearer sk-project-YOUR_KEY" {
"code": 200,
"title": "OK",
"response": {
"id": "prom_8d2c5e41a0b7f39e6c14",
"object": "promotion",
"external_id": "SPRING-2026",
"project": "proj_5a91c7e03d2b48f6a1e9",
"status": "activated",
"name": "Spring sale",
"type": "percentage",
"value": "15.00",
"currency": "EUR",
"min_amount": "50.00",
"audience": "all",
"starts_at": 1774998000,
"ends_at": 1777590000,
"created_at": 1774998000,
"updated_at": 1791745200,
"codes": [
{
"id": "prco_1f6a93c0d4e8b2a75e31",
"object": "promotion_code",
"external_id": "SPRING-2026-PUBLIC",
"status": "activated",
"code": "SPRING15",
"customer": "",
"usage_limit": 0,
"usage_count": 42,
"starts_at": 0,
"expires_at": 0,
"created_at": 1774998000,
"updated_at": 1791745200
},
{
"id": "prco_7b04e2d9a6c1f835b0d2",
"object": "promotion_code",
"external_id": "SPRING-2026-C1001",
"status": "activated",
"code": "SPRING15-MARTIN",
"customer": "cust_c3e9a1074b5d28f6e0a7",
"usage_limit": 1,
"usage_count": 0,
"starts_at": 0,
"expires_at": 0,
"created_at": 1774998000,
"updated_at": 1791745200
}
]
}
} Note — Only percentage and fixed-amount vouchers are imported. Free shipping, gifts, product or segment targeting and the history of each use of a code are managed in your workspace and are not available through the API. The API does not delete a voucher or a code either.