Productfy logoLog In

Merchant Payments

Pay with card.jpg

Note: This feature is still under development and testing and is subject to change.

Overview

Productfy offers the ability for you to accept credit and debit card payments in your app. The money from these payments can settle to your own account, or your customer's accounts seamlessly. Additionally, these payments can integrate with Productfy's Virtual Accounts if you want to build a real-time transfer of money between users on the platform.

Features

  • Accept Visa, Mastercard, Discover and American Express card payments within your app
  • Customizable payment form prevents your app from seeing card information and needing to be PCI compliant
  • Optional integration with Productfy Virtual Accounts to facilitate real-time sender-to-receiver transfer of funds
  • Optional ability to add fees to payments for an additional revenue stream
  • Process refunds and view data from Productfy's Client Portal (coming soon)

Implementation Process

  1. Work with your Productfy representative to finalize contract terms
  2. Submit your merchant setup request here
  3. Obtain your Transcenter ID and Processor ID from the GoEmerchant portal, Security Settings tab - these values will be needed for your technical integration
  4. Follow the steps of the technical integration below

Testing Card Payment Acceptance

In the test environment you can submit payments directly to our API (see Step 2), however in production you must use the hosted iFrame to retrieve cryptograms to be used in place of card numbers in the API.

Step 1 - Integrate Hosted iFrame

You will display an iFrame in your app that generates a cryptogram for the card information that can be used in a subsequent API call to process payments.

You will need to include the iFrame as well as a script that will initialize the iframe. Use the URL, Transcenter ID, and Processor ID from the portal.

iFrame Code

<!-- <iframe id="firstpay-iframe"
src="https://secure-v.goemerchant.com/secure/PaymentHostedForm/v3/CreditCard"
data-transcenter-id="[Transcenter Id Goes Here]" data-processor-id="[Processor Id Goes
Here]" data-transaction-type="Sale" data-manual-submit="false"></iframe>

Initialization Script

<script
src="https://secure-v.1stpaygateway.net/secure/PaymentHostedForm/Scripts/firstpay/firs
tpay.cryptogram.js"
id="firstpay-script-cryptogram" type="text/javascript" data-transcenter="[Transaction
Center Id goes here]" data-processor="[Processor Id goes here]"
data-type="Sale"></script>

Customizing The iFrame

The javascript code sample above will loop through all of the stylesheets in your site and look for all instances of classes with firstpay in them. All the classnames inside of the iframe use selectors with firstpay in them so it’s possible to style the iframe content as long as you mount overriding stylesheet before the javascript initiates.

ClassClass Description
firstpay-containerThe div element in the iFrame where the form element is loaded
firstpay-formThe form element
firstpay-form-rowThe div element representing each field in the form and its label
firstpay-labelLabel element for a form input
firstpay-inputText input or select element
firstpay-validation-errorDiv element for validation errors for each firstpay-input element
firstpay-buttonButton element for manual form submits

Sample Stylesheet

iframe#firstpay-iframe {
border: none;
height: 300px;
}
.firstpay-form-row input, .firstpay-form-row select {
border: 1px solid #c3c3c3;
border-radius: 4px;
font-size: 16px;
padding: 8px 6px;
}
.firstpay-form-row label {
font-size: 14px;
font-family: sans-serif;
}
.firstpay-form-row + .firstpay-form-row {
margin-top: 8px;
}

Communicating With The Form

After a cryptogram is generated you will need to submit the cryptogram to productfy using the Create Merchant Transaction API. The implementation details are up to your application’s workflow but the iFrame will emit message events that you can use to capture changes to the iFrame form state.

// Add event listener for dispatched message from iframe https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
window.addEventListener("message", (event) => {
// Check if event data exists and it is an event from the firstpay iframe
if (event && event.data && event.data.firstpay) {
switch(event.data.type) {
/*
* These are the data types that the iframe will postMessage to
* the parent window. Some of these may be useful to drive the UI
* (e.g. loading indicators, error messages) At a minimum you will need to
* handle `newCryptogram` which will contain the cryptogram that needs to
* be sent to Productfy via [graphql mutation].
*/
case 'formReady':
// form loaded and ready
break;
case 'generatingCryptogram':
// form page has sent a request to generate a cryptogram
break;
case 'newCryptogram':
// cryptogram successfully generated; set cryptogram in form to submit to pfy
const { code, cryptogram, expMonth, expYear, first6, last4, success } = event.data;
if (!success) {
// show client error
//setAppError('Generic error message');
}
// Store cryptogram to send to Productfy later
// setCryptogram(cryptogram);
break;
case 'cryptogramFailed':
// cryptogram failed to generate
const { message, exception } = event.data;
// Message contains user-friendly error message, show client error
// setAppError(message);
// exception contains detailed information about failure, log
// logAppError(exception);
break
}
}
return;
}, false);

Step 2 - Create Merchant Transaction API

The Create Merchant Transaction API will take the cryptogram generated above by the iFrame. On top of taking the cryptogram and the transaction amount, the billing information is required.

