Crypto payment API for Canadian businesses: accepting stablecoin payments

September 09, 2026

Crypto payment API for Canadian businesses: accepting stablecoin payments

Search for a crypto payment API from a Canadian company and the results are almost entirely global vendors with no Canadian standing, alongside software directories that have filtered a generic list by country. Very little of it answers the two questions a Canadian technical buyer actually has: can I settle in CAD, and is the counterparty registered here.

This guide is the developer-facing answer. It covers what registration changes about an integration, how to accept stablecoins or crypto through the EukaPay API, and how CAD settlement and reconciliation work once payments are live.

In this guide, you'll learn:

  • What FINTRAC registration changes in practice about your integration, not just your paperwork

  • How to authenticate and create your first invoice through the API

  • How CAD settlement works, including Interac withdrawals

  • How to reconcile crypto payments against your accounting system

What Canadian businesses need from a payment API

Three requirements separate a usable crypto payment API for a Canadian company from a global vendor that happens to accept Canadian signups.

CAD settlement.

Accepting USDC is straightforward. Getting Canadian dollars into a Canadian business bank account, without routing through a US intermediary and losing a spread on the way, is the part that determines whether finance approves the project.

A registered counterparty.

Money services businesses dealing in virtual currency must register with FINTRAC to operate in Canada. For your integration, the practical question is not whether registration exists on a compliance page. It is whether the processor behaves like a registered entity, because that behaviour shows up in your code.

An auditable trail.

Your auditor will ask how a given deposit in the bank ties back to a given customer order. That answer needs to be a query, not an afternoon.

EukaPay is registered with FINTRAC in Canada and FinCEN in the United States, settles in USD, EUR, GBP, CAD, and supports Interac withdrawals for Canadian merchants.

What registration changes about your integration

This is the part most comparison articles get wrong. They treat registration as a trust badge. It is also a set of behaviours your code has to accommodate.

Onboarding is a review, not a signup

Every EukaPay merchant goes through an onboarding and business review process. There is no instant registration, and any provider offering one in this category is worth a second look.

For a developer (or coding agent) this matters for scheduling rather than for architecture. A sandbox environment is available during the review period, so the integration work happens in parallel with the review instead of waiting behind it. Register for staging, get

sk_test_

keys, and build while the commercial process runs.

Outbound transfers get screened

If your integration also sends money out, EukaPay's crypto payout status list includes a

Reviewing

value alongside

Pending

,

Processing

,

Sent

,

Error

and

Revoked

. A registered processor screens outbound transfers, and

Reviewing

is that screening surfaced in the API rather than hidden behind a silent delay.

Build for it explicitly. A payout sitting in

Reviewing

is progressing normally, and your internal dashboard should tell your finance team that rather than displaying an apparent failure.

Records are the product of the integration

Registration comes with recordkeeping obligations, which is a good reason to capture identifiers properly from the first line of code rather than retrofitting them later. EukaPay returns an

x-request-id

on every response and assigns a code to every invoice, payment and payout. Store both against your own order records at write time.

Integrating the API

Authentication - one header

Generate an API key in the merchant dashboard under Settings > Integrations > API keys. The secret is shown once at creation. Keys are environment-tagged,

sk_test_

for staging and

sk_live_

for production.

curl "https://api.eukapay.com/invoices" \
  -H "x-api-key: sk_live_YOUR_KEY"

Production is

https://api.eukapay.com

and staging is

https://api-stg.eukapay.com

. Paths carry no version prefix, so it is

/invoices

rather than

/v1/invoices

.

Creating an invoice - POST /invoices

An invoice is the object that represents money you expect to receive. Create one, present the payment screens to your customer, and let webhooks tell you what happened.

