laratables/monta-partner-api

Laravel SDK for the Monta Partner API — authentication, token caching, and a fluent HTTP client.

Maintainers

Package info

github.com/laratables/monta-partner-api

Homepage

pkg:composer/laratables/monta-partner-api

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-04-22 13:06 UTC

This package is auto-updated.

Last update: 2026-04-22 13:17:25 UTC


README

A Laravel 11/12/13 SDK for the Monta Partner API. Handles OAuth token exchange, automatic caching & refresh, and exposes a clean fluent client for every HTTP verb.

Installation

composer require laratables/monta-partner-api

The service provider and Monta facade are auto-discovered via Laravel's package discovery. No manual registration needed.

Publish the config (optional):

php artisan vendor:publish --tag=monta-config

Configuration

Add to your .env:

MONTA_CLIENT_ID=your-client-id
MONTA_CLIENT_SECRET=your-client-secret

# Optional — these are the defaults:
MONTA_BASE_URL=https://api.monta.com
MONTA_API_VERSION=v2024-01-18
MONTA_CACHE_STORE=default      # any Laravel cache store
MONTA_HTTP_TIMEOUT=30
MONTA_HTTP_CONNECT_TIMEOUT=10

Usage

Dependency Injection (recommended)

use Monta\PartnerApi\Contracts\MontaClientInterface;

class ChargeController extends Controller
{
    public function __construct(private MontaClientInterface $monta) {}

    public function index(): JsonResponse
    {
        $data = $this->monta->get('/charge-points', ['pageSize' => 25])->json();
        return response()->json($data);
    }

    public function start(int $id): JsonResponse
    {
        $result = $this->monta->post("/charge-points/{$id}/start")->json();
        return response()->json($result);
    }
}

Facade

use Monta\PartnerApi\Facades\Monta;

$chargePoints = Monta::get('/charge-points', ['pageSize' => 50])->json();
$charge       = Monta::post('/charges', ['chargePointId' => 123])->json();
$updated      = Monta::patch('/charge-points/456', ['name' => 'Bay 1'])->json();
Monta::delete('/webhooks/789');

Accessing any Monta API endpoint

The client works with any endpoint from the Monta API docs — just pass the path and any parameters:

// Charges
$charges = $this->monta->get('/charges', ['pageSize' => 25, 'page' => 1])->json();
$charge  = $this->monta->post('/charges', ['chargePointId' => 123])->json();

// Teams
$teams = $this->monta->get('/teams')->json();
$team  = $this->monta->get('/teams/456')->json();

// Webhooks
$webhook = $this->monta->post('/webhooks', [
    'url'    => 'https://yourapp.com/webhooks/monta',
    'events' => ['charge.started', 'charge.stopped'],
])->json();
$this->monta->delete('/webhooks/789');

// Wallets
$wallet = $this->monta->get('/wallets/123')->json();

// Any other endpoint — same pattern
$this->monta->patch('/charge-points/456', ['name' => 'Bay 1']);

Working with responses

Every method returns a standard Laravel Illuminate\Http\Client\Response object:

$response = $this->monta->get('/charges');

$response->json();            // full decoded array
$response->json('data');      // single key from the response
$response->json('data.0.id'); // nested key using dot notation
$response->collect('data');   // returns a Laravel Collection
$response->status();          // HTTP status code e.g. 200
$response->successful();      // true if 2xx

Domain resource classes

Copy ChargePointsResource as a template for each API domain (Charges, Teams, Wallets, Webhooks…):

use Monta\PartnerApi\Http\Resources\ChargePointsResource;

// Register in a service provider:
$this->app->bind(ChargePointsResource::class, fn($app) =>
    new ChargePointsResource($app->make(MontaClientInterface::class))
);

// Use in a controller:
public function __construct(private ChargePointsResource $chargePoints) {}

public function index(): JsonResponse
{
    return response()->json($this->chargePoints->list(['pageSize' => 50]));
}

Error Handling

use Monta\PartnerApi\Exceptions\MontaApiException;
use Monta\PartnerApi\Exceptions\MontaAuthenticationException;

try {
    $result = $this->monta->post('/charges', $payload)->json();
} catch (MontaAuthenticationException $e) {
    // Bad credentials, or the API returned 401
    // The cached token is automatically cleared; the next request will re-authenticate
    Log::critical('Monta auth failed', ['error' => $e->getMessage()]);
} catch (MontaApiException $e) {
    // Any other non-2xx response
    Log::error('Monta API error', [
        'status' => $e->getStatusCode(),
        'body'   => $e->getResponse()->json(),
    ]);
}

Token Caching

Access tokens are cached in the Laravel cache store defined by MONTA_CACHE_STORE. They are proactively refreshed 30 seconds before expiry to avoid clock-skew issues. A 401 response automatically evicts the cached token so the next call re-authenticates transparently.

Testing

Running the test suite

composer test
# or directly:
./vendor/bin/phpunit

Mocking in your application tests

Because everything is bound against MontaClientInterface, swapping in a mock is straightforward:

use Monta\PartnerApi\Contracts\MontaClientInterface;

// Using Laravel's built-in mock helper (Mockery under the hood):
$this->mock(MontaClientInterface::class, function ($mock) {
    $mock->shouldReceive('get')
         ->with('/charge-points', \Mockery::any())
         ->andReturn(new \Illuminate\Http\Client\Response(
             new \GuzzleHttp\Psr7\Response(200, [], json_encode(['data' => []]))
         ));
});

// Or use Http::fake() to intercept at the HTTP layer:
Http::fake([
    'https://api.monta.com/auth/token'    => Http::response(['accessToken' => 'tok', 'expiresIn' => 3600]),
    'https://api.monta.com/charge-points' => Http::response(['data' => []]),
]);

Package Structure

src/
├── Contracts/
│   └── MontaClientInterface.php      Type-hint this in your code
├── Exceptions/
│   ├── MontaApiException.php         Non-2xx API responses
│   └── MontaAuthenticationException.php  Auth / token failures
├── Facades/
│   └── Monta.php                     Monta:: facade
├── Http/
│   ├── MontaClient.php               Core client (auth + all verbs)
│   └── Resources/
│       └── ChargePointsResource.php  Example domain resource — copy this pattern
├── Support/
│   └── MontaToken.php                Token value object with expiry
└── MontaServiceProvider.php          Auto-discovered service provider

config/
└── monta.php

tests/
├── TestCase.php                      Orchestra Testbench base
├── Unit/
│   ├── MontaTokenTest.php            Token parsing & expiry logic
│   ├── ExceptionsTest.php            Exception message / code derivation
│   ├── MontaClientAuthTest.php       Token fetch, caching, refresh
│   ├── MontaClientHttpTest.php       HTTP verbs, headers, error handling
│   └── ChargePointsResourceTest.php  Resource method → client delegation
└── Feature/
    ├── AuthenticationFlowTest.php    Full auth + API call flows
    └── ServiceProviderTest.php       DI bindings, singleton, facade, config