Module for verifing Coinpaymets Instant Payment notifications.
npm install coinpayments-ipn
yarn add coinpayments-ipn
import { isIPNLike, verifyIPN } = 'coinpayments-ipn'
// Fetch IPN data from post request - not provided by lib
const someReceivedPayload = getPOSTDataForIPNUrl()
// Fetch IPN HMAC from request header - not provided by lib
const givenHMAC = getHMACFromPOSTHeader()
if (!isIPNLike(someReceivedPayload)) {
// Notification is not the correct shape
// Discard to faulty IPNs or ignore
}
someReceivedPayload // type narrowed -> CoinpaymentsIPNLike
// Fetch ipnSecret for merchant - not provided by lib
const merchantIPNSecret = resolveMerchantIPNSecret(someReceivedPayload.merchant)
// Generate hmac based on ipnSecret and given payload and compare given hmac
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (!result.success) {
// result.error for more info
}
result.data // CoinpaymentsIPN - Verified
import { isSimpleButtonIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isSimpleButtonIPN(result.data)) {
result.data // SimpleButtonIPN
}
}
import { isAdvancedButtonIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isAdvancedButtonIPN(result.data)) {
result.data // AdvancedButtonIPN
}
}
import { isDonationButtonIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isDonationButtonIPN(result.data)) {
result.data // DonationButtonIPN
}
}
import { isCartIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isCartIPN(result.data)) {
result.data // CartIPN
}
}
import { isDepositIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isDepositIPN(result.data)) {
result.data // DespositIPN
}
}
import { isWithdrawalIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isWithdrawalIPN(result.data)) {
result.data // WithdrawalIPN
}
}
import { isApiIPN } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isApiIPN(result.data)) {
result.data // ApiIPN
}
}
import { isDepositIPN, isPaymentSuccessful } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isDepositIPN(result.data)) {
result.data // DespositIPN -> { fee?: string, feei?: string, fiat_fee?: string, fiat_feei?: string }
if (isPaymentSuccessful(result.data)) {
result.data // DespositIPN & { fee: string, feei: string, fiat_fee: string, fiat_feei: string }
}
}
}
import { isWithdrawalIPN, isPaymentSuccessful } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isWithdrawalIPN(result.data)) {
result.data // WithdrawalIPN
if (isPaymentSuccessful(result.data)) {
result.data // WithdrawalIPN - no additional
}
}
}
Any other beside Withdrawals and Deposits should expect the following result. ApiIPN is used as an example.
import { isApiIPN, isPaymentSuccessful } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isApiIPN(result.data)) {
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
if (isPaymentSuccessful(result.data)) {
// only when status >= 100
result.data // ApiIPN & { send_tx: string, received_amount: string, received_confirms: string }
}
}
}
import { isApiIPN, isPaymentPending } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isApiIPN(result.data)) {
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
if (isPaymentPending(result.data)) {
// only when 0 < status < 100 - Standard
// only when 0 < status < 2 - Withdrawal
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
}
}
}
import { isApiIPN, isPaymentUnsuccessful } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isApiIPN(result.data)) {
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
if (isPaymentUnsuccessful(result.data)) {
// only when status < 0
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
}
}
}
Payment notification has reached some final state.
isPaymentComplete = isPaymentUnsuccessful || isPaymentSuccessful
import { isApiIPN, isPaymentComplete } from 'coinpayments-ipn'
...
const result = verifyIPN(merchantIPNSecret)(givenHMAC)(someReceivedPayload)
if (result.success) {
if (isApiIPN(result.data)) {
result.data // ApiIPN -> { send_tx?: string, received_amount?: string, received_confirms?: string }
if (isPaymentComplete(result.data)) {
// Check isPaymentUnsuccessful OR isPaymentSuccessful
}
}
}