Skip to main content
Inly Core provides production-ready SDKs for integrating with popular third-party services. All SDKs are built using Saloon, a modern PHP HTTP client that provides a clean, Laravel-style API for consuming external APIs.

Available SDKs

Brevo

Email marketing, transactional emails, and SMS

Dropbox

File storage, sharing, and management

HubSpot

CRM, marketing automation, and contact management

Harvest

Time tracking and project management
Additional SDKs including Business Central, Fortnox, and Notion are available in the codebase. Documentation coming soon.

Architecture

All SDKs follow a consistent, layered architecture pattern designed for maintainability, performance, and ease of use.

Architecture Flow

Core Components

Service Class

Main Entry PointThe primary interface for SDK interactions. Uses the WithResources trait to provide organized access to all API functionality.
$brevo = new Brevo();
$brevo->contacts()->list();

Connector

HTTP ClientHandles HTTP connections, authentication, and request/response lifecycle using Saloon. Manages timeouts, retries, and error handling.
class BrevoConnector extends Connector
{
    use AcceptsJson;
    use AlwaysThrowOnErrors;
}

Resources

API OrganizationGroup related API methods into logical units (contacts, lists, emails). Keeps the service class clean and methods discoverable.
$brevo->contacts()->create();
$brevo->lists()->get($id);
$brevo->emails()->send();

Requests

Endpoint DefinitionsDefine individual API endpoints with parameters, query strings, and body data. Implement Paginatable for automatic pagination.
class GetContactsRequest extends Request
{
    protected Method $method = Method::GET;
}

Raw JSON

PerformanceReturns direct JSON responses from the API without transformation overhead. Maximum performance with minimal processing.
$response = $connector->send($request);
return $response->json();

Collections

Data HandlingLaravel Collections wrapping raw arrays. Provides powerful data manipulation methods while maintaining performance.
$contacts = collect($rawData);
$filtered = $contacts->filter(...);

Architecture Layers

1

Application Layer

Your Laravel application interacts with the Service Class using dependency injection or direct instantiation. The service class provides a clean, fluent API for all SDK operations.
2

Resource Layer

Resource Classes organize related API methods into logical groups (contacts, lists, emails). This prevents the main service class from becoming bloated and improves discoverability.
3

Transport Layer

The Connector handles all HTTP communication through Saloon, managing authentication, timeouts, retries, and error handling automatically.
4

Request Layer

Request Classes define individual API endpoints with their specific parameters, headers, and body data. They implement pagination interfaces where applicable.
5

Response Layer

Raw JSON responses are returned directly from the API for maximum performance, wrapped in Laravel Collections when returning multiple items.

Common Patterns

Initialization

All SDKs follow the same initialization pattern:
use Inly\Core\Connectors\Brevo\Brevo;

// Auto-load from config
$service = new Brevo();

// Or with explicit credentials
$service = new Brevo('api-key');

// Or set later
$service->setApiKey('api-key');

// Check configuration
if ($service->isConfigured()) {
    // Ready to use
}

Resource-Based API

SDKs organize functionality into logical resources:
// Contacts resource
$contacts = $service->contacts()->list();
$contact = $service->contacts()->get('id');
$service->contacts()->create([...]);

// Lists resource
$lists = $service->lists()->list();
$list = $service->lists()->get(123);

// Emails resource
$service->emails()->send([...]);

Return Types

All SDK methods follow consistent return types: | Method Pattern | Return Type | Description | | -------------- | ------------ | --------------------------------------- | ------------------------------------- | | list() | Collection | Returns all items as Laravel Collection | | get($id) | array | Returns single item as array | | create() | array | Returns created item data | | update() | void | array | Updates item, may return updated data | | delete() | void | Deletes item | | paginate() | Paginator | Returns paginator for manual control |

Pagination

SDKs handle pagination automatically in list() methods:
// Automatic pagination - fetches all pages
$allContacts = $service->contacts()->list();

// Manual pagination control
$paginator = $service->contacts()->paginate();

foreach ($paginator as $response) {
    $items = $response->json('data', []);
    // Process page...
}

Error Handling

All SDKs use Saloon’s AlwaysThrowOnErrors trait for consistent error handling:
use Saloon\Exceptions\Request\RequestException;

try {
    $result = $service->contacts()->get('nonexistent-id');
} catch (RequestException $e) {
    // Handle API errors (4xx, 5xx)
    $statusCode = $e->getResponse()->status();
    $errorMessage = $e->getResponse()->json('message');

    if ($statusCode === 404) {
        // Not found
    } elseif ($statusCode === 429) {
        // Rate limit exceeded
    } else {
        // Other API error
    }
} catch (Exception $e) {
    // Handle other errors
}

Configuration

Each SDK has a corresponding configuration file in config/{service}.php:
<?php

return [
    'api_key' => env('SERVICE_API_KEY'),
    'base_url' => env('SERVICE_BASE_URL', 'https://api.service.com/v1'),
    'timeout' => env('SERVICE_TIMEOUT', 60),
];

Environment Variables

Add credentials to your .env file:
BREVO_API_KEY=your-key-here
BREVO_BASE_URL=https://api.brevo.com/v3
BREVO_TIMEOUT=60
Never commit API keys to version control. Always use environment variables.

