Skip to content

Create and validate an Order

To accept payments with Montonio, you need to create an Order, redirect the customer, and then validate the status of the Order. This guide will walk you through the process.

Creating an Order

The Order object is the top-level object you create in Montonio. This should match one-to-one with an Order in your system. The Order object is necessary to create a Payment for it.

Complete example

This is a complete example of how to create an Order and redirect the customer to the gateway. You can use this as a starting point for your integration. The process is as follows:

  1. Gather the checkout data you will use to create the Order
  2. Specify the payment method the customer will use to pay for the Order
  3. Generate a JWT (token) from this data
  4. POST the JWT to the API to create the Order
  5. Redirect the customer to the paymentUrl returned by the API
/**
* We recommend using the jsonwebtoken package to generate
* Json Web Tokens. You can install it with npm:
* > npm install jsonwebtoken
* More information can be found at
* https://www.npmjs.com/package/jsonwebtoken
*/
import jwt from 'jsonwebtoken';
import axios from 'axios';
/**
* Note: Please make sure to make these calls from your server,
* and not from the client. This is to prevent your secret key
* from being exposed to the public.
*/
// 1. Gather the checkout data
const payload = {
"accessKey": "MY_ACCESS_KEY",
"merchantReference": "MY-ORDER-ID-123",
"returnUrl": "https://mystore.com/payment/return",
"notificationUrl": "https://mystore.com/payment/notify",
"currency": "EUR",
"grandTotal": 99.99,
"locale": "et",
"billingAddress": {
"firstName": "CustomerFirst",
"lastName": "CustomerLast",
"email": "customer@customer.com",
"addressLine1": "Kai 1",
"locality": "Tallinn",
"region": "Harjumaa",
"country": "EE",
"postalCode": "10111"
},
"shippingAddress": {
"firstName": "CustomerFirstShipping",
"lastName": "CustomerLastShipping",
"email": "customer@customer.com",
"addressLine1": "Kai 1",
"locality": "Tallinn",
"region": "Harjumaa",
"country": "EE",
"postalCode": "10111"
},
"lineItems": [
{
"name": "Hoverboard",
"quantity": 1,
"finalPrice": 99.99
}
],
// 2. Specify the payment method
"payment": {
"method": "paymentInitiation",
"methodDisplay": "Pay with your bank",
"methodOptions": {
"paymentDescription": "Payment for order 123",
// For international banks (e.g., Revolut, N26), ensure this matches
// the country of the bank list you displayed to the customer.
"preferredCountry": "EE",
// This is the code of the bank that the customer chose at checkout.
// See the GET /stores/payment-methods endpoint for the list of available banks.
"preferredProvider": "LHVBEE22"
},
"amount": 99.99, // Yes, this is the same as the grandTotal
"currency": "EUR" // This must match the currency of the order.
}
}
// 3. Generate the token
const token = jwt.sign(
payload,
'MY_SECRET_KEY',
{ algorithm: 'HS256', expiresIn: '10m' }
);
// console.log(token);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJNWV9BQ0NFU1NfS0VZIiwibWVyY2hhbnRSZWZlcmVuY2UiOiJNWS1PUkRFUi1JRC0xMjMiLCJyZXR1cm5VcmwiOiJodHRwczovL215c3RvcmUuY29tL3BheW1lbnQvcmV0dXJuIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cHM6Ly9teXN0b3JlLmNvbS9wYXltZW50L25vdGlmeSIsImN1cnJlbmN5IjoiRVVSIiwiZ3JhbmRUb3RhbCI6OTkuOTksImxvY2FsZSI6ImV0IiwiYmlsbGluZ0FkZHJlc3MiOnsiZmlyc3ROYW1lIjoiQ3VzdG9tZXJGaXJzdCIsImxhc3ROYW1lIjoiQ3VzdG9tZXJMYXN0IiwiZW1haWwiOiJjdXN0b21lckBjdXN0b21lci5jb20iLCJhZGRyZXNzTGluZTEiOiJLYWkgMSIsImxvY2FsaXR5IjoiVGFsbGlubiIsInJlZ2lvbiI6Ikhhcmp1bWFhIiwiY291bnRyeSI6IkVFIiwicG9zdGFsQ29kZSI6IjEwMTExIn0sInNoaXBwaW5nQWRkcmVzcyI6eyJmaXJzdE5hbWUiOiJDdXN0b21lckZpcnN0U2hpcHBpbmciLCJsYXN0TmFtZSI6IkN1c3RvbWVyTGFzdFNoaXBwaW5nIiwiZW1haWwiOiJjdXN0b21lckBjdXN0b21lci5jb20iLCJhZGRyZXNzTGluZTEiOiJLYWkgMSIsImxvY2FsaXR5IjoiVGFsbGlubiIsInJlZ2lvbiI6Ikhhcmp1bWFhIiwiY291bnRyeSI6IkVFIiwicG9zdGFsQ29kZSI6IjEwMTExIn0sImxpbmVJdGVtcyI6W3sibmFtZSI6IkhvdmVyYm9hcmQiLCJxdWFudGl0eSI6MSwiZmluYWxQcmljZSI6OTkuOTl9XSwicGF5bWVudCI6eyJtZXRob2QiOiJwYXltZW50SW5pdGlhdGlvbiIsIm1ldGhvZERpc3BsYXkiOiJQYXkgd2l0aCB5b3VyIGJhbmsiLCJtZXRob2RPcHRpb25zIjp7InBheW1lbnRSZWZlcmVuY2UiOiIxMDEwMTA5IiwicGF5bWVudERlc2NyaXB0aW9uIjoiUGF5bWVudCBmb3Igb3JkZXIgMTIzIiwicHJlZmVycmVkQ291bnRyeSI6IkVFIiwicHJlZmVycmVkUHJvdmlkZXIiOiJMSFZCRUUyMiJ9LCJhbW91bnQiOjk5Ljk5LCJjdXJyZW5jeSI6IkVVUiJ9LCJpYXQiOjE2NzYwNDQ3NTksImV4cCI6MTY3NjA0NTM1OX0.VichbCT2QQUBXE_yGNXAuYuXrwxrNELTHMDH7_dAPzw
axios.post('https://stargate.montonio.com/api/orders', {
data: token
}).then(response => {
const { data } = response;
console.log(data.paymentUrl);
// https://gateway.montonio.com/some-random-uuid
/**
* Note: After you have successfully created the order,
* you may now pass the order.paymentUrl to the client-side.
*/
// 6. Redirect the customer to the checkout page (frontend)
// window.location.href = data.paymentUrl;
});

