Skip to main content

Receive callbacks

In this article, you can learn how to receive callbacks in Fiat API.

Webhooks signature

To make sure that the incoming requests are from a trusted source, validate them with our webhook signature. We highly recommend you use 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 allow you to validate that Changelly submitted the events, not a third party.

Before you can verify signatures for webhook events, pay attetion that all requests must contain the following headers.

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.

General flow of validation x-callback-signature:

  1. Form an object with the orderId parameter sent in the webhook response body.
  2. Serialize the generated object in JSON format.
  3. Use the generated string and the public key from your account manager to verify the signature received from us by checking the SHA256 signature.

For more details, learn the following sample codes.

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');
});

Transaction event payload

Response schema:

ParameterDescription
amountFromAmount of currency the user is going to pay.
сountryCountry ISO 3166-1 code (Alpha-2).
stateState ISO 3166-2 code.
createdAtTime in ISO 8601 format.
updatedAtTime in ISO 8601 format.
currencyFromTicker of the payin currency (in uppercase).
currencyToTicker of the payout currency (in uppercase).
externalUserIdUser ID provided by you.
externalOrderIdOrder ID provided by you. You can use this field to get information that the transaction status was updated.
ipUser's IP address.
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.
orderIdInternal order ID provided by Fiat API. You can use this field to get information that the transaction status was updated.
payinAmountPayin amount.
payoutAmountThe estimated payout amount.
payinCurrencyTicker of the payin currency.
payoutCurrencyTicker of the payout currency.
paymentMethodThe payment method code. Possible values.
providerCodeThe On-Ramp or Off-Ramp provider code. Possible values.
redirectUrlURL to the provider's purchase page.
statusTransaction status. Possible values. You can use this field to get information that the transaction status was updated.
transactionHashTransaction hash in the blockchain.
userAgentUser Agent.
walletAddressRecipient wallet address.
walletExtraIdProperty required for wallet addresses of currencies that use an additional ID for transaction processing (XRP, XLM, EOS, BNB).
Sample callback payload

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"
}

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.