PHP code example of chuckbe / ponto-connect-laravel-sdk

1. Go to this page and download the library: Download chuckbe/ponto-connect-laravel-sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

chuckbe / ponto-connect-laravel-sdk example snippets


use PontoConnect\Facades\PontoConnect;

PontoConnect::api();                          // no token: public endpoints and the OAuth token endpoints
PontoConnect::withAccessToken($accessToken);  // customer (or client) access token

use PontoConnect\Facades\PontoConnect;
use PontoConnect\Support\Pkce;

$pkce = Pkce::generate();                     // ['verifier' => ..., 'challenge' => ...]
$state = Str::random(40);

session(['ponto.state' => $state, 'ponto.verifier' => $pkce['verifier']]);

return redirect()->away(PontoConnect::authorizationUrl(
    redirectUri: route('integrations.ponto.callback'),
    state: $state,
    codeChallenge: $pkce['challenge'],
    language: 'nl',                           // optional: en, fr or nl
    // scopes: ['ai', 'name', 'offline_access'], // optional override of the configured scopes
    // onboardingDetailsId: $onboardingDetails->id, // optional, see below
));

$clientToken = PontoConnect::api()->oauth->clientCredentials();

$onboardingDetails = PontoConnect::withAccessToken($clientToken->accessToken)
    ->onboardingDetails
    ->create([
        'email' => $user->email,
        'firstName' => $user->first_name,
        'lastName' => $user->last_name,
        'organizationName' => $company->name,
        'vatNumber' => $company->vat_number,
        'addressCountry' => 'BE',
    ]);

abort_unless(hash_equals(session('ponto.state'), $request->query('state')), 403);

$token = PontoConnect::api()->oauth->exchangeAuthorizationCode(
    code: $request->query('code'),
    redirectUri: route('integrations.ponto.callback'),
    codeVerifier: session()->pull('ponto.verifier'),
);

$userInfo = PontoConnect::withAccessToken($token->accessToken)->userInfo->get();

$connection->update([
    'organization_id' => $userInfo->sub,      // store it: needed for usage and integration deletion
    'refresh_token' => $token->refreshToken,  // encrypted cast
    'access_token' => $token->accessToken,
    'access_token_expires_at' => $token->expiresAt,
]);

use Illuminate\Support\Facades\Cache;
use PontoConnect\Exceptions\InvalidGrantException;

$accessToken = Cache::lock("ponto-refresh:{$connection->id}", 30)->block(10, function () use ($connection) {
    $connection->refresh();

    if ($connection->access_token_expires_at->isFuture()) {
        return $connection->access_token;     // another process refreshed in the meantime
    }

    try {
        $token = PontoConnect::api()->oauth->refresh($connection->refresh_token);
    } catch (InvalidGrantException $exception) {
        $connection->markRevoked();           // used, expired (90 days) or revoked by the customer
        throw $exception;
    }

    $connection->update([                     // persist immediately, outside any DB transaction
        'refresh_token' => $token->refreshToken,
        'access_token' => $token->accessToken,
        'access_token_expires_at' => $token->expiresAt,
    ]);

    return $token->accessToken;
});

$ponto = PontoConnect::withAccessToken($accessToken);

$page = $ponto->account->list(limit: 50);
foreach ($page as $account) {
    echo $account->reference;                 // IBAN
    echo $account->currentBalance;            // "1234.50" (string)
    echo $account->latestSynchronization?->status;
}
$nextPage = $ponto->account->list(limit: 50, after: $page->nextCursor);

// Or walk every page lazily (one request per page, 100 items per page)
foreach ($ponto->transaction->all($accountId) as $transaction) {
    $transaction->amount;                     // "-85.00"
    $transaction->remittanceInformation;      // "+++090/9337/55493+++"
    $transaction->remittanceInformationType;  // "structured"
    $transaction->valueDate;                  // DateTimeImmutable (UTC)
}

$ponto->pendingTransaction->list($accountId);   // replace your stored pending transactions each time
$ponto->account->revoke($accountId);            // remove an account from the integration

use PontoConnect\Enums\SynchronizationSubtype;

$synchronization = $ponto->synchronization->create(
    resourceId: $accountId,
    subtype: SynchronizationSubtype::ACCOUNT_TRANSACTIONS,
    customerIpAddress: $request->ip(),
    idempotencyKey: (string) Str::uuid(),     // optional, any POST/PATCH accepts one
);

