214 lines
7.5 KiB
PHP
214 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class NowPaymentsClient
|
|
{
|
|
private string $baseUrl;
|
|
private string $apiKey;
|
|
private string $jwtToken; // Added for operations that might need JWT auth (payouts)
|
|
private float $timeout;
|
|
|
|
public function __construct()
|
|
{
|
|
$cfg = config('services.nowpayments');
|
|
// Prefer DB-stored API key from admin settings over config/env
|
|
$dbSettings = \App\Models\AppSetting::get('payments.nowpayments', []);
|
|
$this->baseUrl = rtrim((string) ($cfg['base_url'] ?? 'https://api.nowpayments.io/v1'), '/');
|
|
$this->apiKey = (string) ($dbSettings['api_key'] ?? $cfg['api_key'] ?? '');
|
|
$this->jwtToken = (string) ($dbSettings['jwt_token'] ?? $cfg['jwt_token'] ?? '');
|
|
$this->timeout = (float) ($cfg['timeout'] ?? 10.0);
|
|
}
|
|
|
|
private function client(bool $useJwt = false)
|
|
{
|
|
$headers = [
|
|
'x-api-key' => $this->apiKey,
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json',
|
|
];
|
|
|
|
if ($useJwt && $this->jwtToken) {
|
|
$headers['Authorization'] = 'Bearer ' . $this->jwtToken;
|
|
}
|
|
|
|
return Http::timeout($this->timeout)
|
|
->retry(2, 150, throw: false)
|
|
->baseUrl($this->baseUrl)
|
|
->withHeaders($headers);
|
|
}
|
|
|
|
public function listCurrencies(): array
|
|
{
|
|
$res = $this->client()->get('/currencies');
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments listCurrencies failed', ['status' => $res->status(), 'body' => $res->body()]);
|
|
return [];
|
|
}
|
|
$json = $res->json();
|
|
return is_array($json) ? ($json['currencies'] ?? $json) : [];
|
|
}
|
|
|
|
/**
|
|
* Get available checked currencies (merchant/coins)
|
|
* https://api.nowpayments.io/v1/merchant/coins
|
|
*/
|
|
public function getAvailableCoins(): array
|
|
{
|
|
$res = $this->client()->get('/merchant/coins');
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments getAvailableCoins failed', ['status' => $res->status(), 'body' => $res->body()]);
|
|
return [];
|
|
}
|
|
$json = $res->json();
|
|
return is_array($json) ? ($json['selectedCurrencies'] ?? $json) : [];
|
|
}
|
|
|
|
public function estimate(float $priceAmount, string $priceCurrency, string $payCurrency): ?array
|
|
{
|
|
$payload = [
|
|
'amount' => $priceAmount,
|
|
'currency_from' => strtoupper($priceCurrency),
|
|
'currency_to' => strtoupper($payCurrency),
|
|
];
|
|
$res = $this->client()->post('/estimate', $payload);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments estimate failed', ['status' => $res->status(), 'body' => $res->body(), 'payload' => $payload]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* Get the minimum payment amount
|
|
* https://api.nowpayments.io/v1/min-amount?currency_from=eth¤cy_to=trx
|
|
*/
|
|
public function getMinAmount(string $currencyFrom, string $currencyTo, ?string $fiatEquivalent = null, bool $isFixedRate = false, bool $isFeePaidByUser = false): ?array
|
|
{
|
|
$query = [
|
|
'currency_from' => strtolower($currencyFrom),
|
|
'currency_to' => strtolower($currencyTo),
|
|
'is_fixed_rate' => $isFixedRate ? 'True' : 'False',
|
|
'is_fee_paid_by_user' => $isFeePaidByUser ? 'True' : 'False',
|
|
];
|
|
|
|
if ($fiatEquivalent) {
|
|
$query['fiat_equivalent'] = strtolower($fiatEquivalent);
|
|
}
|
|
|
|
$res = $this->client()->get('/min-amount', $query);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments getMinAmount failed', ['status' => $res->status(), 'body' => $res->body(), 'query' => $query]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
public function createInvoice(array $data): ?array
|
|
{
|
|
// Expected keys: price_amount, price_currency, pay_currency, order_id, order_description, success_url, cancel_url, ipn_callback_url
|
|
$res = $this->client()->post('/invoice', $data);
|
|
if (!$res->ok()) {
|
|
Log::error('NOWPayments createInvoice failed', ['status' => $res->status(), 'body' => $res->body(), 'data' => $data]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* Get payment status
|
|
* https://api.nowpayments.io/v1/payment/:payment_id
|
|
*/
|
|
public function getPayment(string $paymentId): ?array
|
|
{
|
|
$res = $this->client()->get('/payment/' . urlencode($paymentId));
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments getPayment failed', ['status' => $res->status(), 'body' => $res->body(), 'payment_id' => $paymentId]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* Get list of payments
|
|
* https://api.nowpayments.io/v1/payment/?limit=10&page=0&sortBy=created_at&orderBy=asc&dateFrom=2020-01-01&dateTo=2021-01-01&invoiceId=6200264890
|
|
*/
|
|
public function listPayments(array $params = []): ?array
|
|
{
|
|
$res = $this->client()->get('/payment/', $params);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments listPayments failed', ['status' => $res->status(), 'body' => $res->body(), 'params' => $params]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
public function getInvoice(string $invoiceId): ?array
|
|
{
|
|
$res = $this->client()->get('/invoice/' . urlencode($invoiceId));
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments getInvoice failed', ['status' => $res->status(), 'body' => $res->body(), 'invoice_id' => $invoiceId]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* Validate address
|
|
* https://api.nowpayments.io/v1/payout/validate-address
|
|
*/
|
|
public function validateAddress(string $currency, string $address, ?string $extraId = null): ?array
|
|
{
|
|
$payload = [
|
|
'currency' => strtolower($currency),
|
|
'address' => $address,
|
|
];
|
|
if ($extraId !== null) {
|
|
$payload['extra_id'] = $extraId;
|
|
}
|
|
|
|
// According to NOWPayments docs, this uses the standard client
|
|
$res = $this->client()->post('/payout/validate-address', $payload);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments validateAddress failed', ['status' => $res->status(), 'body' => $res->body(), 'payload' => $payload]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* Verify payout
|
|
* https://api.nowpayments.io/v1/payout/:batch-withdrawal-id/verify
|
|
*/
|
|
public function verifyPayout(string $batchWithdrawalId, string $verificationCode): ?array
|
|
{
|
|
$payload = [
|
|
'verification_code' => $verificationCode
|
|
];
|
|
|
|
$res = $this->client(true)->post('/payout/' . urlencode($batchWithdrawalId) . '/verify', $payload);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments verifyPayout failed', ['status' => $res->status(), 'body' => $res->body(), 'batch_id' => $batchWithdrawalId]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
|
|
/**
|
|
* List of payouts
|
|
* https://api.nowpayments.io/v1/payout
|
|
*/
|
|
public function listPayouts(array $params = []): ?array
|
|
{
|
|
$res = $this->client(true)->get('/payout', $params);
|
|
if (!$res->ok()) {
|
|
Log::warning('NOWPayments listPayouts failed', ['status' => $res->status(), 'body' => $res->body(), 'params' => $params]);
|
|
return null;
|
|
}
|
|
return $res->json();
|
|
}
|
|
}
|