ReferenceReference by module

Discounts API

Every Discounts action (12) and data model (10): endpoints, scopes, input, preconditions, events and examples.

Promotions and discount codes — sales, order deals and free gifts.

Module code discounts · 12 actions · 10 data models · 13 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: discounts (everything), discounts:read (read only) or discounts:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
promotion_rule_channelspromotion_rule_channel/api/v1/promotion_rule_channels
promotion_rule_giftspromotion_rule_gift/api/v1/promotion_rule_gifts
promotion_rule_targetspromotion_rule_target/api/v1/promotion_rule_targets
promotion_rulespromotion_rule/api/v1/promotion_rulesdiscounts.save_promotion_rulediscounts.delete_promotion_rule
promotionspromotion/api/v1/promotionsdiscounts.save_promotiondiscounts.delete_promotion
voucher_cataloguesvoucher_catalogue/api/v1/voucher_catalogues
voucher_channel_listingsvoucher_channel_listing/api/v1/voucher_channel_listings
voucher_codesvoucher_code/api/v1/voucher_codes
voucher_customersvoucher_customer/api/v1/voucher_customers
vouchersvoucher/api/v1/vouchersdiscounts.save_voucherdiscounts.delete_voucher

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
discounts.add_voucher_codesdiscounts:writeAdd voucher codes
discounts.announce_promotiondiscounts:writeAnnounce a promotion starting or ending
discounts.delete_promotiondiscounts:deleteDelete a promotion
discounts.delete_promotion_rulediscounts:writeDelete a promotion rule
discounts.delete_voucherdiscounts:deleteDelete a voucher
discounts.delete_voucher_codesdiscounts:deleteRemove voucher codes
discounts.import_voucher_codesdiscounts:writeImport voucher codes
discounts.save_promotiondiscounts:writeSave a promotion
discounts.save_promotion_rulediscounts:writeSave a promotion rule
discounts.save_voucherdiscounts:writeSave a voucher
discounts.set_voucher_cataloguediscounts:writeLimit a voucher to part of the catalogue
discounts.set_voucher_channelsdiscounts:writeSet a voucher’s value per channel

discounts.add_voucher_codes

Add voucher codes — Type codes, or generate up to fifty with an optional prefix.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/voucher_codes/actions/add_voucher_codes
API key or OAuth token · discounts:write
  • Canonical address: POST /api/v1/actions/discounts.add_voucher_codes

Input

FieldTypeRequiredNotes
voucherIduuidyesVoucher · id of voucher
codesobject / arrayCodes
quantitynumberHow many to generate · min 0 · max 50
prefixstringPrefix · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.
no_codesAt least one code must be typed or generated.
too_many_codesAt most fifty at a time.
duplicate_codesA code may be given once.
code_takenA code must be free in this workspace, ignoring case.

Events it publishes: discounts.voucher_codes_added

What it writes: voucher_code (insert) — Writes the codes

curl -X POST https://app.getera.io/api/v1/voucher_codes/actions/add_voucher_codes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"voucherId":"VOUCHER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_codes_added"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.voucherCodes.addVoucherCodes({
  voucherId: "VOUCHER_ID"
})
era voucher_codes add_voucher_codes \
  --voucher-id "VOUCHER_ID"
