Skip to main content

Callbacks receiving

Transaction event payload

Here is an example of a callback payload:

Callback payload example

Header: x-callback-signature

Body:

{
"redirectUrl": "https://buy.moonpay.com/?CurrencyCode=eth&baseCurrencyCode=usd&currencyCode=eth&baseCurrencyAmount=150&externalTransactionId=71ahw34&walletAddress=0x8cfbd31371e9bec8c82ae101e25bd9394c03a227",
"orderId": "5154302e-3stl-75p4",
"status": "pending",
"externalUserId": "122hd",
"externalOrderId": "71ahw34",
"providerCode": "moonpay",
"currencyFrom": "USD",
"currencyTo": "ETH",
"amountFrom": "150",
"country": "EE",
"state": null,
"ip": null,
"walletAddress": "0x8cfbd31371e9bec8c82ae101e25bd9394c03a227",
"walletExtraId": null,
"paymentMethod": "card",
"userAgent": null,
"metadata": null,
"createdAt": "2019-07-22T10:10:09.000",
"payinAmount": "150",
"payoutAmount": "0.0756",
"payinCurrency": "USD",
"payoutCurrency": "ETH",
"transactionHash": "f418********************************38530e9831e9e16"
}

Response schema (application/json):

ParameterDescription
redirectUrlURL to the provider's purchase page.
orderIdInternal order ID provided by Fiat API. You can use this field to get information that the transaction status was updated.
statusTransaction status. [Possible values](Possible values). You can use this field to get information that the transaction status was updated.
externalUserIdUser ID provided by you.
externalOrderIdOrder ID provided by you. You can use this field to get information that the transaction status was updated.
providerCodeThe On-Ramp or Off-Ramp provider code. Possible values.
currencyFromTicker of the payin currency (in uppercase).
currencyToTicker of the payout currency (in uppercase).
amountFromAmount of currency the user is going to pay.
countryCountry ISO 3166-1 code (Alpha-2).
stateState ISO 3166-2 code.
ipUser's IP address.
walletAddressRecipient wallet address.
walletExtraIdProperty required for wallet addresses of currencies that use an additional ID for transaction processing (XRP, XLM, EOS, BNB).
paymentMethodThe payment method code. Possible values.
userAgentUser Agent.
metadataMetadata object, which can contain any parameters you need:
  • If you don't provide the metadata object in the request, null will be returned in metadata in response.
  • If you specify an empty object in the request, an empty object will be returned in the response.
createdAtTime in ISO 8601 format.
updatedAtTime in ISO 8601 format.
payinAmountPayin amount.
payoutAmountThe estimated payout amount.
payinCurrencyTicker of the payin currency.
payoutCurrencyTicker of the payout currency.
transactionHashTransaction hash in the blockchain.

Supported transaction statuses

Webhook payload passes a transaction status in the status field. Learn more details about supported transaction statuses.

info

Pay attention that some providers do not support certain transaction statuses.

Webhooks signature

To make sure that the incoming requests are originating from a trusted source, you can validate them using our webhook signature. We highly recommend using this practice for security reasons.

Changelly signs webhook events sent to you. To use webhooks signature, we will generate public and private API keys. Your account manager will send you a public key to verify the signature in webhooks. Each event includes a signature which is done using the signature header. This header includes orderId signed by the private key. This will allow you to validate that the events have been submitted by Changelly, not a third party.

Before you can verify signatures for webhook events, please notice that all requests must contain the following header:

HeaderDescription
x-callback-api-keyYour public API key to verify the signature in webhooks.
x-callback-signatureThe serialized string with an orderId signed by our private key according to the RSA-SHA256 method.

There is an example of how to validate your x-callback-signature parameter in webhooks with Node.js: Form an object with the orderId parameter that is sent in the response body in the webhook. Serialize the generated object in JSON format. Use the generated string and the public key given by your account manager to verify the signature received from us by checking the SHA256 signature.

There are code examples to validate signature:

import crypto from 'crypto';​​ 
import express from 'express';

const CALLBACK_API_KEY = '<Your API key>';
const CALLBACK_PUBLIC_KEY = '<Your public callback key>';

function _validateSignature(signature, payload) {
const publicKeyObject = crypto.createPublicKey({
key: CALLBACK_PUBLIC_KEY,
type: 'pkcs1',
format: 'pem',
encoding: 'base64',
});

const payloadBuffer = Buffer.from(payload);
const signatureBuffer = Buffer.from(signature, 'base64');

return crypto.verify('sha256', payloadBuffer, publicKeyObject, signatureBuffer);
}

const app = express();

app.use(express.json());

app.post('/callback', (req, res) => {
const payload = req.body;

const apiKey = req.headers['x-callback-api-key'];
const signature = req.headers['x-callback-signature'];

if (apiKey !== CALLBACK_API_KEY) {
return res.status(400).send({status: 'error'});
}

const signaturePayload = JSON.stringify({orderId: payload.orderId});

if (!_validateSignature(signature, signaturePayload)) {
return res.status(400).send({status: 'error'});
}

console.log('Callback payload: ', payload);

return res.status(200).send({status: 'success'});
});

app.listen(4200, () => {
console.log('Server listening on port http://localhost:4200');
});