Creating orders
This page will show you when and how to create orders
This page explains how to create orders by API and has the following sections:
- When to create an order
- Creating an out-of-pocket expense
- Creating a purchase order
- Creating a bank payout
- Updating an order
- Approving an order or payment
- Closing an order
Orders can also be managed manually from the orders section of our web app.
When to create an order
For card payments, we will usually create the order. You just have to display and edit these orders. How to do this is described in the previous tutorial.
There are a few situations in which you should create the order yourself:
- Bank payouts (mass payments)
- Out-of-pocket expenses that the employee paid themselves
- Recurring orders (subscriptions)
- Purchase Orders (POs) that were or need to be approved before the payment is made. This is irrespective of the payment method so POs paid on card also need to be created by you
Our orders are very flexible and these are just examples. If you want to create another type of order not listed here, please contact us.
Creating orders by CSV file
To avoid an API integration and go live faster, you can start by creating orders by CSV. Please contact us to set this up.
The rest of this tutorial will show you how to create and manage these orders by API if that is what you prefer to do.
Creating an out-of-pocket expense
We will start with the simplest case of creating an out-of-pocket expense. You can do so as follows:
curl {baseURL}/aggregate/orders
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"buyerId" : "your-trader-id",
"buyerUserId": "user-id",
"sellerId" : "EXPENSES",
"sellerOrderReference": "Taxi London",
"orderCurrency": "GBP",
"buyerTags": {
"orderType": "EXPENSE"
},
"events": [
{
"eventName": "Out-of-pocket expense",
"paymentType": "PAYMENT",
"pctToBePaid": 100,
"paymentDueDate": "2021-10-20"
}
],
"lineItems": [
{
"lineItemNumber": 1,
"type": "PRODUCT",
"name": "Expense",
"listPriceInCents": 1500,
"quantity": 1
}
]
}'
// Set up the order
Order newOrder = Order.builder().
buyerId("buyerId").
sellerId("sellerId").
orderCurrency("GBP").
orderAmountInCents(12222).
terms("30% upfront 70% before shipping").
build();
// Set up the API keys
RequestOptions requestOptions = RequestOptions.builder().
apiKey("buyerApiKey").
build();
// Create the order
try {
newOrder = Order.createAndApproveOrder(newOrder, buyerApiKey, sellerApiKey, requestOptions );
} catch(YordexException ex) {
// Handle the error
}
// Get the order ID and store it in your database
newOrderId = newOrder.getId();
Amount in cents
Amounts are always sent through in cents. In this example, the value of the order is £15.
We have two resources for orders: /orders which has only the order details and /aggregate/orders which also has line items, approvals and document details. We recommend you use /aggregate/orders in most situations, but you can use /orders
The buyerId, sellerId, orderCurrency, events and lineItems are mandatory. Within events and lineItems, all fields shown here are mandatory.
The sellerOrderReference and userId are not mandatory but strongly recommended. buyerTags are also not mandatory but they will make sure the order shows up on the "Expenses" tab of our web app.
The response will look as follows:
{
"id" : "order_id",
"buyerId" : "your-trader-id",
"buyerCompanyTradingName": "Your company name",
"buyerUserId": "user-id",
"buyerUserName": "John McIntyre",
"sellerId" : "EXPENSES",
"sellerOrderReference": "Taxi London",
"orderAmountInCents": 1500,
"orderCurrency": "GBP",
"orderCurrencyExponent": 2,
"buyerTags": {
"orderType": "EXPENSE"
},
"status": "NOT_APPROVED",
"creationDate": "2021-11-06",
"modificationDate": "2021-11-06",
"events": [
{
"id": "event-id",
"paymentDueDate": "2021-10-20",
"pctToBePaid": 100,
"eventName": "Out-of-pocket expense",
"eventNumber": 1,
"paymentType": "PAYMENT",
"amountToBePaidInCents": 1500,
"status": "NOT_STARTED
}
],
"lineItems": [
{
"id": "lineitem-id",
"lineItemNumber": 1,
"type": "PRODUCT",
"name": "Expense",
"listPriceInCents": 1500,
"quantity": 1,
"lineItemAmountInCents": 1500
}
]
}
Let’s break this down.
The first part of the response is similar to the request:
"id" : "order_id",
"buyerId" : "your-trader-id",
"buyerCompanyTradingName": "Your company name",
"buyerUserId": "user-id",
"buyerUserName": "John McIntyre",
"sellerId" : "EXPENSES",
"sellerOrderReference": "Taxi London",
"orderAmountInCents": 1500,
"orderCurrency": "GBP",
"orderCurrencyExponent": 2,
"buyerTags": {
"orderType": "EXPENSE"
}
The only fields we have added are an id, your company name, the user's name and a currency exponent.
The id was generated by us. The currency exponent indicates how many numbers at the end are reserved for cents. For GBP and most other currencies, 2 numbers are reserved for cents. Some currencies have 0, 1 or 3 numbers. You will find a full list of supported currencies and their exponents here
The second part of the response contains some housekeeping information about the order: the order status and the dates at which this order was created and modified.
"status": "NOT_APPROVED",
"creationDate": "2021-11-06",
"modificationDate": "2021-11-06",
New orders will always have the status “NOT_APPROVED”. The approving an order section explains how to approve this order.
The third part of the response is the events array. What events are is explained here.
"events": [
{
"id": "event-id",
"paymentDueDate": "2021-10-20",
"pctToBePaid": 100,
"eventName": "Out-of-pocket expense",
"eventNumber": 1,
"paymentType": "PAYMENT",
"amountToBePaidInCents": 1500,
"status": "NOT_STARTED
}
],
We have added the id, eventNumber, amountToBePaidInCents and status fields.
The amountToBePaidInCents is calculated by us based on the line items. The status is always NOT_STARTED after creating an order.
Most orders will only have one event. Only recurring orders and orders with multiple partial payments will have more than one event.
The last part of the response are the line items:
"lineItems": [
{
"id": "lineitem-id",
"type": "PRODUCT",
"name": "Expense",
"listPriceInCents": 1500,
"quantity": 1,
"lineItemAmountInCents": 1500
}
]
We have added the id and lineItemAmountInCents fields.
The lineItemAmountInCents is calculated by us based on the listPriceInCents, quantity, vat and discount, the latter two only if provided.
Creating a purchase order
Purchase Orders (POs) can be created almost exactly like out-of-pocket expenses. Orders offer some options that you will probably only need for POs and not for expenses:
- Defining the seller
- Defining a PO number
- Setting payment terms
- Indicating a PO should be paid on card (see further below)
You can create a PO like this:
curl {baseURL}/aggregate/orders
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"sellerId" : "seller-trader-id",
"buyerOrderReference" : "your-PO-number",
"terms":"Name of terms"
... // all other fields required to create an order
}'
To create a PO, you first need to create a seller. This tutorial explains how to do that.
You can set your own PO number in the buyerOrderReference field. If you do not provide this field, we will create a unique PO number for you.
Terms can be defined on the terms page of our web app. You should use the "Name of terms" field as shown on that page in this API call.
Terms replace the events so if you provide terms you no longer need to provide events. The only exception is if you want to set a paymentDueDate as well as terms. You can do that like this:
curl {baseURL}/aggregate/orders
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"terms":"Name of terms"
"events": [
{
"paymentDueDate": "2021-10-20",
"eventNumber": 1
}
],
... // all other fields required to create an order
}'
To indicate an order should be paid on card, you should add the YORDEX_CARD service when creating the order:
curl {baseURL}/aggregate/orders
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"services": [
{
"serviceName": "YORDEX_CARD"
}
],
... // all other fields required to create an order
}'
In this example, a one-off virtual card will be created once the order is approved.
To associate an already existing card with the PO, you should create the order like this:
curl {baseURL}/aggregate/orders
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"services": [
{
"serviceName": "YORDEX_CARD",
"tags": {
"cardId": ":card-id"
}
}
],
... // all other fields required to create an order
}'
Creating a bank payout
As part of our regulatory requirements we need to ensure that bank payouts instructions (ACH, SEPA or Faster Payments instructions) come from end users authorised by the customer to make payouts. To be able do that, we need to manage the session. App APIs can therefore not be used for bank payouts.
If you want to also offer payouts, you will have to either:
- Use the Yordex web app or
- Have a direct relation with one of the Yordex bank providers and use Yordex as a platform only
Updating an order
It is only possible to update orders that that are in the NOT_APPROVED status. If your order was already approved and you want to change it, you should amend it first like this:
curl {baseURL}/orders/:order-id/amend
-H "Authorization:your-api-key"
-X POST
The following fields can be updated:
curl {baseURL}/orders/:order-id
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X PUT
-d '{
"description": "My first order",
"orderCurrency": "USD",
"buyerOrderReference":"PO number",
"terms": "30% upfront 70% before shipping"
}'
Order updatedOrder = Order.builder().
orderCurrency("GBP").
orderAmountInCents(12222).
buyerOrderReference("buyerReference").
sellerOrderReference("sellerOrderReference").
description("First Order").
terms("30% upfront 70% before shipping").
build();
RequestOptions requestOptions = RequestOptions.builder().apiKey("apiKey").build();
updatedOrder = Order.update(updatedOrder, requestOptions);
Specify all fields
We are using a PUT to update the order. This means that fields that are not specified will be set to null. For example, if your order was created with a description but you do not provide that description in this API call, the description field will be set to null.
Many of these fields can also be updated one-by-one as described here
You can only update *terms when the order has no events. When the order already has events, you have to delete the existing events first.
You cannot update the buyerId or sellerId of the order. You should create a new order and close the old order if you want to change them.
Approving an order or payment
Once created, an order is always NOT_APPROVED. You can approve an order like this:
curl{baseURL}/orders/:order-id/approvals
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
-d '{
"approved" : true
}'
After this, the order will have the status APPROVED.
Normally the status of the first event will be PAYMENT_DUE. In the creating a purchase order section we explained how to create events that require confirmation before it can be paid. If an event requires confirmation the status will be FOR_CONFIRMATION.
You can confirm an event like this:
curl{baseURL}/orders/:order-id/events/:event-id/confirmations
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
After this, the event will have the status PAYMENT_DUE.
It is possible to have multiple people approve orders or events using your own custom approvals rules. Please contact us to set up your approval rules.
If you have set up approval rules for orders or events, an internalApproval object will be returned:
"internalApproval": {
"approvers": [
{
"userId": "[email protected]",
"approverNumber": 1,
"userName": "Frank Underwood"
}
],
"nextApproverUserId": "[email protected]",
"approved": false
}
For orders, this will be included at the top level and for events this will be included in the event itself.
This is how to approve an order or confirm an event on behalf of the next approver:
curl{baseURL}/internalapprovals/approvals?orderId=order-id
-H "Authorization:your-api-key"
-H "Content-type: application/json"
-X POST
'{
"userId": "[email protected]",
"approved": true
}'
To confirm an event, you should provide an eventId instead.
If there are multiple approvers, sending "approved":false will reject the order or event and send it back to the owner of the order, the one linked to the buyerUserId.
Closing an order
Orders that you know won’t complete anymore should be closed. Closing an order can be done as follows:
curl {baseURL}/orders/order-id/close
-H "Authorization:your-api-key"
-X POST
If you have closed an order by accident, or if the negotiations re-opened and you do want to continue with the order, you can re-open the order again:
curl {baseURL}/orders/order-id/open
-H "Authorization:your-api-key"
-X POST
No information will be lost when closing an order and then re-opening it again. You can pick up where you had left off.
Updated about 1 year ago