Optional features with this API:

  • Enter the destinationAccountId of a virtual account on Productfy for cases where the card payment is being sent to a user's virtual account that is on Productfy. This will automatically create a transaction on the virtual account.
  • Enter the requestorPersonId or requestorOrganizatonId to tie the payment to the Person or Organization in the Productfy system
  • Enter transactionFees if you would like to add on a surcharge to the credit card payment.

Notes:

  • There is an additional version of this API for testing purposes, which would take the credit card information in the clear vs. the cryptogram.
  • The ipAddress of the end user is required.

Request parameters

ParameterDescription
ipAddressthe end user IP address
transactionAmountthe total amount of the merchant transaction, including any fees.
transactionFeesthe transaction fees if any
transactionDescriptionthe description of the merchant transaction
crytpogramthe cryptogram that contains the encrypted card data
billingNamethe name associated to the billing information
billingStreetthe billing street address
billingCitythe billing city
billingStatethe billing state. 2-character value is recommended
billingZipthe billing zip code. 5-character value is recommended
billingCountrythe billing country. US is the recommended value
orderIdA unique order id. If not provided by the client, this id will be auto generated.
requesterPersonIdthe Productfy requester person ID. It is an optional field.
requesterOrganizationIdthe Productfy requester organization ID. This is an optional field.
destinationAccountIdthe Productfy destination financial account ID if this transaction's recipient is a Productfy account.

CreateMerchantTransactionTest API (QA environment only):

This API can be used for testing purposes only and doesn't require the cryptogram from the iFrame above. This may be useful if you just want to test out basic card payment functionality while building your app.

mutation createMerchantTransactionTest {
createMerchantTransactionTest(
merchantTransactionWithCreditCardRequest: {
billingCity: "",
billingCountry: "",
billingName: "",
billingState: "",
billingStreet: "",
billingZip: "",
creditCardCVV: "",
creditCardExpirationMonth: "",
creditCardExpirationYear: "",
creditCardNumber: "",
destinationAccountId: "",
ipAddress: "",
requesterOrganizationId: "",
requesterPersonId: "",
transactionAmount: 0,
transactionDescription: "",
transactionFees: 0}) {
... on MerchantTransaction {
orderId
referenceNumber
authCode
billingCity
billingCountry
billingName
billingState
billingStreet
billingZip
destinationAccountId
lastFourDigits
refundAmount
refundDate
refundReferenceNumber
refundType
requesterOrganizationId
requesterPersonId
transactionAmount
transactionDate
transactionDescription
transactionFees
transactionStatus
}
... on UserError {
__typename
errors {
key
message
}
}
}
}

CreateMerchantTransaction API:

mutation createMerchantTransaction {
createMerchantTransaction(
merchantTransactionRequest: {
billingCity: "",
billingCountry: "",
billingName: "",
billingState: "",
billingStreet: "",
billingZip: "",
crytpogram: "",
destinationAccountId: "",
ipAddress: "",
orderId: "",
requesterOrganizationId: "",
requesterPersonId: "",
transactionAmount: 1.5,
transactionDescription: "",
transactionFees: 1.5}) {
... on MerchantTransaction {
orderId
referenceNumber
authCode
billingCity
billingCountry
billingName
billingState
billingStreet
billingZip
destinationAccountId
lastFourDigits
refundAmount
refundDate
refundReferenceNumber
refundType
requesterOrganizationId
requesterPersonId
transactionAmount
transactionDate
transactionDescription
transactionFees
transactionStatus
}
... on UserError {
__typename
errors {
key
message
}
}
}
}

Step 3 - Refund Handling

In order to submit refunds, you will have an available API to call. You will need to pass the reference number associated with the sale transaction and the refund amount. The refundType return parameter can be ‘credit’ or ‘void’, depending if the transaction has already been settled.

Request parameters

ParameterDescription
referenceNumberthe transaction reference number
transactionAmountthe total amount of the merchant transaction, including any fees.

Response parameters

ParameterDescription
referenceNumberthe unique reference number for this transaction from the merchant gateway. This is used for requesting a refund.
transactionStatusthe transaction status should be only Declined or Refund accepted
refundReferenceNumberthe reference number of the refund (if any)
refundAmountthe refund amount if the refund was requested
refundTypethe refund type (Void, Refund)

The GraphQL endpoint is defined as follows:

mutation refundMerchantTransaction {
refundMerchantTransaction(referenceNumber: "", transactionAmount: "") {
... on UserError {
__typename
errors {
key
message
}
}
... on MerchantRefundTransaction {
referenceNumber
transactionStatus
refundAmount
refundReferenceNumber
refundType
}
}
}

Step 4 - Settlement Of Funds

When a sale transaction is successfully submitted, it will be in an APPROVED state. We will receive a batch for the settled transactions daily from the processor. Once we receive the batch we will automatically update the status to SETTLED or VOIDED to the corresponding transactions. The status change will be reflected in through the query API.

Step 5 - Handling Chargebacks

Productfy will trigger a chargeback webhook to you when we are notified that a chargeback has been initiated by one of your customers. Upon receiving this webhook, you will need follow chargeback processes to supply necessary information through the portal. Contact your Productfy representative for more information.

Step 6 - Viewing Your Data

We are offering a query graphQL API endpoint so our client can retrieve in-flight or processed transactions as well as retrieving a transaction by reference number.