Skip to main content

Receive payments with Mavis Pay

Overview

This guide describes how to integrate Mavis Pay into your project. The integration process consists of the following steps:

  1. Send a payment request to the Mavis Pay API.
  2. Set up a webhook URL to receive real-time updates whenever a payment status changes.
  3. Verify the authenticity of incoming webhooks.

Prerequisites

  • API key for request authentication. To get your API key, create and set up an app in the Developer Console.
  • Access to the Mavis Pay service. To request, speak to your Sky Mavis point of contact.

Base URLs

Both private and public API hosts are available. The private API calls require your API key, while the public calls do not.

EnvironmentCall typeHost
ProductionPrivate (requires API key)https://api-gateway.skymavis.com/mavispay/v1
ProductionPublic (no API key required)https://api-gateway.skymavis.com/mavispay-public/v1
DevelopmentPrivate (requires API key)https://api-gateway.skymavis.one/mavispay/v1
DevelopmentPublic (no API key required)https://api-gateway.skymavis.one/mavispay-public/v1

Authentication

To authenticate your Mavis Pay API requests, include your API key in the X-API-Key header field with each request.

Steps

Step 1. Create a payment request

To create a new payment request, send information to this API endpoint:

POST /merchant/payments

Request body:

{
"amount": "27500000",
"currency": "usdc",
"items": [
{
"name": "AxieCon 2022 Backpack",
"quantity": 1
}
],
"reference": "55f56c89-b454-4677-a1a1-d3271f47db6f",
"redirect_url": "<https://localhost:3000/checkout>"
}
Fields
FieldTypeDescription
amountStringThe full amount of currency to pay, without decimal places. USDC has 6 decimals places, so “27500000” equals “27.5” USDC.
currencyStringThe currency you as a merchant want to receive. Supported values: usdc, axs, weth, slp, ron. Note: You must enable the currency using a smart contract.
itemsArrayThe items in the user's cart. An array of objects with name and quantity.
items[index].nameStringThe name of the item in the cart.
items[index].quantityStringThe quantity of the item in the cart.
referenceStringA payment reference generated by the merchant to later identify incoming webhook notifications. We suggest using UUID.
reference_urlStringThe URL where the Mavis Pay frontend redirects users after the payment is complete or expired. Must begin with https, even for testing. Note: Request your Sky Mavis point of contact to add this URL to your Sky Mavis Account.

Response:

{
"ID": 1,
"CreatedAt": "0001-01-01T00:00:00Z",
"UpdatedAt": "0001-01-01T00:00:00Z",
"DeletedAt": null,
"payment_id": "99e9f183-e509-478b-8eda-02f6d38c57ab",
"merchant_id": "65e141ec-a735-47fe-8d57-fe514e03ddb6",
"amount": 27500000,
"currency": {
"Name": "USDC",
"Address": "0x067fbff8990c58ab90bae3c97241c5d736053f77"
},
"redirect_url": "<https://localhost:3000/checkout>",
"reference": "55f56c89-b454-4677-a1a1-d3271f47db6f",
"blockchain_reference": "1683256082984259400_40b20d1d-52dc-40cc-8767-14bdd54cf730",
"status": "created",
"transaction_id": "",
"items": [
{
"name": "AxieCon 2022 Backpack",
"quantity": 1
}
],
"expiresAt": "2023-05-05T05:13:02.9842594+02:00",
"createdAt": "2023-05-05T05:08:02.9853351+02:00",
"updatedAt": "2023-05-05T05:08:02.9853351+02:00"
}

After receiving the payment details from the API, redirect the customer to the following URL:

  • Production: https://mavispay.skymavis.com/pay?id=<payment_id>
  • Development: https://mavispay.skymavis.one/pay?id=<payment_id>

Append the value of payment_id that returns from the create payment endpoint.

Payment expiration

Payments expire automatically after 300 seconds (5 minutes). This is a global setting that can’t be changed for individual merchants or payments.

Step 2. Receive payment updates

To receive updates about your payments, set up a webhook receiver URL that can communicate over HTTPS.

Mavis Pay sends a POST request to this endpoint whenever a payment event occurs—for example, when a payment is created through the API or when it is completed.

Webhook events and payloads

The following table describes all payment events sent by Mavis Pay to your webhook URL.

EventSent whenExample payload
Payment createdA new payment is created through the API.Payment created
Payment expiredA payment is not completed within 5 minutes.Payment expired
Payment completedA payment is completed and the funds are in the merchant's wallet.Payment completed
Payment failedThe transaction is included in a block but failed to execute. For example, ran out of gas.Payment failed
Payment created
{
"payment": {
"payment_id": "0459991c-c0a6-4819-b0bc-4aa7a9775f82",
"reference": "2c912268-4327-4bd7-b778-2632e3421ba5",
"status": "created"
}
}
Payment expired
{
"payment": {
"payment_id": "31830bbb-ee10-4970-bd50-18e1e272544b",
"reference": "4a9a29b8-4601-4b1a-8373-fdbca4a96018",
"status": "expired",
"transaction_hash": ""
}
}
Payment completed
{
"payment": {
"payment_id": "5d6feb44-d40a-44e2-8a1d-41b19f117e20",
"reference": "1dde7e08-4379-462d-949b-4e5cd9e373a4",
"status": "completed",
"transaction_hash": "0xf7d5c3ad0ad15a285d430503c2a798dd6103a80a5f1bd59f047952d1718bfd05"
}
}
Payment failed
{
"payment": {
"payment_id": "6eeef102-eb9a-459e-9b1f-6cc584181868",
"reference": "796387aa-ba2c-4bdb-8ec4-0e3d3cc83393",
"status": "failed",
"transaction_hash": "0x6233691e7459f7a057d1a2b2ae7997715b6ead0c7574cd8ebcfc8098c45dee4b"
}
}

Step 3. Verify a webhook

To verify the authenticity of a webhook request, follow these steps:

  1. Extract the webhook signature from the x-signature header of the request.
  2. Verify that the signature is a JWT token (JSON Web Token) using the following public JWKS (JSON Web Key Set):
    1. Production: https://api-gateway.skymavis.com/mavispay-public/.well-known/jwks.json
    2. Development: https://api-gateway.skymavis.one/mavispay-public/.well-known/jwks.json

This example verifies a webhook:

import jwt from 'jsonwebtoken';
import JwksRsa from 'jwks-rsa';

// Your JWT token
const signature = 'your_jwt_token_here';

// JWKS URL
const jwksUrl = 'your_jwks_url_here';

// Initialize JWKS client
const client = JwksRsa({
jwksUri: jwksUrl
});

// Function to get the signing key
function getKey(header: jwt.JwtHeader, callback: jwt.SigningKeyCallback) {
client.getSigningKey(header.kid, (err, key) => {
const signingKey = key.getPublicKey();
callback(null, signingKey);
});
}

// Verify the token
jwt.verify(signature, getKey, (err, decoded) => {
if (err) {
console.log('Token is invalid:', err);
} else {
console.log('Token is valid. Decoded payload:', decoded);
}
});