Now let’s break it down into step-by-step instructions.

1. Order data structure

First, you need to create an Order object from the checkout page’s data. Not all fields are required, but it is recommended to provide as much information as possible to improve the customer experience. The following table describes the fields that can be used to create an Order object.

The fields marked with an asterisk are required.

KeyTypeDescription
accessKey*stringYour Access Key obtained from the Partner System.
merchantReference*stringThe order reference in the merchant’s system (e.g. the WooCommerce Order ID). This value must be unique for each order of a store. If you use the same value for multiple orders, the existing order will be updated. To avoid unintended behavior and use the parameter correctly, read this help center article.
returnUrl*stringThe URL where the customer will be redirected back to after completing or canceling a payment. See below for details on payment verification.
notificationUrl*stringThe URL to send a webhook notification about Order updates, e.g when a payment is completed. See below for details on payment verification.
grandTotal*numberOrder grand total up to 2 decimal places (e.g 19.99).
currency*stringPayment currency. Currently EUR and PLN are supported depending on the payment method provided.
exp*numberExpiration time of the token in Unix time. Set that to 10 minutes from the time of issuing the token. (e.g. 1675860645)
payment*objectThe payment method to use.

Key Type Description
amount* number The amount to charge. This is the total amount of the order, including tax and shipping.
currency* string The currency of the order. This is a 3-letter ISO currency code.
method* string The Identifier of the Montonio Payment Method. See below for details
methodDisplay string The Payment Method’s title as is shown to the customer at checkout.
methodOptions object Additional options for the payment method. See below for details
Please make sure to provide the correct method as this defines which payment gateway the customer will be redirected to.
locale*stringThe preferred language of the payment gateway. Defaults to the merchant country’s official language. Available values are de, en, et, fi, lt, lv, pl, ru.
expiresInnumberThe number of minutes that the order can be paid for. The default is 30 minutes, minimum 5 minutes, and maximum 44640 minutes (31 days). This is used to calculate the expiration time of the order. The order will be abandoned if it is not paid within this time frame.

