承接 tangentopay/tangentopay-php 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

tangentopay/tangentopay-php

最新稳定版本:v0.8.0

Composer 安装命令:

composer require tangentopay/tangentopay-php

包简介

Official PHP SDK for the TangentoPay API

README 文档

README

Official PHP SDK for the TangentoPay API — accept payments, issue refunds, manage wallets, and verify webhooks with a clean, fully-typed interface.

Packagist Version CI PHP 8.1+ License: MIT

Table of contents

Requirements

  • PHP 8.1 or later
  • Guzzle 7 (guzzlehttp/guzzle)
  • A TangentoPay account — sign up

Installation

composer require tangentopay/tangentopay-php

Quick start

use TangentoPay\ServiceClient;
use TangentoPay\MerchantClient;

// ── Storefront: create a Stripe checkout session ──────────────────────────────
$service = new ServiceClient(['serviceKey' => getenv('TANGENTOPAY_SERVICE_KEY')]);

$session = $service->checkout->create([
    'products'      => [['name' => 'Pro Plan', 'price' => 49.99, 'quantity' => 1]],
    'currency_code' => 'USD',
    'customer_email'=> 'buyer@example.com',
    'return_url'    => 'https://myshop.com/thank-you',
]);
// redirect your customer to $session['redirect_url']

// ── Backend: manage payments with an API token ────────────────────────────────
$merchant = new MerchantClient(['apiToken' => getenv('TANGENTOPAY_API_TOKEN')]);

$payments = $merchant->payments->list(['perPage' => 20]);
$balance  = $merchant->wallets->mainBalance();

Authentication

TangentoPay has two credential types:

Credential Where it goes Client to use
Service Key (pk_live_… / pk_test_…) X-Service-Key header ServiceClient
API Token (Bearer) Authorization: Bearer … MerchantClient

Never expose an API token in browser or mobile code. Use ServiceClient on the frontend and MerchantClient only on your server.

ServiceClient

$service = new ServiceClient([
    'serviceKey'   => getenv('TANGENTOPAY_SERVICE_KEY'),
    // optional:
    'baseUrl'      => 'https://api.tangentopay.com/api/v1',
    'timeoutS'     => 30,
    'maxRetries'   => 3,
]);

MerchantClient

$merchant = new MerchantClient(['apiToken' => getenv('TANGENTOPAY_API_TOKEN')]);

Obtain an API token programmatically:

$client = new MerchantClient();
$client->auth->login(['email' => $email, 'password' => $password]);
$token = $client->auth->verifyOtp(['email' => $email, 'otp' => $otp]);
$merchant = new MerchantClient(['apiToken' => $token->accessToken]);

Token expiry and refresh

Catch AuthenticationException and re-authenticate in place:

use TangentoPay\Exceptions\AuthenticationException;

try {
    $payments = $merchant->payments->list();
} catch (AuthenticationException $e) {
    $merchant->auth->login(['email' => $email, 'password' => $password]);
    $token = $merchant->auth->verifyOtp(['email' => $email, 'otp' => $otp]);
    $merchant->setToken($token->accessToken); // updates all resources in place
    $payments = $merchant->payments->list();  // retry
}

Test mode

Pass a pk_test_… service key to use Stripe test mode:

$service = new ServiceClient(['serviceKey' => 'pk_test_<your_test_key>']);
var_dump($service->testMode); // bool(true)

Test-mode sessions go through Stripe's sandbox and never move real money.

Resources

ServiceClient resources

Property Description
$service->checkout Create Stripe-hosted checkout sessions; poll payment status
$service->topups Collect money from a customer's MoMo account into the service wallet
$service->withdrawals Send money from the service wallet to a customer's MoMo account
$service->providerStatus Real-time health for MTN MoMo, Orange Money, and Stripe

MerchantClient resources

