Accept a Canadian pre-authorized debit payment
Build a custom payment form or use Stripe Checkout to accept payments with pre-authorized debit in Canada.
Accepting Canadian pre-authorized debit (PAD) payments on your website consists of creating an object to track a payment, collecting payment method information and mandate acknowledgement, submitting the payment to Stripe for processing and verifying your customer’s bank account.
Stripe uses this payment object, the Payment Intent, to track and handle all the states of the payment until the payment completes.
Set up StripeServer-side
First, you need a Stripe account. Register now.
Use our official libraries for access to the Stripe API from your application:
Create or retrieve a CustomerServer-side
To reuse a bank account for future payments, it must be attached to a Customer.
You should create a Customer object when your customer creates an account with your business. Associating the ID of the Customer object with your own internal representation of a customer enables you to retrieve and use the stored payment method details later.
Create a new Customer or retrieve an existing Customer to associate with this payment. Include the following code on your server to create a new Customer.
Create a PaymentIntentServer-side
A PaymentIntent is an object that represents your intent to collect a payment from a customer and tracks the lifecycle of the payment process through each stage.
In order to use Canadian pre-authorized debits, you must obtain authorization from your customer for one-time and recurring debits using a pre-authorized debit agreement (see PAD Mandates). The Mandate object records this agreement and authorization.
First, create a PaymentIntent on your server and specify the amount to collect and currency (usually cad
). If you already have another integration using the Payment Intents API, add acss_
to the list of payment method types for your PaymentIntent. Specify the id of the Customer.
If you want to reuse the payment method in the future, provide the setup_future_usage parameter with a value of off_
.
In order to define a payment schedule and verification method on the Mandate for this PaymentIntent, also include the following parameters:
Parameter | Value | Required? |
---|---|---|
payment_ | The mandate payment schedule. Accepted values are interval , sporadic , or combined . See the PAD Mandates overview to help you select the right schedule for your business. | Yes |
payment_ | Text description of the interval of payment schedule. See the PAD Mandates overview to help you construct the right interval description for your business. | If payment_ is specified as interval or combined |
payment_ | The type of the mandate you are creating, either personal (if your customer is an individual) or business (if your customer is a business). | Yes |
Retrieve the client secret
The PaymentIntent includes a client secret that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side.
Collect payment method details and submitClient-side
When a customer clicks to pay with Canadian pre-authorized debit, we recommend you use Stripe.js to submit the payment to Stripe. Stripe.js is our foundational JavaScript library for building payment flows. It will automatically handle integration complexities, and enables you to easily extend your integration to other payment methods in the future.
Include the Stripe.js script on your checkout page by adding it to the head
of your HTML file.
<head> <title>Checkout</title> <script src="https://js.stripe.com/v3/"></script> </head>
Create an instance of Stripe.js with the following JavaScript on your checkout page.
// Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe(
);'pk_test_TYooMQauvdEDq54NiTphI7jx'
Rather than sending the entire PaymentIntent object to the client, use its client secret from the previous step. This is different from your API keys that authenticate Stripe API requests.
The client secret should still be handled carefully because it can complete the charge. Do not log it, embed it in URLs, or expose it to anyone but the customer.
Use stripe.confirmAcssDebitPayment to collect bank account details and verification, confirm the mandate, and complete the payment when the user submits the form. Including the customer’s email address and the account holder’s name in the billing_
property of the payment_
parameter is required to create a PAD payment method.
const form = document.getElementById('payment-form'); const accountholderName = document.getElementById('accountholder-name'); const email = document.getElementById('email'); const submitButton = document.getElementById('submit-button'); const clientSecret = submitButton.dataset.secret; form.addEventListener('submit', async (event) => { event.preventDefault(); const {paymentIntent, error} = await stripe.confirmAcssDebitPayment( clientSecret, { payment_method: { billing_details: { name: accountholderName.value, email: email.value, }, }, } ); if (error) { // Inform the customer that there was an error. console.log(error.message); } else { // Handle next step based on PaymentIntent's status. console.log("PaymentIntent ID: " + paymentIntent.id); console.log("PaymentIntent status: " + paymentIntent.status); } });
Stripe.js then loads an on-page modal UI that handles bank account details collection and verification, presents a hosted mandate agreement and collects authorization.
Note
stripe.
may take several seconds to complete. During that time, disable your form from being resubmitted and show a waiting indicator like a spinner. If you receive an error, show it to the customer, re-enable the form, and hide the waiting indicator.
If successful, Stripe returns a PaymentIntent object, with one of the following possible statuses:
Status | Description | Next step |
---|---|---|
processing | The bank account has been instantly verified or verification was not necessary. | Step 6: Confirm the PaymentIntent succeeded |
requires_ | Further action needed to complete bank account verification. | Step 5: Verifying bank accounts with micro-deposits |
After successfully confirming the PaymentIntent, an email confirmation of the mandate and collected bank account details must be sent to your customer. Stripe handles these by default, but you can choose to send custom notifications if you prefer.
Note
Mandate confirmation emails will not be sent to the customer’s email address when testing the integration.
If the customer chooses to close the modal without completing the verification flow, Stripe.js returns the following error:
{ "error": { "type": "validation_error", "code": "incomplete_payment_details", "message": "Please provide complete payment details." } }
Verify bank account with micro-depositsClient-side
Not all customers can verify the bank account instantly. This step only applies if your customer has elected to opt out of the instant verification flow in the previous step.
In this case, Stripe automatically sends two micro-deposits to the customer’s bank account. These deposits take 1–2 business days to appear on the customer’s online statement and have statement descriptors that include ACCTVERIFY
.
The result of the stripe.
method call in the previous step is a PaymentIntent in the requires_
state. The PaymentIntent contains a next_
field that contains some useful information for completing the verification.
Stripe notifies your customer at the billing email when the deposits are expected to arrive. The email includes a link to a Stripe-hosted verification page where they can confirm the amounts of the deposits and complete verification.
There is a limit of three failed verification attempts. If this limit is exceeded, the bank account can no longer be verified. In addition, there is a timeout for micro-deposit verifications of 10 days. If micro-deposits are not verified in that time, the PaymentIntent reverts to requiring new payment method details. Clear messaging about what these micro-deposits are and how you use them can help your customers avoid verification issues.
Optional: Custom email and verification page
If you choose to send custom email notifications, you have to email your customer instead. To do this, you can use the verify_
URL in the next_
object to direct your customer to complete the verification process.
If you are sending custom emails and don’t want to use the Stripe hosted verification page, you can create a form on your site for your customers to relay these amounts to you and verify the bank account using Stripe.js.
stripe.verifyMicrodepositsForPayment(clientSecret, { amounts: [32, 45], });
When the bank account is successfully verified, Stripe returns the PaymentIntent object with a status
of processing
, and sends a payment_
webhook event.
Verification can fail for several reasons. The failure may happen synchronously as a direct error response, or asynchronously through a payment_
webhook event (shown in the following examples).
Error Code | Synchronous or asynchronous | Message | Status Change |
---|---|---|---|
payment_ | Synchronously, or asynchronously through webhook event | Microdeposits failed. Please check the account, institution and transit numbers provided | status is requires_ , and last_ is set. |
payment_ | Synchronously | The amounts provided do not match the amounts that were sent to the bank account. You have {attempts_remaining} verification attempts remaining. | Unchanged |
payment_ | Synchronously, and asynchronously through webhook event | Exceeded number of allowed verification attempts | status is requires_ , and last_ is set. |
payment_ | Asynchronously through webhook event | Microdeposit timeout. Customer hasn’t verified their bank account within the required 10 day period. | status is requires_ , and last_ is set. |
Confirm the PaymentIntent succeededServer-side
Canadian pre-authorized debits are a delayed notification payment method. This means that it can take up to five business days to receive notification of the success or failure of a payment after you initiate a debit from your customer’s account.
The PaymentIntent you create initially has a status of processing
. Successful completion of the payment updates the PaymentIntent status from processing
to succeeded
.
The following events are sent when the PaymentIntent status is updated:
Event | Description | Next step |
---|---|---|
payment_ | The customer’s payment was submitted to Stripe successfully. | Wait for the initiated payment to succeed or fail. |
payment_ | The customer’s payment succeeded. | Fulfill the goods or services that the customer purchased. |
payment_ | The customer’s payment was declined. This can also apply to a failed microdeposit verification. | Contact the customer via email or push notification and request another payment method. If the webhook was sent due to a failed microdeposit verification, the user needs to enter in their bank account details again and a new set of microdeposits will be deposited in their account. |
We recommend using webhooks to confirm the charge has succeeded and to notify the customer that the payment is complete. You can also view events on the Stripe Dashboard.
Test your integration
Receive micro-deposit verification email
In order to receive the micro-deposit verification email in test mode after collecting the bank account details and accepting a mandate, provide an email in the payment_
field in the form of {any_
when confirming the payment method details.
Test account numbers
Stripe provides several test account numbers you can use to make sure your integration for manually-entered bank accounts is ready for production. All test accounts that automatically succeed or fail the payment must be verified using the test micro-deposit amounts below before they can be completed.
Institution Number | Transit Number | Account Number | Scenario |
---|---|---|---|
000 | 11000 | 000123456789 | Succeeds the payment immediately after micro-deposits are verified. |
000 | 11000 | 900123456789 | Succeeds the payment with a three-minute delay after micro-deposits are verified. |
000 | 11000 | 000222222227 | Fails the payment immediately after micro-deposits are verified. |
000 | 11000 | 900222222227 | Fails the payment with a three-minute delay after micro-deposits are verified. |
000 | 11000 | 000666666661 | Fails to send verification micro-deposits. |
000 | 11000 | 000777777771 | Fails the payment due to the payment amount causing the account to exceed its weekly payment volume limit. |
000 | 11000 | 000888888881 | Fails the payment due to the payment amount exceeding the account’s transaction limit. |
To mimic successful or failed bank account verifications in test mode, use these meaningful amounts for micro-deposits:
Micro-deposit Values | Scenario |
---|---|
32 and 45 | Successfully verifies the account. |
Any other number combinations | Fails account verification. |