Order Management
- How to confirm an orderline?
- How to mark an orderline as shipped?
- How to upload an invoice to an orderline?
- How to cancel an orderline?
- How to handle returns?
- How to upload a credit-note?
- How to upload a return-label?
- How to download documents?
1. How to confirm an orderline?
Once you have the information of the order, you need to confirm it.
For that you can send a POST
request to /openapi/v2/order-lines/{orderLineId}/confirm
using the orderLineId
that you have received previously in the GET /openapi/v2/orders/{orderId} request.
Example:
https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/a861342f-17aa-43c4-a322-d149ee83ce68/confirm
Response is an http status code 204
with empty body.
2. How to mark an orderline as shipped?
Once you have confirmed the orderline, you can send us its ship information using PUT /openapi/v2/order-lines/{orderLineId}/ship
.
The structure of the body is:
{
"trackings": [
{
"trackingId": "string",
"carrier": "string",
"customCarrier": "string"
}
]
}
trackingId
is the tracking number and needs to be provided if carrier or customCarrier is provided.carrier
is the carrierid
defined in our dictionary. If customCarrier is provided, carrier doens´t need to be provided.customCarrier
: if you don´t find a carrier in our dictionary, you can provide another carrier name. If carrier is provided, customCarrier doesn´t need to be provided. This needs to be used only if carrier is not reflected in the carrier dictionary.
Example of orderline being delivered by the Deutsche Post specifying trackingnumber:
Endpoint: PUT https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/125ec5c4-c267-4210-ba27-31e746eaa29e/ship
Body:
{
"trackings": [
{
"trackingId": "123456",
"carrier": "deutsche_post"
}
]
}
More than one carrier
and trackingId
can be delivered in the same request.
Example:
{
"trackings": [
{
"trackingId": "123456",
"carrier": "dhl"
},
{
"trackingId": "78910",
"carrier": "ups"
}
]
}
Response is http status code 204
with empty body.
Get a full list of delivery carriers
To get a full list of provided carriers you need to use GET /openapi/v2/dictionary/delivery-carrier
.
This list is updated on regulary basis, we let you know when you need to update it as well on your end.
Please use the id
delivered in the response to indicate us the carrier in the ship request.
3. How to upload an invoice to an orderline?
Once you have confirmed the order you can attach the invoice to the orderline with POST /openapi/v2/order-lines/{orderLineId}/invoice
.
You can also attach the invoice once you have shipped the order.
The invoice needs to be attached per orderline
, however you can generate only one invoice
and upload it for all orderlines
which are inside an orderId
.
The file needs to be defined as “invoice” (not as a file). The type needs to be .pdf and not bigger than 2MB.
For generating the invoice, please have a look at the Seller Support FAQs - Order Management - Upload and content of customer invoices.
Request example: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/125ec5c4-c267-4210-ba27-31e746eaa29e/invoice
Response is http status code 200
with the following body:
{
"fileStorageId": "38b89efa-73fd-453b-b816-33bcd856e6f7"
}
Code example in php:
<?php
namespace OrderManagement\Order\Presentation\Console;
use OrderManagement\Common\Infrastructure\Service\Logger\SymfonyStyleAdapterFactory;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class TestDocumentAttachmentCommand extends Command
{
protected static $defaultName = 'test-file-upload';
private $loggerFactory;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var HttpClientInterface
*/
private $httpClient;
public function __construct(SymfonyStyleAdapterFactory $loggerFactory, HttpClientInterface $httpClient)
{
parent::__construct();
$this->loggerFactory = $loggerFactory;
$this->httpClient = $httpClient;
}
protected function configure()
{
$this->setDescription('test');
}
public function execute(InputInterface $input, OutputInterface $output):
int
{
$io = new SymfonyStyle($input, $output);
$this->logger = $this
->loggerFactory
->create($io);
$clientKey = '46f889d4-61db-4c41-bb29-8f4241c636af';
$secretKey = '180f9031edee9a73788c9c6a6a77cc65';
$method = 'POST';
$url = 'https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/443cb785-70a6-4730-a7dc-cacd02748576/invoice';
$time = time();
$fileName = 'sample-3kb.pdf';
$path = '/var/www/service/var/';
$boundary = uniqid();
$delimiter = '----' . $boundary;
$body = $this->buildDataFiles($boundary, 'invoice', $fileName, file_get_contents($path . $fileName));
$response = $this
->httpClient
->request($method, $url, ['headers' => ['Accept-Language' => 'en', 'Accept' => 'application/json', 'Content-Type' => 'multipart/form-data; boundary=' . $delimiter, 'X-Client-Id' => $clientKey, 'X-Timestamp' => $time, 'X-Signature' => $this->createSignature($method, $url, '', $time, $secretKey) , ], 'body' => $body]);
//$response->getStatusCode() - 200 OK
//$response->getContent() - {"fileStorageId":"d591a25a-cb7c-49d9-9eac-7477fa0d94af"}
}
private function createSignature($method, $uri, $body, $timestamp, $secretKey)
{
$string = implode("\n", [$method, $uri, $body, $timestamp, ]);
return hash_hmac('sha256', $string, $secretKey);
}
private function buildDataFiles($boundary, $name, $fileName, $content)
{
$data = '';
$eol = "\r\n";
$delimiter = '----' . $boundary;
$data .= "--" . $delimiter . $eol . 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $fileName . '"' . $eol . 'Content-Type: application/pdf' . $eol . 'Content-Transfer-Encoding: binary' . $eol;
$data .= $eol;
$data .= $content . $eol;
$data .= "--" . $delimiter . "--" . $eol;
return $data;
}
}
Body of this code:
b"""
------6051f71a07298\r\n
Content-Disposition: form-data; name="invoice"; filename="sample-3kb.pdf"\r\n
Content-Type: application/pdf\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
%PDF-1.3\r\n
%âãÏÓ\r\n
\r\n
1 0 obj\r\n
(other part of pdf file)\r\n
------6051f71a07298--\r\n
"""
4. How to cancel an orderline?
You can cancel an orderline when its status is placed or confirmed.
You can do it with POST /openapi/v2/order-lines/{orderLineId}/cancel
and indicating in the body a cancellationReason
value which you get from this cancellation reason dictionary.
Example of a request to cancel an orderline line because there is no inventory:
Endpoint: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/b488cb4f-ba13-4269-b5fc-2356af29b9bb/cancel
Body:
{
"cancellationReason": 2
}
How to get all possible values of cancellation reasons?
You can send a GET /openapi/v2/dictionary/cancellation-reason request
.
Request example:
https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/dictionary/cancellation-reason
Snippet response:
[
{
"value": 1,
"title": "No inventory"
},
{
"value": 2,
"title": "Wrong price"
},
.......
]
Response is http status code 204
with empty body
5. How to handle returns?
When a buyer requests a return you will get this information sending the GET /openapi/v2/orders/{orderId}
where you will see the orderlineId
with status": "return_requested"
and returnReason[].
"orderLines": [
{
"orderLineId": "125ec5c4-c267-4210-ba27-31e746eaa29e",
.........
"status": "return_requested",
..........
"returnReason": {
"value": 3,
"title": "It does not work"
},
.......
Accept return
After receiving product back and checking its state, you can accept this return request using POST /openapi/v2/order-lines/{orderLineId}/accept-return
. Accept of return will trigger refund process.
Example:
Request endpoint: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/125ec5c4-c267-4210-ba27-31e746eaa29e/accept-return
Body:
{
"resolution": "We apologize for the inconvenience.",
"quantity": 2
}
quantity
is used for partial returns and is optional. For more information see splits here.
In case of total return the response is http status code 204
with empty body and the orderLineId
get "status": "return_accepted"
.
In case of partial return (quantity
is used) the response is http status code 201
the body contains the new splitOrderLineId
which gets "status": "return_accepted"
.
{
"splitOrderLineId": "e6495796-59ec-4e7f-9535-eb7e904cee48"
}
Decline return
You can decline this return request using POST /openapi/v2/order-lines/{orderLineId}/decline-return
.
Example
Request endpoint: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/471d0784-d62f-4de9-a75b-82df39e2d589/decline-return
Body:
{
"resolution": "We can't refund items that have been used.",
"quantity": 2
}
quantity
is used for partial returns and is optional. For more information see splits here.
In case of total return the response is http status code 204
with empty body and the orderLineId
get "status": "return_declined"
.
In case of partial return (quantity
is used) the response is http status code 201
the body contains the new splitOrderLineId
which gets "status": "return_declined"
.
{
"splitOrderLineId": "e6495796-59ec-4e7f-9535-eb7e904cee48"
}
Mark order as returned
In case you as a seller want to set the status return
of an item, without the buyer having previously requested it, you can use POST /openapi/v2/order-lines/{orderLineId}/mark-returned
Example: the carrier has sent you back the parcel because buyer couldn´t receive it.
Request endpoint: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/8547b489-c77e-4e0d-b86f-cccdee1e7b42/mark-returned
Body:
{
"resolution": "Wrong address",
"quantity": 3
}
quantity
is used for partial returns and is optional. For more information see splits here.
In case of total return the response is http status code 204
with empty body and the orderLineId
get "status": "return_accepted"
.
In case of partial return (quantity
is used) the response is http status code 201
the body contains the new splitOrderLineId
which gets "status": "return_accepted"
.
{
"splitOrderLineId": "e6495796-59ec-4e7f-9535-eb7e904cee48"
}
Return reasons
Using GET /openapi/v2/dictionary/return-reason
you will get a full list of the return reasons (title
) that the buyer can enter and its value
.
Example:
https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/dictionary/return-reason
Snippet response:
[
{
"value": 1,
"title": "Have changed my mind"
},
{
"value": 2,
"title": "Delayed delivery"
},
{
"value": 3,
"title": "It does not work"
},
....
]
6. How to upload a credit note?
Credit-notes can be attached in case of refunds. Refund could be issued after product is Shipped partially as a discount, or for full amount in case of return. Once refund is executed, “refunds” property within “orderLines” is populated with refund details.
If the status of the orderlineId
is shipped
, return_requested
, return_accepted
or return_declined
you can attach a credit note with with POST /openapi/v2/order-lines/{orderLineId}/credit-note
.
The file needs to be defined as “creditNote” (not as a file). The type needs to be .pdf and not bigger than 2MB.
Request example: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/b0f12520-9b6d-46ed-b98a-9da93703c168/credit-note
Response:
{
"fileStorageId": "1e15523f-5c3d-4d72-a184-1f761b74ce28"
}
7. How to upload a return label?
When the return is requested (status: return_requested
), you can upload a returnLabel
to that orderline.
The file needs to be defined as “returnLabel” (not as a file). The type needs to be .pdf and not bigger than 2MB.
Request example: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/order-lines/83ce966c-3d85-4a7e-8f5e-3674fcba1ef1/return-label
Response:
{
"fileStorageId": "2b34523f-5c3d-4d72-a184-1f761b74ab28"
}
8. How to download documents?
If you would like to download any document (invoice, credit-note, return-label), you can use POST /openapi/v2/documents/{documentId}/links
which creates a temporary signed url for downlading the document.
You just need to provide the documentId
that can be found in:
fileStorageId
given in our response in the previous api call when you sent us that document OR- In the response of the get the order details (
orderLines/documents/id
)
Request example: https://app-order-management.sandbox.infra.metro-markets.cloud/openapi/v2/documents/b442d353-0df1-44fb-910a-1d5af233fed4/links
Response:
{
"documentId": "b442d353-0df1-44fb-910a-1d5af233fed4",
"downloadUrl": "https://storage.googleapis.com/service-file-documents-bucket-sandbox/invoice/b442d353-0df1-44fb-910a-1d5af233fed4?GoogleAccessId=app-bucket-connector%40metro-markets-dev.iam.gserviceaccount.com&Expires=1620998349&Signature=kKRWxyGwKYqkZ%2BbKxgAYEr6sXxQ%2B0%2FrxLU7Na8xL7HNUj6whkk42N6k30VsyOwfPp3cGPHL%2F88UH5L2FXecCSOEIli63gQUG5n2Jvi7jcTyftwh4i22LStC3uFVgztdvirD%2Bj4iwOkysS6UaCHcdVdTOgz3ZgpxWub5LltVGx%2Be6OC3KWpCqhXJY1BXFxZtHilSgLE2QeDK%2FpdhriqrwMoeq0kBzoTdMASRyZLxYtJnuY32u2rCSmZm6SY7bP9eKX1F1pTuLYvnwkhijWL7tXmVqSyHNpJqs5w2%2F1RMmQaNtC%2FTGrKUpfxHs1X0edHjbxMaixgQ%2BRbXhgElXT4e3fA%3D%3D"
}