$synchronization = $ponto->synchronization->get($synchronization->id);
if ($synchronization->isSuccessful()) {
    foreach ($ponto->transaction->allUpdatedForSynchronization($synchronization->id) as $transaction) {
        // new or changed transactions
    }
}
if ($synchronization->hasFailed()) {
    $synchronization->errorCodes();           // e.g. ['authorizationExpired']
}

$reauthorization = $ponto->reauthorizationRequest->create(
    accountId: $accountId,
    redirectUri: route('integrations.ponto.reauthorized'),
);

return redirect()->away($reauthorization->redirectUrl);

use Illuminate\Support\Facades\Cache;
use PontoConnect\Enums\WebhookEventType;
use PontoConnect\Exceptions\UnknownWebhookKeyException;
use PontoConnect\Exceptions\WebhookVerificationException;

public function __invoke(Request $request)
{
    $verifier = PontoConnect::webhookVerifier();
    $signature = (string) $request->header('Signature');
    $rawBody = $request->getContent();        // the raw body, not the parsed JSON

    try {
        try {
            $keys = Cache::remember('ponto-connect.webhook-keys', 3600, fn () => PontoConnect::api()->webhook->keys());
            $event = $verifier->verify($signature, $rawBody, $keys);
        } catch (UnknownWebhookKeyException) {
            $keys = PontoConnect::api()->webhook->keys();  // Ponto rotated its signing keys
            Cache::put('ponto-connect.webhook-keys', $keys, 3600);
            $event = $verifier->verify($signature, $rawBody, $keys);
        }
    } catch (WebhookVerificationException) {
        abort(400);
    }

    if (! Cache::add("ponto-connect.webhook-jti.{$event->jti}", true, now()->addDay())) {
        return response()->noContent();       // replayed
    }

    if ($event->is(WebhookEventType::ACCOUNT_TRANSACTIONS_CREATED)) {
        SyncPontoTransactions::dispatch($event->organizationId, $event->accountId, $event->synchronizationId);
    }

    return response()->noContent();           // answer within 5 seconds, do the work in a job
}

$fakeAccounts = $ponto->sandbox->listFinancialInstitutionAccounts($financialInstitutionId);

$ponto->sandbox->createFinancialInstitutionTransaction(
    financialInstitutionId: $financialInstitutionId,
    financialInstitutionAccountId: $fakeAccounts->items[0]->id,
    attributes: [
        'valueDate' => now(),
        'executionDate' => now(),
        'amount' => '121.00',
        'currency' => 'EUR',
        'description' => 'Payment invoice 2026-0042',
        'remittanceInformationType' => 'structured',
        'remittanceInformation' => '+++090/9337/55493+++',
        'counterpartName' => 'Acme BV',
        'counterpartReference' => 'BE68539007547034',
    ],
);

$client = PontoConnect::withAccessToken(PontoConnect::api()->oauth->clientCredentials()->accessToken);

$client->usage->get($organizationId, '2026-09');          // accountCount is a decimal string (prorated)
$client->integrationAccount->all();                       // every account linked to your application
$client->integration->delete($organizationId);            // revoke, even without a valid refresh token

try {
    $ponto->account->get($accountId);
} catch (PontoConnectException $exception) {
    $exception->status;        // 404
    $exception->errorCodes();  // the `code` of each error in the response
    $exception->errors;        // [['code' => ..., 'detail' => ..., 'meta' => [...]]]
    $exception->requestId;     // ibanity-request-id header, quote it to Ponto support
}
bash
php artisan vendor:publish --tag=ponto-connect-config

config/ponto-connect.php            # Configuration file
src/
  Api/
    PontoConnectApiClient.php       # Saloon connector: mTLS, auth, error mapping, resources
    Requests/                       # One Saloon request per endpoint, grouped per resource
    Resources/                      # Fluent resources returning DTOs and pages
  Data/                             # Readonly DTOs with fromArray()/toArray(), Page
  Enums/                            # Environment, Scope, Language, SynchronizationSubtype, ...
  Exceptions/                       # PontoConnectException, InvalidGrantException, webhook exceptions
  Facades/PontoConnect.php
  Support/                          # JsonApiResource, Decimal, DateParser, Pkce
  Webhooks/                         # WebhookVerifier, WebhookEvent
  Configuration.php                 # Immutable application settings
  PontoConnectManager.php
  PontoConnectServiceProvider.php