Migrating from CoinGate to EukaPay: an endpoint map
August 14, 2026

Plenty of articles compare crypto payment providers on fees and supported coins. Very few tell a developer (or coding agent) which line of code changes. If you have a working CoinGate integration and you are evaluating EukaPay, the question is not which platform is better in the abstract. It is how many hours the move costs and where the surprises are.
This guide is the answer at endpoint level. EukaPay is a licensed processor registered with FINTRAC in Canada and FinCEN in the United States, settling to your bank account in USD, EUR, GBP, CAD, and the migration from CoinGate is a mapping exercise rather than a rewrite. Two things do require real work, and both are in the callback handler.
Note:
is the source of truth for every EukaPay endpoint, field and event named in this guide. Check it for the latest before you write code.
In this guide, you'll learn:
How CoinGate's order model maps onto EukaPay's invoice model, field by field
Why the callback handler is the bulk of the migration, and exactly what changes
How CoinGate's nine order statuses map onto EukaPay's webhook events
How to run both integrations in parallel and cut over by traffic percentage
The endpoint map
Start with the shape of the two APIs side by side.
Concern | CoinGate | EukaPay |
|---|---|---|
Base URL | https://api.coingate.com- see the path note below | |
Sandbox | | |
Version in path | Yes, /v2 | No prefix |
Auth header | | |
Create payment | | |
Fetch payment | | |
List payments | | |
Pagination | Page-based: page, per_page | Cursor: starting_after, ending_before, limit |
Refunds | | POST /refunds, GET /refunds |
Payouts | Withdrawals are read-only | POST /crypto_payoutsand five more endpoints |
Callback verification | Token match, not cryptographic | HMAC SHA-512 signature |
Idempotency | Not offered | x-idempotent-keyheader |
Note: this table is a snapshot taken while writing. Confirm current hosts, paths and parameters at
.
A path detail worth checking before you write anything
CoinGate's own documentation is inconsistent about the base path. The environments page lists
https://api.coingate.com/v2, while the official OpenAPI specification declares
https://api.coingate.com/api/v2in its
serversblock, and reference pages render paths as
/api/v2/orders.
If you are auditing an existing integration before migrating, check which form your code actually uses rather than trusting either document. EukaPay removes the question by carrying no version prefix at all: the endpoint is
/invoices, even though the reference is labelled v1.0.
Authentication - a different header, same simplicity
A correction worth making, because it is commonly written down wrong: CoinGate uses
Authorization: Token, not
Authorization: Bearer. If you have ever debugged a 401 against CoinGate, that is often why.
# CoinGate
curl "https://api.coingate.com/v2/orders" \
-H "Authorization: Token YOUR_API_TOKEN"
# EukaPay
curl "https://api.eukapay.com/invoices" \
-H "x-api-key: sk_live_YOUR_KEY"One useful difference. CoinGate notes that credentials generated on the live site will not work in test mode, which means environment mistakes surface as authentication failures. EukaPay encodes the environment in the key itself,
sk_test_against
https://api-stg.eukapay.comand
sk_live_against
https://api.eukapay.com, so a mismatched key is visible by reading it.
Note: key formats, header names and environment hosts are documented at
, which is where any change lands first.
Creating a payment
CoinGate's
POST /ordersrequires
price_amount,
price_currency,
titlebetween 3 and 150 characters, and
descriptionbetween 3 and 500 characters. Optional fields include
order_id,
receive_currencyor the literal
DO_NOT_CONVERT,
callback_url,
success_url,
cancel_url,
tokenand a
shopperobject.
EukaPay's equivalent is
POST /invoices. Two migration notes matter more than the field names.
Your `order_id` becomes your idempotency key.
CoinGate's
order_idis your own reference carried on the order. EukaPay accepts the same kind of reference and adds something CoinGate does not offer: an
x-idempotent-keyheader. Derive it from the identifier you were already passing as
order_id, a V4 UUID is recommended, keys expire after 24 hours, and a network timeout followed by a retry can no longer create two payments for one order.
`DO_NOT_CONVERT` has no direct equivalent.
If your CoinGate integration uses
DO_NOT_CONVERTto hold received crypto rather than converting it, there is nothing to configure on the EukaPay side. EukaPay is non-custodial and never holds crypto on your behalf, so every payment is converted at a locked exchange rate and settled to your bank account.
Pagination - the one place you rewrite rather than remap
This is the change most likely to be missed in a quick migration, because both endpoints return lists and the code looks like it should work.
CoinGate is page-based. You request
page=1, then
page=2, with
per_pagecapped at 100, plus
sortvalues of
created_at_ascor
created_at_descand date filters like
created_at[from].
EukaPay is cursor-based. You pass
limitwith either
starting_afteror
ending_before, never both, and read
has_morefrom the
{data, has_more}envelope to decide whether to continue.
A page counter cannot be translated into a cursor. Rewrite the loop rather than adapting it. Note also that EukaPay's default
limitvaries by resource, 100 for invoices but 10 for customers, refunds and crypto payouts, so set it explicitly.
Note: default and maximum page sizes vary by resource and are listed at
. Read the current values there rather than hard-coding the ones above.
What changes in your callback handler
Here is the real work, and there are two distinct changes.
From token matching to cryptographic signatures
CoinGate posts a callback to your
callback_urlwhenever an order status, refund status or billing status changes. The payload includes
id,
order_id,
status,
price_amount,
price_currency,
receive_currency,
receive_amount,
pay_amount,
pay_currency,
underpaid_amount,
overpaid_amount,
is_refundable,
created_at,
token,
feesand
paid_at.
Verification works by matching the
tokenfield against the callback token returned when the order was created. CoinGate's guidance is to check the token, allowlist their IP addresses, and re-fetch the order to confirm its status and amount independently.
That is a coherent design, and re-fetching to confirm is good practice under any scheme. It is a different security model from a signed payload, though, and the difference matters when you are the one maintaining the handler. A shared secret compared field-by-field proves the sender knew a token. An HMAC over the request body proves the payload itself was not altered in transit.
EukaPay sends an
x-eukapay-signatureheader containing an HMAC of the payload, keyed to that webhook's secret, using
SHA-512
. Most gateways use SHA-256, so if a code review suggests correcting the algorithm, the suggestion is wrong.
Two implementation rules:
Capture the raw bytes before parsing.
Any JSON library that reorders keys or normalises whitespace produces a different digest. Be aware that EukaPay's own documentation is inconsistent on this point: the written steps call for the unaltered payload, while the published code sample re-serialises an already-parsed body with
JSON.stringify. Verify one real delivery against the raw body and try the re-serialised form only if that fails.
Test the negative case.
Alter one byte of a captured payload, leave the signature untouched, and confirm your handler rejects it. A verification function that never returns false has not been tested.
Compare in constant time.
Use
crypto.timingSafeEqualrather than
===, guarding for equal lengths first, so a comparison does not exit early on the first differing character.
Keeping the re-fetch habit from CoinGate is still worthwhile. Verify the signature, then read the invoice back with
GET /invoices/{code}before you fulfil anything expensive.
Note: the webhook payload format, the signature header and the verification steps are all documented at
. Where a sample here and the reference disagree, the reference wins.
From a status string to named events
CoinGate drives your logic from a
statusfield with nine documented lowercase values. EukaPay drives it from named webhook events. This table is the core of the migration:
CoinGate status | EukaPay equivalent | What your handler does |
|---|---|---|
| No event, invoice created by your own API call | Nothing, you already know |
| No event | Nothing, wait |
| No event | Nothing, wait |
| | Mark paid, fulfil |
| No direct equivalent | Handle as unpaid, reconcile |
| No direct equivalent | Handle as unpaid, reconcile |
| No direct equivalent | Handle as unpaid, reconcile |
| | Close the refund |
| refundCompletedwith amount | Close the partial refund |
Two things fall out of the mapping.
Underpayment and overpayment become explicit.
CoinGate carries
underpaid_amountand
overpaid_amountas fields on a callback, so your handler has to inspect them. EukaPay raises
paymentUnderpaidand
paymentOverpaidas separate events carrying
paidAmount,
totalPaidAmountand
invoicedAmount. If your CoinGate handler quietly ignores those two fields, which is common, writing the two branches is new work that removes a class of stuck order.
Timing assumptions need re-checking.
CoinGate expires a
neworder after two hours if no currency is selected, and times out a
pendingorder after 20 minutes. If any of your logic hard-codes those windows, confirm EukaPay's behaviour against the current documentation rather than carrying the numbers across. Separately, note that EukaPay's 20-minute figure is a webhook retry interval, not an order timeout, and the two are unrelated.
Note: the current event list, payload fields and timing behaviour are published at
. If you are building today, map against that page rather than this table alone.
Retries and duplicate delivery
EukaPay retries a failed webhook delivery every 20 minutes for up to two hours. Record the
webhookIdfrom each payload and return early on a repeat. Verify, deduplicate, return a 2xx quickly, and do slow work asynchronously.
Use
invoiceCodeas the join key back to your own order, in the same place your CoinGate handler used
order_id.
Refunds and payouts
CoinGate's refund endpoint is
POST /orders/{order_id}/refundsand takes a substantial body:
amount,
address,
currency_id,
platform_id,
reason,
emailand
ledger_account_id, with optional
address_memo,
callback_urland
skip_user_address_confirmation.
EukaPay separates refunds from the order path entirely, with
POST /refundsand
GET /refunds, and publishes refund statuses of
Created,
Pending,
Success,
Failand
Unknown.
Payouts are a genuine capability difference rather than a mapping. CoinGate's withdrawals API is read-only, offering
GET /withdrawalsand
GET /withdrawals/{id}. EukaPay exposes six payout endpoints including
POST /crypto_payoutsto create a payout,
GET /crypto_payouts/balanceand
POST /crypto_payouts/estimate. If your business also sends money out, that moves from a dashboard task to an API operation.
One EukaPay payout status deserves a note because it has no CoinGate counterpart. Alongside
Pending,
Processing,
Sent,
Errorand
Revoked, there is
Reviewing. A registered processor screens outbound transfers, and
Reviewingsurfaces that screening in the API rather than hiding it in a silent delay. Build for it so your finance team sees progress rather than an apparent failure.
Note: refund and payout statuses change as the product develops. The current set is published at
.
Rate limits and error handling
CoinGate publishes concrete numbers: 200 requests per minute, and 500 orders per hour per business including orders created in the dashboard, with a
RateLimitExceededreason on the error.
EukaPay documents rate limiting and recommends exponential backoff without publishing a specific requests-per-second figure. The practical consequence is that you build against the 429 response itself rather than tuning to a threshold, which is the more robust approach in either case. EukaPay returns three error types,
api_error,
idempotency_errorand
invalid_request_error, and an
x-request-idon every response that is worth logging for support conversations.
On client libraries, CoinGate maintains an official Ruby gem and a PHP package, and lists .NET, Node.js and Python as community-maintained. EukaPay does not publish official SDKs, and the documentation recommends calling the API with
fetchor
axios. There is also an official documentation MCP server at
docs.eukapay.com/mcp, which is useful when a coding agent is doing the migration.
Note: rate limit guidance, error types and tooling recommendations are documented at
and are updated as they change.
Running both in parallel
Build against staging.
Register at
stg.eukapay.com, generate a
sk_test_key, and run the full flow on testnet. Test USDT and USDC come from EukaPay support rather than a public faucet, so request them early.
Add a provider column
to your order records. Every refund path, reconciliation report and support query needs to know which processor created a payment.
Route new payments by percentage.
Send a small share of new checkouts to EukaPay and raise it as confidence builds.
Let in-flight payments finish where they started.
An order created on CoinGate settles and reconciles on CoinGate.
Run both handlers until the last old order resolves.
Token matching and SHA-512 verification coexisting for a period is correct, not untidy.
Reconcile both providers for a full period
before you decommission anything.
One platform underneath
Whichever EukaPay product you collect through, the infrastructure is shared: 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. EukaPay supports most major cryptocurrencies like BTC, ETH, LTC, SOL, USDC, USDT.
Invoices, payment links, hosted checkouts, subscriptions that send invoices on a recurring schedule, refunds and crypto payouts all sit on one account and one reconciliation surface. For a migrating team, the value is that pay-ins and payouts stop being two integrations with two sets of records.
Get started with EukaPay
The full reference, including request schemas, the webhook payload format and every error type, is public at
. Register for staging, request approval and test stablecoins from support in a single message, and build the migration while your business review runs. For the commercial comparison rather than the endpoint detail, see
CoinGate alternatives for accepting USDT and stablecoins
.
Frequently asked questions
How long does a CoinGate to EukaPay migration take?
The API mapping is small: a header, a host, and two endpoint names. Budget your real time for the callback handler, where signature verification and status-to-event mapping both change, and for rewriting page-based pagination as cursor-based.
Does EukaPay sign its webhooks?
Yes. Every delivery carries an
x-eukapay-signatureheader with an HMAC of the payload keyed to that webhook's secret, using SHA-512. Compute your comparison over the raw request body.
Does EukaPay offer idempotency keys?
Yes. Send
x-idempotent-keyon writes, ideally a V4 UUID derived from the reference you previously passed as CoinGate's
order_id. Keys expire after 24 hours.
Can I create crypto payouts through the EukaPay API?
Yes.
POST /crypto_payoutscreates a payout, with
GET /crypto_payouts/balanceand
POST /crypto_payouts/estimatealongside it. There is no bulk endpoint, so batch runs are either a loop with per-recipient idempotency keys or a CSV upload in the dashboard.
What does the Reviewing payout status mean?
The payout is under compliance review before release. EukaPay is registered with FINTRAC and FinCEN, and a registered processor screens outbound transfers.
Does EukaPay publish a rate limit?
No specific requests-per-second figure is published. EukaPay documents rate limiting and recommends exponential backoff, so build against the 429 response.
Which stablecoins and networks does EukaPay support?
USDT on Ethereum and Tron, and USDC on Ethereum, alongside BTC, ETH, BCH, LTC, SOL and BTC over the Lightning Network.
Does EukaPay publish official client libraries?
No. The documentation recommends calling the API directly with
fetchor
axios, and an official documentation MCP server is available at
docs.eukapay.com/mcp.
Note: these answers reflect the API at the time of writing.
is the source of truth for EukaPay's API and the place to check for the latest updates.
Products
Use Cases
© 2026 EukaPay. All rights reserved.
FINTRAC: M22233887