#YYYY-MM-DD-short-slug, so a link to an entry keeps working forever. Deprecations are announced here first. See Versioning.
02. 11. 2026: stricter input checks
No endpoint and no field is removed. Requests that were already wrong now get a clear422 instead of a 500 or a silent repair.
- Long text on
POST /v1/cardsanswers422, not500. A text field above its stored length answers422 validation_failedwith the field name, for exampleissuer.company_name. The stored length counts an emoji as 2 characters. field_errors[]lists at most 100 entries. A request with more errors gets the first 100.- Webhook endpoint
urlis checked more strictly. A URL with a space, a control character, a backslash, a user name or password, or more than 2,048 characters answers422 webhook_url_invalid. Endpoints you saved before keep working. enabled_eventsstores each event name once. A name sent twice is saved once.- Schema fix:
referral.referrer_bonusandreferral.referee_bonusin a card response no longer show amaximumof 1000. The real limit depends on the card and is described in the field text. The API could already return values above 1000, for example on a points card.
01. 11. 2026: money limits, one business currency and reward percentages
This release adds limits on cards and transactions, makes the business currency explicit, and adds three read fields. No endpoint is removed. Some requests that were accepted before now answer422, as listed below. See Money and currency for the rules in one place.
New and changed fields
- New field
percentageon a reward. A percent-off reward carriesmechanics.rewards[].percentage, a whole number from 1 to 99, on read and on write. Sendpercentageorvalue, not both. A reward with neither is a free product. valueon a reward reads back for every currency. Before, a fixed-amount reward made in the dashboard in a currency other than the euro read back withoutvalue. Now it reads back withvalue.valueis a whole number of minor units, at least 1.- A reward sent back unchanged keeps its value. A reward with its
idand with neithervaluenorpercentagekeeps the stored reward in aPATCH. Before, it was saved as a free product, so the old advice not to send such a reward back is gone. - New field
currencyon a card and on a customer card slot. Both carry the business currency. Customer webhooks carry it too. - New field
expected_currencyinfield_errors[]. It is sent only oncurrency_mismatch. cashback_balance_minorandbalance_after.cashback_minoruse the rate of the till. On a card connected to a till that sets its own point value, the money figure uses that rate, as on the wallet pass.
422 validation_failed with field_errors[].code out_of_range (or invalid_value where noted). On PATCH only a changed value is checked, so a card that already pays more keeps saving other fields.
- Cashback is limited to 30 percent on a card without levels and 60 percent per level. The percent is
earn_rate_per_unitxcashback_point_valuex 100, times the level multiplier. This replaces the 20 percent that the dashboard editor offered on a card without levels. On a card connected to Oberon, or to Papaya with the card basis, the point value of the till counts.param:mechanics.earn_rate_per_unit,mechanics.cashback_point_valueormechanics.tiers. - At most 20 rewards on a card.
param:mechanics.rewards. points_requiredof a reward is at least 1. Before, 0 was accepted.percentageis 1 to 99,valueis a whole number of at least 1. Avaluewith decimals or below 1 answers422onmechanics.rewards[n].value.cashback_point_valuemust be above 0. Before, 0 was accepted.- A discount card needs at least 1 level. Level names are unique, and each level needs a spend above the level before it. The same holds for the levels of a reward card. A repeated name or a level that is not higher answers
invalid_valueonmechanics.tiers. The first step of an employee discount is at least 1 percent. - An unknown key inside
mechanicsanswers422 parameter_unknownwith the full name, for examplemechanics.rewards[0].colour. This also covers keys inside a reward, a level andemployee. Before, such a key was ignored. PATCHonreferralmerges key by key. A key you leave out keeps its stored value. Before, the block replaced the stored settings and an omitted bonus became 0.initial_state.pointsonPOST /v1/customersabove the starting bonus limit of the card answers422 validation_failedwithfield_errors[].codeout_of_range.
rewards[].percentage, currency on the card and on the customer card slot, and field_errors[].expected_currency.
One business currency and new limits on transactions
currencyonPOST /v1/transactionsis optional. When you send it, it must be the business currency, in any letter case. Another code answers422 currency_mismatchwithfield_errors[0].expected_currency. This also holds for a coupon redeem and for the MCP toolcreate_transaction.- Largest bill per currency.
amount_minorabove 10,000 EUR, 250,000 CZK, 4,000,000 HUF, 45,000 PLN, 50,000 RON, 9,000 GBP, 10,000 CHF or 11,000 USD answers422 amount_too_large. The maximum transaction amount that the business sets in the dashboard now applies on the API and the MCP server too. - Largest
value. An explicitvalueabove 100,000 points (points card), above the worth of the largest bill (cashback card) or above one full card (stampaward) answers422 value_too_large. amount_minoron a redeem answers422 amount_not_valid_for_action, also on a coupon redeem.external_idcompares the whole transaction. A retry that sendsamount_minororcurrencymust match what was booked. A differentaction,value,amount_minororcurrencyanswers409 external_id_conflict.- MCP
create_transaction:external_idstays required. A retry with the sameexternal_idbooks once; a new purchase needs a new one. - Employee discount over the API. The saving is capped at the monthly limit of the card. On a card that counts net spend, the bill minus the discount counts.
transaction.createdcarriesteam_member_id(when a team member booked it) andproducts.- A coupon redeem made through
POST /v1/transactionssendstransaction.created. Before, no event was sent.
422 and 409 codes in this release: currency_mismatch, amount_too_large, value_too_large, amount_not_valid_for_action, and external_id_conflict on POST /v1/transactions. See Errors.
01. 11. 2026: bonus limits, cashback levels and earn rate 0
This release adds limits on bonuses, rules for cards with levels, and a clearer earn rate of 0. Nothing is removed and no field or endpoint is added. Some requests that were accepted before now answer422, as listed below.
-
Limits on the referral bonus and the starting bonus.
POST /v1/cardsandPATCH /v1/cards/{id}checkreferral.referrer_bonus,referral.referee_bonus,mechanics.starting_pointsandmechanics.starting_stampsagainst the limit of the card, the same limits as in the dashboard. The referral limits have been live since 26. 10. 2026 and are part of this entry. The starting bonus limit on the API is new: before, the API accepted a starting bonus up to 100,000,000,000. The limits are:- A stamp card: up to 1,000 referral stamps. Starting stamps at most the card’s
stamps_required, and never above 1,000. - A points card: up to 100,000 points.
- A cashback card: about 50 EUR of credit in your currency (CZK 1,250, HUF 20,000, PLN 200, RON 250, GBP 50, CHF 50, USD 50). The most points are that amount divided by
cashback_point_value. - A discount card: about 1,000 EUR of spend (CZK 25,000, HUF 400,000, PLN 4,000, RON 5,000), in whole major currency units.
422 validation_failedwithfield_errors[].codeout_of_range. OnPATCHonly a changed value is checked. Every stored value is checked again when the change makes a point worth more (a highercashback_point_value, or a switch into cashback), or lowersstamps_required. See Errors. - A stamp card: up to 1,000 referral stamps. Starting stamps at most the card’s
-
Changed
paramon the referral error. This changes an existing error. The422for a referral bonus above the limit used to name the internal pathreferralSettings.referrerBonusorreferralSettings.refereeBonus. It now names the field you sent:referral.referrer_bonusorreferral.referee_bonus. The errorcodeis unchanged. If you branch onparam, update the check. -
Cards with levels need a level. A reward card with
earn_mode: "tiered"needs at least one level. Without one,POSTandPATCHanswer422 levels_need_a_level. A level with a multiplier below 1 or a spend below 0 answers422 levels_invalid_level. Both namemechanics.tiers. Before, such a card was saved. Switching levels on places every customer in a level from past purchases. See Update a card template. -
field_immutableonmechanics.is_prepaid. A stamp card cannot switch between prepaid and normal after it is created.PATCHwith the other value answers400 field_immutablewithparammechanics.is_prepaid. -
reward_tieron cashback cards. A customer on a cashback card with levels carriesreward_tier, as on a points card. It is absent when the card’s levels are off. -
Awards on a card with levels.
POST /v1/transactionswithvaluebooksvaluetimes the level multiplier, rounded to the nearest whole point. The bill inamount_minorcounts toward level spend, so the customer can level up.tier_at_earningis the level name, for exampleSilver. -
earn_rate_per_unit: 0earns nothing. Before, a rate of 0 earned 1 point per currency unit. Now it earns 0 points from spend. A card with no rate set still earns 1 point per currency unit. An award withamount_minoron a card with rate 0 answers201withvalue: 0, and the balance does not change. An explicitvaluestill booksvaluepoints. -
Event descriptions. The text served by
GET /v1/webhook_endpoints/event_typesforcustomer.updatedandtransaction.creatednow says what is sent. Which events fire did not change.
20. 10. 2026 (live since 21. 10. 2026): level retention on discount cards, employee discount without a limit, and fixes
This release adds two optional fields and lets discount cards use level retention. It also fixes four behaviours. Nothing is removed.- Level retention on discount cards.
mechanics.tier_demotionnow works on discount cards with 2 or more tiers. Before, it answered422 mechanic_not_available. A customer who makes no qualifying transaction forinactivity_daysdrops one tier. On an employee discount card (is_employee_discount: true) the field is ignored on write and reads back asnull. See Update a card template. - New field
level_valid_untilon customers. Customer responses carry the date until which the customer keeps the current tier. It isnullwhen level retention does not apply. See List customers. - New field
mechanics.employee.no_limiton employee discount cards. Withno_limit: truethe discount does not stop at a monthly limit: the highest step applies until the reset day. Send it on create or update, and read it back on every card. On a card with no limit,monthly_budget_minoris left out of the response. Anemployeeblock with neithermonthly_budget_minornorno_limit: trueanswers422 parameter_missing, and one with both answers422 validation_failed. To switch a card from no limit to a limit, sendmonthly_budget_minorin the same request. A new employee discount card (or a card you switch to one) needs theemployeeblock. Withno_limit: true, the highest step must be below 100 %, else422 validation_failedonmechanics.tiers. - Employee settings on update. A
PATCHnow changes only the employee fields it sends. Before, aPATCHwithmechanics.employeebut withoutis_employee_discountturned the card into a normal discount card. APATCHwith onlyis_employee_discountreset the monthly limit and the reset day. - Discount tier order. Discount tiers are stored and returned from the lowest to the highest
spend_to_achieve_minor, also when you send them in another order. Tierids do not change. - Notification delivery counts.
GET /v1/notificationsandGET /v1/notifications/{id}count deliveries per device. Some older sends where a device never confirmed now count that device as failed, so theirstatuschanges fromcompletedtopartial. Thestatusfilter uses the same counts. - Idempotent retries. A retry sent the moment the first response arrives now gets the replayed response. Before, it could get
409 idempotency_key_in_use.
11. 10. 2026 (live since 17. 10. 2026): small /v1 changes that ship with the MCP server
These changes reach every API client, not only the MCP server. They add no field, no endpoint and no required parameter, and they remove nothing. The first and third change the answer to a request in a narrow case, as described below.DELETE /v1/notifications/{id}now answers409 broadcast_not_cancellablefor a scheduled broadcast whose send time is less than a minute away. A job that is about to run can no longer be stopped. Repeating the cancel of a broadcast that is already cancelled still returns 200. See Cancel a scheduled notification.- Error texts.
image_ingest_failedanddelivery_failednow carry a message from a fixed template with no internal detail. Failures in the authentication, scope, account-state, rate-limit and idempotency layers answer with the same fixedinternal_errortext,An unexpected error occurred.Branch onerror.code, never on the message. - List filters with a cursor.
GET /v1/transactionsandGET /v1/notificationsnow return an empty list when a filter can match nothing, for example acard_idthat is not of the requestedcard_type, also when you passstarting_afterorending_before. Before, the cursor could bring rows back.
07. 10. 2026: look up a customer by serial number
GET /v1/customers accepts a new serial_number filter. Pass the value scanned from the wallet pass QR code or barcode, or the number printed on a physical card, and you get that customer back without listing your customers. The change is additive: nothing existing was changed. See List customers.
27. 09. 2026: v1 (1.0.0) is generally available
The first public release of the VEXiON cards Public API.- 54 REST endpoints across customers, cards, transactions, products, notifications, locations, team members, custom fields, webhook endpoints, events, the organization and its invoices, API keys and icons. Base URL
https://api.vexioncards.one/v1. - 22 webhook events, signed with HMAC-SHA-256 under the Standard Webhooks scheme.
- The additive-only guarantee is in force for everything under
/v1/from this date. Removing or renaming a field, or changing a status or error code, is a breaking change and is announced here first. See Versioning. - Notifications accept
titleandbodyas plain text in one language. Template variables and more than one locale are answered with422 template_variables_unavailableand422 multiple_locales_unavailable, and nothing is sent. - API access is included in every plan except VEXiON ONE. Creating an API key requires accepting the API terms in the dashboard.