Importing Mandates#
Why import mandates?#
Importing mandates allows you to migrate existing Direct Debit authorisations from another provider into GoCardless without requiring your customers to re-authorise. Once imported, you can manage and collect against them alongside any mandates created directly through GoCardless.
This feature must be enabled on your account before use. Contact
support@gocardless.com or your account manager to request access.
Each mandate import can only contain mandates from a single scheme. If you're migrating mandates
across multiple schemes, you'll need a separate import for each.
How it works#
You create a Mandate Import specifying the scheme
You add an entry for each mandate you want to import
You submit the import for review
GoCardless reviews and approves the import
Mandates are created, and you reconcile them with your internal records
What happens to your customers
Customers do not need to take any action. Their mandate reference may change — if your scheme
requires this, you'll need to notify customers of the new reference in line with your scheme
rules.
Step-by-step guide#
Create a Mandate Import#
POST https://api.gocardless.com/mandate_imports HTTP / 1.1
{
"mandate_imports" : {
"scheme" : "sepa_core"
}
}
HTTP/ 1.1 201 (Created)
Location: /mandate_imports/IM 000010790 WX 1
{
"mandate_imports" : {
"id" : "IM000010790WX1" ,
"scheme" : "sepa_core" ,
"status" : "created" ,
"created_at" : "2018-03-12T14:03:04.000Z"
}
}
Hold onto the ID, you'll need it to add entries and submit.
Add Mandate Import Entries#
Add one entry per mandate. Each entry requires:
links.mandate_import: the ID from Step 1
customer: identifying details for the customer
bank_account: account holder name and either an IBAN or [local bank details]
record_identifier: Your own reference for this mandate (see below)
Set record_identifier for every entry
This is your reference string that links each entry back to your internal records. Without it,
reconciling your existing customer IDs with the new GoCardless IDs after the import is processed
is significantly harder. It must be unique within the mandate import.
SEPA mandates only: You must also provide amendment details, the original mandate reference, creditor ID, and creditor name from your previous provider. These are required by the SEPA scheme to maintain a valid audit trail.
PHP Python Ruby Java JavaScript net Go
$mandateImportEntry = $client -> mandateImportEntries () -> create ([
"params" => [
"links" => [
"mandate_import" => $mandateImport -> id
],
"record_identifier" => "bank-file.xml/line-1" ,
"customer" => [
"company_name" => "Théâtre du Palais-Royal" ,
"email" => "moliere@tdpr.fr"
],
"bank_account" => [
"account_holder_name" => "Jean-Baptiste Poquelin" ,
"iban" => "FR14BARC20000055779911"
],
// Amendment details are required for SEPA only
"amendment" => [
"original_mandate_reference" => "REFNMANDATE" ,
"original_creditor_id" => "FR123OTHERBANK" ,
"original_creditor_name" => "Amphitryon"
]
]
]); mandate_import_entry = client.mandate_import_entries.create( params = {
"links" : {
"mandate_import" : mandate_import.id
},
"record_identifier" : "bank-file.xml/line-1" ,
"customer" : {
"company_name" : "Théâtre du Palais-Royal" ,
"email" : "moliere@tdpr.fr"
},
"bank_account" : {
"account_holder_name" : "Jean-Baptiste Poquelin" ,
"iban" : "FR14BARC20000055779911"
},
# Amendment details are required for SEPA only
"amendment" : {
"original_mandate_reference" : "REFNMANDATE" ,
"original_creditor_id" : "FR123OTHERBANK" ,
"original_creditor_name" : "Amphitryon"
}
}) mandate_import_entry = @client. mandate_import_entries . create ( params: {
links: {
mandate_import: mandate_import. id
},
record_identifier: "bank-file.xml/line-1" ,
customer: {
company_name: "Théâtre du Palais-Royal" ,
email: "moliere@tdpr.fr"
},
bank_account: {
account_holder_name: "Jean-Baptiste Poquelin" ,
iban: "FR14BARC20000055779911"
},
# Amendment details are required for SEPA only
amendment: {
original_mandate_reference: "REFNMANDATE" ,
original_creditor_id: "FR123OTHERBANK" ,
original_creditor_name: "Amphitryon"
}
}) MandateImportEntry mandateImportEntry = client. mandateImportEntries (). create ()
. withCustomerCompanyName ( "Théâtre du Palais-Royal" )
. withCustomerEmail ( "moliere@tdpr.fr" )
. withBankAccountAccountHolderName ( "Jean-Baptiste Poquelin" )
. withBankAccountIban ( "FR14BARC20000055779911" )
// Amendment details are required for SEPA only
. withAmendmentOriginalMandateReference ( "REFNMANDATE" )
. withAmendmentOriginalCreditorId ( "FR123OTHERBANK" )
. withAmendmentOriginalCreditorName ( "Amphitryon" )
. withLinksMandateImport (mandateImport. getId ())
. execute (); const request = {
customer: {
company_name: "Théâtre du Palais-Royal" ,
email: "moliere@tdpr.fr" ,
},
bank_account: {
account_holder_name: "Jean-Baptiste Poquelin" ,
iban: "FR14BARC20000055779911" ,
},
// Amendment details are required for SEPA only
amendment: {
original_mandate_reference: "REFNMANDATE" ,
original_creditor_id: "FR123OTHERBANK" ,
original_creditor_name: "Amphitryon" ,
},
links: {
mandate_import: mandateImport.id,
},
};
const mandateImportEntry = await client.mandateImportEntries. create (request); var request = new GoCardless.Services.MandateImportEntryCreateRequest()
{
Customer = new GoCardless.Services.MandateImportEntryCreateRequest.MandateImportEntryCustomer()
{
CompanyName = "Théâtre du Palais-Royal"
Email = "moliere@tdpr.fr"
}
BankAccount = new GoCardless.Services.MandateImportEntryCreateRequest.MandateImportEntryBankAccount()
{
AccountHolderName = "Jean-Baptiste Poquelin"
Iban = "FR14BARC20000055779911"
}
// Amendment details are required for SEPA only
Amendment = new GoCardless.Services.MandateImportEntryCreateRequest.MandateImportEntryAmendment()
{
OriginalMandateReference = "REFNMANDATE"
OriginalCreditorId = "FR123OTHERBANK"
OriginalCreditorName = "Amphitryon"
}
Links = new GoCardless.Services.MandateImportEntryCreateRequest.MandateImportEntryLinks()
{
MandateImport = mandateImport.Id
}
};
var importResponse = await gocardless.MandateImportEntries.CreateAsync(request);
GoCardless.Resources.MandateImportEntry entry = importResponse.MandateImportEntry; ctx := context. TODO ()
mandateImportEntryCreateParams := gocardless . MandateImportEntryCreateParams {
Customer: gocardless . MandateImportEntryCreateParamsCustomer {
CompanyName: "Théâtre du Palais-Royal" ,
Email: "moliere@tdpr.fr" ,
},
BankAccount: gocardless . MandateImportEntryCreateParamsBankAccount {
AccountHolderName: "Jean-Baptiste Poquelin" ,
Iban: "FR14BARC20000055779911" ,
},
Amendment: & gocardless . MandateImportEntryCreateParamsAmendment {
OriginalMandateReference: "REFMANDATE" ,
OriginalCreditorId: "FR123OTHERBANK" ,
OriginalCreditorName: "Amphitryon" ,
},
Links: gocardless . MandateImportEntryCreateParamsLinks {
MandateImport: "MandateImportId" ,
},
}
client. MandateImportEntries (). Create (ctx, mandateImportEntryCreateParams)
POST https://api.gocardless.com/mandate_import_entries HTTP / 1.1
{
"mandate_import_entries" : {
"links" : {
"mandate_import" : "IM000010790WX1"
},
"record_identifier" : "bank-file.xml/line-1" ,
"customer" : {
"company_name" : "Théâtre du Palais-Royal" ,
"email" : "moliere@tdpr.fr"
},
"bank_account" : {
"account_holder_name" : "Jean-Baptiste Poquelin" ,
"iban" : "FR14BARC20000055779911"
},
"amendment" : {
"original_mandate_reference" : "REFNMANDATE" ,
"original_creditor_id" : "FR123OTHERBANK" ,
"original_creditor_name" : "Amphitryon"
}
}
}
HTTP/ 1.1 201 (Created)
{
"mandate_import_entries" : {
"record_identifier" : "bank-file.xml/line-1" ,
"created_at" : "2018-03-03T00:00:00Z" ,
"links" : {
"mandate_import" : "IM000010790WX1"
}
}
}
Repeat for each mandate. If you provide invalid data, the API returns a descriptive error for that entry — fix it and retry before submitting.
SEPA example with amendment details:
curl -X POST https://api.gocardless.com/mandate_import_entries \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mandate_import_entries": {
"links": {
"mandate_import": "IM123"
},
"record_identifier": "your-internal-customer-id-456",
"customer": {
"company_name": "Théâtre du Palais-Royal",
"email": "moliere@tdpr.fr"
},
"bank_account": {
"account_holder_name": "Jean-Baptiste Poquelin",
"iban": "FR14BARC20000055779911"
},
"amendment": {
"original_mandate_reference": "REFNMANDATE",
"original_creditor_id": "FR123OTHERBANK",
"original_creditor_name": "Amphitryon"
}
}
}
Submit for Review#
Once all entries are added, submit the import. All imports are reviewed by GoCardless before processing to prevent fraudulent use.
POST https://api.gocardless.com/mandate_imports/IM000010790WX1/actions/submit HTTP / 1.1
HTTP / 1.1 200 (OK)
{
"mandate_imports" : {
"id" : "IM000010790WX1" ,
"scheme" : "bacs" ,
"status" : "submitted" ,
"created_at" : "2018-03-12T14:03:04.000Z"
}
}
Need to cancel?
You can cancel a submitted import before it is approved using the [cancellation API]. Once
approved, an import cannot be reversed.
Await Approval#
GoCardless reviews all submitted imports before processing. During this time the import status will be submitted.
Common reasons for rejection:
Entries contain invalid or mismatched bank details
SEPA amendment details are missing or incorrect
The scheme specified doesn't match the bank accounts provided
If your import is rejected, GoCardless will contact you with details. You'll need to create a new import with corrected entries.
Reconcile your records#
When the import is approved, GoCardless processes the mandates. You'll receive webhooks as each mandate is created, the same events as mandates created through the standard API:
Event Meaning mandate.createdMandate successfully imported mandate.activeMandate active and ready to collect against mandate.failedMandate could not be created (e.g. invalid bank details)
To map your internal records to the new GoCardless IDs, retrieve the entries once the import status is processed. Match each entry using the record_identifier you set in Step 2:
GET https://api.gocardless.com/mandate_import_entries?mandate_import=IM000010790WX1 HTTP / 1.1
HTTP / 1.1 200 (OK)
{
"mandate_import_entries" : [
{
"record_identifier" : "bank-file.xml/line-2" ,
"created_at" : "2018-03-03T00:00:01Z" ,
"links" : {
"mandate_import" : "IM000010790WX1" ,
"customer" : "CU456" ,
"customer_bank_account" : "BA456" ,
"mandate" : "MD456"
}
},
{
"record_identifier" : "bank-file.xml/line-1" ,
"created_at" : "2018-03-03T00:00:00Z" ,
"links" : {
"mandate_import" : "IM000010790WX1" ,
"customer" : "CU123" ,
"customer_bank_account" : "BA123" ,
"mandate" : "MD123"
}
}
],
"meta" : {
"cursors" : {
"before" : null ,
"after" : null
},
"limit" : 50
}
}
Use the mandate ID from each entry to start collecting payments. See One-off payments and Recurring payments .
What's next?#