Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sdk Php Laravel Package

bunq/sdk_php

The official PHP SDK for the bunq banking API, helping developers build apps that manage accounts, payments, cards, and webhooks programmatically. It handles authentication, request signing, and API calls for bunq's neobank platform.

Deep Wiki
Context7

Getting Started

  1. composer require bunq/sdk_php then check the examples/ directory and the README's example.php — that file shows the full bootstrap in one place. The generated API surface lives under src/Model/Generated/Endpoint/; that's your real reference for what operations exist.
  2. Get a sandbox API key first. Sign up at https://sandbox.bunq.com, create an app, and copy the API key. Production keys are separate and will reject sandbox keys, and vice versa.
  3. Bootstrap an ApiContext once and persist it — do not create a new one per request:
use bunq\ApiContext;
use bunq\BunqContext;
use bunq\Util\BunqEnumApiEnvironmentType;

$apiContext = ApiContext::create(
    BunqEnumApiEnvironmentType::SANDBOX(),
    getenv('BUNQ_API_KEY'),
    'my-app-name',
    ['my-device']
);
$apiContext->save('/secure/bunq.conf');
  1. On every subsequent process, restore and load it before touching any endpoint:
BunqContext::loadApiContext(ApiContext::restore('/secure/bunq.conf'));
$userId = BunqContext::getUserId();
  1. First useful call — list monetary accounts and make a payment:
use bunq\Model\Generated\Endpoint\MonetaryAccountBank;
use bunq\Model\Generated\Endpoint\Payment;
use bunq\Model\Generated\Object\Amount;
use bunq\Model\Generated\Object\Pointer;

$accounts = MonetaryAccountBank::list($userId)->getValue();
$accountId = $accounts[0]->getId();

$payment = Payment::create(
    new Amount('EUR', '0.01'),
    new Pointer('EMAIL', '[email protected]'),
    'first sandbox payment'
);

Implementation Patterns

  • One bootstrap, many calls. Wrap context creation/restore in a small BunqClient or service class registered in the container. ApiContext::create() hits the API three times (installation, device server, session server) — never do it inside a request loop.
  • Static endpoint style is the modern API. Payment::create(), Payment::list($userId, $accountId), RequestInquiry::create(), etc. Older 0.x releases used PaymentService::create() — pin bunq/sdk_php in composer.json and don't mix the two.
  • Responses are wrapped. Endpoint calls return typed BunqResponse* objects. Use ->getValue() for a single entity or the list array, and ->getItems() when iterating paginated lists. Check getResponseCode() on the wrapper before assuming success.
  • Idempotency on every write. Pass an Idempotency object with a deterministic token (e.g. hash of your order ID) to create() calls so retries don't double-charge:
$idempotency = Idempotency::create('order-12345-attempt-1');
Payment::create($amount, $counterparty, 'desc', $idempotency);
  • Pagination. Default page size is small. Use Pagination::create(50) and loop with setOlderId() until the result array is shorter than the page size. Don't assume one call returns all history.
  • Request money vs. pay. RequestInquiry creates a request the counterparty sees; listen for accepted responses via RequestResponse or a webhook, then reconcile.
  • Scheduled/recurring payments are DraftPayment + Schedule + ScheduleInstance. Create the schedule first, then reference its ID in the draft.
  • Webhooks. Register NotificationFilterUrlUser (all events) or NotificationFilterUrlMonetaryAccount for one account. The callback URL must be public HTTPS. The SDK does not verify signatures — treat the body as a hint and re-fetch the referenced object via the API before acting on it.
  • Attachments. Upload via Attachment::create() first, then pass the returned ID in the payment body; you cannot inline binary content.
  • Multi-tenant. Each bunq user gets their own ApiContext (and their own API key). Store the serialized context encrypted, keyed by your user ID, and load the right one per request.
  • Testing. In setUp(), call BunqContext::clearContext() and load a fixture context; stub the SDK's low-level ApiClient (or use a fake HTTP client) so unit tests don't hit bunq. Keep integration tests against sandbox only.

Gotchas and Tips

  • The context file is a secret. It contains your installation private key, device server, and session token. Encrypt it at rest, exclude from git, and rotate by deleting/regenerating rather than sharing.
  • Session expiry. Sessions expire (roughly a week of inactivity). ApiContext will attempt a session re-creation, but if the installation/device server is stale you'll see 401s. Catch, restore(), and retry once; if that fails, re-run ApiContext::create() (which re-registers the device).
  • Static global state. BunqContext is a singleton — anything calling endpoint methods after another bootstrap will silently use the wrong context. Always loadApiContext() explicitly; call clearContext() in tests and long-running workers between tenants.
  • Sandbox resets. sandbox.bunq.com wipes its database periodically. API keys stop working, sandbox monetary account IDs change, and you cannot assume IDs are stable. Treat sandbox IDs as ephemeral.
  • Environment enum, not string. Newer releases require BunqEnumApiEnvironmentType::SANDBOX() / PRODUCTION(), not the literal 'SANDBOX'. Mismatches throw TypeError — a common failure after upgrading.
  • Production device confirmation. ApiContext::create() in production blocks until the user approves the device in the bunq app. In automation, wrap it in a poll loop on DeviceServer::get() and surface a clear error if not approved within a timeout.
  • Errors are in the body, not the exception message. BunqException::getErrorDescriptions() returns an array of Error objects with getErrorDescription(), getCategory(), and getCode() — log all three. HTTP 429 means rate limited; back off exponentially and respect Retry-After.
  • IDs drift. UserId and MonetaryAccountId are what you should persist, not Payment::getId() from a sandbox response. Cache the user ID from BunqContext::getUserId() at login time instead of resolving it every request.
  • MonetaryAccount vs MonetaryAccountBank. The generic MonetaryAccount list returns references; to get balances use MonetaryAccountBank::get($userId, $accountId) or the MonetaryAccountSavings/Joint variants. getBalance() returns an Amount where the currency is the first field — don't assume EUR.
  • OAuth only if you serve other bunq users. OauthClient + BunqEnumOauthResponseType are for third-party apps that let users connect their own bunq account. For a single-tenant integration, API key + ApiContext::restore() is sufficient and much simpler.
  • Logging. The SDK ships its own logger and a BunqLogger util; enable debug mode during integration to see request/response payloads. In production route it to a proper logger and redact the Authorization header and context contents.
  • Watch PHP version. Recent SDK versions require PHP 8.1+; older versions support 7.4 but lack typed endpoint responses. Pin a minor version and re-run the sandbox example after every upgrade — the generated model surface changes quietly between releases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib