Payment Service Provider

Payment service providers can build an App to handle payments. Following are the requirements.


Settings

Apps will most likely have to be configured with api keys and other credentials. We recommend you start onboarding the customer directly after installation, when we call your configured redirect_uri. To give users the possibility to edit these settings later, you could add a command with identifier settings and context model subscription, which will add a button at the top of your app.


Payment Methods

You will receive payment requests for payments methods that are managed by your app. An API Managed payment method can be added to BEX via the POST payment_method endpoint. An example can be found in the Recipe below.

After you've created a payment method, save the ID in the response data to your system. When we send a payment request, we will pass this ID in the payment_request relationship. This way, you know which payment method the customer selected.


Initiate payment

Apps that act as a payment provider must provide an command with identifier initiate_payment and context model payment_request. This command will be invoked when a user makes an online payment.

The response of this command must be a redirect URL to a payment page when no issues occur, otherwise it should return a notice or an alert.

When you receive a status update on the payment from the Payment Service Provider, (ex: when the payment is successful or failed), you must invoke the 'payment result' endpoint to update the payment state of the payment request. After having done this, the user must be redirected to the url passed as the back_url parameter to the initiate_payment command.

Below, there is an example of a payment_request, sent to the endpoint handling the initiate_payment command, followed by the response to this command, and an example of the payment_result that the app sent when a payment arrives. See POST payment_results for more information about payment_results.

// Payload for the endpoint of the initiate_payment command

{
  "data": {
    "id": "541",
    "type": "payment_request",
    "attributes": {
      "price": { "currency": "EUR", "value": "312.56" },
      "locale": "nl",
      "country_code": "NL",      
      "description": "Rent for reservation B123",
      "reference": "B123"
    },
    "relationships": {
      "payment_method": {
        "data": {
          "id": "24",
          "type": "payment_method"
        }
      },
      "debtor": {
        "data": {
          "id": "11",
          "type": "debtor"
        }
      },
      "administration": {
        "data": {
          "id": "3",
          "type": "administration"
        }
      }
    }
  }
}
 
// Response to the initiate_payment command, that will redirect the customer to the given url.

{ "redirect_url": "https://mypaymentprovider.com/start_payment/2abe47d423f0" }

 
// Endpoint: POST payment_results

{
  "data": {
    "type": "payment_result",
    "attributes": {
      "amount": {
        "currency": "EUR",
        "value": "312.56"
      },
      "result": "success",
      "enable_recurring_payments": false
    },
    "relationships": {
      "payment_request": {
        "data": {
          "id": "541",
          "type": "payment_request"
        }
      }
    }
  }
}
 

Initiate refund

Payment provider apps that support refund must provide an command with identifier initiate_refund and context model refund_request. This command will be invoked when a user refunds a payment that has been created through your app. In the relationships object, you will receive the payment ID and the payment request ID that was sent when the payment was started using initiate_payment.

The response of this command must be a notice or an alert. When receiving an alert, the refund request will be deleted.

When you receive a status update of the refund from the Payment Service Provider, (ex: when the refund is refunded or failed) you must invoke the 'refund result' endpoint to update the state of the refund request.

Below, there is an example of a refund_request sent to the endpoint handling the initiate_refund command, followed by examples of a successful or error response to this command, and an example of the refund_result that the app sent when a refund has been refunded. See POST refund_results for more information about refund_results.

// Payload for the endpoint of the initiate_refund command
{
  "data": {
    "id": "1",
    "type": "refund_request",
    "attributes": {
      "amount": {
        "currency": "EUR",
        "value": "1.00"
      },
      "locale": "en",
      "description": "Refund of € 1,00",
      "status": "open"
    },
    "relationships": {
      "payment_request": {
        "data": {
          "id": "1",
          "type": "payment_request"
        }
      },
      "payment": {
        "data": {
          "id": "1",
          "type": "payment"
        }
      }
    }
  }
}
// Example success response to the initiate_refund command
{ "notice": "Refund initiated!" }
 
// Example error response to the initiate_refund command
{ "alert": "Could not find the payment to refund" }

// Endpoint: POST refund_results

{
  "data": {
    "type": "refund_result",
    "attributes": {
      "amount": {
        "currency": "EUR",
        "value": "1.00"
      },
      "result": "refunded"
    },
    "relationships": {
      "refund_request": {
        "data": {
          "id": "1",
          "type": "refund_request"
        }
      }
    }
  }
}

