Supporting mandates set up outside of your product#
Some of your users will already have Direct Debit mandates set up with their payers. Let them link those mandates to customer records in your platform, so they can collect payments straight away.
Some of your users already use GoCardless, and have Direct Debit mandates set up with their payers before connecting to your platform.
Your users can move their existing mandates from another Direct Debit provider to GoCardless in a bulk change (subject to availability).
Your users might set up some mandates in the GoCardless dashboard, through the API or through another integration, to suit how they work.
Choose how to import mandates#
- Automatic matching (recommended): your platform lists your user's mandates and links them to your customer records. Your user only reviews what can't be matched
- Manual import: your user exports their customers from your platform as a spreadsheet, adds the GoCardless mandate IDs and uploads it back
Build automatic mandate matching#
1. Retrieve your user's mandates#
When your user clicks "Import mandates" after connecting their GoCardless account, your platform should immediately fetch their mandates using their saved access token. Make a List mandates request, filter by the statuses you want to import, and set the include parameter to customer,bank_account so that the linked customers and bank accounts are returned in the same response.
Importing mandates with the active, submitted and pending_submission statuses covers every mandate that is, or is about to be, usable for collecting payments.
The linked customers and bank accounts are returned in top-level linked.customers and linked.bank_accounts arrays, alongside the mandates array. Look up each mandate's customer by matching mandates[].links.customer against linked.customers[].id, and its bank account by matching mandates[].links.customer_bank_account against linked.bank_accounts[].id:
The response is paginated. Follow the after cursor in meta.cursors until there are no more pages, so that you retrieve every mandate. See cursor pagination.
2. Match mandates to your customer records#
Once the data is retrieved, run automated matching. The matching logic is tiered: each tier is attempted in order, and the first successful match wins. Unresolved records fall through to the next tier.
Skip any mandate that is already linked to a customer in your platform, so that running the import again never creates duplicate links. Users with a lot of mandates can take a while to process, so run matching as a background job rather than within a single web request, to avoid request timeouts.
Tier 1: Exact email match#
Compare customer.email (GoCardless) against the customer's email in your platform. This is the highest-confidence match and will resolve the majority of records. Treat an email that matches exactly one record in your platform as confirmed, without requiring your user to review it.
Don't match automatically when the email is blank, or when it matches more than one record in your platform, as it isn't possible to tell which record is correct. Move on to the next tier instead.
Tier 2: Metadata match#
If no email match is found, check whether the GoCardless customer record contains your metadata key (for example partner_id) with a value that corresponds to a customer ID in your platform.
Tier 3: Fuzzy name and postal code match (optional)#
If neither of the above tiers produces a match, attempt a fuzzy match on the combination of the customer's full name and postal code.
Show fuzzy matches in the summary as "Suggested matches" rather than automatic matches. Your user should review and confirm these before they're linked.
Records that fail all tiers are marked "Unmatched" and need your user to match them manually.
3. Let your user review the results#
Once matching completes, show your user a summary of what was matched automatically and what needs their attention:
| Status | Count | Action required |
|---|---|---|
| Matched automatically | 85 | None. Show them for reference, so your user can unmatch any that are wrong. |
| Suggested matches | 6 | Your user confirms the match or picks a different customer record |
| Unmatched | 5 | Your user matches the mandate to a customer record |
You'll only have suggested matches if you use name and postcode matching.
For each suggested or unmatched mandate, show the payer's name, email, bank name and account ending, and the mandate reference, alongside a search or dropdown of your customer records. This helps your user pick the right record.
Your user should be able to:
- Confirm a suggested match
- Pick a different customer record for a suggested match
- Match an unmatched mandate to a customer record
- Skip a mandate that shouldn't be linked, for example for a payer who's no longer a customer
- Unmatch a mandate linked to the wrong record, and match it again
4. Save the link#
When a mandate is linked, automatically or by your user:
- Save the mandate ID, the GoCardless customer ID and how it was matched against your customer record. You'll use the mandate ID to collect payments
- Add your customer ID to the GoCardless customer's metadata, using the same key every time (these docs use
partner_id). The next import then matches it straight away
You only need the bank details from linked.bank_accounts for display. Don't store full bank details.
When your user unmatches a mandate, remove the link from your record and your key (partner_id in this example) from the customer's metadata, in the same way, so the next import doesn't link it again.
5. Keep matching new mandates#
Your user can set up mandates outside your product after their first import. When you receive a mandate webhook for a mandate you haven't saved:
- Get the mandate and its customer. Don't rely on the webhook body
- Skip it if its status is
failed,cancelled,expired,consumedorblocked - Match it as in step 2, then link it or add it to review
Webhooks can arrive in any order. If a mandate you set up through a Billing Request matched by email first, let the link from the fulfilled webhook take over.
Edge cases#
| Case | What to do |
|---|---|
| Your user has no mandates | Show an empty state. Don't show the review list. |
| You hit the rate limit | Back off and retry from the last after cursor. See rate limiting. |
| Your access token stops working | Ask your user to reconnect their account. |
| A linked mandate is replaced | Update the saved mandate ID to links.new_mandate from the replaced webhook. |
| A linked mandate is cancelled, fails or expires | Keep the link, update the state and show the new status. Let your user ask the payer for a new mandate. See mandate webhooks. |