Property Description
$merchant->auth Login, OTP verification, profile, logout
$merchant->payments View and search your incoming payment history
$merchant->refunds Issue refunds on completed payments
$merchant->topups Top up your main wallet via card or MoMo
$merchant->payouts Send funds out (bank, MoMo, TP wallet, debit card)
$merchant->wallets Main and service wallet balances
$merchant->services View services; manage enabled payment methods per service
$merchant->customers Create and manage customer records
$merchant->analytics Payment summaries, revenue, and volume over time
$merchant->logs Per-service API request logs
$merchant->transfers Internal wallet transfer history
$merchant->providerStatus Real-time health for MTN MoMo, Orange Money, and Stripe

Note on service administration: Creating services, rotating API keys, updating webhooks, and other one-time setup tasks are done from the TangentoPay Dashboard. These operations are intentionally not exposed in the SDK.

Provider status

Check provider health before initiating any collection or disbursement — this lets you show users a clear error message instead of a silent payment failure.

$status = $merchant->providerStatus->get();
// or: $service->providerStatus->get()

// $status is an associative array keyed by provider slug:
// [
//   'mtn_momo'     => ['slug' => 'mtn_momo',     'name' => 'MTN Mobile Money', 'status' => 'operational', ...],
//   'orange_money' => ['slug' => 'orange_money', 'name' => 'Orange Money',     'status' => 'degraded',    ...],
//   'stripe'       => ['slug' => 'stripe',       'name' => 'Stripe',           'status' => 'operational', ...],
// ]

if ($status['mtn_momo']['status'] === 'down') {
    return response()->json([
        'message' => 'MTN Mobile Money is currently unavailable. Try Orange Money or pay by card.',
    ], 503);
}

Possible status values:

Value Meaning
"operational" Fully functional — proceed normally
"degraded" Partial outage — expect higher failure rates
"down" Provider unreachable — do not attempt payments

Currency and provider guide

Provider Supported currencies Notes
MTN Mobile Money XAF only Cameroon; USSD push via Fapshi. Min 100 XAF, max 500 000 XAF.
Orange Money XAF only Cameroon; USSD push via Fapshi. Min 100 XAF, max 500 000 XAF.
Stripe USD, EUR, GBP, and more Multi-currency card checkout and instant payouts.

When a customer pays via MoMo the transaction currency is XAF. When they pay via Stripe card the currency is whatever currency_code you pass to checkout->create().

Use $merchant->wallets->mainBalance() to get per-currency balances — the response includes a balances array showing only currencies with a non-zero funded amount, which you can use to build a currency-selector UI in your withdrawal flow.

Service wallet operations (B2B2C)

The service wallet is funded when customers pay through your service's checkout flow.

// ── Collect from a customer's MoMo ───────────────────────────────────────────
$topup = $service->topups->create([
    'amount'          => 5000,              // XAF
    'customer_phone'  => '237XXXXXXXXX',
    'external_ref'    => 'ORDER-001',
    'notify_url'      => 'https://yourapp.com/webhooks/momo',
]);
// pending — wallet credited after Fapshi webhook confirms

// ── Disburse to a customer's MoMo ────────────────────────────────────────────
$withdrawal = $service->withdrawals->create([
    'amount'           => 4000,             // XAF
    'recipient_phone'  => '237XXXXXXXXX',
    'external_ref'     => 'PAYOUT-001',
]);

Payouts

Two-step flow: initiate → confirm.

// Step 1 — initiate
$initiation = $merchant->payouts->initiate([
    'amount'            => 50_000,
    'currency_code'     => 'XAF',
    'recipient_type'    => 'tangentopay_wallet',
    'recipient_details' => ['wallet_address' => 'user@example.com'],
    'note'              => 'Freelance payment',
]);

// Step 2 — confirm with payout PIN
$merchant->payouts->confirm($initiation->payoutRef, ['pin' => getenv('PAYOUT_PIN')]);

Virtual card payout (USD, Instant Payout)

