Download the PHP package chuckbe/ponto-connect-laravel-sdk without Composer
On this page you can find all versions of the php package chuckbe/ponto-connect-laravel-sdk. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download chuckbe/ponto-connect-laravel-sdk
More information about chuckbe/ponto-connect-laravel-sdk
Files in chuckbe/ponto-connect-laravel-sdk
Package ponto-connect-laravel-sdk
Short Description Laravel SDK for the Ponto Connect API v2 (Isabel Group / Ibanity)
License MIT
Homepage https://github.com/chuckbe/ponto-connect-laravel-sdk
Informations about the package ponto-connect-laravel-sdk
Ponto Connect Laravel SDK
A Laravel SDK for the Ponto Connect API v2 by Isabel Group (Ibanity). Built on Saloon PHP with a fluent, resource-based interface: OAuth with PKCE, accounts, transactions, synchronizations, reauthorization, organization endpoints, sandbox test data and webhook signature verification.
Payment initiation endpoints (payments, bulk payments, payment requests and their activation requests) are not implemented yet.
Requirements
- PHP 8.2+
- Laravel 10, 11, 12 or 13
- A Ponto Connect application in the Isabel API Hub developer portal, with its TLS certificate
Installation
Publish the configuration file:
Configuration
| Variable | Description |
|---|---|
PONTO_CONNECT_ENVIRONMENT |
sandbox or live. Selects the authorization host (https://sandbox-authorization.myponto.com or https://authorization.myponto.com). The API host is the same for both; Ponto routes your calls by certificate. |
PONTO_CONNECT_CLIENT_ID / _CLIENT_SECRET |
OAuth client credentials from the security tab of the Ponto Connect product. |
PONTO_CONNECT_APPLICATION_ID |
The application id, used as the expected aud of webhook signatures. Defaults to the client id. |
PONTO_CONNECT_CERTIFICATE_PATH / _PRIVATE_KEY_PATH / _PRIVATE_KEY_PASSPHRASE |
The TLS certificate and private key for mutual TLS. Every API request uses them. |
PONTO_CONNECT_CA_CHAIN_PATH |
Optional CA chain to verify the API server. Uses the system CA bundle when empty. |
PONTO_CONNECT_SCOPES |
Scopes requested in the authorization URL, separated by spaces or commas. Default ai pi name offline_access. Drop pi if your application may not initiate payments. |
Certificates
Keep the certificate and private key outside the repository and outside public/: for example ~/.config/chuck/ponto-sandbox/ locally, and a directory owned by the deploy user on the server, provisioned by your server recipes. Never commit them. Restrict the private key's permissions (chmod 600).
The sandbox and live environments use different certificates and client credentials. "Going live" means swapping these values, not changing code.
Usage
The manager never stores a token. Each call returns a fresh connector, so tokens for different organizations cannot leak into each other, for example in queue workers.
1. Connect with PKCE
Optionally, prefill the Ponto sign-up first with a client access token. Use the id within five minutes:
2. Exchange the code
$userInfo also exposes name, onboardingComplete, paymentsActivated, paymentsActivationRequested, paymentRequestsActivated, paymentRequestsActivationRequested, and, when the customer acts as a representative, representativeOrganizationId and representativeOrganizationName.
3. Refresh with rotation
Access tokens live 30 minutes. Refresh tokens are single-use: every refresh returns a new refresh token and invalidates the old one immediately.
- Lock around the refresh. Two workers refreshing with the same token means one gets
invalid_grantand the integration looks revoked. - Persist the new refresh token straight away, outside a database transaction. If an outer transaction rolls back after a successful refresh, the stored token is already invalid and the integration is lost.
InvalidGrantException(aPontoConnectException) is thrown only forinvalid_grant. The customer then has to connect again.- Refresh at least once every 90 days, or the refresh token expires.
4. Accounts and transactions (cursor pagination)
Lists return a Page with items, nextCursor (page[after]), previousCursor (page[before]) and limit. Pages accept ?int $limit = null (1 to 100, default 10), ?string $after and ?string $before.
Amounts are strings. Ponto sends amounts and balances as JSON numbers. They are converted to decimal strings with the shortest representation that matches the decoded number exactly, padded (never rounded) to at least two decimals: -85 becomes "-85.00", -99.29 stays "-99.29". Use bcmath or a money library, never floats. Dates are DateTimeImmutable in UTC.
5. Synchronizations (customer present only)
Ponto synchronizes in the background four times a day. You may trigger an extra synchronization only while the customer is actively using your application, and you must pass their real IP address. A new synchronization of the same account and subtype is refused within 30 minutes of the previous one.
6. Reauthorization
When an account's bank consent expires (authorizationExpirationExpectedAt, or a synchronization error like authorizationExpired):
7. Webhooks
The verifier accepts only RS512, picks the key by kid, checks aud (your application id), iss (https://api.ibanity.com) and digest (base64 SHA-512 of the raw body), and checks exp/iat with 30 seconds of leeway. WebhookEvent exposes id, type, eventType(), createdAt, attributes, count(), synchronizationSubtype(), accountId, organizationId, synchronizationId, paymentRequestId and jti.
8. Sandbox test transactions
Sandbox only, with a customer access token of a sandbox integration:
The transaction appears in transaction->list() after the next synchronization of that account.
Organization endpoints (client access token)
PontoConnect::api()->oauth->revoke($refreshToken) revokes with the refresh token instead.
Errors
Every 4xx/5xx response throws PontoConnect\Exceptions\PontoConnectException:
InvalidGrantException extends it for invalid_grant from the token endpoint.
Security
- Mutual TLS on every request. Keep the certificate and key outside the repository, readable only by the app user.
- Secrets: the client secret, passphrase, access and refresh tokens are marked
#[SensitiveParameter].ConfigurationandTokenhide them fromprint_r/var_dump. Do not logToken::toArray(). Store refresh tokens encrypted. - Webhooks: always verify the signature against the raw body before using the payload. Store the
jtito reject replays. Keep the event handler idempotent, because Ponto retries and does not guarantee order. - Synchronizations: never send a fake or server IP address. Creating synchronizations without the customer present breaks the Ponto Connect terms (PSD2 RTS).
- HTTP signatures are required by Ponto only for payment requests of live applications, which this SDK does not implement yet.
API reference
| Resource | Method | Endpoint |
|---|---|---|
oauth |
authorizationUrl(redirectUri, state, codeChallenge, ?scopes, ?language, ?onboardingDetailsId) |
{authorization host}/oauth2/auth (no API call) |
oauth |
exchangeAuthorizationCode(code, redirectUri, codeVerifier) |
POST /ponto-connect/oauth2/token |
oauth |
refresh(refreshToken) |
POST /ponto-connect/oauth2/token |
oauth |
clientCredentials() |
POST /ponto-connect/oauth2/token |
oauth |
revoke(refreshToken) |
POST /ponto-connect/oauth2/revoke |
userInfo |
get() |
GET /ponto-connect/userinfo |
onboardingDetails |
create(attributes, ?idempotencyKey) |
POST /ponto-connect/onboarding-details |
financialInstitution |
list(?limit, ?after, ?before, filters), all(filters), get(id) |
GET /ponto-connect/financial-institutions[/{id}] |
account |
list(...), all(), get(id), revoke(id) |
GET/DELETE /ponto-connect/accounts[/{id}] |
transaction |
list(accountId, ...), all(accountId), get(accountId, id) |
GET /ponto-connect/accounts/{accountId}/transactions[/{id}] |
transaction |
listUpdatedForSynchronization(synchronizationId, ...), allUpdatedForSynchronization(...) |
GET /ponto-connect/synchronizations/{id}/updated-transactions |
pendingTransaction |
list, all, get, listUpdatedForSynchronization, allUpdatedForSynchronization |
.../pending-transactions, .../updated-pending-transactions |
synchronization |
create(resourceId, subtype, customerIpAddress, resourceType = 'account', ?idempotencyKey), get(id) |
POST/GET /ponto-connect/synchronizations[/{id}] |
reauthorizationRequest |
create(accountId, redirectUri, ?idempotencyKey) |
POST /ponto-connect/accounts/{accountId}/reauthorization-requests |
integrationAccount |
list(...), all() |
GET /ponto-connect/integration-accounts |
usage |
get(organizationId, month) |
GET /ponto-connect/organizations/{organizationId}/usage/{month} |
integration |
delete(organizationId) |
DELETE /ponto-connect/organizations/{organizationId}/integration |
sandbox |
listFinancialInstitutionAccounts, getFinancialInstitutionAccount |
GET /ponto-connect/sandbox/financial-institutions/{id}/financial-institution-accounts[/{id}] |
sandbox |
listFinancialInstitutionTransactions, getFinancialInstitutionTransaction, createFinancialInstitutionTransaction, updateFinancialInstitutionTransaction |
GET/POST/PATCH .../financial-institution-accounts/{id}/financial-institution-transactions[/{id}] |
webhook |
keys() |
GET /webhooks/keys |
Architecture
Development
Unit tests use Orchestra Testbench and Saloon's MockClient, with fixtures copied from the example responses in the API reference (tests/Fixtures).
Sandbox smoke test
tests/Integration/SandboxSmokeTest.php calls the real sandbox: it requests a client-credentials token, lists financial institutions and fetches the webhook keys. When PONTO_CONNECT_TEST_REDIRECT_URI is set to a registered redirect URI, it also checks that the authorization server accepts the configured scopes. It is not part of the default suite and is skipped unless the PONTO_CONNECT_* variables are set:
It prints status codes only, never tokens or secrets.
Official documentation
License
MIT
All versions of ponto-connect-laravel-sdk with dependencies
ext-json Version *
ext-openssl Version *
firebase/php-jwt Version ^6.11|^7.0
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
saloonphp/laravel-plugin Version ^3.0
saloonphp/saloon Version ^3.0