Maypay APIs - OpenAPI 3.0 (1.0.0)
Download OpenAPI specification:Download
Welcome to the Maypay APIs documentation.
Here you can find all the details on how to get access, input parameters and expected results for each individual API exposed by the Maypay service.
Before proceeding to the details of each API, we strongly recommend you read the Authorization section in order to implement the correct API access algorithm
Access to the APIs service is protected by an authorisation mechanism based on an API Key. Every merchant wishing to integrate their e-commerce with Maypay must first obtain their own API Key, that consists of a private part that must remain secret and a public part.
To be authorised, the request must contain the following headers:
Authorization
:MAYPAY <public_key>:<digest>;
(mind the semicolon)x-maypay-req-id
: random UUID as request identifier.Date
: Date string based on rfc7231 date format, to ensure request freshness.How to build Authorization header
As can be seen above, the header consists of 3 distinct fields:- MAYPAY: fixed string
- public_key: the public part of the API Key
- digest: digitally signed payload of the request using the private part of the API Key
The payload of the request must be a string having the following structure:
<http_method> <url>
<date>
<x-maypay-req-id>
<content-type> (optional)
<json_serialized_body> (optional)
Here are 2 examples of payloads of a post and a get requests:
POST https://europe-west1-maypay-app.cloudfunctions.net/cancelMerchantPaymentRequest
Mon, 20 Mar 2023 08:34:32 GMT
72f9a80a-5a2c-4200-b719-24399d6f3965
application/json
{"merchantPaymentRequestId":"jA6EqoCld0lYMc55o1gw"}
GET https://europe-west1-maypay-app.cloudfunctions.net/getMerchantPaymentRequest?merchantPaymentRequestId=jA6EqoCld0lYMc55o1gw
Mon, 20 Mar 2023 08:33:51 GMT
dac7b351-c861-49b9-8a55-770608b075e9
After building the string representing the request payload, the digest is obtained by creating a Base64-encoded hash of the payload using the HMAC SHA1 algorithm with the private part of the API Key as secrete key.
Below is an implementation example in NodeJs of how to build headers to access APIs.
const crypto = require("crypto");
const maypayAPIRequest = async (
method,
url,
contentType,
data,
publicKey,
privateKey
) => {
try {
let payload, body;
const headers = {
"X-MAYPAY-Req-ID": crypto.randomUUID(),
Date: new Date().toUTCString(),
};
payload = `${method} ${url}\n${headers["Date"]}\n${headers["X-MAYPAY-Req-ID"]}`;
if (contentType === "application/json") {
headers["Content-Type"] = contentType;
payload += `\n${headers["Content-Type"]}`;
if (data) {
body = JSON.stringify(data)
payload += `\n${body}`;
}
}
const hm = crypto.createHmac("sha1", privateKey);
hm.update(payload);
headers["Authorization"] = `MAYPAY ${publicKey}:${hm.digest().toString("base64")};`;
const apiResponse = await fetch(url, {
method,
headers,
body,
});
const json = await apiResponse.json();
return json;
} catch (error) {
console.log("fetch error", error);
}
};
How to handle Webhook responses
When creating the payment request, you must provide a callback URL that will act as an endpoint for the communication of the outcome of the transaction.
To ensure security for this communication as well, the request from our servers uses the same authentication mechanism described above.
When the webhook is triggered, you can authenticate the packet by comparing the signature contained in the x-maypay-digest header and the signature created from the packet. The HMAC signature is created using the same API key with which the payment request was created.
Below is an example of how to verify that the signature was created from the same private key written in NodeJS. The req object has the same properties as the Express request object.
const authenticateWebhookResult = (req, privateKey) => {
try {
const authorization = req.header("x-maypay-digest");
const date = req.header("date");
const contentType = req.header("content-type");
const xMaypayReqId = req.header("x-maypay-req-id");
const reg =
/^MAYPAY\s(maypay_pk_(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})):((?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4}));$/;
let auth = authorization || "";
auth = auth.trim();
const check = auth.match(reg);
if (!check || check.length <= 2) {
throw { message: "Invalid Authorization header", code: 401 };
}
const pk = check[1];
const digest = check[2];
if (!pk || !digest) {
throw { message: "Missing public key or digest", code: 401 };
}
const requestDate = new Date(date).getTime();
const actualDate = Date.now();
// Request Freshness
if (actualDate - requestDate > 5 * 60 * 1000 /* max 5 minutes old*/) {
throw { message: "Timeout", code: 410 /* GONE */ };
}
const hm = crypto.createHmac("sha1", privateKey);
const fullUrl = `${req.headers["x-forwarded-proto"]}://${req.headers.host}${req.url}`;
let payload = `${req.method} ${fullUrl}\n${date}\n${xMaypayReqId}`;
payload += "\n" + contentType + "\n" + JSON.stringify(req.body);
hm.update(payload);
const compareDigest = hm.digest().toString("base64");
if (compareDigest !== digest) {
throw {
message: "Invalid digest. Received payload: " + payload,
code: 401,
};
}
console.log("Authorized");
return true;
} catch (error) {
console.error(error);
return false;
}
};
A payment request represents the willingness of an e-commerce to initiate a payment procedure over the Maypay service.
APIs offer the possibility of:
- Create a new payment request
- Cancel an existing and pending one
- Get the data of a request
Flows
When creating a request you can use one of the following flows:
Flow | Use case | Payment Flow | Create API core parameter | Capture Method |
---|---|---|---|---|
Web Button | Online - Web Button | One-off - Web Button | buyerFlowType buyerPhoneNumber (optional) |
IMMEDIATE |
Mobile app | Mobile app - Android SDK / Mobile app - iOS SDK | One-off - Mobile app | redirectUrl |
IMMEDIATE |
Funds Lock - Web button | - | Funds Lock - Web Button | buyerFlowType buyerPhoneNumber (optional) estimatedAmount (optional) |
MANUAL |
Funds Lock - Mobile app | - | Funds Lock - Web Button | redirectUrl estimatedAmount (optional) |
MANUAL |
Create
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
payment request generated after a checkout
amount required | integer [ 100 .. 50000 ] Payment amount expressed in cents, i.e. 2.99€ => amount = 299 |
currency required | string ISO 4217 code of payment currency. At the moment the only supported currency is "EUR" |
buyerFlowType required | string Enum: "phone" "qr" "all" Mode of interaction to be shown to the user during payment.
|
buyerPhoneNumber | string Buyer's E.164 format Phone Number. Maypay can use this optional field to pre-fill the number in case the need arises. |
orderId required | string e-commerce internal order ID |
callbackUrl required | string endpoint used by Maypay to provide payment results. It must be a valid https URL. |
storeId required | string Maypay store ID |
timeout | integer [ 1 .. 60 ] Default: 5 minutes after which payment is treated as expired |
metadata required | object ecommerce data for internal use |
captureMethod | string Default: "IMMEDIATE" Enum: "IMMEDIATE" "MANUAL" It indicates whether the payment is one-off ( |
estimatedAmount | integer [ 100 .. 50000 ] Estimated payment amount expressed in cents, i.e. 2.99€ => 299. It can be used only when |
redirectUrl | string universal link (iOS), app link (Android) of eCommerce application or eCommerce website https url. Used to come back on eCommerce app/website after paying with Maypay app. |
Responses
Request samples
- Payload
{- "amount": 299,
- "currency": "EUR",
- "buyerFlowType": "phone",
- "buyerPhoneNumber": "+393001112222",
- "orderId": "orderId",
- "storeId": "storeId",
- "timeout": 10,
- "metadata": { },
- "captureMethod": "IMMEDIATE",
- "estimatedAmount": 299,
}
Response samples
- 201
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": {
- "merchantPaymentRequestId": "jA6EqoCld0lYMc55o1gw",
- "amount": 299,
- "capturedAmount": 299,
- "currency": "EUR",
- "buyerPhoneNumber": "+393001112222",
- "buyerFlowType": "phone",
- "orderId": "orderId",
- "callbackResponse": {
- "body": { },
- "status": 0,
- "error": "string"
}, - "xMaypayReqId": "xMaypayReqId",
- "merchantId": "merchantId",
- "storeId": "storeId",
- "storeName": "Test Store",
- "createdAt": 1678880363344,
- "expirationTime": 1678880663344,
- "metadata": { },
- "state": "PAYED",
- "transactionId": "transactionId",
- "isWinningTransaction": true,
- "captureMethod": "IMMEDIATE",
- "estimatedAmount": 299,
- "isSandbox": false,
- "apiKeyId": "apiKeyId"
}
}
Cancel
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
merchant payment request ID
merchantPaymentRequestId | string ID of the payment request to be cancelled |
Responses
Request samples
- Payload
{- "merchantPaymentRequestId": "string"
}
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
- 412
{- "success": true,
- "error": null,
- "data": {
- "merchantPaymentRequestId": "merchantPaymentRequestId",
- "state": "CANCELLED_BY_MERCHANT"
}
}
Get
Authorizations:
query Parameters
merchantPaymentRequestId required | string Example: merchantPaymentRequestId=merchantPaymentId ID of merchant payment request to be fetched |
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Responses
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": {
- "merchantPaymentRequest": {
- "id": "paymentRequestId",
- "amount": 299,
- "capturedAmount": 299,
- "currency": "EUR",
- "buyerPhoneNumber": "+393001112222",
- "buyerFlowType": "phone",
- "orderId": "orderId",
- "callbackResponse": {
- "body": { },
- "status": 0,
- "error": "string"
}, - "xMaypayReqId": "xMaypayReqId",
- "merchantId": "merchantId",
- "storeId": "storeId",
- "storeName": "Test Store",
- "createdAt": 1678880363344,
- "expirationTime": 1678880663344,
- "metadata": { },
- "state": "PAYED",
- "transactionId": "transactionId",
- "isWinningTransaction": true,
- "captureMethod": "IMMEDIATE",
- "estimatedAmount": 299,
- "isSandbox": false,
- "apiKeyId": "apiKeyId"
}
}
}
Capture
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
merchantPaymentRequestId required | string ID of the payment request to be captured |
amount required | integer [ 100 .. 50000 ] The amount to capture from the pre-authorized amount, which must be less than or equal to the original amount. It is expressed in cents, i.e. 2.99€ => 299 |
metadata | object ecommerce data for internal use |
Responses
Request samples
- Payload
{- "merchantPaymentRequestId": "merchantPaymentRequestId",
- "amount": 299,
- "metadata": { }
}
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
{- "success": true,
- "error": null,
- "data": {
- "merchantPaymentRequest": {
- "metadata": { },
- "state": "PAYED",
- "isWinningTransaction": true
}
}
}
Create Refund
This api creates a Refund Request object by passing a paymentRequestId
or transactionId
passed in request body. At least one of these must be specified in the request. Valid values states for refund are REFUNDED
, WAITING_REFUND
, REFUND_FAILED
. The refundedFailureReason response field is returned only if state is REFUND_FAILED
.
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
transactionId | string ID of the transaction to be refunded |
paymentRequestId | string ID of the payment request to be refunded |
amount required | integer [ 100 .. 50000 ] Amount to be refunded, which must be less than or equal to the original amount. It is expressed in cents, i.e. 2.99€ => 299 |
Responses
Request samples
- Payload
{- "transactionId": "transactionId",
- "paymentRequestId": "paymentRequestId",
- "amount": 299
}
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
- 500
{- "success": true,
- "error": null,
- "data": {
- "state": "REFUNDED",
- "refundedAt": 1688540497025,
- "refundedAmount": 299,
- "refundedFailureReason": "expired_or_canceled_card"
}
}
Get Refund
This api returns a Refund Request object by its paymentRequestId
or transactionId
passed in query parameters. At least one of these must be specified in the request. Valid values states for refund are REFUNDED
, WAITING_REFUND
, REFUND_FAILED
. The refundedFailureReason response field is returned only if state is REFUND_FAILED
.
Authorizations:
query Parameters
paymentRequestId | string Example: paymentRequestId=paymentRequestId ID of merchant payment request to be refunded |
transactionId | string Example: transactionId=transactionId ID of transaction to be refunded |
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Responses
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
- 500
{- "success": true,
- "error": null,
- "data": {
- "state": "REFUNDED",
- "refundedAt": 1688540497025,
- "refundedAmount": 299,
- "refundedFailureReason": "expired_or_canceled_card"
}
}
A Store represents a point of sale of a merchant. The API makes it possible to get information on one or more of a merchant's stores.
getStoreList API does not require any additional input parameters, as the API Key uniquely identifies a merchant or his specific store. Depending on the type of API Key used, the results vary as follows:
- API Key associated with a merchant: list of stores belonging to the merchant with that specific merchantId and meeting the search parameters.
- API Key associated with a store: list containing the data of the individual store
Get a store list
Authorizations:
query Parameters
limit | integer [ 1 .. 25 ] Default: 10 Example: limit=5 Maximum number of stores to be fetched |
match | string Example: match=Apple it can be used to search by store name, postal code or city |
starAfter | string Example: starAfter=lastStoreId ID of the last store fetched. It is used to move forward in the pagination of results |
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Responses
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": [
- {
- "store_id": "storeId",
- "store_name": "Apple Store",
- "store_address": "Via Roma",
- "store_address_number": "21B",
- "store_cap": "00010",
- "store_city": "Roma",
- "store_state": "IT",
- "store_category": "Ristorante",
- "deleted": false,
- "deletedAt": null,
- "enabled": true,
- "userId": "merchantId"
}
]
}
Get Pending Payment Requests
Authorizations:
query Parameters
storeId | string Example: storeId=storeId Search for pending transactions only of the shop identified by storeId |
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Responses
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": [
- {
- "store_id": "storeId",
- "store_name": "Apple Store",
- "transactions": [
- {
- "amount": 2.99,
- "transactionId": "transactionID",
- "buyerName": "John W.",
- "buyerProfilePic": "www.buyerProfilePic.com/J.Wick"
}
]
}
]
}
Accept Payment request
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
transactionId required | string ID of the payment request to be accepted |
Responses
Request samples
- Payload
{- "transactionId": "transactionId"
}
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": {
- "transactionId": "transactionId",
- "state": "COMPLETED_WITH_LOSS"
}
}
Refuse Payment request
Authorizations:
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Request Body schema: application/json
transactionId required | string ID of the transaction to be refused |
Responses
Request samples
- Payload
{- "transactionId": "transactionId"
}
Response samples
- 200
- 400
- 401
- 403
- 404
- 409
- 410
{- "success": true,
- "error": null,
- "data": {
- "transactionId": "transactionId",
- "state": "COMPLETED_WITH_LOSS"
}
}
Get Transactions
This API returns an array of transactions based on input parameters:
transactionId
: returns the transaction with the given idstoreId
: used to filter by store in the previous querystartTime
,startAfter
,limit
: see description below- no parameters: the merchant's last 10 transactions
Authorizations:
query Parameters
transactionId | string Example: transactionId=transactionId Id of the transaction to be retrieved. The response still contains an array containing a single transaction |
storeId | string Example: storeId=storeId filter transactions by storeId |
startTime | integer Example: startTime=1697100695075 Unix Timestamp in milliseconds. This parameter allows searching for transactions with an equal or more recent |
startAfter | integer Example: startAfter=transactionId ID of the transaction to be used for paging. The results depend on the use of
|
limit | integer [ 1 .. 25 ] Default: 10 Example: limit=5 Maximum number of transactions to be fetched |
header Parameters
x-maypay-req-id required | string Unique id of the request |
date required | string Date string based on rfc7231 date format, i.e. 'Sun, 06 Nov 1994 08:49:37 GMT' |
Responses
Response samples
- 200
- 400
- 401
- 403
- 404
{- "success": true,
- "error": null,
- "data": [
- {
- "amount": 2.99,
- "transactionId": "transactionId",
- "storeId": "storeId",
- "storeName": "StoreName",
- "merchantId": "merchandId",
- "endTime": 1697100695075,
- "state": "COMPLETE_WITH_WINNINGS",
- "buyerName": "John W.",
- "buyerProfilePic": "www.buyerProfilePic.com/J.Wick"
}
]
}