Crypto payment API for Canadian businesses: accepting stablecoin payments
September 09, 2026

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
Reviewingvalue alongside
Pending,
Processing,
Sent,
Errorand
Revoked. A registered processor screens outbound transfers, and
Reviewingis that screening surfaced in the API rather than hidden behind a silent delay.
Build for it explicitly. A payout sitting in
Reviewingis 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-idon 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.comand staging is
https://api-stg.eukapay.com. Paths carry no version prefix, so it is
/invoicesrather 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" }
}'currencyIdhere is 1, which is the Canadian Dollar. This is the field Canadian merchants most often misread, so it is worth stating plainly:
currencyIdsets 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
customerCodebecomes required once the total invoice price reaches 1,000, along with
address1,
city,
stateand
countryon that customer record. For a Canadian business invoicing in the low thousands, that threshold arrives quickly, so create the customer first with
POST /customersrather than discovering the requirement in a 400.
Send an
x-idempotent-keyon 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
codeand a
paymentUrlyou 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,
currencyId1 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 |
|---|---|
| Mark the order paid and fulfil |
| Hold the order, contact the customer for the difference |
| Fulfil, then handle the surplus per your refund policy |
| Close the refund on your side |
The payload for a payment event carries
webhookId,
event,
paymentCode,
paidAmount,
totalPaidAmount,
status,
paidDatetime,
invoiceCode,
invoiceNumber,
invoicedAmountand
invoiceCurrency.
invoiceCodeis your join key back to your own order.
Verifying the signature
Each delivery carries an
x-eukapay-signatureheader 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
webhookIdand 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 /invoicesaccepts
starting_after,
ending_beforeand
limit, and returns a
{data, has_more}envelope. The two cursor parameters are mutually exclusive, so pick a direction and page through until
has_moreis 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
limitexplicitly rather than relying on the default.
For month-end, store
invoiceCodeand
x-request-idalongside 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
, 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,
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
invoiceCodereturned when you create the invoice against your own order record, and keep the
x-request-idfrom 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
paymentUnderpaidwebhook event with
paidAmountand
invoicedAmount, so your code can hold the order and request the difference.
Products
Use Cases
© 2026 EukaPay. All rights reserved.
FINTRAC: M22233887