Laravel Integration

Service Container Registration

For optimal Laravel integration, register SDKs as singletons in your AppServiceProvider. The Inly Core package provides a stub file with examples for all available SDKs. Reference file: vendor/inly/core/stubs/laravel/app/Providers/AppServiceProvider.php Copy the relevant SDK registration from the stub to your application’s app/Providers/AppServiceProvider.php:
use Inly\Core\Connectors\Brevo\Brevo;
use Inly\Core\Connectors\HubSpot\HubSpot;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Brevo SDK
        $this->app->singleton(Brevo::class, function ($app) {
            return new Brevo(
                apiKey: config('brevo.api_key')
            );
        });

        // HubSpot SDK
        $this->app->singleton(HubSpot::class, function ($app) {
            return new HubSpot(
                accessToken: config('hubspot.access_token')
            );
        });

        // Add more SDKs as needed...
    }
}
The stub file contains commented examples for all available SDKs including Brevo, HubSpot, Business Central, Harvest, Notion, Fortnox, and more. Simply uncomment the ones you need.

Dependency Injection

Once registered as a singleton, inject SDKs directly into your classes:
use Inly\Core\Connectors\Brevo\Brevo;

class NewsletterController extends Controller
{
    public function __construct(
        protected Brevo $brevo
    ) {}

    public function subscribe(Request $request)
    {
        $this->brevo->contacts()->create(
            email: $request->email,
            listIds: [config('brevo.newsletter_list_id')]
        );
    }
}

Benefits of Singleton Registration

  1. Single Instance - One configured instance shared across your application
  2. Auto-Configuration - Automatically loads credentials from config
  3. Type Hinting - Full IDE support with dependency injection
  4. Testability - Easy to mock in tests
  5. Performance - No repeated instantiation or configuration

Testing

Each SDK includes a test command for verifying configuration:
# Test Brevo SDK
php artisan test:brevo

# Test other SDKs
php artisan test:{service}
These commands will:
  • ✅ Verify credentials are configured
  • ✅ Test API connectivity
  • ✅ Display sample data from your account

Performance

Our SDKs are optimized for performance:
  • Raw JSON responses: No unnecessary data transformation overhead
  • Automatic pagination: Efficiently fetches all pages
  • Connection pooling: Reuses HTTP connections
  • Configurable timeouts: Prevent hanging requests
  • Rate limit handling: Automatic retry with backoff (where supported)

Building Your Own SDK

Want to integrate a new service? Check out our Saloon SDK Implementation Guide for step-by-step instructions on building production-ready SDKs following our patterns.

Reference Implementations

Study these existing SDKs as templates for your implementation:

Brevo SDK

Best for: Simple token-based authenticationSimple API key authentication with organized resources for contacts, lists, and emails.

Dropbox SDK

Best for: OAuth 2.0 with token refreshFull OAuth 2.0 flow with automatic token refresh and cursor-based pagination.

HubSpot SDK

Best for: Complex search and filteringFluent search filter API with type-safe operators and complex CRM operations.

Harvest SDK

Best for: Multi-credential authenticationRequires both access token and account ID with comprehensive resource management.

Quick Start Template

<?php

namespace Inly\Core\Connectors\YourService;

use Exception;

class YourService
{
    use WithResources;

    protected YourServiceConnector $connector;

    public function __construct(
        protected ?string $apiKey = null
    ) {
        $this->connector = new YourServiceConnector($this->apiKey);
    }

    public function setApiKey(string $apiKey): self
    {
        $this->apiKey = $apiKey;
        $this->connector->setApiKey($apiKey);
        return $this;
    }

    public function isConfigured(): bool
    {
        return !empty($this->apiKey);
    }

    public function connector(): YourServiceConnector
    {
        return $this->connector;
    }
}

Best Practices

1. Always Check Configuration

if (!$service->isConfigured()) {
    throw new Exception('Service not configured');
}

2. Use Try-Catch for API Calls

try {
    $result = $service->resource()->action();
} catch (RequestException $e) {
    Log::error('API error', ['message' => $e->getMessage()]);
    throw $e;
}

3. Batch Operations Efficiently

// Good: Process in chunks with rate limiting
foreach ($users->chunk(100) as $chunk) {
    foreach ($chunk as $user) {
        $service->contacts()->create([...]);
    }
    sleep(1); // Rate limit protection
}

4. Cache Responses When Appropriate

$account = Cache::remember('brevo.account', 3600, function () use ($brevo) {
    return $brevo->account()->get();
});

5. Use Resource Methods, Not Raw Requests

// Good
$contacts = $brevo->contacts()->list();

// Avoid
$response = $brevo->connector()->send(new GetContactsRequest());

Rate Limiting

Each third-party service has different rate limits. Check the individual SDK documentation for specific limits and how to handle them.

General Guidelines

  • Process large datasets in chunks
  • Add delays between batches
  • Handle 429 Too Many Requests errors gracefully
  • Use queued jobs for bulk operations
  • Monitor your API usage in the service dashboard

Support

For SDK-related questions:
  1. Check the specific SDK documentation
  2. Review the Saloon SDK Implementation Guide
  3. Check the third-party service’s API documentation
  4. Contact the Inly Core team

Additional Resources