curl -X POST "https://api.eukapay.com/invoices" \
  -H "x-api-key: sk_live_YOUR_KEY" \
  -H "x-idempotent-key: 3c8f21ab-7d64-4e19-b0a5-9fe2d47c1b88" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 1450.00,
    "currencyId": 1,
    "number": "INV-260813-42",
    "message": "Consulting retainer, August 2026",
    "dueDate": "2026-08-27",
    "customerCode": "cus_q06lpsoz2v7cwd5mn2tlxkr2jvjxxi",
    "redirectUri": "https://example.com/orderCompleted",
    "metadata": { "externalId": "ord_8814", "productCode": "RETAINER-AUG" }
  }'
currencyId

here is 1, which is the Canadian Dollar. This is the field Canadian merchants most often misread, so it is worth stating plainly:

currencyId

sets the

fiat

currency the invoice is denominated in, not the cryptocurrency the customer pays with. Cryptocurrencies live in a separate identifier space in EukaPay's documentation. You price in CAD, and your customer chooses which supported coin to pay with at the payment screen.

Two constraints on the price field. The minimum invoice price is 1 and the maximum is 100,000. And

customerCode

becomes required once the total invoice price reaches 1,000, along with

address1

,

city

,

state

and

country

on that customer record. For a Canadian business invoicing in the low thousands, that threshold arrives quickly, so create the customer first with

POST /customers

rather than discovering the requirement in a 400.

Send an

x-idempotent-key

on every write. The value is yours to generate, a V4 UUID is recommended, and keys expire after 24 hours. Deriving it from your own order identifier means a network timeout and retry cannot create a second invoice for the same order.

The response returns the invoice

code

and a

paymentUrl

you can redirect the customer to:

{
  "code": "inv_h2qjo7e1qpaled08q0cecn1cal",
  "price": 1450,
  "number": "INV-260813-42",
  "status": "Unpaid",
  "paymentUrl": "https://app.eukapay.com/payments/inv_h2qjo7e1qpaled08q0cecn1cal",
  "totalPaidAmount": 0,
  "currency": { "name": "Canadian Dollar", "unit": "CAD", "sign": "CA$" }
}

Retrieve an invoice with

GET /invoices/{code}

, and list them with

GET /invoices

.

Which currencies you can actually accept

Worth naming precisely rather than promising a round number. EukaPay supports BTC, ETH, BCH, LTC, SOL, BTC over the Lightning Network, USDT on Ethereum and Tron, and USDC on Ethereum.

Two constraints to design around: USDT is available on Ethereum and Tron only, and USDC on Ethereum only. If a Canadian customer base is used to holding USDT on Tron, that path is supported. Solana-based USDC is not.

On the fiat side,

currencyId

1 is the Canadian Dollar, 2 is the US Dollar, 3 is the Euro and 4 is Pound Sterling, which maps onto the USD, EUR, GBP, CAD settlement set.

Handling payment events

Configure a webhook endpoint under Settings > Integrations > Webhooks. Rather than polling for an invoice status, let the events drive your order state machine. EukaPay publishes eight events, and four of them are the ones a pay-in integration cares about:

Event

What your code should do

paymentCompleted

Mark the order paid and fulfil

paymentUnderpaid

Hold the order, contact the customer for the difference

paymentOverpaid

Fulfil, then handle the surplus per your refund policy

refundCompleted

Close the refund on your side

The payload for a payment event carries

webhookId

,

event

,

paymentCode

,

paidAmount

,

totalPaidAmount

,

status

,

paidDatetime

,

invoiceCode

,

invoiceNumber

,

invoicedAmount

and

invoiceCurrency

.

invoiceCode

is your join key back to your own order.

Verifying the signature

Each delivery carries an

x-eukapay-signature

header holding an HMAC of the payload, keyed to that webhook's secret. The algorithm is

SHA-512

, not the SHA-256 most gateways use.

const crypto = require('crypto');

function verifyEukaPaySignature(rawBody, signatureHeader, secret) {
  const digest = crypto.createHmac('sha512', secret).update(rawBody).digest('hex');
  if (digest.length !== signatureHeader.length) {
    return false;
  }
  return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signatureHeader));
}

