Learn how to send a SWIFT wire programmatically from any bank in 30 minutes using the ISO 20022 standard.


Sending international payments can be complex, but with the right tools and information, you can automate SWIFT wire transfers seamlessly. In this guide, we’ll walk you through how to send a SWIFT wire programmatically, what recipient information you’ll need, and the software required to make it happen. We’ll use Python code samples with pyiso20022 to illustrate the process.


Swift Transfer Diagram

Step 1: Configure Direct Transmission With Your Bank

To send SWIFT payments directly, you’ll need to communicate with your bank programmatically. This involves setting up direct transmission, typically via SFTP (Secure File Transfer Protocol). Think of it as a secure shared folder where you deposit your payment instructions.

Action Items:

  • Contact your bank to set up direct transmission capabilities.
  • Obtain SFTP credentials and any necessary configuration details.

Step 2: Retrieve Credentials From Your Bank

Before initiating payments, gather essential information from your bank:

  • SFTP Host Credentials:
    • Host URL
    • Username
    • Password
    • Unique ID (if applicable)
  • Your Bank Account Details:
    • Account number
    • Bank Identifier Code (BIC)
    • Country of origin

Example:

# Store your bank's SFTP credentials securely
SFTP_HOST = 'sftp.piggybank.com'
SFTP_USERNAME = 'your_username'
SFTP_PASSWORD = 'your_password'
BANK_UNIQUE_ID = 'SAASSTARTUP'

# Your bank account details
BANK_ACCOUNT_NUMBER = '123456789012'
BANK_BIC = 'PIGGUS33'
BANK_COUNTRY = 'US'

Step 3: Collect the Creditor (Payee) Information

Gather the necessary information about the recipient to ensure the payment clears successfully. Requirements may vary by country, but generally, you’ll need:

  • Creditor’s Name: e.g., PaaS Corp
  • Creditor’s Bank Account Number: e.g., 0001001112345
  • Creditor’s Bank’s BIC: e.g., WARTHOGJPJT
  • Creditor’s Address:
    • Street address
    • City
    • Postal code
    • Country
  • Payment Details:
    • Amount and currency (e.g., 1,000,000 JPY)
    • Purpose or remittance information (e.g., Payment for services rendered)

Example:

creditor = {
    'name': 'PaaS Corp',
    'account_number': '0001001112345',
    'bic': 'WARTHOGJPJT',
    'address': {
        'street_name': '1-2-3 Shibuya',
        'town_name': 'Shibuya-ku',
        'postal_code': '150-0002',
        'country': 'JP',
    }
}

Step 4: Create ISO 20022 Payment Initiation Message

With all the necessary information, you can now create an ISO 20022-compliant payment initiation message. This XML standard is used globally for financial messaging, ensuring interoperability between banks.

We’ll use the pyiso20022 Python library to construct the message. If you don’t have this library, you can install it using pip.

Installation:

pip install pyiso20022

Example:

import datetime
from pyiso20022 import pain_001_001_03 as pain
from lxml import etree

# Create the initiating party
initiating_party = pain.PartyIdentification32(
    Nm='SaaS Startup',
    Id=pain.Party6Choice(
        OrgId=pain.OrganisationIdentification4(
            BICOrBEI=BANK_UNIQUE_ID
        )
    )
)

# Create the payment information
payment_info = pain.PaymentInstructionInformation3(
    PmtInfId='PMT123456789',
    PmtMtd='TRF',
    NbOfTxs='1',
    CtrlSum=1000000.00,
    PmtTpInf=pain.PaymentTypeInformation19(
        InstrPrty='NORM'
    ),
    ReqdExctnDt=datetime.date.today(),
    Dbtr=initiating_party,
    DbtrAcct=pain.CashAccount16(
        Id=pain.AccountIdentification4Choice(
            Othr=pain.GenericAccountIdentification1(
                Id=BANK_ACCOUNT_NUMBER
            )
        )
    ),
    DbtrAgt=pain.BranchAndFinancialInstitutionIdentification4(
        FinInstnId=pain.FinancialInstitutionIdentification7(
            BIC=BANK_BIC
        )
    ),
    CdtTrfTxInf=[
        pain.CreditTransferTransactionInformation10(
            PmtId=pain.PaymentIdentification1(
                InstrId='INSTR123456789',
                EndToEndId='E2E123456789'
            ),
            Amt=pain.AmountType3Choice(
                InstdAmt=pain.ActiveOrHistoricCurrencyAndAmount(
                    Ccy='JPY',
                    value=1000000.00
                )
            ),
            CdtrAgt=pain.BranchAndFinancialInstitutionIdentification4(
                FinInstnId=pain.FinancialInstitutionIdentification7(
                    BIC=creditor['bic']
                )
            ),
            Cdtr=pain.PartyIdentification32(
                Nm=creditor['name'],
                PstlAdr=pain.PostalAddress6(
                    StrtNm=creditor['address']['street_name'],
                    TwnNm=creditor['address']['town_name'],
                    PstCd=creditor['address']['postal_code'],
                    Ctry=creditor['address']['country']
                )
            ),
            CdtrAcct=pain.CashAccount16(
                Id=pain.AccountIdentification4Choice(
                    Othr=pain.GenericAccountIdentification1(
                        Id=creditor['account_number']
                    )
                )
            ),
            RmtInf=pain.RemittanceInformation5(
                Ustrd=['Payment for services rendered']
            )
        )
    ]
)

# Create the group header
group_header = pain.GroupHeader32(
    MsgId='MSG123456789',
    CreDtTm=datetime.datetime.now(),
    NbOfTxs='1',
    CtrlSum=1000000.00,
    InitgPty=initiating_party
)

# Assemble the CustomerCreditTransferInitiationV03 message
credit_transfer = pain.CustomerCreditTransferInitiationV03(
    GrpHdr=group_header,
    PmtInf=[payment_info]
)

# Generate the XML
document = pain.Document(CstmrCdtTrfInitn=credit_transfer)
payment_xml = etree.tostring(
    document.to_etree(), pretty_print=True, xml_declaration=True, encoding='UTF-8'
)

Step 5: Send ISO 20022 Payment Initiation Message to the Bank

With your payment initiation message ready, you can now send it to your bank via SFTP.

Example:

import paramiko
import io

# Establish SFTP connection
transport = paramiko.Transport((SFTP_HOST, 22))
transport.connect(username=SFTP_USERNAME, password=SFTP_PASSWORD)
sftp = paramiko.SFTPClient.from_transport(transport)

# Define the remote file path
remote_file_name = f'SAASSTARTUP_{datetime.datetime.now():%Y%m%d%H%M%S}.xml'
remote_file_path = f'/payments/{remote_file_name}'

# Upload the payment initiation XML
with io.BytesIO(payment_xml) as file_obj:
    sftp.putfo(file_obj, remote_file_path)

# Close the connection
sftp.close()
transport.close()

Retrospective

Congratulations on sending an international SWIFT payment over the internet!

By automating SWIFT payments using Python and the ISO 20022 standard, you’ve streamlined a complex process into a few manageable steps.


Next Steps

  • Process Incoming Transactions: Adapt your system to handle incoming payments and acknowledgments.
  • Monitor Account Balances: Integrate balance checks into your workflow.
  • Expand Automation: Explore automating other banking operations like reconciliations and reporting.

Reference: Original Guide