Keep in mind this is different from the JWT’s exp field which is the expiration time of the token itself, not the order.
sessionUuidstringThis is only relevant and required for embedded card payments. It is the UUID of the Session created in step one of the Embedded Cards guide. Only include this field if you are creating an order for an embedded card payment.
billingAddressobjectThe customer’s billing address.

Key Type Description
firstName string The customer’s first name.
lastName string The customer’s last name.
email string The customer’s email address.
phoneNumber string The customer’s phone number.
phoneCountry string The customer’s phone country. (e.g 372)
addressLine1 string The customer’s address line 1. (e.g Some Street 8-40)
addressLine2 string The customer’s address line 2.
locality string The customer’s city or town.
region string The customer’s state or province.
postalCode string The customer’s postal code.
country string The customer’s country. See the full list of codes.
shippingAddressobjectThe customer’s shipping address.

Key Type Description
firstName string The customer’s first name.
lastName string The customer’s last name.
email string The customer’s email address.
phoneNumber string The customer’s phone number.
phoneCountry string The customer’s phone country. (e.g 372)
addressLine1 string The customer’s address line 1. (e.g Some Street 8-40)
addressLine2 string The customer’s address line 2.
locality string The customer’s city or town.
region string The customer’s state or province.
postalCode string The customer’s postal code.
country string The customer’s country. See the full list of codes.
lineItemsarrayThe list of items in the order. All fields are required if the lineItems property exists in the data.

Key Type Description
name* string The line item’s name
quantity* integer Quantity of the product
finalPrice* number The product’s sale price (tax included). It would make sense if all line item finalPrice x quantity’s added up would amount to the grandTotal of the order, however this is not enforced.

2. Payment method

Secondly, you need to specify the payment method to use. This information is passed in the payment key of Order object. The payment method to use is identified by the method key. The following payment methods are currently supported:

Payment Initiation is a payment method that allows customers to pay with their bank account. The customer is redirected to their bank’s online banking service where they can authorize the payment. Payment Initiation is currently available in the EU.

Method Identifier: paymentInitiation See the Order data structure > Payment > Method to see how to pass the payment method to use.

Supported currencies: EUR, PLN

// See the full example above
order.payment = {
"method": "paymentInitiation",
"methodOptions": {
// This is the code of the bank that the customer chose at checkout.
// See the GET /stores/payment-methods endpoint for the list of available banks.
"preferredProvider": "LHVBEE22",
// For international banks (e.g., Revolut, N26), ensure this matches
// the country of the bank list you displayed to the customer.
"preferredCountry": "EE",
"preferredLocale": "et",
"paymentDescription": "Payment for order 123"
}
}

Method Options for Payment Initiation:

KeyTypeDescription
preferredProviderstringThe bank that the customer chose for this payment if you allow them to select their bank of choice in your checkout. Leave this blank to let the customer choose their bank in our interface. See the Payment methods guide on how to fetch the list of available banks. The value can be found in the code parameters of the response. It is highly recommended you send this to us as it improves the customer experience and saves time at checkout.
preferredCountrystringThe preferred country for the methods list of the payment gateway. Defaults to the merchant’s country. Available values are EE, LV, LT, FI, PL, DE.