One detail to settle against your own account. EukaPay's documentation gives two instructions that do not agree: the written steps say to use the payload without any alteration, while the code sample re-serialises an already-parsed body with

JSON.stringify

. Those produce different bytes whenever key order or whitespace differs. Verify one real delivery against the raw body first, and try the re-serialised form only if that fails.

EukaPay retries a failed delivery every 20 minutes for up to two hours, so your handler will see repeats. Record the

webhookId

and return early when you have already processed it.

Settlement to CAD

When a customer pays in stablecoins or crypto, EukaPay applies instant crypto-to-fiat conversion at a locked exchange rate to remove all crypto volatility. Your business recognises a Canadian dollar amount rather than a crypto balance that moves overnight.

Settlement reaches your bank account in USD, EUR, GBP, CAD. Canadian merchants can also take Interac withdrawals, which is the fastest route to a Canadian business account and the reason CAD settlement is usually the deciding factor for a Canadian buyer comparing EukaPay against a global vendor.

Tax treatment of crypto received by a Canadian business is a question for your accountant rather than your payment processor, and the answer depends on your circumstances. What the integration gives you is a clean set of records to hand them.

Reconciliation

Cursor pagination makes period pulls straightforward.

GET /invoices

accepts

starting_after

,

ending_before

and

limit

, and returns a

{data, has_more}

envelope. The two cursor parameters are mutually exclusive, so pick a direction and page through until

has_more

is false.

Default page sizes differ by resource, which is a small trap when you write a shared pagination helper: 100 for invoices, 10 for customers, refunds and crypto payouts. Set

limit

explicitly rather than relying on the default.

For month-end, store

invoiceCode

and

x-request-id

alongside your own order record at write time. Reconciliation then becomes a join between your ledger and a paged API pull, rather than a manual match against a bank statement.

One platform underneath

Whether a Canadian company collects through invoices, payment links, a hosted checkout or the API directly, the same infrastructure sits underneath: instant crypto-to-fiat conversion at a locked exchange rate to remove all crypto volatility, protection against chargebacks, support for a wide range of cryptocurrencies, and settlement in USD, EUR, GBP, CAD to your bank account.

The choice amongst those products is a question of fit rather than capability. A company invoicing thirty buyers a month has different needs from a platform creating a payment per checkout, and both draw on the same rails and the same reconciliation surface.

Get started with EukaPay

The full API reference is public at

docs.eukapay.com

, including request schemas, error types and the webhook payload format. Register for staging, generate a

sk_test_

key, and build the integration while your business review runs. For the commercial and operational view,

crypto payments in Canada

covers the same ground for a non-developer audience.

Frequently asked questions

Is EukaPay registered in Canada?

Yes. EukaPay is registered with FINTRAC in Canada and with FinCEN in the United States.

Can EukaPay settle in Canadian dollars?

Yes. EukaPay settles to your bank account in USD, EUR, GBP, CAD, and Canadian merchants can also use Interac withdrawals.

Can I start building before my account is approved?

Yes. A sandbox environment is available during the onboarding and business review period, so you can build against staging with a

sk_test_

key while the review runs.

Which stablecoins can a Canadian business accept through the API?

USDT on Ethereum and Tron, and USDC on Ethereum. EukaPay also supports BTC, ETH, BCH, LTC, SOL and BTC over the Lightning Network.

How do I tie a crypto payment back to my order for my auditor?

Store the

invoiceCode

returned when you create the invoice against your own order record, and keep the

x-request-id

from the response. Both appear in webhook payloads and API pulls.

Does EukaPay charge back like a card network?

No. Crypto payments settle on-chain, so a confirmed payment cannot be reversed by the payer's bank. Protection against chargebacks is part of what the rails provide.

What happens if a customer underpays an invoice?

You receive a

paymentUnderpaid

webhook event with

paidAmount

and

invoicedAmount

, so your code can hold the order and request the difference.