# FinDock Payment API

The FinDock Payment API is a REST API for handling one-time and recurring payments. The API also
provides informational endpoints you can use to build dynamic front-end applications that are
not dependent on a specific Salesforce of FinDock configuration.

Alongside primitive data types such as `string`, the Payment API uses data types that might be unfamiliar
to you if you have not worked with Salesforce. These data types are Salesforce objects, record types
and fields.

## Objects, record types and fields

Salesforce objects (sObjects) are stored as records in the Salesforce database. These records are persistent representations of data.
Some API resources accept, or even require, sObjects. The Payer block, for example, requires sObjects such as Contact and Account.
The API allows you to define these objects in payloads. FinDock sObjects like Inbound Report can be included as well,
but they require you to specify the object fields as Salesforce fields.

**Record types** let Salesforce administrators offer specific business processes, picklist values, and page layouts to different users.
Organizations can, for example, differentiate between `Account` object records by assigning them an `Organization` or `Household` record type.
This facilitates the application of different types of page layouts or possible field values based on what record type an `Account` is.

**Fields** are defined at the object level in Salesforce. Next to the out-of-the-box fields from Salesforce, custom fields can be added to objects. 
Use the Object Manager in Salesforce Setup to see available fields. Implementations of Salesforce can use different fields for a value like `email`.

Custom fields for *standard Salesforce objects* like `Contact` and `Account` are passed with "__c" at the end of the field name.
In the example below, you see the standard fields `FirstName` and `LastName` and a custom field `TwitterHandle` for the Contact object.

```json
{
  "Payer":{
    "Contact":{
      "SalesforceFields":{
            "FirstName":"Test",
            "LastName":"Payer",
            "TwitterHandle__c": "@TestPayerFamily"
        }
    }
  }
}
```

Custom fields for **custom FinDock objects** like `Installment` and `Recurring Payment` can also be passed in a `SalesforceFields` object. `SalesforceFields`
passed in the `OneTime` object are copied to the `Installment` record in Salesforce and `SalesforceFields` passed in the `Recurring` object are copied to the
`Recurring` object in Salesforce. To which `Recurring` object the values are stored depends on the FinDock configuration.

```json
    {
      "OneTime":{
        "Amount": 10.0,
        "SalesforceFields": {
          "Sales_Invoice__c": "a506E0000009TfL"
        }
      }
    }
    ```

## Working with payer details

Salesforce provides two objects to define the Payer:
  - Account: usually an organization
  - Contact: an individual

