How to use the Payment API v2
In this article we present a few hands-on examples of how to use the FinDock Payment API.
- To find out how our API works, please visit our How the Payment API works article.
- If you haven’t already, please check out Getting started with the Payment API before continuing.
- For detailed information about our API, please visit our API reference guide.
- To learn about and configure online reconciliation with Guided Matching, check our processing and reconciliation article.
- If you run into any issues, please visit our Troubleshooting the API article.
The examples here use credit card as the payment method and FinDock as the source. If these terms (method and source) are unfamiliar to you, please read our getting started article.
New one-time payment
Payments are initiated by performing a POST to the FinDock /PaymentIntent
endpoint. The request must have a body and an authorization header.
Request
The Root of the request contains the success and failure URLs and the origin (e.g. what website or platform is making the request). The Root may also include a webhook URL, but this attribute is not required. If the transaction is successful, the customer is redirected to the success URL. If the customer cancels the transaction, the redirection is to the failure URL. The origin is logged in Salesforce as a text string to indicate what form was used for initiating the transaction.
{
"SuccessURL": "https://www.example.com/success",
"FailureURL": "https://www.example.com/error"
}
The Payer object contains the details of the payer, Eric Johnson, in this example. AllowDedupulication is set to true, so if Salesforce finds an existing Eric Johnson in the database (according to the deduplication rules), the existing contact shall be used.
Please note we put all the Contact and Account fields in a SalesforceFields
object. In this object, you can pass any field - both standard Salesforce and custom - that is available on this object in your Salesforce environment.
{
"SuccessURL": "https://www.example.com/success",
"FailureURL": "https://www.example.com/error",
"Payer": {
"Contact": {
"SalesforceFields": {
"FirstName":"Eric",
"LastName":"Johnson",
"Email":"eric@johnson.com",
"MailingStreet":"Rocket Rd",
"MailingCity":"Hawthorne0",
"MailingPostalCode":"CA 90250",
"MobilePhone":"98989898"
}
},
"Account":{
"SalesforceFields": {
"Name":"Johnson Family",
"Website":"www.spacex.com",
"BillingStreet":"Rocket Rd",
"BillingCity":"Hawthorne",
"BillingPostalCode":"CA 90250"
}
}
}
If you are using NPSP, we recommend adding AccountRecordTypeName to the Account declaration.
The Payment object indicates this request is a one-time transaction. The amount is 10, and since there is no CurrencyISOCode attributed, the default currency defined for the Salesforce org is used.
"OneTime": {
"Amount": "36"
},
The PaymentMethod object indicates the transaction uses the credit card payment method. Since this Salesforce org has several processors configured that can be used to perform credit card payments, we explicitly specify Stripe as the processor.
"PaymentMethod": {
"Name": "CreditCard",
"Processor": "PaymentHub-Stripe"
}
}
If no processor is provided, FinDock uses the default payment processor configured for this payment method in the FinDock setup. To find out which processor is the default, perform a GET on the /PaymentMethods
endpoint.
The Settings object explicitly defines FinDock as the source. This means we are using FinDock Standalone and there are no source apps, such as Nonprofit Success Pack, in the Salesforce org that would need the payment data.
You can leave theSourceConnector
parameter out if you always want to use the default source connector in the Salesforce environment.
"Settings": {
"SourceConnector": "PaymentHub"
}
The full message sent to https://your-org-url.force.com/services/apexrest/cpm/v2/PaymentIntent
should look something like this:
{
"SuccessURL": "https://www.example.com/success",
"FailureURL": "https://www.example.com/error",
"Payer": {
"Contact": {
"SalesforceFields": {
"FirstName": "Eric",
"LastName": "Johnson",
"Email": "eric@johnson.com",
"MailingStreet": "Rocket Rd",
"MailingCity": "Hawthorne0",
"MailingPostalCode": "CA 90250",
"MobilePhone": "98989898"
}
},
"Account": {
"SalesforceFields": {
"Name": "Johnson Family",
"Website": "www.spacex.com",
"BillingStreet": "Rocket Rd",
"BillingCity": "Hawthorne",
"BillingPostalCode": "CA 90250"
}
}
},
"OneTime": {
"Amount": "36"
},
"PaymentMethod": {
"Name": "CreditCard",
"Processor": "PaymentHub-Stripe"
},
"Settings": {
"SourceConnector": "PaymentHub"
}
}
Response
The response on the new one-time payment request has a similar structure to the request:
{
"Settings": {
"SourceConnector": "PaymentHub",
"ProcessingType": "Default"
},
"RedirectURL": "https://redirect.test.findock.com/3xnllmuai2/PaymentHub-Stripe/checkout?publicKey=pk_test_eGC6TxzQ60CdjpAkt2RG3CwZ008WiiOn12&sessionId=cs_test_ifQhP4ggbSQrjJYoi3AEVrEmO3Agl5O6ihy4THgYtuswvW1yX9wjmA59",
"PaymentMethod": {
"Processor": "PaymentHub-Stripe",
"Name": "CreditCard"
},
"Id": "pi_vqv330n7dvd9j8210"
}
The Settings object response indicates that the payment was created with FinDock Standalone (PaymentHub) as SourceConnector
.
The PaymentMethod object response indicates that the transaction will be processed as a Credit Card payment through Stripe.
The Id is an Id that identifies this Payment Intent. This id is stable across all communication from and to FinDock, and can be found:
- on the created Inbound Report record in Salesforce. On this Inbound Report the API call is processed through Guided Matching.
- in Webhook notifications to the
WebhookURL
you can specify in the request body.
You can also retrieve the status of the Payment through a GET
request on the /PaymentIntent
endpoint.
For more information on processing and reconciliation of online Payments through Guided Matching, please read our processing and reconciliation article.
Finalizing the one-time transaction
Because this is a new payment for a new contact, the customer/donor needs to provide credit card details and should be forwarded to the RedirectURL in the response.
"RedirectURL": "https://redirect.test.findock.com/3xnllmuai2/PaymentHub-Stripe/checkout?publicKey=pk_test_eGC6TxzQ60CdjpAkt2RG3CwZ008WiiOn12&sessionId=cs_test_ifQhP4ggbSQrjJYoi3AEVrEmO3Agl5O6ihy4THgYtuswvW1yX9wjmA59"
In our example, since Stripe is the processor, the payment form is a Stripe payment form.
Although this Stripe payment page is close to the production version, many payment processors show different pages for testing. We strongly recommend performing a ‘penny test’ with a real, small payment amount in your production environment to account for these differences in the test setup.
Once the customer completes the transaction, the customer is redirected to the SuccessURL
or FailureURL
value from the initial PaymentIntent
. In parallel, FinDock receives a callback from
the PSP (Stripe) and the following actions are performed in Salesforce through Guided Matching:
- The installment record is updated (status is set to ‘Collected’ and amount is reduced by the amount paid to 0).
- A Payment record is created for the Installment.
- A Payment Profile is created related to the Contact based on the data provided by the PSP, like the type of credit card. If the Payment Profile had already existed for this contact, it would have been updated instead. This data can be used to personalize (e.g. pre-fill forms) future payment requests for this customer. Payment profiles are deduplicated automatically by FinDock.
Pay existing outstanding installment
Payments are initiated by performing a POST to the FinDock /PaymentIntent
endpoint. The request must have a body and an authorization header. Make sure the Installment you are trying to pay has an open amount.
Request
The request body is the same as for a new one-time payment with one important exception: an InstallmentId is added in the OneTime object. No Payer object is required, since this customer data is already in Salesforce. A basic request looks something like this:
{
"SuccessURL": "https://www.example.com/success",
"FailureURL": "https://www.example.com/error",
"OneTime":{
"Id":"a083X00001gpxeGQAQ"
},
"PaymentMethod": {
"Name": "CreditCard",
"Processor": "PaymentHub-Stripe"
},
"Settings": {
"SourceConnector": "PaymentHub"
}
}
Response
If additional actions are required from the customer, a redirectURL is returned in the response body. Once the transaction has been completed or cancelled, the PSP notifies FinDock through the callback, and FinDock updates the data in Salesforce accordingly.
{
"Settings": {
"SourceConnector": "PaymentHub",
"ProcessingType": "Default"
},
"RedirectURL": "https://redirect.test.findock.com/3xnllmuai2/PaymentHub-Stripe/checkout?publicKey=pk_test_eGC6TxzQ60CdjpAkt2RG3CwZ008WiiOn12&sessionId=cs_test_l5JXe6THfn7e99Ip3OoGDf1SsT19fZrrsBvAhrmARWx6jU0QYi2EKS1Z",
"PaymentMethod": {
"Processor": "PaymentHub-Stripe",
"Name": "CreditCard"
},
"Id": "pi_2qha50n78o0qezuln"
}
New recurring payment
Payments are initiated by performing a POST to the FinDock /Payment endpoint. The request must have a body and an authorization header.
Request
The request body is the same as for a new, one-time payment except that it uses a Recurring object that replaces the Payment object. Some PSPs require an ‘initial’ transaction for authentication. In those cases both a Payment and a Recurring object is passed. Whether such an authorization is required can be queried from the GET /PaymentMethod
endpoint. For further information, see the relevant PSP articles under Payment Extensions.
The Recurring object defines the amount and frequency of the recurring transaction, as well as the start date (when the first transaction can be billed).
"Recurring": {
"Amount": "25",
"Frequency": "Monthly",
"StartDate": "2023-04-01"
}
Some PSPs may require an initial payment when setting up a new recurring payment. Some make it optional, while others disallow initial payment completely. This is part of the GET /PaymentMethod
response which includes the InitialPaymentonRecurring
parameter value. The options are:
- Required: The recurring payment setup must include a one-time payment block.
- Optional: The recurring payment setup may include a one-time payment block.
- No: The recurring payment setup must not include a one-time payment block.
For example, if the initial payment is required, the above Recurring object would need a OneTime block like below.
"Recurring": {
"Amount": "25",
"Frequency": "Monthly",
"StartDate": "2023-04-01"
}
"OneTime": {
"Amount": 25
},
The parameter RecurringRequiresInitialPayment [true | false] may be included in the GET /PaymentMethod
response, but this parameter is deprecated and should not be used.
Response
In the response, you get a similar response to a OneTime
request, with - in this case - a RedirectURL
to perform an authorization.
{
"Settings": {
"SourceConnector": "PaymentHub",
"ProcessingType": "Default"
},
"RedirectURL": "https://redirect.test.findock.com/3xnllmuai2/PaymentHub-Stripe/checkout?publicKey=pk_test_eGC6TxzQ60CdjpAkt2RG3CwZ008WiiOn12&sessionId=cs_test_FOnCWoRsNOVea8NBYMhOObAYvr7784jvKirv8mRkfxo0OxontIMduM6X",
"PaymentMethod": {
"Processor": "PaymentHub-Stripe",
"Name": "CreditCard"
},
"Id": "pi_1v0c50n728ke1inuu"
}
Related to the Recurring Payment, you can find:
- the first Installment that was created through the API request.
- the Mandate with data (in this case a Stripe Credit Card token) to collect further installments through the Payment Schedule.
- the Payment Profile with any Credit Card details that Stripe has returned.
Override the Default Bank Statement Description
field with Salesforce automation or by passing a value to the Description
parameter in the Parameters
block in the PaymentMethod
object in your API call, to show the Payer a friendly description on their bank statement.
Next
Visit our API Reference to find more examples of Payment scenarios that can be executed through our API.
Check out the Integration checklist for additional tips on how to get the maximum value from our API.