Chargebacks

A chargeback can be sent for a given payment request. This will create a chargeback payment (negative) for the given amount and notify the administration. Be sure to pass a unique reference as we will use it to check if we have already processed the chargeback.

A chargeback request can be seen below. When successful, you will receive the chargeback back as the response or an error when something went wrong. For example, you might receive an error with code DUPLICATE_CHARGEBACK when the reference is already known in our system.

See POST chargebacks for more information about chargebacks.

// Endpoint: POST chargebacks
 {
  "data": {
    "type": "chargeback",
    "attributes": {
      "amount": {
        "currency": "EUR",
        "value": "1.00"
      },
      "reference": "chargeback_1"
    }
  }
}

Recurring payments

Apps that support recurring payments must provide commands with identifiers :

  • initiate_initial_recurring_payment
  • initiate_recurring_payment
  • delete_mandates
  • respective context models of payment_request, payment_request and debtor.

Initiate initial Recurring payment

This command will be invoked when an owner wants to give a mandate for automatic recurring payments.

The response of this command must be a redirect URL to a payment page when no issues occur, otherwise it should return a notice or an alert.

When the mandate is successful you must communicate this using the payment_result endpoint and enable recurring payments by setting the enable_recurring_payments parameter.

After having done this, the user must be redirected to the url passed as the return_url parameter to the initiate_payment command.

All in all it is very similar to the initiate_payment command, except for having to set the enable_recurring_payments properly as shown in the example below.

// Endpoint: POST payment_results
{
  "data": {
    "type": "payment_result",
    "attributes": {
      "amount": {
        "currency": "EUR",
        "value": "312.56"
      },
      "result": "success",
      "enable_recurring_payments": true
    },
    "relationships": {
      "payment_request": {
        "data": {
          "id": "541",
          "type": "payment_request"
        }
      }
    }
  }
}

Initiate recurring payment

This command will be invoked whenever a recurring payment is made. This always happens without any user involvement. Instead of a redirect you must return the json shown below. If unsuccessful, you may return one of the following errors:

  • no_mandate: Owner will receive a message describing them how to create a new mandate. Recurring payments will be disabled for that owner in Booking Experts.
  • no_customer: Owner will receive a message informing them that they are not known at the side of the payment provider. Recurring payments will be disabled for that owner in Booking Experts.
  • amount_too_high: Owner will receive a message explaining the amount on the invoice is too high to be paid through recurring payments and the owner will be instructed to pay this invoice manually. In this case recurring payments will remain enabled for the owner, but this invoice will no longer be retried.
// Response to the initiate_recurring_payment command if successful
{ "data": { "success": true } }
// Response to the initiate_recurring_payment command if failed
{ "data": { "success": false, "error": "no_mandate" } }

Delete mandates

This command will be invoked whenever an owner want to delete their mandate. In that case you could delete the mandate in the Payment Service Provider. You must return the json shown below.

// Response to the delete_mandates command if successful
{ "data": { "success": true } }
// Response to the delete_mandates command if failed
{ "data": { "success": false, "error_message": "Mandate does not exist" } }

Redirect to Payment Service Provider

Apps can provide a command with identifier redirect_to_psp_backoffice and a payment_request context model. If this command is present, payment requests in Booking Experts will have a link the user can click that invokes this command. The response of this command must be a redirect to the page that shows this payment request in the psp backoffice, so the user can inspect the payment's status in there. See the example on the right.

// Payload for the endpoint of the redirect_to_psp_backoffice command
{
  "data": {
    "id": "541",
    "type": "payment_request",
    "attributes": {
      "price": { "currency": "EUR", "value": "312.56" },
      "locale": "nl",
      "description": "Rent for reservation B123",
      "reference": "B123"
    },
    "relationships": {
      "payment_method": {
        "data": {
          "id": "24",
          "type": "payment_method"
        }
      },
      "debtor": {
        "data": {
          "id": "11",
          "type": "debtor"
        }
      },
      "administration": {
        "data": {
          "id": "3",
          "type": "administration"
        }
      }
    }
  }
}

// Response to the redirect_to_psp_backoffice command, that will redirect the customer to the given url.
{ "redirect_url": "https://mypaymentprovider.com/show_payment/2abe47d423f0" }