Added to that simple split is [Person Account](https://help.salesforce.com/s/articleView?id=sf.account_person.htm&type=5), which
stores information about individual people by combining certain Account and Contact fields into a single record. It is not its
own object, but can be stored as an Account with a specific record type (see below).

Some features of Salesforce - like Fundraising used in NonProfit Cloud (NPC) - *require* Person Account. The payer details are a Person Account
record rather than a Contact. Make sure to always check with your Salesforce admin whether they are enabled and used.

To send Person Account details to the Payment API, use an Account object with a `RecordTypeName` (API name) of the type Person Account.
By default the API name is `PersonAccount`, but there can be customized or the org (Salesforce environment may have multiple
Person Account record types. Always consult your Salesforce admin regarding record types.

Whether an Account or Contact record, you always need to take into consideration how the payer is deduplicated. Every organization 
has [configured deduplication rules](https://help.salesforce.com/s/articleView?id=sales.managing_duplicates_overview.htm&type=5)
that define the information the payment intent message needs to include for deduplication, bearing in mind that the more data points you 
have, the more effective deduplication is.

```json
{
  "Account":{
    "RecordTypeName": "person-account-record-type",
        "SalesforceFields":{
          "Name":"Test Payer",
          "BillingStreet":"Any Street",
          "BillingCity":"Any City",
          "BillingPostalCode":"00000"
        }
      }
}
```

For Person Accounts the following exceptions for (custom) field notations apply:
- Standard Account fields can be passed as regular fields: `"BillingStreet":"Any Street"`.
- Custom Account fields can be passed with the regular `__c` suffix: `"Custom_Street__c":"Any Street"`.
- Standard Contact fields need to be prefixed with `Person`, with the exception of FirstName, LastName, Salutation which are passed as regular fields: `"PersonEmail" : "test@findock.com"`.
- Custom Contact fields need to be suffixed with `__pc`: `"Custom_email__pc":"test@findock.com"`

```json
{
  "Account":{
    "RecordTypeName": "person-account-record-type",
    "SalesforceFields":{
      "FirstName": "John",
      "LastName": "Payer",
      "PersonEmail": "test@findock.com",
      "BillingStreet": "Any Street",
      "Custom_account_field__c": "Apartment Name",
      "Custom_contact_field__pc": "Middle Name"
    }
  }
}
```

For the FinDock for Fundraising source connector used with NonProfit Cloud (NPC), for example, the following exception applies:
Since the "Recurring" object (Gift Commitment) is split in two objects (Gift Commitment & Gift Commitment Schedule), a prefix `GiftCommitment` is required to set SalesforceFields on this object.
Fields without prefix are assumed to be set on the Gift Commitment Schedule object. Example: `GiftCommitment.GiftVehicle`.

You can check which Source Connectors are available by performing a GET operation on the [Source Connector](/api/payment-api-v2/source-connectors) endpoint.

## Authentication

Authentication is accomplished through an [Oauth2.0 authorization flow](https://help.salesforce.com/articleView?id=remoteaccess_oauth_web_server_flow.htm&type=5). Each Salesforce environment requires
its own token. A [refresh token](https://help.salesforce.com/articleView?id=remoteaccess_oauth_flows.htm&type=5) can be used to acquire a new access token if the current token has expired.
Read more on how to authenticate to Salesforce in the [Salesforce developer guide](https://help.salesforce.com/articleView?id=remoteaccess_oauth_flows.htm&type=5).
Both `client_id` and `client_secret` can be acquired from the Salesforce 'Setup' from a 'Connected App'.
- The `Authorization` token can be passed as a Bearer token in the request Header.
- To Acquire a new `Authorization` token with the returned `Refresh` token, please make sure to pass the right `grant_type`, `client_id`, `client_secret` and `refresh_token` as specified in the
Salesforce documentation referenced above. To get up and running quickly, use the (unofficial-but-provided-by) [Salesforce Postman Collection](https://github.com/scolladon/postman-salesforce-apis),
as explained in this [blog](https://developer.salesforce.com/blogs/2020/03/explore-the-salesforce-apis-with-a-postman-collection.html) and look for the 'auth' folder.

## Error and response codes

IF the API is not called successfully, you receive a HTTP Status Code `4xx` or `500`. A `422` code is returned when the message was well-formed, but could not be processed because of, for instance, wrong data. 
In the response you find additional information on how to prevent or handle the error through an array of `Errors` with an `error_code` and `error_message`, like in the following example.

```json
{
  "Errors": [
    {
      "error_message": "Amount can't be 0 or negative",
      "error_code": "200"
    }
  ]
}
```

Below are some of the possible error codes:

| Code | Description |
| --- | --- |
| 010 | Malformed request: missing one or more mandatory core parameter(s)
| 011 | Malformed request: missing one or more mandatory Payment Processor parameters
| 012 | Malformed request: missing one or more mandatory SourceConnector parameters
| 200 | Invalid data: the supplied data is incorrect (e.g. an invalid e-mail address).
| 201 | Sort code or bank account is invalid (Bacs Direct Debit).
| 202 | IBAN _&lt;your-IBAN&gt;_ is not valid.
| 203 | The provided IBAN is not in SEPA geographical zone.
| 204 | BIC is required to collect SEPA Direct Debit from a non-EAA country bank account.
| 205 | Street, Housename or Number, Zip code and City are required to collect SEPA Direct Debit from a non-EEA country bank account.
| 206 | Clearing number and/or bank account invalid (Sweden).
| 998 | An object is missing and no default is specified in the org.
| 999 | Error without specific category: consult the `error_message` for details.

## Webhook events and notifications

To receive updates on payments created with the `/PaymentIntent` endpoint:

- pass an endpoint URL in the `WebhookURL` parameter in the request body.
- add your URL to the [Remote Site Setting](https://help.salesforce.com/articleView?id=configuring_remoteproxy.htm&type=5) of the Salesforce org.

FinDock sends you notifications for the following events around your API call:

| Event | Description |
| ----- | ------------ |
|`paymentIntent.processed` | Processing of the API call has finished successfully. This does not mean a payment is collected. |
|`paymentIntent.in_review` | Processing of the API call has stalled and manual intervention from Salesforce side is needed. This does not stop the payer from completing the payment flow. |
|`paymentIntent.failed` | Processing of theAPI call has failed and needs to be handled in the Salesforce environment. This does not stop the payer from completing the payment flow. |
|`installment.created` | When an Installment record (expected one-time payment) is created. |
|`installment.status_change` | If the `status` of the Installment record changes, either via a notification from a PSP or manually changed. |

No specific events are sent for recurring payments other than the `paymentIntent` which contains the Salesforce Id of the recurring record.

For more information about processing online payments, please [Processing online payments](/docs/@production/reconciliation/processing-and-reconciling-online-payments.md).

For `paymentIntent` you receive notifications with the following body. Each event contains a `type` and a `data` object with further details.
Check out the [PaymentIntent object schema](/api/payment-api-v2/payment-intent) for definitions.

```json
{
  "type": "paymentIntent.processed",
  "data": {
    "Status": "Matched",
    "Recurring": {
      "Url": "/services/data/v65.0/sobjects/cpm__Recurring_Payment__c/a0V3X00000S7b5YUAR",
      "Type": "cpm__Recurring_Payment__c",
      "Id": "a0V3X00000S7b5YUAR"
    },
    "Payer": {
      "Contact": {
        "Url": "/services/data/v65.0/sobjects/Contact/0033X00003H9uZPQAZ",
        "Type": "Contact",
        "Id": "0033X00003H9uZPQAZ",
        "Name": "Test Payment"
      },
      "Account": {
        "Url": "/services/data/v65.0/sobjects/Account/0013X00002bZPGIQA4",
        "Type": "Account",
        "Id": "0013X00002bZPGIQA4",
        "Name": "Payment Family"
      }
    },
    "OneTime": {
      "Url": "/services/data/v65.0/sobjects/cpm__Installment__c/a083X00001mFTBAQA4",
      "Type": "cpm__Installment__c",
      "Id": "a083X00001mFTBAQA4",
      "Status": "Pending"
    },
    "Id": "pi_6cazikr7625yqt9mf"
  }
}
```

For `installment` you receive a notification with the following body.

```json
{
  "type": "installment",
  "data": {
    "Url": "/services/data/v65.0/sobjects/cpm__Installment__c/a083X00001kJynLQAS",
    "Type": "cpm__Installment__c",
    "Id": "a083X00001kJynLQAS",
    "Target": "Adyen1",
    "Status": "Collected",
    "RecordTypeName": "Receivable",
    "PayUrl": "https://link.dev.findock.com/pay/3xxxxmuai2/8897b4da-e48a-7ff3-90dd-ecb65094802c",
    "Payments": [
      {
        "Url": "/services/data/v65.0/sobjects/cpm__Payment__c/a0R3X00000V1sutUAB",
        "Type": "cpm__Payment__c",
        "Id": "a0R3X00000V1sutUAB",
        "PaymentProcessor": "PaymentHub-Adyen",
        "PaymentMethod": "CreditCard",
        "CollectionDate": "2020-11-26",
        "Amount": 15
      }
    ],
    "PaymentProcessor": "PaymentHub-Adyen",
    "PaymentMethod": "CreditCard",
    "PaymentIntentId": "pi_5jthokq7z8som0w6o",
    "AmountOpen": 0,
    "Amount": 15
  }
}
```


API reference specification. Last updated on 2026-06-22.

Version: v2
License: FinDock

## Servers

Salesforce
```
https://{instance}.my.salesforce.com/services/apexrest/cpm/v2
```

Variables:
- `instance`: The domain name for your org.
  Default: "demo"

## Security

### Salesforce_Production

[object Object]

Type: oauth2
Authorization URL: https://login.salesforce.com/services/oauth2/authorize
Token URL: https://{instance}.my.salesforce.com/services/oauth2/token
Scopes:
- `full`: Full access

### Salesforce_Sandbox

[object Object]

Type: oauth2
Authorization URL: https://test.salesforce.com/services/oauth2/authorize
Token URL: https://{instance}.my.salesforce.com/services/oauth2/token
Scopes:
- `full`: Full access

## Download OpenAPI description

 - [FinDock Payment API](https://docs.findock.com/_bundle/api/payment-api-v2.yaml)

## Payment Intent

 - [POST /PaymentIntent](https://docs.findock.com/api/payment-api-v2/payment-intent/paymentintent.md): The `/PaymentIntent` endpoint supports four POST operations: (1) create a new one-time payment, (2) create a new recurring payment, (3) pay an existing installment, and (4) update an existing recurrin
 - [GET /PaymentIntent/{ID}](https://docs.findock.com/api/payment-api-v2/payment-intent/paymentstatus.md): Use this operation to get the status of the inbound report of a payment intent along with information about the related installment or recurring payment (Recurring Payment, Gift Commitment or Recurrin
 - [PaymentIntent](https://docs.findock.com/api/payment-api-v2/payment-intent/paymentintent.md): Schema: #/components/schemas/PaymentIntent
## Installment

 - [GET /Installment/{ID}](https://docs.findock.com/api/payment-api-v2/installment/installmentdetails.md): This endpoint returns detailed information of an Installment record in Salesforce, including status and related Payment records.
## Recurring

 - [GET /Recurring/{ID}](https://docs.findock.com/api/payment-api-v2/recurring/recurringdetails.md): This endpoint returns detailed information of a recurring payment in Salesforce. The record is source-specific, so you need to ensure you are referencing the correct object record. The object may be t
## Payment Methods

 - [GET /PaymentMethods](https://docs.findock.com/api/payment-api-v2/payment-methods/getpaymentmethods.md): This endpoint returns a complete list of activated payment methods in the Salesforce org and the payment processors configured to process those methods.
## Source Connectors

 - [GET /SourceConnector](https://docs.findock.com/api/payment-api-v2/source-connectors/getsourceconnectors.md): This endpoint returns the configured source connectors in the Salesforce org.
## Package Actions

 - [GET /PackageActions](https://docs.findock.com/api/payment-api-v2/package-actions/getpackageactions.md): This endpoint returns a list of unique actions that specific to a given source connector or payment extension.
