PHPackages                             sudiptpa/wise-php-sdk - 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. sudiptpa/wise-php-sdk

ActiveLibrary

sudiptpa/wise-php-sdk
=====================

Unofficial Wise Platform PHP SDK with rich models and transport-agnostic architecture.

v0.1.0(1mo ago)01↓100%MITPHPPHP ^8.2CI passing

Since Mar 13Pushed 1mo agoCompare

[ Source](https://github.com/sudiptpa/wise-php-sdk)[ Packagist](https://packagist.org/packages/sudiptpa/wise-php-sdk)[ RSS](/packages/sudiptpa-wise-php-sdk/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (7)Versions (2)Used By (0)

wise-php-sdk
============

[](#wise-php-sdk)

Unofficial PHP SDK for Wise Platform APIs.

[![Tests](https://github.com/sudiptpa/wise-php-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/sudiptpa/wise-php-sdk/actions/workflows/ci.yml)[![Latest Version](https://camo.githubusercontent.com/0aa9279b7d10ae13d02f842f2ca6fcd98f936f6568a08e31733152d262e82bda/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73756469707470612f776973652d7068702d73646b2e737667)](https://packagist.org/packages/sudiptpa/wise-php-sdk)[![Total Downloads](https://camo.githubusercontent.com/c0d96f1bba88f9ff16760612fbdc0dd05a8b535cde9b36fdf575ca645388e3fd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73756469707470612f776973652d7068702d73646b2e737667)](https://packagist.org/packages/sudiptpa/wise-php-sdk)[![License](https://camo.githubusercontent.com/596477f26b724fb019a7c4eb7f80addcf85bc3fd302a0617852ad9662a2fb711/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f73756469707470612f776973652d7068702d73646b2e737667)](LICENSE)

Unofficial Disclaimer
---------------------

[](#unofficial-disclaimer)

This package is not affiliated with, endorsed by, or maintained by Wise.

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

[](#requirements)

- PHP 8.2+
- A transport implementation of `Sujip\Wise\Contracts\TransportInterface`

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

[](#installation)

```
composer require sudiptpa/wise-php-sdk
```

Quick Start
-----------

[](#quick-start)

```
use GuzzleHttp\Client;
use Http\Factory\Guzzle\RequestFactory;
use Http\Factory\Guzzle\StreamFactory;
use Sujip\Wise\Config\ClientConfig;
use Sujip\Wise\Transport\Psr18Transport;
use Sujip\Wise\Wise;

$config = ClientConfig::apiToken('your-wise-api-token', ClientConfig::SANDBOX_BASE_URL);
$transport = new Psr18Transport(new Client());

$wise = Wise::client($config, $transport, new RequestFactory(), new StreamFactory());

$profiles = $wise->profile()->list();
$firstProfileId = $profiles->all()[0]->id ?? null;

$rates = $wise->rate()->list();
$balances = $wise->balance()->list((int) $firstProfileId);
```

Available Resources
-------------------

[](#available-resources)

- `$wise->profile()`
- `$wise->contact()`
- `$wise->currencies()`
- `$wise->address()`
- `$wise->quote()`
- `$wise->recipientAccount()`
- `$wise->transfer()`
- `$wise->payment()`
- `$wise->webhook()`
- `$wise->activity()`
- `$wise->balance()`
- `$wise->rate()`
- `$wise->balanceStatement()`
- `$wise->bankAccountDetails()`
- `$wise->user()`
- `$wise->userTokens()`

Configuration
-------------

[](#configuration)

```
use Sujip\Wise\Config\ClientConfig;

$api = ClientConfig::apiToken('your-wise-api-token');
$apiSandbox = ClientConfig::apiToken('your-wise-api-token', ClientConfig::SANDBOX_BASE_URL);

$oauth = ClientConfig::oauth2('oauth-access-token');
$oauthSandbox = ClientConfig::oauth2('oauth-access-token', ClientConfig::SANDBOX_BASE_URL);
```

Base URLs:

- Production: `https://api.wise.com`
- Sandbox: `https://api.wise-sandbox.com`

Auth Modes
----------

[](#auth-modes)

ModeUse caseCredentialToken handlingNotesAPI TokenAutomating your own Wise accountPersonal/Business API tokenManaged by youBest fit for single-account access; do not assume API funding is availableOAuth2Wise Platform / partner integrationsOAuth2 access tokenRefresh flow in your appRequired for partner-style flows and connected-account accessSee the full auth capability guide:

- `docs/AUTH_CAPABILITIES.md`

Auth Capability Summary
-----------------------

[](#auth-capability-summary)

CapabilityPersonal API TokenOAuth2Read your own account dataYesYesCreate quotes and transfer draftsYesYesFund transfers through APILimited and not guaranteedYes, in partner setupsManage other Wise accountsNoYes, in partner setupsUse `/oauth/token` app credentials flowNoYesNotes:

- Personal API tokens are for your own Wise account.
- OAuth2 with `clientId` / `clientSecret` is the Wise partner path.
- If your profile is in the UK or EEA, do not rely on personal-token funding by API.
- Outside the UK/EEA, funding can still depend on your account setup. Check with Wise if this matters for your use case.
- If you only need self-account automation, start with personal token support.
- If you need delegated account access or API funding flows, plan for OAuth2.

If you rotate OAuth2 tokens, provide your own token provider:

```
use Sujip\Wise\Auth\AuthMode;
use Sujip\Wise\Config\ClientConfig;
use Sujip\Wise\Contracts\AccessTokenProviderInterface;

final class OAuthProvider implements AccessTokenProviderInterface
{
    public function getAccessToken(): string
    {
        return 'fresh-access-token';
    }
}

$config = new ClientConfig(
    authMode: AuthMode::OAuth2,
    accessTokenProvider: new OAuthProvider(),
    baseUrl: ClientConfig::DEFAULT_BASE_URL,
);
```

Transport Options (Choose One)
------------------------------

[](#transport-options-choose-one)

The SDK does not pick a transport for you.

### 1) PSR-18 + Guzzle

[](#1-psr-18--guzzle)

Install optional dependencies:

```
composer require guzzlehttp/guzzle http-interop/http-factory-guzzle
```

```
use GuzzleHttp\Client;
use Http\Factory\Guzzle\RequestFactory;
use Http\Factory\Guzzle\StreamFactory;
use Sujip\Wise\Transport\Psr18Transport;
use Sujip\Wise\Wise;

$transport = new Psr18Transport(new Client());
$wise = Wise::client($config, $transport, new RequestFactory(), new StreamFactory());
```

### 2) Curl transport (example)

[](#2-curl-transport-example)

```
final class CurlTransport implements \Sujip\Wise\Contracts\TransportInterface
{
    public function send(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\ResponseInterface
    {
        // Run curl and map response to PSR-7.
    }
}
```

### 3) Laravel transport (example)

[](#3-laravel-transport-example)

```
final class LaravelTransport implements \Sujip\Wise\Contracts\TransportInterface
{
    public function send(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\ResponseInterface
    {
        // Call Laravel HTTP client and map response to PSR-7.
    }
}
```

See full transport setup guides:

- `docs/transports/guzzle.md`
- `docs/transports/curl.md`
- `docs/transports/laravel.md`

Send Money in 4 Steps
---------------------

[](#send-money-in-4-steps)

```
use Sujip\Wise\Resources\Payment\Requests\FundTransferRequest;
use Sujip\Wise\Resources\Quote\Requests\CreateAuthenticatedQuoteRequest;
use Sujip\Wise\Resources\RecipientAccount\Requests\CreateRecipientAccountRequest;
use Sujip\Wise\Resources\Transfer\Requests\CreateTransferRequest;

$quote = $wise->quote()->createAuthenticated(
    123,
    CreateAuthenticatedQuoteRequest::fixedTarget('USD', 'EUR', 100)
);

$recipient = $wise->recipientAccount()->create(
    new CreateRecipientAccountRequest(123, 'Jane Doe', 'EUR', 'iban', ['iban' => 'DE123'])
);

$transfer = $wise->transfer()->create(CreateTransferRequest::from($quote, $recipient));

$payment = $wise->payment()->fundTransfer(123, $transfer->id, new FundTransferRequest('BALANCE'));
```

Important:

- The funding step is not the same as creating a draft transfer.
- If your profile is in the UK or EEA, do not rely on personal-token funding by API.
- Outside the UK/EEA, check with Wise if API funding is important for your flow.
- In most cases, personal-token users will create the transfer draft by API and complete funding in Wise web or mobile.
- OAuth2 partner environments are the expected path for API funding.

Activity Listing + Pagination
-----------------------------

[](#activity-listing--pagination)

```
use Sujip\Wise\Resources\Activity\Requests\ListActivitiesRequest;

$page = $wise->activity()->list(123, new ListActivitiesRequest(status: 'COMPLETED', size: 20));

foreach ($page->activities as $activity) {
    echo $activity->status().' - '.$activity->titlePlainText().PHP_EOL;
}

while ($page->hasNext()) {
    $page = $wise->activity()->list(123, new ListActivitiesRequest(nextCursor: $page->nextCursor(), size: 20));
}
```

Or iterate through all pages:

```
foreach ($wise->activity()->iterate(123, new ListActivitiesRequest(size: 50)) as $activity) {
    echo $activity->titlePlainText().PHP_EOL;
}
```

Finding Your Profile ID
-----------------------

[](#finding-your-profile-id)

```
curl -sS https://api.wise-sandbox.com/v2/profiles \
  -H "Authorization: Bearer " \
  -H "Accept: application/json"
```

Use the `id` field from the response. `member id` is different from `profile id`.

Error Handling
--------------

[](#error-handling)

```
use Sujip\Wise\Exceptions\ApiException;
use Sujip\Wise\Exceptions\AuthException;
use Sujip\Wise\Exceptions\RateLimitException;

try {
    $quote = $wise->quote()->get(123, 456);
} catch (AuthException $e) {
    // 401/403
} catch (RateLimitException $e) {
    // 429, retry delay in $e->retryAfter (seconds)
} catch (ApiException $e) {
    // Other 4xx/5xx, payload in $e->errorBody
}
```

Error Map
---------

[](#error-map)

HTTP statusExceptionTypical action401 / 403`AuthException`Check token type, token value, and scope429`RateLimitException`Wait and retry using `retryAfter`4xx / 5xx`ApiException`Check error payload and request IDsTransport failure`TransportException`Check connectivity and transport implementationRetry and Idempotency
---------------------

[](#retry-and-idempotency)

Retries are off by default. Enable them explicitly:

```
use Sujip\Wise\Auth\AuthMode;
use Sujip\Wise\Auth\StaticAccessTokenProvider;
use Sujip\Wise\Config\ClientConfig;

$config = new ClientConfig(
    authMode: AuthMode::ApiToken,
    accessTokenProvider: new StaticAccessTokenProvider('your-token'),
    baseUrl: ClientConfig::DEFAULT_BASE_URL,
    retryEnabled: true,
    retryMaxAttempts: 4,
    retryBaseDelayMs: 200,
    retryMaxDelayMs: 2000,
    retryMethods: ['GET', 'POST'],
    idempotencyKey: 'your-stable-idempotency-key',
);
```

Notes:

- Retry middleware applies only when enabled.
- It retries 429 and selected 5xx responses.
- Use idempotency keys for retryable write operations.
- Idempotency key is attached to SDK `POST` operations when configured.

Webhooks
--------

[](#webhooks)

Create subscriptions through `WebhookResource`.

Verify payload signatures before processing:

```
use Sujip\Wise\Resources\Webhook\WebhookVerifier;

$payload = file_get_contents('php://input') ?: '';
$signature = $_SERVER['HTTP_X_SIGNATURE_SHA256'] ?? '';
$secret = 'your-webhook-secret';

$ok = (new WebhookVerifier())->verify($payload, $signature, $secret);
```

Replay protection helper:

```
use Sujip\Wise\Resources\Webhook\WebhookReplayProtector;
use Sujip\Wise\Support\InMemoryWebhookReplayStore;

$replayProtector = new WebhookReplayProtector(new InMemoryWebhookReplayStore(), 300);
$replayProtector->validate($eventId, $eventTimestamp);
```

Redis replay store example:

```
use Sujip\Wise\Contracts\WebhookReplayStoreInterface;

final class RedisWebhookReplayStore implements WebhookReplayStoreInterface
{
    public function __construct(private \Redis $redis) {}

    public function remember(string $eventId, int $ttlSeconds): bool
    {
        return (bool) $this->redis->set("wise:webhook:{$eventId}", '1', ['nx', 'ex' => $ttlSeconds]);
    }
}
```

Production Checklist
--------------------

[](#production-checklist)

- Set `timeoutSeconds` to a value suitable for your runtime and workload.
- Keep retries off by default; enable only with explicit retry methods and limits.
- Use idempotency keys for retryable write flows.
- Rotate API/OAuth credentials and never store them in source control.
- Verify webhook signatures and enforce replay checks in persistent storage.
- Track `requestId` / `correlationId` from exceptions in logs and alerts.

Test Confidence
---------------

[](#test-confidence)

- Unit tests cover request path/method/body contracts for implemented endpoints.
- Fixtures in `tests/Fixtures/wise` are used for deterministic model hydration tests.
- Middleware tests cover retry, idempotency behavior, and logging sanitization.
- Sandbox workflow provides scheduled live verification against Wise sandbox.

Production Checklist
--------------------

[](#production-checklist-1)

- Set timeout and connect-timeout values.
- Use structured logging and keep secrets redacted.
- Rotate API/OAuth credentials.
- Use idempotency for retryable writes.
- Log request/correlation IDs for support.
- Monitor auth, rate-limit, and server error rates.

Versioning and Compatibility
----------------------------

[](#versioning-and-compatibility)

- SemVer.
- Runtime target: PHP `^8.2`.
- CI runs on `8.2`, `8.3`, `8.4`; `8.5` is non-blocking.

Guides
------

[](#guides)

- `docs/transports/guzzle.md`
- `docs/transports/curl.md`
- `docs/transports/laravel.md`
- `docs/API_REFERENCE.md`
- `docs/WISE_API_STATUS.md`
- `docs/SANDBOX_CHECKS.md`
- `docs/VERSIONING.md`
- `RELEASE.md`

FAQ
---

[](#faq)

### I get `invalid_token`. What should I check?

[](#i-get-invalid_token-what-should-i-check)

- Match token type to environment (`api.wise.com` vs `api.wise-sandbox.com`).
- Confirm token is active and complete.
- Confirm scope/profile access.

### Is profile ID the same as member ID?

[](#is-profile-id-the-same-as-member-id)

No. Use `id` from `/v2/profiles`.

### Can I use live personal token in CI?

[](#can-i-use-live-personal-token-in-ci)

Not recommended. Use sandbox credentials in CI.

### Why does SDK require transport + PSR-17 factories?

[](#why-does-sdk-require-transport--psr-17-factories)

The SDK stays transport-agnostic. You bring the HTTP stack.

Quality
-------

[](#quality)

```
composer qa
```

API Reference
-------------

[](#api-reference)

See `docs/API_REFERENCE.md`.

Sandbox Checks
--------------

[](#sandbox-checks)

See `docs/SANDBOX_CHECKS.md`.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance89

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

Unknown

Total

1

Last Release

58d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/89a8c4cc02c4a958a03c60826c3d24b9dcbade10d3439e60e266702dbacc61e4?d=identicon)[sudiptpa](/maintainers/sudiptpa)

---

Top Contributors

[![sudiptpa](https://avatars.githubusercontent.com/u/7222620?v=4)](https://github.com/sudiptpa "sudiptpa (37 commits)")

---

Tags

api-clientpaymentspayments-platformwisewise-apiwise-php-sdk

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sudiptpa-wise-php-sdk/health.svg)

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

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.8k18.5M1.6k](/packages/cakephp-cakephp)[aporat/store-receipt-validator

PHP receipt validator for Apple App Store and Amazon Appstore

6503.9M9](/packages/aporat-store-receipt-validator)[opensearch-project/opensearch-php

PHP Client for OpenSearch

15024.3M64](/packages/opensearch-project-opensearch-php)[tempest/framework

The PHP framework that gets out of your way.

2.1k23.1k9](/packages/tempest-framework)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

81733.7k](/packages/flow-php-flow)[neos/flow

Flow Application Framework

862.0M450](/packages/neos-flow)

PHPackages © 2026

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