Skip to main content
Work in progressThis section is currently under active development as part of improvements planned for 2026. Content may change as we expand product capabilities.If you’re interested in early access or want to learn more about what’s coming, feel free to reach out to the team.
This guide walks through the complete flow to generate a PAD (Pre-Authorized Debit) signing link using the EFT API, starting from a contact ID. The PAD link is a URL you present to your end user so they can authorize the payment.

Prerequisites

  • A valid x-client-id API key
  • A stored contact with at least one EFT bank account

Overview

The flow requires five API calls in sequence:
StepEndpointReturns
1GET /api/v1/contacts/{contactId}Contact details + bank account IDs
2GET /api/v1/purposecategories/{direction}Valid purpose codes
3POST /api/v1/transactionsSchedule with id
4GET /api/v1/schedules/{scheduleId}Schedule details with padId
5GET /api/v1/pads/{padId}PAD details with padLink

Step 1: Get the Contact

Retrieve the contact to obtain their EFT bank account ID.
curl 'https://payments.flinksapp.com/api/v1/contacts/{{contactId}}' \
  --header 'x-client-id: {{your-client-id}}'
From the response, note the id from the contact’s EFT account — you’ll use it as the accountId in the transaction request.

Step 2: Get Purpose Categories

Fetch the available purpose categories for DEBIT transactions.
curl 'https://payments.flinksapp.com/api/v1/purposecategories/Debit' \
  --header 'x-client-id: {{your-client-id}}'
Each category contains purposeCodes — pick the one that matches your use case and note its value. This becomes the transactionCode in the next step.

Step 3: Create the Transaction

Create a DEBIT transaction using the contact’s contactId and accountId from Step 1, and the transactionCode from Step 2.
curl 'https://payments.flinksapp.com/api/v1/transactions' \
  --header 'Content-Type: application/json' \
  --header 'x-client-id: {{your-client-id}}' \
  --data '[{
    "transactionCode": 450,
    "amount": 250.00,
    "paymentDirection": "DEBIT",
    "currency": "CAD",
    "payor": {
      "accountInfo": {
        "accountId": "{{accountId}}"
      },
      "contactInfo": {
        "contactId": "{{contactId}}"
      }
    },
    "scheduleInfo": {
      "paymentFrequency": "Monthly",
      "startDate": "2026-05-01",
      "transactionsCount": 12
    }
  }]'
The response contains a schedules array. Note the id (schedule ID) from the first item.
The padId field in the create transaction response is null at this point. The PAD agreement is generated asynchronously — you need to poll the schedule to obtain it.

Step 4: Get the Schedule (poll for padId)

Retrieve the schedule to check if the PAD has been generated.
curl 'https://payments.flinksapp.com/api/v1/schedules/{{scheduleId}}' \
  --header 'x-client-id: {{your-client-id}}'
Check the padId field in the response:
  • If padId is not null — proceed to Step 5
  • If padId is null — the PAD is still being generated; wait and retry
We recommend polling every 2–3 seconds for up to 30 seconds. If padId is still null after that, contact Flinks support.
Once you have the padId, retrieve the PAD agreement details including the signing link.
curl 'https://payments.flinksapp.com/api/v1/pads/{{padId}}' \
  --header 'x-client-id: {{your-client-id}}'
The response includes a padLink field — this is the URL you present to your end user.

Presenting the PAD to the End User

Redirect or display the padLink to your end user so they can review and sign the PAD agreement. Once signed, the payment schedule becomes active.
// Example: redirect user to the PAD signing page
window.location.href = padLink;

Complete Example

const BASE_URL = 'https://payments.flinksapp.com/api/v1';
const headers = {
  'Content-Type': 'application/json',
  'x-client-id': 'your-client-id'
};

async function generatePadLink(contactId) {
  // Step 1: Get contact details
  const contact = await fetch(`${BASE_URL}/contacts/${contactId}`, { headers })
    .then(r => r.json());

  const accountId = contact.accounts.eftAccounts[0].id;

  // Step 2: Get purpose categories
  const categories = await fetch(`${BASE_URL}/purposecategories/Debit`, { headers })
    .then(r => r.json());

  const transactionCode = categories[0].purposeCodes[0].value;

  // Step 3: Create transaction
  const txResponse = await fetch(`${BASE_URL}/transactions`, {
    method: 'POST',
    headers,
    body: JSON.stringify([{
      transactionCode,
      amount: 250.00,
      paymentDirection: 'DEBIT',
      currency: 'CAD',
      payor: {
        accountInfo: { accountId },
        contactInfo: { contactId }
      },
      scheduleInfo: {
        paymentFrequency: 'Monthly',
        startDate: '2026-05-01',
        transactionsCount: 12
      }
    }])
  }).then(r => r.json());

  const scheduleId = txResponse.schedules[0].id;

  // Step 4: Poll schedule for padId
  let padId = null;
  for (let i = 0; i < 10; i++) {
    const schedule = await fetch(`${BASE_URL}/schedules/${scheduleId}`, { headers })
      .then(r => r.json());

    if (schedule.padId) {
      padId = schedule.padId;
      break;
    }
    await new Promise(resolve => setTimeout(resolve, 3000));
  }

  if (!padId) throw new Error('PAD not generated within timeout');

  // Step 5: Get PAD link
  const pad = await fetch(`${BASE_URL}/pads/${padId}`, { headers })
    .then(r => r.json());

  return pad.padLink;
}

API Reference