📝 Note: For international banks (e.g., Revolut, N26), you must set preferredCountry to match the country of the payment methods displayed to the customer.
These banks can be identified via the GET /payment-methods endpoint as they often share the same code across multiple countries.
Example: If customer sees Estonian banks and selects Revolut → use “preferredCountry”: “EE”
preferredLocalestringThe preferred language of the payment gateway. Defaults to the Order locale. Available values are de, en, et, fi, lt, lv, pl, ru.
paymentDescriptionstringDescription of the payment that will be relayed to the bank’s payment order. If not included, it will default to the value of merchantReference.
paymentReferencestringStructured payment reference number. This is a standardized reference number used for accounting purposes and will be validated by banks. Do not include if you do not use reference numbers to link payments in your accounting software. Banks validate this number strictly and payments will start failing if this number is not formatted correctly.

3. Generating the JWT

Now, you need to generate a JWT (JSON Web Token) from the Order object. We use JWT to securely pass the Order object to the API and use the JWT’s signature to verify the integrity of the request.

The exact implementation of how to generate the JWT varies by programming language and you can see some examples in the Complete Example section.

  • The payload of the JWT is the Order object.
  • The JWT is signed with your Secret Key using HMAC SHA256 (HS256).
  • The headers of the JWT must contain the alg and typ keys. They are described below.
KeyRequiredTypeDescription
algyesstringMust be set to HS256
typyesstringMust be set to JWT

4. Submitting the token

After you have generated the token, you can submit it to Montonio’s API to create an Order. The API endpoint is:

Terminal window
POST /orders

An example request using curl is shown below:

Terminal window
curl --location --request POST 'https://stargate.montonio.com/api/orders' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJNWV9BQ0NFU1NfS0VZIiwibWVyY2hhbnRSZWZlcmVuY2UiOiJNWS1PUkRFUi1JRC0xMjMiLCJyZXR1cm5VcmwiOiJodHRwczovL215c3RvcmUuY29tL3BheW1lbnQvcmV0dXJuIiwibm90aWZpY2F0aW9uVXJsIjoiaHR0cHM6Ly9teXN0b3JlLmNvbS9wYXltZW50L25vdGlmeSIsImN1cnJlbmN5IjoiRVVSIiwiZ3JhbmRUb3RhbCI6OTkuOTksImxvY2FsZSI6ImV0IiwiYmlsbGluZ0FkZHJlc3MiOnsiZmlyc3ROYW1lIjoiQ3VzdG9tZXJGaXJzdCIsImxhc3ROYW1lIjoiQ3VzdG9tZXJMYXN0IiwiZW1haWwiOiJjdXN0b21lckBjdXN0b21lci5jb20iLCJhZGRyZXNzTGluZTEiOiJLYWkgMSIsImxvY2FsaXR5IjoiVGFsbGlubiIsInJlZ2lvbiI6Ikhhcmp1bWFhIiwiY291bnRyeSI6IkVFIiwicG9zdGFsQ29kZSI6IjEwMTExIn0sInNoaXBwaW5nQWRkcmVzcyI6eyJmaXJzdE5hbWUiOiJDdXN0b21lckZpcnN0U2hpcHBpbmciLCJsYXN0TmFtZSI6IkN1c3RvbWVyTGFzdFNoaXBwaW5nIiwiZW1haWwiOiJjdXN0b21lckBjdXN0b21lci5jb20iLCJhZGRyZXNzTGluZTEiOiJLYWkgMSIsImxvY2FsaXR5IjoiVGFsbGlubiIsInJlZ2lvbiI6Ikhhcmp1bWFhIiwiY291bnRyeSI6IkVFIiwicG9zdGFsQ29kZSI6IjEwMTExIn0sImxpbmVJdGVtcyI6W3sibmFtZSI6IkhvdmVyYm9hcmQiLCJxdWFudGl0eSI6MSwiZmluYWxQcmljZSI6OTkuOTl9XSwicGF5bWVudCI6eyJtZXRob2QiOiJwYXltZW50SW5pdGlhdGlvbiIsIm1ldGhvZERpc3BsYXkiOiJQYXkgd2l0aCB5b3VyIGJhbmsiLCJtZXRob2RPcHRpb25zIjp7InBheW1lbnRSZWZlcmVuY2UiOiJQQVlNRU5ULUZPUi1NWS1PUkRFUi1JRC0xMjMiLCJwYXltZW50RGVzY3JpcHRpb24iOiJQYXltZW50IGZvciBvcmRlciAzNyIsInByZWZlcnJlZENvdW50cnkiOiJFRSIsInByZWZlcnJlZFByb3ZpZGVyIjoiTEhWQkVFMjIifSwiYW1vdW50Ijo5OS45OSwiY3VycmVuY3kiOiJFVVIifSwiaWF0IjoxNjc1OTMxMzMzLCJleHAiOjE2NzU5MzE5MzN9.PBgJswAac6e1LRXSwGTAPpb_ghjoCQZZ-uIzxxBCX2E"
}'

