How To: Implement Interac Payments

Learn how to accept Interac e-Transfer payins via the Coinflow API.

Overview

Merchants can accept payments from Canadian customers via Interac e-Transfer. Coinflow supports two checkout flows:

  • New Contact Checkout — for a customer’s first Interac payin, or to send the e-Transfer request to a different email/phone than what’s on file.
  • Saved Contact Checkout — for returning customers, using a previously saved Interac contact.

In both cases, calling the checkout endpoint only initiates the e-Transfer request — the customer still has to complete the payment themselves from their own banking app before funds settle.

Interac payins must be enabled on your merchant account before you can use these endpoints. Contact the Coinflow integrations team to enable Interac payins and configure your fee settings.

Prerequisites

Before implementing Interac payins, ensure:

  1. Interac payins are enabled on your merchant account (contact the Coinflow integrations team).
  2. Customer has a Canadian bank account enrolled in Interac e-Transfer with Autodeposit, or is able to access their online banking app to manually accept an e-Transfer.

Interac payins are presented and settled in CAD. subtotal.currency must be CAD on every request below — passing any other currency returns an error.

1. Create a Session Key

Call the Get Session Key endpoint to authenticate the customer. The x-coinflow-auth-user-id can be any unique customer identifier string that you, the merchant, use to identify the buyer.

$curl --request GET \
> --url https://api-sandbox.coinflow.cash/api/auth/session-key \
> --header 'Authorization: YOUR_API_KEY' \
> --header 'accept: application/json' \
> --header 'x-coinflow-auth-user-id: user123'
1{
2 "key": "<SESSION_KEY>"
3}

Pass this key as the x-coinflow-auth-session-key header on every subsequent request in this guide.

2. (Optional) Tokenize Checkout Parameters

If the checkout call is made from the browser rather than server-to-server, use the Get Checkout Jwt Token endpoint from your backend to lock in the purchase parameters before the customer’s device calls checkout. This prevents the amount or other sensitive fields (like webhookInfo) from being tampered with client-side.

$curl --request POST \
> --url https://api-sandbox.coinflow.cash/api/checkout/jwt-token \
> --header 'Authorization: YOUR_API_KEY' \
> --header 'accept: application/json' \
> --header 'content-type: application/json' \
> --data '{
> "subtotal": {
> "currency": "CAD",
> "cents": 5000
> },
> "settlementType": "USDC"
>}'
1{
2 "checkoutJwtToken": "<CHECKOUT_JWT_TOKEN>"
3}

Pass the returned value as the jwtToken field on the New Contact or Saved Contact Checkout call in the next step. This step is optional — you can call the checkout endpoints directly with the plain subtotal if you trust the calling environment (e.g. a server-to-server integration).

3. Initiate the Checkout

Option A: New Contact Checkout

Use this the first time a customer pays with Interac, or any time they want to use different contact details than what’s on file.

Call the Interac e-Transfer Checkout (New Contact) endpoint:

$curl --request POST \
> --url https://api-sandbox.coinflow.cash/api/checkout/interac \
> --header 'accept: application/json' \
> --header 'content-type: application/json' \
> --header 'x-coinflow-auth-session-key: <YOUR_SESSION_KEY>' \
> --data-raw '{
> "merchantId": "<YOUR_MERCHANT_ID>",
> "subtotal": {
> "currency": "CAD",
> "cents": 5000
> },
> "firstName": "Jamie",
> "lastName": "Smith",
> "email": "jamie.smith@example.com"
>}'

Response:

1{
2 "paymentId": "abc123-def456",
3 "email": "jamie.smith@example.com"
4}
FieldDescription
paymentIdUnique identifier for the payment. Use this to poll for status updates or look up the payment record.
emailPresent when the e-Transfer request was sent to an email address.
phonePresent when the e-Transfer request was sent to a phone number.

Request Fields

FieldRequiredDescription
merchantIdYesYour merchant identifier.
subtotalYesPurchase subtotal. currency must be CAD.
firstNameYesCustomer’s first name.
lastNameYesCustomer’s last name.
emailOne of email / phone requiredCustomer’s email address. Used as the Interac payin destination when phone is not provided.
phoneOne of email / phone requiredCustomer’s 10-digit phone number, no formatting or country code (e.g. 4165551234). When provided, the e-Transfer request is sent to the phone number instead of the email.
jwtTokenNoThe checkoutJwtToken from step 2, if used.

Provide exactly one destination for the e-Transfer request. If you pass both email and phone, Coinflow sends the request to the phone number and ignores email.

