Create Promotion Quote
Prices a payment before you create it and returns a signed quote when a promotion applies.
Two ways to call it
- Secret key, from your server. Send
amountandaccount_id, and nocheckout_session. This is the flow described below. - Public key, from the browser. Send
checkout_sessioninstead ofamount; the amount comes from the session. Yuno takes the account from the checkout session, soaccount_idis optional here, and a value you send must match the session’s account.countryis still validated against that session. The session must not have been used to pay yet, be at most 2 hours old, and belong to your organization.
payment_method is required on both. A quote is valid for 30 minutes after it is issued, on both. Leave code out: it’s reserved for promotion codes, which aren’t available yet.
How to use the quote
- Send the context of the payment you’re about to create.
amountis the original amount, before any promotion. For a card, send insidepayment_methodeither itsbin(the first 6 to 8 digits) or a token (tokenorvaulted_token), never both. - On
200, showcharge_amountto your customer. That’s what they’ll pay. The answer includesquote_id,promotions(one entry today:id,name,description,discount,discount_amount), the three totals outside the list (original_amount,discount_amount,charge_amount) andexpires_at. Thequote_idis long, about 300 to 730 characters: store it whole (up to 1000 characters) and send it unchanged. - Create the payment with the same original
amountandadditional_data.order.discounts: [{ "type": "YUNO_PROMOTION", "quote_id": "<quote_id>" }]. See Create Payment and Promotions.
quote_id on a discount line. A payment without one is charged in full.
Rules
- Biggest saving wins. When two or more promotions match, the quote is for the one that saves the customer the most, then the oldest, then the smallest
id. One promotion per payment; no stacking. - 30 minutes. A quote is valid until
expires_at, 30 minutes after it is issued. Inside that time the payment charges the quoted price, even if the promotion’s end date passed after the quote was issued, or you disabled the promotion after the quote was issued. - Every condition must already be true. A quote exists only when the promotion’s conditions all hold for the context you send.
- Quoted price or no payment. If the quote expired, or the payment’s amount, currency or account differs from what you quoted, or the payment differs in a detail the quote is bound to (the country, payment method, card type and card BIN when the promotion’s conditions use them, and the checkout session when the quote was made with one), Yuno rejects the payment with
422and one of thePROMOTION_*codes listed in Promotions. It never re-prices. Get a new quote, and send the retry with a newX-Idempotency-Key. - Nothing is consumed. A quote is a read. Asking again gives the same price; the
expires_at, and so thequote_id, move with the time you ask, so don’t use the id as a key. A quote you never use needs no cleanup, and one quote can back several payments. - No match isn’t an error. The answer is
204when nothing applies. Create the payment as usual, with noquote_idon a discount line. A204also means Promotions is not enabled for your organization or is temporarily disabled by Yuno, Yuno could not price the payment in time, or the promotion would make the charge zero (a promotion never makes a charge of zero). If the request itself fails (408,5xx, no answer), create the payment as usual too: a quote never blocks a payment. - BIN or token, never both, inside
payment_method. A server that holds the card number sendspayment_method.bin, the first 6 to 8 digits. A server that holds a token sendspayment_method.tokenorpayment_method.vaulted_token, and Yuno resolves the BIN and the card type from the card, exactly as it does on the payment. Any two ofbin,tokenandvaulted_tokentogether are rejected with400 INVALID_PARAMETERS, so don’t copy thepayment_methodof a Create Payment request that carries both tokens. A promotion with abinscondition needs the BIN, and one with acard_typescondition needs thecard_type(not the BIN); without them it doesn’t apply. Wallets (Apple Pay, Google Pay) aren’t a supported target for this release: don’t build on a wallet quote yet. - Send the BIN, never the card number.
payment_method.binis the first 6 to 8 digits of the card, digits only. Fewer than 6 digits, more than 8 (a longer card prefix or the full card number included), or anything but digits is rejected with400 INVALID_PARAMETERS. - Promotion codes aren’t available yet. The Dashboard creates promotions that apply automatically, and no promotion can require a code today.
codeis reserved for them: leave it out. A quote that carries acodefinds no promotion.
Answers
Authorizations
Body
- Option 1
- Option 2
The account that will create the payment (UUID). Required with the secret key. With the public key and checkout_session, it's optional: Yuno takes the account from the checkout session, and a value you send must match it.
The original amount of the payment, before any promotion. It must be the same amount you later send on the payment. Secret key only: send this, not checkout_session.
The country of the payment (MAX 2; MIN 2; ISO 3166-1).
The payment method of the payment you are about to create. For a card, identify it in ONE of three ways: send bin, or token, or vaulted_token. Any two of them together are rejected with 400 INVALID_PARAMETERS.
Checkout session id (UUID v4). Use it with the public key instead of amount; the amount comes from the session. The session must not have been used to pay yet, be at most 2 hours old, and belong to your organization. Never send it with the secret key.
Reserved for promotion codes, which aren't available yet: the Dashboard creates promotions that apply automatically, and no promotion can require a code today. Leave it out. A quote that carries a code finds no promotion.
Response
200
Opaque and long: about 300 to 730 characters. Store it whole, up to 1000 characters, and send it unchanged on the payment as quote_id on an additional_data.order.discounts line with type: YUNO_PROMOTION. Never parse or shorten it.
The promotions that apply. One entry in this release; a later release may return more than one. The outer discount_amount is the sum of each entry's discount_amount.
1The amount you sent, before the discount.
Total discount (sum of promotions[].discount_amount). Always positive.
What the customer pays: original minus discount.
The quote is valid until this instant: 30 minutes after it was issued.