PHPackages                             tangentopay/tangentopay-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. tangentopay/tangentopay-php

ActiveLibrary[Payment Processing](/categories/payments)

tangentopay/tangentopay-php
===========================

Official PHP SDK for the TangentoPay API

v0.9.0(1mo ago)014MITPHP &gt;=8.1

Since May 20Compare

[ Source](https://github.com/Grut-Design-Agency/tangentopay-php)[ Packagist](https://packagist.org/packages/tangentopay/tangentopay-php)[ Docs](https://tangentopay.com)[ RSS](/packages/tangentopay-tangentopay-php/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (6)Versions (18)Used By (0)

tangentopay-php
===============

[](#tangentopay-php)

Official PHP SDK for the [TangentoPay](https://tangentopay.com) API — accept payments, issue refunds, manage wallets, and verify webhooks with a clean, fully-typed interface.

[![Packagist Version](https://camo.githubusercontent.com/02757cfbc098b4d6e021114948fc00d75a0207da2c65bc790aba43fbfd4dd085/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f74616e67656e746f7061792f74616e67656e746f7061792d706870)](https://packagist.org/packages/tangentopay/tangentopay-php)[![CI](https://github.com/Grut-Design-Agency/tangentopay-php/actions/workflows/ci.yml/badge.svg)](https://github.com/Grut-Design-Agency/tangentopay-php/actions)[![PHP 8.1+](https://camo.githubusercontent.com/fa899ece46c935a890231176d14070ebca810802ca806025647b9b9feee7e32b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e312b2d626c75652e737667)](https://www.php.net/)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](LICENSE)

---

Table of contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Authentication](#authentication)
- [Token expiry and refresh](#token-expiry-and-refresh)
- [Test mode](#test-mode)
- [Resources](#resources)
- [Provider status](#provider-status)
- [Currency and provider guide](#currency-and-provider-guide)
- [Service wallet operations (B2B2C)](#service-wallet-operations-b2b2c)
- [Payouts](#payouts)
- [Merchant wallet top-up](#merchant-wallet-top-up)
- [Payment methods](#payment-methods)
- [Error handling](#error-handling)
- [Webhook verification](#webhook-verification)
- [Contributing](#contributing)
- [Security](#security)
- [License](#license)

---

Requirements
------------

[](#requirements)

- PHP 8.1 or later
- Guzzle 7 (`guzzlehttp/guzzle`)
- A TangentoPay account — [sign up](https://tangentopay.com)

---

Installation
------------

[](#installation)

```
composer require tangentopay/tangentopay-php
```

---

Quick start
-----------

[](#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->redirectUrl

// ── Or: hosted checkout — let the customer pick the payment method ────────────
// Returns a checkout.tangentopay.com URL showing the methods you've enabled
// (card, Google/Apple Pay, Alipay, WeChat, MTN MoMo, Orange Money).
$hosted = $service->checkout->createHosted([
    'amount'        => 5000,
    'currency_code' => 'XAF',
    'return_url'    => 'https://myshop.com/thank-you',
    'cancel_url'    => 'https://myshop.com/cart',
]);
// redirect your customer to $hosted['checkout_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
--------------

[](#authentication)

TangentoPay has two credential types:

CredentialWhere it goesClient 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

[](#serviceclient)

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

### MerchantClient

[](#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
------------------------

[](#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
---------

[](#test-mode)

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

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

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

---

Resources
---------

[](#resources)

### ServiceClient resources

[](#serviceclient-resources)

PropertyDescription`$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

[](#merchantclient-resources)

PropertyDescription`$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](https://tangentopay.com). These operations are intentionally not exposed in the SDK.

---

Provider status
---------------

[](#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:

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

Currency and provider guide
---------------------------

[](#currency-and-provider-guide)

ProviderSupported currenciesNotes**MTN Mobile Money**XAF onlyCameroon; USSD push via Fapshi. Min 100 XAF, max 500 000 XAF.**Orange Money**XAF onlyCameroon; USSD push via Fapshi. Min 100 XAF, max 500 000 XAF.**Stripe**USD, EUR, GBP, and moreMulti-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)
---------------------------------

[](#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
-------

[](#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)

[](#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

[](#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
----------------------

[](#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
---------------

[](#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
-------------------------

[](#environment-configuration)

```
TANGENTOPAY_SERVICE_KEY=pk_live_
TANGENTOPAY_SECRET_KEY=sk_live_
TANGENTOPAY_WEBHOOK_SECRET=whsec_
```

---

Error handling
--------------

[](#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
--------------------

[](#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
------------

[](#contributing)

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

```
composer install
vendor/bin/phpunit
```

---

Security
--------

[](#security)

Please report security vulnerabilities to **** rather than opening a public issue.

---

License
-------

[](#license)

[MIT](LICENSE)

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance93

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

17

Last Release

37d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f0d3346c3a7c5e5b884bc413f966af7e10ce77bd9b3b90a7afea841027635346?d=identicon)[tangentogroup-devs](/maintainers/tangentogroup-devs)

---

Tags

sdkstripepaymentsfintechafricatangentopay

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/tangentopay-tangentopay-php/health.svg)

```
[![Health](https://phpackages.com/badges/tangentopay-tangentopay-php/health.svg)](https://phpackages.com/packages/tangentopay-tangentopay-php)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.2k543.5M2.7k](/packages/aws-aws-sdk-php)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

293.1k](/packages/eslazarev-wildberries-sdk)[chargebee/chargebee-php

ChargeBee API client implementation for PHP

758.5M9](/packages/chargebee-chargebee-php)[tatter/stripe

Stripe SDK integration for CodeIgniter 4

115.3k](/packages/tatter-stripe)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