tools/call
{
  "name": "era__discounts__add_voucher_codes",
  "arguments": {
    "voucherId": "VOUCHER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, no_codes, too_many_codes, duplicate_codes, code_taken · 429 slow down

discounts.announce_promotion

Announce a promotion starting or ending — Machine: the shop sweep announces a start or an end once, as Saleor’s scheduled task does.

Needs discounts:write · reaches outside (sends, publishes or charges)

POSThttps://app.getera.io/api/v1/promotions/{id}/actions/announce_promotion
API key or OAuth token · discounts:write
  • Canonical address: POST /api/v1/actions/discounts.announce_promotion

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Promotion · id of promotion

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe promotion must exist.
nothing_to_announceA start or an end must have passed since the last announcement.

Events it publishes: discounts.promotion_started, discounts.promotion_ended

What it writes: promotion (update) — Stamps when it was announced

curl -X POST https://app.getera.io/api/v1/promotions/PROMOTION_ID/actions/announce_promotion \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.promotion_started",
    "discounts.promotion_ended"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.promotions.announcePromotion("PROMOTION_ID")
era promotions announce_promotion PROMOTION_ID
tools/call
{
  "name": "era__discounts__announce_promotion",
  "arguments": {
    "id": "PROMOTION_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, nothing_to_announce · 429 slow down

discounts.delete_promotion

Delete a promotion — Its rules go with it. Orders already sold keep what they were charged.

Needs discounts:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/promotions/{id}/actions/delete_promotion
API key or OAuth token · discounts:delete
  • REST alias: DELETE /api/v1/promotions/{id}
  • Canonical address: POST /api/v1/actions/discounts.delete_promotion

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Promotion · id of promotion

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe promotion must exist.

Events it publishes: discounts.promotion_deleted

What it writes: promotion (delete) — Removes the promotion and its rules

curl -X POST https://app.getera.io/api/v1/promotions/PROMOTION_ID/actions/delete_promotion \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.promotion_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.promotions.deletePromotion("PROMOTION_ID")
era promotions delete_promotion PROMOTION_ID
tools/call
{
  "name": "era__discounts__delete_promotion",
  "arguments": {
    "id": "PROMOTION_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

discounts.delete_promotion_rule

Delete a promotion rule — The prices it painted go back to normal.

Needs discounts:write · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/promotion_rules/{id}/actions/delete_promotion_rule
API key or OAuth token · discounts:write
  • REST alias: DELETE /api/v1/promotion_rules/{id}
  • Canonical address: POST /api/v1/actions/discounts.delete_promotion_rule

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Rule · id of promotion_rule

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe rule must exist.

Events it publishes: discounts.rule_deleted

What it writes: promotion_rule (delete) — Removes the rule

curl -X POST https://app.getera.io/api/v1/promotion_rules/PROMOTION_RULE_ID/actions/delete_promotion_rule \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.rule_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.promotionRules.deletePromotionRule("PROMOTION_RULE_ID")
era promotion_rules delete_promotion_rule PROMOTION_RULE_ID
tools/call
{
  "name": "era__discounts__delete_promotion_rule",
  "arguments": {
    "id": "PROMOTION_RULE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

discounts.delete_voucher

Delete a voucher — Its codes stop working. Orders keep the code text they were sold with.

Needs discounts:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/vouchers/{id}/actions/delete_voucher
API key or OAuth token · discounts:delete
  • REST alias: DELETE /api/v1/vouchers/{id}
  • Canonical address: POST /api/v1/actions/discounts.delete_voucher

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Voucher · id of voucher

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.

Events it publishes: discounts.voucher_deleted

What it writes: voucher (delete) — Removes the voucher and its codes

curl -X POST https://app.getera.io/api/v1/vouchers/VOUCHER_ID/actions/delete_voucher \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.vouchers.deleteVoucher("VOUCHER_ID")
era vouchers delete_voucher VOUCHER_ID
tools/call
{
  "name": "era__discounts__delete_voucher",
  "arguments": {
    "id": "VOUCHER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

discounts.delete_voucher_codes

Remove voucher codes — Used ones too, as in Saleor — the result says how many had been used.

Needs discounts:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/voucher_codes/actions/delete_voucher_codes
API key or OAuth token · discounts:delete
  • Canonical address: POST /api/v1/actions/discounts.delete_voucher_codes

Input

FieldTypeRequiredNotes
voucherIduuidyesVoucher · id of voucher
codeIdsobject / arrayyesCodes

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.

Events it publishes: discounts.voucher_codes_deleted

What it writes: voucher_code (delete) — Removes the codes

curl -X POST https://app.getera.io/api/v1/voucher_codes/actions/delete_voucher_codes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"voucherId":"VOUCHER_ID","codeIds":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_codes_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.voucherCodes.deleteVoucherCodes({
  voucherId: "VOUCHER_ID",
  codeIds: {}
})
era voucher_codes delete_voucher_codes --data '{"voucherId":"VOUCHER_ID","codeIds":{}}'
tools/call
{
  "name": "era__discounts__delete_voucher_codes",
  "arguments": {
    "voucherId": "VOUCHER_ID",
    "codeIds": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found · 429 slow down

discounts.import_voucher_codes

Import voucher codes — Codes from a CSV file — the first column, a header optional. All or none.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/voucher_codes/actions/import_voucher_codes
API key or OAuth token · discounts:write
  • Canonical address: POST /api/v1/actions/discounts.import_voucher_codes

Input

FieldTypeRequiredNotes
voucherIduuidyesVoucher · id of voucher
codesobject / arrayyesCodes

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.
no_codesThe file has at least one code.
import_too_largeAt most five thousand codes per file.
duplicate_codesA code may be given once.
code_takenA code must be free in this workspace, ignoring case.

Events it publishes: discounts.voucher_codes_added

What it writes: voucher_code (insert) — Writes the codes

curl -X POST https://app.getera.io/api/v1/voucher_codes/actions/import_voucher_codes \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"voucherId":"VOUCHER_ID","codes":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_codes_added"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.voucherCodes.importVoucherCodes({
  voucherId: "VOUCHER_ID",
  codes: {}
})
era voucher_codes import_voucher_codes --data '{"voucherId":"VOUCHER_ID","codes":{}}'
tools/call
{
  "name": "era__discounts__import_voucher_codes",
  "arguments": {
    "voucherId": "VOUCHER_ID",
    "codes": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, no_codes, import_too_large, duplicate_codes, code_taken · 429 slow down

discounts.save_promotion

Save a promotion — A catalogue sale that paints prices, or an order deal on the basket total.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/promotions/{id}/actions/save_promotion
API key or OAuth token · discounts:write
  • REST alias: PATCH /api/v1/promotions/{id}
  • Canonical address: POST /api/v1/actions/discounts.save_promotion

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Promotion · id of promotion
namestringyesName · max 255
typestring (enum)Type · Allowed values: catalogue, order
descriptionstringDescription · max 4000
startDatedate-timeStarts
endDatedate-timeEnds

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
invalid_nameA promotion needs a name.
not_foundAn edited promotion must exist.
end_before_startIt must end after it starts.

Events it publishes: discounts.promotion_created, discounts.promotion_updated

What it writes: promotion (upsert) — Creates or edits the promotion

curl -X POST https://app.getera.io/api/v1/promotions/PROMOTION_ID/actions/save_promotion \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.promotion_created",
    "discounts.promotion_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.promotions.savePromotion("PROMOTION_ID", {
  name: "Name"
})
era promotions save_promotion PROMOTION_ID \
  --name "Name"
tools/call
{
  "name": "era__discounts__save_promotion",
  "arguments": {
    "id": "PROMOTION_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 invalid_name, not_found, end_before_start · 429 slow down

discounts.save_promotion_rule

Save a promotion rule — What it covers, in which channels, and what it gives.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/promotion_rules/{id}/actions/save_promotion_rule
API key or OAuth token · discounts:write
  • REST alias: PATCH /api/v1/promotion_rules/{id}
  • Canonical address: POST /api/v1/actions/discounts.save_promotion_rule

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Rule · id of promotion_rule
promotionIduuidPromotion · id of promotion
namestringName · max 255
descriptionstringDescription · max 2000
channelIdsobject / arrayChannels
rewardValueTypestring (enum)Off by · Allowed values: percentage, fixed
rewardValuenumberValue · min 0
rewardTypestring (enum)Reward · Allowed values: subtotal_discount, gift
targetsobject / arrayCovers
cataloguePredicateobject / arrayCovers (AND / OR tree)
orderPredicateobject / arrayOrder condition
giftVariantIdsobject / arrayGifts

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe promotion and an edited rule must exist.
channel_not_foundEvery channel must exist.
predicate_requiredA catalogue rule covers something; an order rule has a total condition.
predicate_not_allowedA rule carries only its own promotion type’s condition.
invalid_rangeAn order total range (minor units) is positive and runs low to high.
invalid_predicateA condition tree is Saleor-shaped: AND / OR groups alone at their level, known leaves, ids and amounts.
reward_type_not_allowedA catalogue rule has no reward type.
reward_type_requiredAn order rule says money off or gift.
mixed_currenciesAmounts and order-total conditions need channels in one currency.
gift_rule_invalidA gift rule has gifts and no value.
reward_value_requiredA discount rule has a value above zero and its kind.
channels_requiredAn amount off needs at least one channel.
invalid_percentageA percentage is at most 100.

Events it publishes: discounts.rule_created, discounts.rule_updated

What it writes: promotion_rule (upsert) — Creates or edits the rule; promotion_rule_channel (insert) — Replaces its channels; promotion_rule_target (insert) — Replaces what it covers; promotion_rule_gift (insert) — Replaces its gifts

curl -X POST https://app.getera.io/api/v1/promotion_rules/PROMOTION_RULE_ID/actions/save_promotion_rule \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"promotionId":"PROMOTION_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.rule_created",
    "discounts.rule_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.promotionRules.savePromotionRule("PROMOTION_RULE_ID", {
  promotionId: "PROMOTION_ID"
})
era promotion_rules save_promotion_rule PROMOTION_RULE_ID \
  --promotion-id "PROMOTION_ID"
tools/call
{
  "name": "era__discounts__save_promotion_rule",
  "arguments": {
    "id": "PROMOTION_RULE_ID",
    "promotionId": "PROMOTION_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, channel_not_found, predicate_required, predicate_not_allowed, invalid_range, invalid_predicate, reward_type_not_allowed, reward_type_required, mixed_currencies, gift_rule_invalid, reward_value_required, channels_required, invalid_percentage · 429 slow down

discounts.save_voucher

Save a voucher — A code customers type — its reach, its limits, its dates.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/vouchers/{id}/actions/save_voucher
API key or OAuth token · discounts:write
  • REST alias: PATCH /api/v1/vouchers/{id}
  • Canonical address: POST /api/v1/actions/discounts.save_voucher

Input

FieldTypeRequiredNotes
iduuidFilled from the path {id} · Voucher · id of voucher
namestringName · max 255
typestring (enum)Applies to · Allowed values: entire_order, shipping, specific_product
discountValueTypestring (enum)Off by · Allowed values: fixed, percentage
usageLimitnumberUsage limit · min 1
startDatedate-timeStarts
endDatedate-timeEnds
applyOncePerOrderbooleanOnce per order
applyOncePerCustomerbooleanOnce per customer
singleUsebooleanEach code once
onlyForStaffbooleanStaff only
minCheckoutItemsQuantitynumberMinimum items · min 0
countriesobject / arrayCountries
codesobject / arrayCodes

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundAn edited voucher must exist.
end_before_startIt must end after it starts.
invalid_percentageA switch to percent needs every channel value at most 100.
duplicate_codesA code may be given once.
code_takenA code must be free in this workspace, ignoring case.

Events it publishes: discounts.voucher_created, discounts.voucher_updated

What it writes: voucher (upsert) — Creates or edits the voucher; voucher_code (insert) — Writes its first codes on create

curl -X POST https://app.getera.io/api/v1/vouchers/VOUCHER_ID/actions/save_voucher \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_created",
    "discounts.voucher_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.vouchers.saveVoucher("VOUCHER_ID", {
  name: "Name"
})
era vouchers save_voucher VOUCHER_ID \
  --name "Name"
tools/call
{
  "name": "era__discounts__save_voucher",
  "arguments": {
    "id": "VOUCHER_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, end_before_start, invalid_percentage, duplicate_codes, code_taken · 429 slow down

discounts.set_voucher_catalogue

Limit a voucher to part of the catalogue — The products, variants, categories and collections a specific-products voucher covers.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/voucher_catalogues/actions/set_voucher_catalogue
API key or OAuth token · discounts:write
  • Canonical address: POST /api/v1/actions/discounts.set_voucher_catalogue

Input

FieldTypeRequiredNotes
voucherIduuidyesVoucher · id of voucher
itemIdsobject / arrayProducts
variantIdsobject / arrayVariants
categoryIdsobject / arrayCategories
collectionIdsobject / arrayCollections

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.
catalogue_not_allowedOnly a specific-products voucher has a catalogue.

Events it publishes: discounts.voucher_updated

What it writes: voucher_catalogue (insert) — Replaces what it covers

curl -X POST https://app.getera.io/api/v1/voucher_catalogues/actions/set_voucher_catalogue \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"voucherId":"VOUCHER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.voucherCatalogues.setVoucherCatalogue({
  voucherId: "VOUCHER_ID"
})
era voucher_catalogues set_voucher_catalogue \
  --voucher-id "VOUCHER_ID"
tools/call
{
  "name": "era__discounts__set_voucher_catalogue",
  "arguments": {
    "voucherId": "VOUCHER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, catalogue_not_allowed · 429 slow down

discounts.set_voucher_channels

Set a voucher’s value per channel — How much it takes off in each channel, and the minimum spend there.

Needs discounts:write · changes data

POSThttps://app.getera.io/api/v1/voucher_channel_listings/actions/set_voucher_channels
API key or OAuth token · discounts:write
  • Canonical address: POST /api/v1/actions/discounts.set_voucher_channels

Input

FieldTypeRequiredNotes
voucherIduuidyesVoucher · id of voucher
listingsobject / arrayyesChannels

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe voucher must exist.
channel_not_foundEvery channel must exist.
value_requiredEvery channel needs a value above zero.
invalid_percentageA percentage is at most 100.

Events it publishes: discounts.voucher_updated

What it writes: voucher_channel_listing (upsert) — Replaces the per-channel values

curl -X POST https://app.getera.io/api/v1/voucher_channel_listings/actions/set_voucher_channels \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"voucherId":"VOUCHER_ID","listings":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "discounts.voucher_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.voucherChannelListings.setVoucherChannels({
  voucherId: "VOUCHER_ID",
  listings: {}
})
era voucher_channel_listings set_voucher_channels --data '{"voucherId":"VOUCHER_ID","listings":{}}'
tools/call
{
  "name": "era__discounts__set_voucher_channels",
  "arguments": {
    "voucherId": "VOUCHER_ID",
    "listings": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold discounts:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, channel_not_found, value_required, invalid_percentage · 429 slow down

Data models

PromotionRuleChannel

Table promotion_rule_channel · Resource promotion_rule_channels

  • GET /api/v1/promotion_rule_channels
  • GET /api/v1/promotion_rule_channels/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
rule_idstring (uuid) · uuidpromotion_rule
channel_idstring (uuid) · uuidchannel

Primary key: id

Unique: rule_id, channel_id

PromotionRuleGift

Table promotion_rule_gift · Resource promotion_rule_gifts

  • GET /api/v1/promotion_rule_gifts
  • GET /api/v1/promotion_rule_gifts/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
rule_idstring (uuid) · uuidpromotion_rule
item_variant_idstring (uuid) · uuiditem_variant

Primary key: id

Unique: rule_id, item_variant_id

PromotionRuleTarget

Table promotion_rule_target · Resource promotion_rule_targets

  • GET /api/v1/promotion_rule_targets
  • GET /api/v1/promotion_rule_targets/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
rule_idstring (uuid) · uuidpromotion_rule
item_idstring (uuid) · uuidyesitem
item_variant_idstring (uuid) · uuidyesitem_variant
category_idstring (uuid) · uuidyesitem_category
collection_idstring (uuid) · uuidyesitem_collection

Primary key: id

Checks:

  • CHECK ((num_nonnulls(item_id, item_variant_id, category_id, collection_id) = 1))

PromotionRule

Table promotion_rule · Resource promotion_rules

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
promotion_idstring (uuid) · uuidpromotion
namestring · textyes
descriptionstring · textyes
reward_value_typestring · textyesfixed, percentage
reward_valuestring (decimal) · numericyes
reward_typestring · textyessubtotal_discount, gift
order_predicateobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
catalogue_predicateobject · jsonb

Primary key: id

Checks:

  • CHECK (((reward_value_type <> 'percentage'::text) OR (reward_value IS NULL) OR (reward_value <= (100)::numeric)))
  • CHECK (((reward_value IS NULL) OR (reward_value >= (0)::numeric)))

Promotion

Table promotion · Resource promotions

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
descriptionstring · textyes
typestring · textcatalogue, order
start_datestring (date-time) · timestamptz
end_datestring (date-time) · timestamptzyes
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
last_notification_scheduled_atstring (date-time) · timestamptzyes

Primary key: id

Checks:

  • CHECK (((end_date IS NULL) OR (end_date > start_date)))

VoucherCatalogue

Table voucher_catalogue · Resource voucher_catalogues

  • GET /api/v1/voucher_catalogues
  • GET /api/v1/voucher_catalogues/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
voucher_idstring (uuid) · uuidvoucher
item_idstring (uuid) · uuidyesitem
item_variant_idstring (uuid) · uuidyesitem_variant
category_idstring (uuid) · uuidyesitem_category
collection_idstring (uuid) · uuidyesitem_collection

Primary key: id

Checks:

  • CHECK ((num_nonnulls(item_id, item_variant_id, category_id, collection_id) = 1))

VoucherChannelListing

Table voucher_channel_listing · Resource voucher_channel_listings

  • GET /api/v1/voucher_channel_listings
  • GET /api/v1/voucher_channel_listings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
voucher_idstring (uuid) · uuidvoucher
channel_idstring (uuid) · uuidchannel
discount_valuestring (decimal) · numeric
currencystring · bpcharmax 3
min_spent_amountstring (int64) · int8yes

Primary key: id

Unique: voucher_id, channel_id

Checks:

  • CHECK ((currency ~ '^[A-Z]{3}$'::text))
  • CHECK ((discount_value > (0)::numeric))
  • CHECK (((min_spent_amount IS NULL) OR (min_spent_amount >= 0)))

VoucherCode

Table voucher_code · Resource voucher_codes

  • GET /api/v1/voucher_codes
  • GET /api/v1/voucher_codes/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
voucher_idstring (uuid) · uuidvoucher
codestring · text
usedinteger · int4
is_activeboolean · bool
created_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((length(code) >= 1) AND (length(code) <= 255)))
  • CHECK ((used >= 0))

VoucherCustomer

Table voucher_customer · Resource voucher_customers

  • GET /api/v1/voucher_customers
  • GET /api/v1/voucher_customers/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
voucher_code_idstring (uuid) · uuidvoucher_code
customer_emailstring · textyes
order_idstring (uuid) · uuid
created_atstring (date-time) · timestamptz

Primary key: id

Unique: voucher_code_id, order_id

Voucher

Table voucher · Resource vouchers

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · textyes
typestring · textentire_order, shipping, specific_product
discount_value_typestring · textfixed, percentage
usage_limitinteger · int4yes
start_datestring (date-time) · timestamptz
end_datestring (date-time) · timestamptzyes
apply_once_per_orderboolean · bool
apply_once_per_customerboolean · bool
single_useboolean · bool
only_for_staffboolean · bool
min_checkout_items_quantityinteger · int4yes
countriesstring[] · bpchar[]
metadataobject · jsonb
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((end_date IS NULL) OR (end_date > start_date)))
  • CHECK (((min_checkout_items_quantity IS NULL) OR (min_checkout_items_quantity >= 0)))
  • CHECK (((usage_limit IS NULL) OR (usage_limit >= 1)))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
discounts.promotion_createdA promotion was created.id, type
discounts.promotion_deletedA promotion was removed.id, type
discounts.promotion_endedA promotion’s end date passed.id, type, endDate
discounts.promotion_startedA promotion’s start date passed.id, type, startDate
discounts.promotion_updatedA promotion was edited.id, type
discounts.rule_createdA promotion rule was added.id, promotionId, type, channelIds
discounts.rule_deletedA promotion rule was removed.id, promotionId, type
discounts.rule_updatedA promotion rule was edited.id, promotionId, type, channelIds
discounts.voucher_codes_addedCodes were added to a voucher.voucherId, count
discounts.voucher_codes_deletedCodes were removed from a voucher.voucherId, count, used
discounts.voucher_createdA voucher was created.id, codes
discounts.voucher_deletedA voucher was removed.id
discounts.voucher_updatedA voucher was edited.id