Creates an order.

This is the final method related to order creation that takes all order data as arguments, optional delivery data and other user specified data, validates it and makes the order or returns error string.


This section describes main data of the make_order call, starting with full example.

Example of input

These examples are written in JSON because presenting POST data visually is really hard. Or atleast I didn’t find any good way to do it. This applies to every section in this page.

Please make sure that you don’t try to submit JSON, but proper HTTP POST request, exactly like with other requests. Thanks.

    1: {
      "additional_info":"This Customer Wants Restaurant To Know This Product Is No Good"
    "address":"Funky Address 1",
  "additional_info":"Something special customer wants to tell to the restaurant, like door code",
    "voucher_codes":[ "foobar", "509nogtlsee94" ]

Description of values

POST nameValueRequired?
session_idintegerNo. If given, user’s data will be used from the session. See below for description.
user_idintegerIf supplied, it is used to check customer data other than delivery address for the order
forenamestringYes if no user_id given
surnamestringYes if no user_id given
emailstring with @ at itYes if no user_id given
phone_numberphone number (string)Yes if no user_id given
productsSee linkYes
delivery_addressSee linkSee link
delivery_methodfetch or delivery method’s idYes
alternative_delivery_timeunix timestamp (integer)No
small_order_additional_feedoubleIf not given, zero is assumed
payment_dataSee linkYes


For order creation, session_id determines whether order is made for pre-made account. If no session id is passed, the order won’t have an user account binded to it. Generally it’s preferable to have customer to create an account so the customer will be able to track her orders and possibly use bonus she’s gained, along with other possibilities an account allows. But sometimes customer just don’t want to do that, in which case you could just automatically create an account and store it in device’s memory, so next time the customer opens the application, she could be automatically logged in.

If this kind of automatic account doesn’t make sense, it’d be possible to not insert session_id and create an order without any account, by not passing the session_id. When not passing session id, api_key and secret must be passed. Information about formatting these values can be found from authentication section.


Must be atleast one hour in future. Also applies to fetch orders. The time should be maximum of 7 days to future. Remember to check that alternative delivery time customer has chosen is valid delivery/fetch time.

Note that when calculating delivery methods that are available for customer to do the order to the restaurant is decided by time and distance between customer and restaurant.

For example, if restaurant has delivery method that can do deliveries between 5-10 km at time of 17:00-21:00, and otherwise closed, customer could set alternative delivery time to 18:00 at morning (when customer wakes up, for example) and that way do the order to the restaurant from far-away location.


For how total price is calculated, please see total price calculation section.

The total price returned in errors will not have delivery fee included in them. So the sum is delivery fee’s amount less than total price given to the server.


This one is a special case. For overview, see page Chain specific workflow.

Delivery information


A restaurant may have a number of delivery methods that should be used instead of "delivery" if conditions of it matches. How those methods works are better described at /restaurant/get.

If there is suitable delivery method, its id should be in this field and correct delivery fee at delivery_price block. Then order validator can recognize that customer has chosen certain delivery method over another and correct price.


Delivery fee for the order.

Noe that small_order_additional_fee will be in receipts customer receives in delivery fee. There is no separate attribute in database for this, so this has been the solution to handle small order fee. This does not affect API, but in possible order history handlers, where it is documented so.


Required for delivery orders and optional for takeaway (fetch) orders.

It can be either manually inserted address or id of user’s address received with /customer/address/get.

  "address":"Funky Address 1",



If giving an address, address and city are mandatory. postal_code is optional.

Product data

  "price" # price of product
  "variant_id" # id of variant, or size, of the product
  "side_dish" # id of side dish chosen by customer. Used for both side_dish and lunch_time_side_dish
  "amount" # Quantity of products. If customer wants more than one of this specific product, you can use this parameter. Defaults to 1.
    "original_id" => "new_id"
    "another_id" => "new_id"
    # ..
POST nameValueRequired?
changed_ingredientshash; { "original_id":"new_id", .. }No
added_ingredientshash; { "id", "another id", .. }No
extrashash; { "id", "another id", .. }No

Product data set to products should be an object that is numbered from 1 to upwards.

For example, product array would be passed like this (without line breaks or spaces):


One product in the product array is identified with a “counting number”. Technically it would be possible to use any numbers, but this kind of numbering makes it easy for developer to check for example if it was third or fourth product that was not validated correctly and look data of that product instead of first spending time to dig the problem out.

Then there is product_id field that takes product’s id and variant_id that takes variant’s id. When both of these fields are submitted with same counting number, a product can be fully identified as whole product, regardless of product_id and variant_id being same id.

products are required data.


Describes changeable ingredients. This should contain an array which contains key-value pairs with key being old id and value being ingredient old ingredient is changed to.

If the new id is zero (0), it means that ingredient is removed from product completely.


Additional ingredients added to this product. Contains ingredients from both addable_ingredients and addable_free_ingredients.

Payment data

  "voucher_codes":[ "foobar", "509nogtlsee94" ]
POST nameValueRequired?


This should be an int that describes payment method used for payment. For cash "1", for example. Can be compound for example when using bonus or po_credit too. For more information, see Payment methods.


token_id is only relevant for Solinor payment method. There is support for optionally paying without inserting the credit card information with each new payment, where the card where the payment will be accounted from is identified by specific id. The token from /customer/cards should be inserted to payment_data’s token_id if customer wants to pay with its pre-existing card instead of inserting new card information.

When token has been passed, the payment will be processed instantly, instead of returning a link like without the token. If the payment succeeds, order_id is returned, like with cash payment. Otherwise, error array will be returned; for invalid token, for example, SOLINOR_TOKEN_ID_INVALID would be returned. In such case, customer should be instructed to do the payment without token or try with some other payment method.


if save_token is true, token will be requested from Solinor and saved to customer’s data. This data can then be accessed with /customer/cards and upon next payment, customer can do a payment using a token, in which case customer should pass it to token_id.

This value defaults to true.


A customer can use a voucher to pay a portion of an order with a voucher. There is attribute voucher_codes that can be used to pass one or more vouchers. When using a voucher, a special payment bit for voucher should be applied to rest of payment methods.

If the payment is fully paid with the voucher, cash should be chosen as the payment method. If voucher’s value is larger than order’s total price, unused value of the voucher won’t be returned to the customer.


If you are not running web browser in separate instance the client can monitor, returning from payment is pretty hard, for example if you want to create website based client over Fiidmi. In such case, there is possibility to have automatic redirection from page after payment to the client’s own page.

When redirection is done, there is GET parameter applied to the URI given, with key payment_status and value one of the following:

There will also be order id. For example, http://custom.url.org/payment?payment_status=success&order_id=1

Maximum length for URI is 150 characters. Please contact us if this limit is too small.


Payment method cost is additional cost applied on top of over order for specific payment methods to cover costs introduced by the payment method. Payment methods and their costs are in payment data in /restaurant/metadata.

0.15 would mean 15 cnt extra to total price of order. This should be applied to total price.


This is essentially same as payment method cost (see above), but instead of cost, total price of order should be multiplied with this percent and that value passed on top of total price and in payment_method["percent"].


Customer can add one or more vouchers to an order. Vouchers can be used to an order either fully or just a part of it. If voucher’s value is more than order’s total price, rest of the value is not refunded to the customer.

Price calculation

Information about how to calculate prices and fees can be found from examples page.

Note that structure of this value is an array. That means, as with products, you should pass them in standard HTTP POST array, for example in following way:



payment_url will only be returned if order must be prepaid. The order won’t be delivered to restaurant until it has been marked as paid (customer confirms the payment by returning to the service).

In practice, when the API returns the payment URL, client should open that URL in a web browser or web view, where customer will be redirected to the payment method she chose. After she has completed the payment, she will be redirected back to our service, where we will validate the payment. If the payment is sucessful, we output a single text success in the page. In case the payment has been canceled or otherwise failed, the status will be canceled or failure, respectively. Sometimes, when the payment service provider is providing is wrong information, there may be other errors visible in the page, instead of cancel/failure (which are not exactly errors but that the payment has gracefully failed). Due to that, it may make sense to just check for success text and otherwise just redirect to failure page.

One exception to above rule is Mobilepay payment method, where the URL will be returned, but client should not call that page. It only contains instructional information in case the client mistakenly redirects customer there. Instead, after we’ve OK’ed the order, client should redirect customer to Mobilepay application for payment, and after customer has successfully returned to your client, you should call /restaurant/order_status to finalize the payment.

Solinor payment method contains two payment modes and are better described above under token_id documentation. Without the token, Solinor payment method will also return a payment url and should work equally as with other payment methods.

Status of orders can be followed using /restaurant/order_status.

NOTE: In some cases, a customer may be required to verify herself before the order can be made. In such case, USER_NEEDS_VERIFICATION error will be returned. See /account/verify for details.

Expectable errors

See error conventions section for explanation how error system works.

Label Additional data Description
INVALID_RESTAURANT_IDNoneEither missing or not numeric. Problem in client, I suspect.
INVALID_VALIDATION_RESTAURANT_IDNonethis means the id you have given validate_against_restaurant_id is not valid id for a restaurant.
INVALID_DELIVERY_METHODNoneDelivery method must be either fetch, delivery or integer from delivery_methods array.
NO_PRODUCTSNoneYou can’t order without products...
PRODUCT_ID_MISSINGNoneProblem in client.
PRODUCT_NOT_FOUNDNoneProduct id given is invalid. Client is doing something funky.
INVALID_DELIVERY_ADDRESS_TO_APINoneAddress in malformed format passed through the api. Fix the client.
INVALID_ADDITIONAL_INFONoneCustomer’s input does not make any sense. The message should be shown to customer as error message.
INVALID_PRODUCT_DATANoneProblem in client.
MOBILE_PAYMENT_TOTAL_EXCEEDEDNoneMaximum sum for mobile payments at the moment is 40,9 euros. Because the amount may change, it’s better to just take this error from the server and show the error message and let customer to fix their order after it instead of hardcoding the limit to client.
REGULAR_CASH_NOT_ALLOWEDNoneProblem in client.
ADDITIONAL_FEE_SUM_DOES_NOT_MATCHgiven_fee, restaurant_fee, limit, identifierAdditional fee sum given does not match to the sum in the restaurant. Client could tell correct additional sum to client and ask if it is okay and submit order with that sum. Getting this error indicates a problem in a client though.
TOTAL_PRICE_DOES_NOT_MATCHgiven_price, calculated_price

Whether server calculated total price of the order differently. This is the ultimate sum that is actually charged from the customer, so it’s important thing to get right.

Price calculation in general is fairly complex process, where, if ingredient’s price is not added, or something like that, gets wrong, the total price automatically is wrong. This indicates correct price and it may be fruitful to ask customer if she accepts new price, but it may not work, if there actually is some errors in actual data which needs to be fixed first.


This just indicates there is validation failure in product. This is just there to make sure validation does not pass if something not expected happens, which usually means invalid input in a way that it passes prevalidation but does not contain enough data to actually getting validated.

This is something that usually shouldn’t be shown to customers; instead, if there is any other errors, those should be handled, shown to customer and that way errors resolved. If there is no other errors but this, showing this or some kind of internal error message could be viable.

PRODUCT_PRICE_MISSINGNoneProblem in client.
INVALID_SIDE_DISHside_dish_idSide dish customer tried to choose for the product is not valid for the product. Most likely broken client.
INVALID_VARIANTNoneSome kind of internal error related to variants. Please poke maintainer of the API if you see this one.
INVALID_EXTRASNoneThis means the extras array passed can’t be properly validated. Problem in client.
INVALID_EXTRA_IDgiven_extra_idPlease ensure you pass correct extras. Problem in client.
PRODUCT_DOES_NOT_BELONG_TO_RESTAURANTgiven_product_id, restaurant_id, restaurant_product_idIf the product belongs to different restaurant order was made for, this error is returned.
VARIANT_ID_MISSINGNoneProblem in client.
INVALID_VARIANT_IDNoneVariant id is not valid for this product or something like that. Problem in client.
PRODUCT_PRICE_NOT_GIVENNoneProblem in client.
PRODUCT_PRICE_DOES_NOT_MATCHgiven_price, calculated_pricePrice for product submitted by client does not match to the price server calculated for the product. Please validate that your calculations you work. It is possible to ask customer if the price received from the server is ok and recalculate product price and total price according that and retry order creation.
INVALID_AMOUNTNoneProblem in client.
INVALID_INGREDIENTSNoneProblem in client. Or actually, this should never happen, so please contact the maintainer if you think everything is correct at your end.
CHANGED_TOO_MANY_INGREDIENTSproduct_idA restaurant may have a limit how many ingredients can be changed. Solving this happens by letting customer to remove enough ingredients from the product. Indicates a problem in client, better just implement the restriction that takes account that ingredient change amount limit.
INGREDIENT_REMOVE_PROHIBITEDproduct_id, ingredient_idIt is not allowed to remove an ingredient from product where changing ingredients is not possible. Well, atleast now.
CHANGED_INGREDIENT_NOT_CHANGEABLEproduct_id, old_ingredient_id, new_ingredient_idSome ingredients of the product can’t be changed to another. Please make sure those don’t get changed by customer...
INVALID_CHANGED_INGREDIENTproduct_id, old_ingredient_id, new_ingredient_idId of original or changed ingredient is invalid. Problem in client.
CHANGED_INGREDIENT_GROUP_ID_DOES_NOT_MATCHproduct_id, old_ingredient_id, new_ingredient_idProblem in client.
INVALID_ADDED_INGREDIENTingredient_idCustomer tried to add an ingredient to product where the ingredient to be added was not addable for the product.
INVALID_DELIVERY_TIMEalternative_delivery_timeRestaurant is closed or there is other problem that makes restaurant to deliver the order. If alternative_delivery_time is used, that time is used in this check, otherwise current time.
DELIVERY_TOO_SMALL_TOTAL_PRICEtotal_price, delivery_possible_overFor some restaurants delivery orders are not possible unless total order price is over certain sum.
NO_DELIVERY_METHODSgiven_methodThis restaurant does not have custom delivery methods. Please recheck your code handling delivery methods.
DELIVERY_METHOD_NOT_AVAILABLEgiven_methodMaybe times does not match or customer is too far away or something like that.
INVALID_DELIVERY_METHODgiven_methodPlease try to atleast insert valid data...
DELIVERY_PRICE_MISMATCHgiven_price, calculated_price, restaurant_idPrice you inserted as delivery fee does not match with the price system calculated from restaurant’s data. It is possible to ask customer if she asks this correct price and recalculate order’s data according this.
RESTAURANT_NOT_OPEN_ALTERNATIVEtimestampAt the time alternative delivery time customer has chosen the restaurant is closed.
RESTAURANT_NOT_OPENNoneRestaurant is not open for the moment. Please instruct customer to choose another restaurant or to use alternative delivery time.
EMPTY_FORENAMENonePlease ensure customer’s information is present in a form or another.
EMPTY_SURNAMENonePlease ensure customer’s information is present in a form or another.
EMPTY_PHONE_NUMBERNonePlease ensure customer’s information is present in a form or another.
EMPTY_DELIVERY_METHODNoneProblem in client. Please make sure customer chooses delivery method and submit the method with the data too.
DELIVERY_DATA_MISSINGNonePlease assure that name, email, method, price and address is present in delivery data.
USED_BONUS_WHEN_BONUS_PAYMENT_NOT_SPECIFIEDNoneProblem in client. You need to add bonus payment bit in payment if customer chose to use bonus.
USED_PO_CREDIT_WHEN_PO_CREDIT_PAYMENT_NOT_SPECIFIEDNoneProblem in client. You need to add PO-credit payment bit in payment if customer chose to use PO-credit.
TOO_MUCH_BONUS_USEDused_bonus, available_bonusCustomer doesn’t in the end have this much bonus available. Please tell her to lower her bonus usage.
TOO_MUCH_PO_CREDIT_USEDused_po_credit, available_po_creditCustomer doesn’t in the end have this much PO-credit available. Please tell her to lower her PO-credit usage.
BONUS_EXCEEDS_TOTAL_PRICEused_bonus, used_po_creditCreating an order that uses more PO-credit or bonus from customer than total price is not wise.
REALLY_INVALID_ALTERNATIVE_DELIVERY_TIMEalternative_delivery_timeAlternative delivery time must be atleast one hour to future and at most 7 days to future.
VALIDATION_RESTAURANT_ID_NOT_ALLOWEDNoneIn case client is not allowed to use this restaurant_id with this validation restaurant id. If you don’t know why you’re getting this, please contact the API maintainer.
INVALID_PARTNER_IDNoneNot int or not present in database or similar.
ADDED_INGREDIENT_COUNT_TOO_MUCHcount, maximum_allowedThere is limit of ingredients allowed in a single product.
LUNCH_TIME_SIDE_DISH_AT_NOT_LUNCH_TIMEside_dish, product_idWhen one is trying to use lunch time side dish at non-lunch-time, this error is thrown.
INVALID_ADDRESSNoneIn case address data is missing or invalid. Usually means order data validation in client side is failing.
NIGHT_TIME_FEE_DIFFERSgiven_fee, calculated_feeIf night time fee given differs from one passed. Check your input.
MULTIPLE_PAYMENT_METHODSNoneIn case client tried to specify more than one actual payment (cash + luottokunta for example), this is raised.
PAYMENT_COST_MISMATCHgiven_cost, actual_costIf you forgot to supply to cost or supplied wrong cost, this is raised.
PAYMENT_PERCENT_MISMATCHgiven_percent, actual_percentIf you forgot to supply to percent or supplied wrong percent, this is raised.
INVALID_DELIVERY_ADDRESScustomer_address, restaurant_addressIf the address given by customer is not valid, this is returned.
DELIVERY_DISTANCE_OUTSIDE_RANGEcustomer_address, restaurant_address, distanceIf customer is too far away from restaurant, this is thrown.
KLARNA_PAYMENT_REQUIRES_SSNNoneIn case of Klarna payment, social_security_number must be passed. This will be returned if it isn’t passed.
INVALID_SOCIAL_SECURITY_NUMBERNoneThe social_security_number passed is not in valid Finnish form.
KLARNA_PAYMENT_FAILEDcodeIn case we can’t access klarna payment, we throw this error. The error comes from Klarna’s service, so it’s adviced to show the error message to customer so customer can determine how to proceed.
KLARNA_ORDER_WITH_FETCHNoneIt is not allowed to do Klarna payment as takeaway order
USER_INFORMATION_MISSINGNoneforename, surname, email or phone number is missing.
INVALID_VOUCHER_TYPENoneIn case invalid voucher has been passed to order process
VOUCHER_USED_OUTSIDE_OF_VALID_TIMEidentifierIf trying to use voucher that’s not usable at given day or time, this is returned.
VOUCHER_USED_FOR_NON_NEW_CUSTOMERNoneIf trying to use voucher that’s only available for new customers.
VOUCHER_USED_OR_NOT_FOUNDNoneIf voucher is already used or voucher does not exist in our system
VOUCHER_USES_EXCEEDEDNoneIf voucher has already been used maximum times it’s allowed to be used.
NO_PAYMENT_METHODS_SETNoneHappens if zero is passed as payment method.
DISABLED_VARIANTvariant_idIf the variant can’t be ordered
TOKEN_ID_FOR_WRONG_PAYMENT_METHODNoneWhether you tried to pass token_id in payment_data for other payment methods than Solinor.
SOLINOR_TOKEN_ID_INVALIDNoneIf the token id you passed is not valid. You should instruct customer to add new card or try another payment method.
INVALID_PAYMENT_DATA_ARRAYNoneReturned when given payment_data array is invalid.
NO_VOUCHERS_GIVENNoneIn case there is voucher payment bit but no vouchers given
VOUCHERS_GIVENNoneIn case there is no voucher payment bit but vouchers was present
INGREDIENT_CHANGED_TO_UNCHANGEABLE_INGREDIENTproduct_id, new_ingredient_id, old_ingredient_idClient tried to change an ingredient to an ingredient that was not choosable.
USER_NEEDS_VERIFICATIONNoneIn some cases, a customer may require verification. Please see /account/verify for details.

Internal errors

These are something that should never happen, errors in the server and not in client, hopefully.

Label Additional data Description
ORDER_VALIDATION_FAILURENoneGeneric error that is thrown when there is validation failures. There should be other errors too; in case totally invalid data it should happen that only this is returned.
PRODUCT_OBJECT_NOT_FOUNDidTotally internal error, I guess. Please tell us about it if you see it, data you passed and the id that is passed along.
PRODUCT_INGREDIENT_MISSINGmissing_ingredient_idTotally internal error. If you see this, there is something really shady going on in the server.
PRODUCT_INGREDIENT_MISSING_FROM_PRODUCTextra_ingredient_idTotally internal error. If you see this, there is something really shady going on in the server.
INVALID_ADDABLE_INGREDIENTSNoneInternal server error. Please tell us about it.
INVALID_USER_OBJECTNoneProblem in server.
INVALID_RESTAURANTNoneSomething is failing quite well on the server. This is just sanity check for it... Totally internal.
INVALID_PRODUCT_IDgiven_product_idThis totally should never happen. If you see exactly this label, please contact to API maintainer.
RESTAURANT_DOES_NOT_KNOW_HOW_TO_MAKE_PIZZANoneIf restaurant can’t deliver fetch (takeaway) orders. Fetch orders are hardcoded for each restaurant so this won’t ever materialize (documented here only for completeness).
MALFORMED_DELIVERY_ADDRESS_STRINGNoneInternal. Means order has been saved incorrectly.
ORDER_SAVE_ERRORNoneThis is another of those errors that are just catching malfunctioned code. There should be other errors that tells what actually has happened.
RESTAURANT_BROKEN_BONUS_DATANoneRestaurant does not have bonus payment enabled. This kind of restaurants should never exist, this is ”just to be sure” -check
NO_PAYMENT_DATANoneJust a safeguard. There should be other errors that needs to be taken in account.
PAYMENT_USER_NOT_FOUNDNoneJust a safeguard. There should be other errors that needs to be taken in account.
PRODUCT_NOT_PRESENT_CATCHNoneJust a safeguard. There should be other errors that needs to be taken in account.
INVALID_PAYMENT_METHOD_IDNoneIn case input payment method id was invalid. If I’m correct, this should never been invoked.
VOUCHER_UPDATE_FAILEDNoneIn case something is wrong in our voucher data.
VOUCHER_GROUP_NOT_FOUNDNoneIf the voucher group is not found for the voucher.