The response will be a JSON object with the following structure:

{
"uuid": "12228dce-2f7c-4db5-8d28-5d82a19aa3b6", // This is the Montonio Order UUID. Use this to identify the order in the future and query its status.
"paymentStatus": "PENDING",
"locale": "et",
"merchantReference": "MY-ORDER-ID-123",
"merchantReferenceDisplay": "MY-ORDER-ID-123",
"merchantReturnUrl": "https://mystore.com/payment/return",
"merchantNotificationUrl": "https://mystore.com/payment/notify",
"grandTotal": "99.99",
"currency": "EUR",
"paymentMethodType": "paymentInitiation",
"storeUuid": "703a60eb-ed19-4fc3-8a62-4474150a962a", // This is the UUID of your store in the Montonio Partner System.
"paymentIntents": [
{
"uuid": "302f259c-7501-49ed-b3aa-39a4bbcafec1",
"paymentMethodType": "paymentInitiation",
"paymentMethodMetadata": {
"preferredLocale": "et",
"preferredCountry": "EE",
"paymentDescription": "Payment for order 123"
},
"amount": "99.99",
"currency": "EUR",
"status": "PENDING",
"serviceFee": null,
"serviceFeeCurrency": "EUR",
"createdAt": "2023-12-13T12:02:35.522Z"
}
],
"refunds": [],
"availableForRefund": 0,
"isRefundableType": false,
"lineItems": [
{
"name": "Hoverboard",
"quantity": 1,
"finalPrice": 99.99
}
],
"billingAddress": {
"firstName": "CustomerFirst",
"lastName": "CustomerLast",
"email": "customer@customer.com",
"phoneNumber": null,
"phoneCountry": null,
"addressLine1": "Kai 1",
"addressLine2": null,
"locality": "Tallinn",
"region": null,
"country": "EE",
"postalCode": "10111",
"companyName": null,
"companyLegalName": null,
"companyRegCode": null,
"companyVatNumber": null
},
"shippingAddress": {
"firstName": "CustomerFirstShipping",
"lastName": "CustomerLastShipping",
"email": "customer@customer.com",
"phoneNumber": null,
"phoneCountry": null,
"addressLine1": "Kai 1",
"addressLine2": null,
"locality": "Tallinn",
"region": null,
"country": "EE",
"postalCode": "10111",
"companyName": null,
"companyLegalName": null,
"companyRegCode": null,
"companyVatNumber": null
},
"expiresAt": null,
"createdAt": "2023-02-08T13:32:55.099Z",
"storeName": "My Store Name",
"businessName": "My Business Name",
"paymentUrl": "https://stargate.montonio.com/e694c95b-0335-493d-a713-af95720f885d"
}

Some errors which might occur during the request are listed below:

CodeDescription
400Bad request. Please double-check the request body and the JWT contents. There are issues with some fields in the JWT body. You will get a more detailed error message.
401STORE_NOT_FOUND. Please double check you are passing accessKey in the token and using the correct environment.
403Forbidden. Please double check you are using the correct secretKey for signing and using the correct environment.
500Internal server error. Something went wrong on our side.