// Option A: use a saved card
$merchant->payouts->initiate([
    'amount'            => 100,
    'currency_code'     => 'USD',
    'recipient_type'    => 'virtual_card',
    'recipient_details' => ['payout_method_id' => 'pm_...'],
]);

// Option B: one-time Stripe.js token (card never stored)
$merchant->payouts->initiate([
    'amount'            => 100,
    'currency_code'     => 'USD',
    'recipient_type'    => 'virtual_card',
    'recipient_details' => ['stripe_token_id' => 'tok_...'],
]);

Bulk payout

$batch = $merchant->payouts->bulk->initiate([
    'csv_file'             => fopen('payouts.csv', 'r'),
    'default_recipient_type' => 'tangentopay_wallet',
]);
$merchant->payouts->bulk->confirm($batch->batchRef, ['pin' => getenv('PAYOUT_PIN')]);

Merchant wallet top-up

// Via MoMo
$topup = $merchant->topups->create([
    'amount'   => 100_000,      // XAF
    'phone'    => '237XXXXXXXXX',
    'provider' => 'mtn_momo',
]);

// Via card (Stripe-hosted page)
$cardTopup = $merchant->topups->createCardTopup([
    'amount'        => 200,
    'currency_code' => 'USD',
    'return_url'    => 'https://dashboard.yourapp.com/wallet',
]);

Payment methods

$methods = $merchant->services->listPaymentMethods($serviceId);
// [['slug' => 'mtn_momo', 'name' => 'MTN Mobile Money', 'enabled' => true, 'locked' => false, ...], ...]

// Disable Orange Money if provider is down
$status = $merchant->providerStatus->get();
if ($status['orange_money']['status'] === 'down') {
    $merchant->services->setPaymentMethod($serviceId, 'orange_money', false);
}

// Replace entire set (card must always be included)
$merchant->services->setPaymentMethods($serviceId, ['card', 'mtn_momo']);

Environment configuration

TANGENTOPAY_SERVICE_KEY=pk_live_<your_public_key>
TANGENTOPAY_SECRET_KEY=sk_live_<your_secret_key>
TANGENTOPAY_WEBHOOK_SECRET=whsec_<your_webhook_secret>

Error handling

use TangentoPay\Exceptions\AuthenticationException;  // 401
use TangentoPay\Exceptions\PermissionException;      // 403
use TangentoPay\Exceptions\NotFoundException;        // 404
use TangentoPay\Exceptions\ValidationException;      // 422 — has ->errors array
use TangentoPay\Exceptions\RateLimitException;       // 429 — has ->retryAfter seconds
use TangentoPay\Exceptions\ServerException;          // 5xx
use TangentoPay\Exceptions\NetworkException;         // connection-level failure
use TangentoPay\Exceptions\TangentoPayException;     // base class

try {
    $merchant->payouts->initiate([...]);
} catch (ValidationException $e) {
    print_r($e->errors);           // field-level validation messages
} catch (RateLimitException $e) {
    echo "Retry after {$e->retryAfter}s";
} catch (TangentoPayException $e) {
    throw $e;
}

Webhook verification

use TangentoPay\Webhook;
use TangentoPay\Exceptions\WebhookSignatureException;

$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_TANGENTOPAY_SIGNATURE'] ?? '';

try {
    $event = Webhook::constructEvent($payload, $signature, getenv('TANGENTOPAY_WEBHOOK_SECRET'));
} catch (WebhookSignatureException $e) {
    http_response_code(400);
    exit('Bad signature');
}

if ($event->event === 'transaction.payment_completed') {
    fulfillOrder($event->payload);
}

http_response_code(200);
echo json_encode(['received' => true]);

Contributing

Pull requests are welcome. For major changes please open an issue first.

composer install
vendor/bin/phpunit

Security

Please report security vulnerabilities to security@tangentopay.com rather than opening a public issue.

License

MIT

统计信息

  • 总下载量: 14
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 5
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-20

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固