定制 sudiptpa/wise-php-sdk 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

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

sudiptpa/wise-php-sdk

Composer 安装命令:

composer require sudiptpa/wise-php-sdk

包简介

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

README 文档

README

Wise PHP SDK for Wise Platform APIs.

Tests Latest Version Total Downloads License

Sponsor

If this package has been useful to you, GitHub Sponsors is a simple way to support ongoing maintenance, improvements, and future releases.

Unofficial Disclaimer

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

Requirements

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

Installation

composer require sudiptpa/wise-php-sdk

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

  • $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

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

Mode Use case Credential Token handling Notes
API Token Automating your own Wise account Personal/Business API token Managed by you Best fit for single-account access; do not assume API funding is available
OAuth2 Wise Platform / partner integrations OAuth2 access token Refresh flow in your app Required for partner-style flows and connected-account access

See the full auth capability guide:

  • docs/AUTH_CAPABILITIES.md

Auth Capability Summary

Capability Personal API Token OAuth2
Read your own account data Yes Yes
Create quotes and transfer drafts Yes Yes
Fund transfers through API Limited and not guaranteed Yes, in partner setups
Manage other Wise accounts No Yes, in partner setups
Use /oauth/token app credentials flow No Yes

Notes:

  • 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)

The SDK does not pick a transport for you.

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)

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)

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

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

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

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

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

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

HTTP status Exception Typical action
401 / 403 AuthException Check token type, token value, and scope
429 RateLimitException Wait and retry using retryAfter
4xx / 5xx ApiException Check error payload and request IDs
Transport failure TransportException Check connectivity and transport implementation

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

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

  • 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

  • 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

  • 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

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

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

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?

No. Use id from /v2/profiles.

Can I use live personal token in CI?

Not recommended. Use sandbox credentials in CI.

Why does SDK require transport + PSR-17 factories?

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

Quality

composer qa

API Reference

See docs/API_REFERENCE.md.

Sandbox Checks

See docs/SANDBOX_CHECKS.md.

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-13

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固