5. Redirecting the customer

Once you have created the Order, it’s time to redirect the customer to Montonio’s gateway. Notice the paymentUrl in the response. This is the URL that you should redirect the customer to.

An example redirect would look like this:

window.location.href = "http://stargate.montonio.com/a9816a11-f08e-4fcf-bf7c-2dd04ccbb6dd";

That’s really all there is to it. The customer will be redirected to Montonio’s payment gateway where they can complete the payment.

Validating the payment

Redirecting back to the store

Once the customer completes the payment, they will be redirected back to the returnUrl that you specified in the Order JWT, with a new order-token appended to the URL as a query parameter. Validate the contents and the signature of this token to confirm the order.

Example return URL:

Terminal window
https://my-store.com/orders/27731773/thank_you?order-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoidGhlLW1vbnRvbmlvLW9yZGVyLXV1aWQiLCJhY2Nlc3NLZXkiOiJNWV9BQ0NFU1NfS0VZIiwibWVyY2hhbnRSZWZlcmVuY2UiOiJNWS1PUkRFUi1JRC0xMjMiLCJtZXJjaGFudFJlZmVyZW5jZURpc3BsYXkiOiJNWS1PUkRFUi1JRC0xMjMiLCJwYXltZW50U3RhdHVzIjoiUEFJRCIsImdyYW5kVG90YWwiOjk5Ljk5LCJjdXJyZW5jeSI6IkVVUiIsIm1lcmNoYW50X3JlZmVyZW5jZSI6Ik1ZLU9SREVSLUlELTEyMyIsIm1lcmNoYW50X3JlZmVyZW5jZV9kaXNwbGF5IjoiTVktT1JERVItSUQtMTIzIiwicGF5bWVudF9zdGF0dXMiOiJQQUlEIn0.X6Ym70AA1bYIsKyNc1NL4NpznKXCrGX5xacqc1ovtuE

Webhook notification

In addition to redirecting the customer, we will send a POST request to the notificationUrl parameter you specified in the Order JWT. You can retrieve the orderToken from the request’s body. Validate the contents and the signature of this token to confirm the order. Read more about responding to webhooks below.

This is used to confirm the order in the background, without relying on the customer to return to the merchant’s website, to prevent the issue where a customer closes the browser window before the redirect happens and the order is not confirmed, even though the payment was successful.

🛠️ Testing locally
To test webhooks locally, there are a few options, but currently the easiest one is to use a service like ngrok to expose your local server to the internet or webhook.site for quick troubleshooting. We have written a more detailed guide in our Help Center. Have a look at it if you need more information.

These are the contents of the webhook:

{
"orderToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiYzhlMzZkMTMtNTIzMC00NTczLTk3MGYtMGE3N2ZmODIyYTBjIiwiYWNjZXNzS2V5IjoiWU9VUl9BQ0VTU19LRVkiLCJncmFuZFRvdGFsIjoyMiwibWVyY2hhbnRSZWZlcmVuY2UiOiI5OTk5OSIsIm1lcmNoYW50UmVmZXJlbmNlRGlzcGxheSI6Ijk5OTk5IiwicGF5bWVudFN0YXR1cyI6IlBBSUQiLCJwYXltZW50TWV0aG9kIjoicGF5bWVudEluaXRpYXRpb24iLCJwYXltZW50UHJvdmlkZXJOYW1lIjoiU0VCIEVzdG9uaWEiLCJzZW5kZXJJYmFuIjoiRUU0NzEwMDAwMDEwMjAxNDU2ODUiLCJzZW5kZXJOYW1lIjoiSm9obiBEb2UiLCJjdXJyZW5jeSI6IkVVUiIsIm1lcmNoYW50X3JlZmVyZW5jZSI6Ijk5OTk5IiwibWVyY2hhbnRfcmVmZXJlbmNlX2Rpc3BsYXkiOiI5OTk5OSIsInBheW1lbnRfc3RhdHVzIjoiUEFJRCIsImlhdCI6MTY5MjE4MDUyMywiZXhwIjoxNjkyMTk0OTIzfQ.yoy7KPvMYhXINZpA2UDfEW5Zz82Wpd1L-f5qhYFW7xU"
}

