web config
```
		/**
		* Coinbase
		* @url https://www.coinbase.com/en-ca
		*/
		'coinbase' => [
			'class' => 'app\components\YiiCoinbase',
			'apiKey' => getenv('COINBASE_COMMERCE_API_KEY'),
			'webhookSecret' => getenv('COINBASE_COMMERCE_WEBHOOK_SECRET'),
			'btcUsdUrl' => 'https://www.coinbase.com/en-ca',
		],
```
this is what I was using for Stripe
```
<?php
declare(strict_types=1);

namespace app\components;

use Stripe\Stripe;
use Stripe\StripeClient;

use Yii;
use yii\base\BaseObject;
use yii\base\NotSupportedException as YiiNotSupportedException;

/**
* Stripe's Yii2 Configuration
* In your application configuration (e.g., config/web.php):
*
*	return [
*		'components' => [
*			'stripe' => [
*				'class' => 'path\to\YiiStripe',
*				'publishableKey' => 'pk_test_abc', // Your actual publishable key
*				'apiKey' => 'sk_test_xyz', // Your actual secret key
*			],
*		],
*	];
*
* In Yii2, private and protected properties in a component class pose challenges when used with the 
* framework's Dependency Injection (DI) mechanism.
*
* Private Properties: 
* When properties are declared as private, they cannot be accessed or set by the 
* DI container during component instantiation. This results in "Invalid Call" errors when Yii attempts 
* to inject values into these properties from the configuration array, as the properties are not accessible 
* from outside the class. As a consequence, the component cannot be properly configured with values defined 
* in the application configuration file.
*
* Protected Properties:
* Though protected properties can be set by the DI container, they are still accessible to any subclasses of 
* that component. This means that while the DI mechanism can populate these properties, it potentially exposes 
* them to modification from outside the intended context, which can lead to security issues or unintended behavior 
* if not managed properly.
*
* Best Practice: 
* To overcome these challenges while maintaining proper encapsulation, it is advisable to:
*	
* 	- Use public properties for settings that need to be configured via DI, ensuring they can be injected 
* 	from the configuration.
* 
*	- Implement getter methods (and avoid setters) for these properties to control access and prevent external
* 	modification after instantiation.
*	
*	- If sensitive data needs to remain secure, consider using alternative strategies such as environment variables
*	or dedicated mapping methods that handle sensitive data more securely.
*/
class YiiStripe extends BaseObject
{
	/**
	* string The Stripe API version to use.
	* @url https://stripe.com/docs/api/versioning
	* Last version used: '2023-10-16'
	*/
	private const STRIPE_API_VERSION = '2024-11-20.acacia';
	
	/**
	* For sample support and debugging. Not required for production:
	* @param null|string $appName The application's name
	*
	*	Stripe::setAppInfo("appName", "appVersion", "appURL");
	*/
	private const STRIPE_APP_NAME = "test-site";
	private const STRIPE_APP_VERSION = '0.2.0';
	private const STRIPE_APP_URL = 'https://github.com/test-site/';
	
	// Stripe client instance.
	private $stripeClient;
	
	/**
	* See your keys here https://dashboard.stripe.com/account/apikeys
	* Publishable and API Key
	* @var string
	*/
	public $publishableKey;
	public $apiKey;
	
	/**
	* Initializes the object.
	* This method is invoked at the end of the constructor after the object is initialized with the given configuration.
	* @url https://www.yiiframework.com/doc/api/2.0/yii-base-baseobject#init()-detail
	*/
	public function init()//: __construct()
	{
		/**
		* The default implementation does two things:
		* 	Initializes the object with the given configuration $config.
		*	Call init().
		*
		* If this method is overridden in a child class, it is recommended that the last parameter of the constructor 
		* is a configuration array, like $config here. call the parent implementation at the end of the constructor.
		*/
		parent::init();
		
		// Custom code here...
		
		if (empty($this->publishableKey))
		{
			throw new YiiNotSupportedException("Stripe's Publishable API Key is not set.");
		}
		if (empty($this->apiKey))
		{
			throw new YiiNotSupportedException("Stripe's Secret API Key is not set.");
		}
		
		// Instantiate the Stripe client with the secret API key.
		$this->stripeClient = new StripeClient($this->apiKey);
        }
        
	public function getStripeClient()
	{
		return $this->stripeClient;
	}
	
	public function getPublishableKey()
	{
		return $this->publishableKey;// Expose publishable key for use in frontend.
	}
}
```
needs to be converted to work for Coinbase... Than I should be able to create a CoinbaseApi.php 
where we
```
class StripeApi
{
	private bool $_debugMode = false;

	// StripeClient used to communicate with the Stripe API.
	private $_stripeClient;
	
	/**
	* Constructor for the StripeApi class.
	* @param StripeClient $stripeClient 
	* An instance of the StripeClient that will be used for making API calls 
	* to Stripe. This allows for separation of concerns and facilitates dependency 
	* injection, enabling easier testing and modularity.
	*/
	public function __construct(StripeClient $stripeClient)
	{
		$this->_stripeClient = $stripeClient;
	}
	
	/**
	* Private helper for consistent debug logging with 
	* category-based filtering.
	*/
	private function _logDebug(string $message, array $context = [], string $category = 'stripeApi'): void
	{
		if (!$this->_debugMode)
		{
			return;
		}
		
		$defaultContext = [
			//'class' => __CLASS__,
			'method' => __METHOD__,
			//'function' => __FUNCTION__,
			'file' => __FILE__,
			'line' => __LINE__,
		];
		
		LogHelper::debug($message, array_merge($defaultContext, $context), $category);
	}
	
	/**
 * Get current spot price of BTC in USD from Coinbase Public API.
 *
 * @return float BTC price per 1 USD
 * @throws \GuzzleHttp\Exception\GuzzleException
 * @throws \RuntimeException
 */
public function getBtcUsdSpotPrice(): float
{
    // Use public Coinbase API for prices - no API key required, base_uri different
    $client = new \GuzzleHttp\Client([
        'base_uri' => 'https://api.coinbase.com/',
        'timeout'  => 5.0,
    ]);

    $response = $client->get('v2/prices/BTC-USD/spot');
    $data = json_decode($response->getBody()->getContents(), true);

    if (!isset($data['data']['amount'])) {
        throw new \RuntimeException('Invalid response when fetching BTC/USD spot price');
    }

    return (float) $data['data']['amount'];
}
}
```
for commandline
```
class CoinbasePriceController extends Controller
{
	/**
	* Fetch BTC/USD spot price from Coinbase and cache it.
	* @return int Exit code
	*
	* Usage:
	* 
	* 	php yii coinbase-price/fetch
	*/
	public function actionFetch(): int
	{
		try
		{
			// TODO Call YiiCoinbase
			$btcUsdPrice = \Yii::$app->coinbase->client->getBtcUsdSpotPrice();
		}
		catch (Throwable $e)
		{
			$this->stderr("Failed to fetch BTC price: " . $e->getMessage() . PHP_EOL);
			
			\Yii::error("Failed to fetch BTC price: " . $e->getMessage(), __METHOD__);
			
			return ExitCode::UNSPECIFIED_ERROR;
		}
		
		// Cache price for 5 minutes (300 seconds)
		\Yii::$app->cache->set('btc_usd_spot_price', $btcUsdPrice, 300);
		
		$this->stdout("Cached BTC/USD spot price: {$btcUsdPrice}" . PHP_EOL);
		
		return ExitCode::OK;
	}
}
```
and add other features into the CoinbaseApi.. for creating transactions/checkout for orders