Coinflow automatically saves this contact to the customer’s record so it can be reused with Saved Contact Checkout.

Option B: Saved Contact Checkout

Use this for a returning customer who already has an Interac contact saved.

1

Retrieve the Saved Interac Token

Call the Get Customer endpoint and read the interacs array on the response:

$curl --request GET \
> --url https://api-sandbox.coinflow.cash/api/customer/v2 \
> --header 'accept: application/json' \
> --header 'x-coinflow-auth-session-key: <YOUR_SESSION_KEY>'
1{
2 "customer": {
3 "interacs": [
4 {
5 "type": "interac",
6 "alias": "jamie.smith@example.com",
7 "token": "a8bbb23b-8732-42b0-82d9-afad14f51453"
8 }
9 ]
10 }
11}

alias displays either a masked phone number (e.g. (XXX) XXX-1234) or the full email address, depending on which was used to link the contact. The interacs array is empty if the customer has never completed New Contact Checkout.

2

Initiate the Checkout

Call the Interac e-Transfer Checkout (Saved Contact) endpoint with the saved token:

$curl --request POST \
> --url https://api-sandbox.coinflow.cash/api/checkout/interac/token \
> --header 'accept: application/json' \
> --header 'content-type: application/json' \
> --header 'x-coinflow-auth-session-key: <YOUR_CUSTOMER_SESSION_KEY>' \
> --data-raw '{
> "merchantId": "<YOUR_MERCHANT_ID>",
> "subtotal": {
> "currency": "CAD",
> "cents": 5000
> },
> "token": "a8bbb23b-8732-42b0-82d9-afad14f51453"
>}'

Response:

1{
2 "paymentId": "def456-ghi789",
3 "email": "jamie.smith@example.com"
4}

Saved Contact Checkout requires the customer to already be authenticated with a customer-scoped session key, unlike New Contact Checkout, which can be used on a customer’s very first purchase.

4. Customer Completes the Transfer

Neither checkout call above moves any money by itself — it only tells Interac to send an e-Transfer request. To finish the payment, the customer must:

  1. Receive the e-Transfer notification from their bank at the email address or phone number that was submitted.
  2. Open their online banking app.
  3. Accept and deposit the e-Transfer (automatically, if they have Interac Autodeposit enabled, or manually otherwise).

Coinflow cannot complete the payin on the customer’s behalf. If the customer never deposits the e-Transfer, the payment remains INITIATED and eventually moves to EXPIRED.

5. Listen for Webhooks

Configure your webhook endpoint to listen for Settled events. This is the recommended way to confirm a payment has completed rather than relying solely on polling.

Updating or Removing a Saved Contact

Each customer can only have one Interac contact saved at a time.

  • Calling New Contact Checkout again with a different email/phone replaces the saved contact — unless the customer already has a completed Interac payin (DEPOSITED or SETTLED) or a completed Interac payout on file. In that case, the original saved contact is preserved and the new contact details are ignored, to protect payment continuity.
  • To remove a saved contact outright, call the Delete Interac Account endpoint with the customer’s token:
$curl --request DELETE \
> --url https://api-sandbox.coinflow.cash/api/customer/interac/a8bbb23b-8732-42b0-82d9-afad14f51453 \
> --header 'accept: application/json' \
> --header 'x-coinflow-auth-session-key: <YOUR_CUSTOMER_SESSION_KEY>'

Payment Statuses

Inspect the interacInfo.status field on the payment record, or poll Get Purchase History:

StatusDescription
INITIATEDe-Transfer request sent, waiting for the customer to deposit it.
DEPOSITEDCustomer has deposited the e-Transfer; funds are being processed.
SETTLEDPayment settled. USDC delivered to the merchant.
FAILEDPayment failed or was declined.
EXPIREDCustomer did not deposit the e-Transfer before it expired.
REFUNDEDPayment was refunded.

Error Handling

Error CodeDescriptionSolution
422New Interac payin requires first and last namefirstName and lastName are required on New Contact Checkout.
422Must provide either phone number or emailProvide at least one of email / phone on New Contact Checkout.
404Invalid Interac tokenThe token passed to Saved Contact Checkout doesn’t match a saved, non-deleted contact for this customer. Re-fetch the Get Customer record to confirm the current token.
404Purse not foundNo customer record could be found for this wallet. Ensure the customer is authenticated correctly before calling Saved Contact Checkout.

Testing

In sandbox, Interac payments are processed by a mock provider. Use any test email address or a fake 10-digit phone number (e.g. 4165551234) to verify your integration — sandbox payments settle automatically without a real e-Transfer deposit.