See the following section for how to validate the Order Token.

Validating the returned Order Token

The Order Token contains information about the order and the payment.

  • In the case of a redirect, the token is appended to the returnUrl as the query parameter order-token.
  • In the case of a webhook notification, the orderToken can be found in the body of the POST request.

If you decode the token, you will get the following contents:

{
"uuid": "the-montonio-order-uuid",
"accessKey": "MY_ACCESS_KEY",
"merchantReference": "MY-ORDER-ID-123",
"merchantReferenceDisplay": "MY-ORDER-ID-123",
"paymentStatus": "PAID",
"paymentMethod": "paymentInitiation",
"grandTotal": 99.99,
"currency": "EUR",
// Both senderIban and senderName, will be filled if the bank provides us the info and the order status is "PAID"
"senderIban": "EE471000001020145685",
"senderName": "John Doe",
// Can be string or null. If the payment method is "paymentInitiation" then it contains the bank name used in the transaction.
"paymentProviderName": "New Wave Bank Group",
"iat": 1632967333,
"exp": 1632967333,
// Fields that will be removed in the future.
"merchant_reference": "MY-ORDER-ID-123",
"merchant_reference_display": "MY-ORDER-ID-123",
"payment_status": "PAID"
}

The merchantReferenceDisplay is an internal reference that we use for stores that needs multiple or human-readable order references. If you don’t pass it in the Order JWT, it will be the same as the merchantReference… And you can just ignore it 🤭

The token is signed with your Secret Key and needs to be validated.

See the example below for validating the token:

/*
* We recommend using the jsonwebtoken package to verify
* Json Web Tokens. You can install it with npm:
* > npm install jsonwebtoken
* More information can be found at
* https://www.npmjs.com/package/jsonwebtoken
*/
import jwt from 'jsonwebtoken';
// fetched from the URL for returnUrl and from POST body->orderToken when it's a notification
const orderToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoidGhlLW1vbnRvbmlvLW9yZGVyLXV1aWQiLCJhY2Nlc3NLZXkiOiJNWV9BQ0NFU1NfS0VZIiwibWVyY2hhbnRSZWZlcmVuY2UiOiJNWS1PUkRFUi1JRC0xMjMiLCJtZXJjaGFudFJlZmVyZW5jZURpc3BsYXkiOiJNWS1PUkRFUi1JRC0xMjMiLCJwYXltZW50U3RhdHVzIjoiUEFJRCIsImdyYW5kVG90YWwiOjk5Ljk5LCJjdXJyZW5jeSI6IkVVUiIsIm1lcmNoYW50X3JlZmVyZW5jZSI6Ik1ZLU9SREVSLUlELTEyMyIsIm1lcmNoYW50X3JlZmVyZW5jZV9kaXNwbGF5IjoiTVktT1JERVItSUQtMTIzIiwicGF5bWVudF9zdGF0dXMiOiJQQUlEIn0.X6Ym70AA1bYIsKyNc1NL4NpznKXCrGX5xacqc1ovtuE';
// The Order ID you got from Montonio as a response to creating the order
const montonioOrderId = 'the-montonio-order-uuid';
// Use your secret key to verify the orderToken
const decoded = jwt.verify(orderToken, 'MY_SECRET_KEY'); // can throw
if (
decoded.paymentStatus === 'PAID' &&
decoded.uuid === montonioOrderId &&
decoded.accessKey === 'MY_ACCESS_KEY'
) {
// payment completed
} else {
// payment not completed
}

The values for paymentStatus are described here: Lifecycle of an Order.

Responding to the webhook

Respond to our webhooks with HTTP status code 200 OK or 201 Created. If you don’t respond with 200 or 201, we will retry the webhook 13 times over the next 48 hours until a successful response is received.