Skip to content

Add BTC Direct fiat buy provider#6037

Open
j0ntz wants to merge 1 commit into
developfrom
jon/integrate-btcdirect
Open

Add BTC Direct fiat buy provider#6037
j0ntz wants to merge 1 commit into
developfrom
jon/integrate-btcdirect

Conversation

@j0ntz

@j0ntz j0ntz commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

Integrate BTC Direct as a fiat on-ramp (buy) provider, following the existing FiatProviderFactory pattern (modeled on revolutProvider).

BTC Direct exposes a v2 "Unified Checkout" REST API. The flow:

  1. Partner-authenticate (POST /api/v1/authenticate) for a 1-hour JWT.
  2. Fetch live prices (GET /api/v2/prices) to build the supported-asset list and estimate quotes.
  3. Mint a single-use checkoutUrl (POST /api/v2/buy/checkout) and open it in a webview where the user selects a payment method and pays.

Scope:

  • New API client src/plugins/gui/util/fetchBtcDirect.ts (authenticate + token caching, prices, checkout, with cleaners).
  • New provider src/plugins/gui/providers/btcdirectProvider.ts registered in amountQuotePlugin.ts.
  • btcdirect credentials wired into PLUGIN_API_KEYS (envConfig.ts): { username, password, sandbox? }.
  • EUR buys for EU/EEA regions across credit card, iDEAL, and SEPA. Native assets only for now (token assets need contract addresses BTC Direct does not yet expose).

Not in scope (follow-ups):

  • Partner API credentials: Edge does not yet have BTC Direct partner credentials. The test account in the task is an end-user login (rejected by /api/v1/authenticate with ER038), not partner credentials, so the live checkout could not be exercised yet.
  • Surfacing the provider to users requires adding btcdirect to fiatPluginPriority in edge-info-server once partner credentials are in place (a deliberate go-live step, like revolut).
  • btcdirect.png partner icon upload to the content server.

Asana: https://app.asana.com/0/1215088146871429/1215776835822919

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

No user-visible change in this build: the provider is only instantiated when PLUGIN_API_KEYS.btcdirect is configured, which it is not yet (no partner credentials). Verified statically with tsc --noEmit, eslint, and the jest suite (398 tests pass). The live payment-method webview cannot be exercised until partner credentials are provisioned.


Note

Medium Risk
New third-party payment checkout and credential handling in the buy flow; limited blast radius until keys and info-server priority enable it for users.

Overview
Adds BTC Direct as a fiat buy provider using their Unified Checkout REST API (partner JWT auth, cached prices, hosted checkoutUrl in a webview with return.edge.app deeplink conversion tracking).

New pieces: fetchBtcDirect.ts (authenticate, /api/v2/prices, /api/v2/buy/checkout), btcdirectProvider.ts implementing FiatProviderFactory, optional PLUGIN_API_KEYS.btcdirect in envConfig.ts, and registration in amountQuotePlugin.ts. EUR-only buys for EU/EEA with credit card, iDEAL, and SEPA; quotes are fiat-amount estimates from live buy prices; native chain assets only (no ERC-20 tokens until contract mapping exists).

Provider only loads when API keys are configured; go-live also needs btcdirect on info-server fiatPluginPriority and the partner icon asset (called out in the PR description).

Reviewed by Cursor Bugbot for commit 5b3e2f7. Bugbot is set up for automated code reviews on this repo. Configure here.

Integrate BTC Direct as a fiat on-ramp using their Unified Checkout REST
API: partner-authenticate, fetch prices, then mint a single-use checkout
URL that opens in a webview for payment-method selection. Supports EUR
buys for EU/EEA regions across credit card, iDEAL, and SEPA.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5b3e2f7. Configure here.

},
title: lstrings.fiat_plugin_buy_complete_title,
message
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancel treated as successful buy

High Severity

The checkout returnUrl always includes transactionStatus=success, and the deeplink handler never inspects redirect outcome before calling trackConversion('Buy_Success') and the purchase-complete modal. BTC Direct redirects to the same returnUrl after cancel as well as success, so cancelled checkouts can be recorded and shown as completed buys.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5b3e2f7. Configure here.

XLM: { pluginId: 'stellar', currencyCode: 'XLM' },
TRX: { pluginId: 'tron', currencyCode: 'TRX' },
AVAX: { pluginId: 'avalanche', currencyCode: 'AVAX' },
POL: { pluginId: 'polygon', currencyCode: 'POL' },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Polygon native asset mapping wrong

Medium Severity

The POL entry maps to Edge polygon with currencyCode: 'POL', but Polygon’s native currency in Edge is MATIC. getTokenId only treats the wallet’s native code as native, so getEdgeAsset drops POL-EUR pairs and Polygon never appears in supported buy assets despite being in the BTC Direct price map.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5b3e2f7. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant