PHPackages                             yusufgenc/foreplay-laravel-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. yusufgenc/foreplay-laravel-sdk

ActiveLibrary[API Development](/categories/api)

yusufgenc/foreplay-laravel-sdk
==============================

Unofficial Laravel SDK for the Foreplay Data API (public.api.foreplay.co). Typed DTOs, cursor pagination, exception mapping, and a sandbox mode with pre-recorded fixtures.

v0.1.1(2mo ago)05MITPHP ^8.3

Since May 14Compare

[ Source](https://github.com/yusufgenc34/foreplay-laravel-sdk)[ Packagist](https://packagist.org/packages/yusufgenc/foreplay-laravel-sdk)[ Docs](https://github.com/yusufgenc34/foreplay-laravel-sdk)[ RSS](/packages/yusufgenc-foreplay-laravel-sdk/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (10)Versions (3)Used By (0)

Foreplay Laravel SDK
====================

[](#foreplay-laravel-sdk)

Unofficial Laravel SDK for the [Foreplay](https://foreplay.co) Data API (`public.api.foreplay.co`). Wraps every read-only GET endpoint with typed responses, exception mapping, cursor-based pagination helpers, and a sandbox mode that replays pre-recorded fixtures so you can explore the surface without spending credits.

> This is a third-party, community-maintained SDK. It is not affiliated with, endorsed by, or supported by Foreplay Inc.

Requirements
------------

[](#requirements)

- PHP 8.3 or newer
- Laravel 13.x
- A Foreplay Data API key (generated from the Foreplay dashboard)

Installation
------------

[](#installation)

```
composer require yusufgenc/foreplay-laravel-sdk
```

The service provider and the `Foreplay` facade are auto-discovered. Publish the config if you need to override the defaults:

```
php artisan vendor:publish --tag=foreplay-config
```

Configuration
-------------

[](#configuration)

Add your API key to `.env`. The Foreplay API accepts the raw key as the `Authorization` header (no `Bearer` prefix), which the SDK handles for you.

```
FOREPLAY_API_KEY=your_key_here
```

Optional settings (defaults shown):

```
FOREPLAY_BASE_URL=https://public.api.foreplay.co
FOREPLAY_TIMEOUT=30
FOREPLAY_RETRY_TIMES=3
FOREPLAY_RETRY_SLEEP_MS=250
FOREPLAY_RETRY_EXPONENTIAL=true
FOREPLAY_SANDBOX=false
```

Retries are applied to network errors and 5xx responses with exponential backoff. Client errors (4xx) are not retried — they are translated into exceptions immediately.

Quick start
-----------

[](#quick-start)

```
use Foreplay\LaravelSdk\Facades\Foreplay;

$ad = Foreplay::ads()->get('997846782598437');

echo $ad->name;       // "Stadium"
echo $ad->brand_id;   // "s5N67F6UaV5gScE5SN03"
```

The same client is available from the container:

```
$client = app(\Foreplay\LaravelSdk\ForeplayClient::class);
$ad = $client->ads()->get('997846782598437');
```

Resources
---------

[](#resources)

The client exposes one resource per logical group. Methods return either a typed DTO, an array of DTOs, or a `CursorPaginator` for cursor-paginated endpoints.

### Ads

[](#ads)

```
$ad     = Foreplay::ads()->get($adId);                       // AdData
$dupes  = Foreplay::ads()->duplicates($adId);                // AdData[]
$search = Foreplay::ads()->search('nike', $filters);         // CursorPaginator
$brand  = Foreplay::ads()->byBrandIds([$brandId], $filters); // CursorPaginator
$page   = Foreplay::ads()->byPageId($pageId, $filters);      // CursorPaginator
```

### Brands

[](#brands)

```
$byDomain = Foreplay::brands()->byDomain('nike.com');
$results  = Foreplay::brands()->search('nike');
$discover = Foreplay::brands()->discoverByAds($filters);
$rows     = Foreplay::brands()->analytics($brandIdOrPageId, $start, $end);
```

`analytics()` returns one row per day; the API enforces a 30-day maximum window per call.

### Boards

[](#boards)

```
$boards = Foreplay::boards()->all($offset = 0, $limit = 10);
$ads    = Foreplay::boards()->ads($boardId, $filters);  // CursorPaginator
$brands = Foreplay::boards()->brands($boardId, $offset = 0, $limit = 10);
```

### Spyder

[](#spyder)

```
$tracked = Foreplay::spyder()->brands($offset = 0, $limit = 10);
$brand   = Foreplay::spyder()->brand($brandId);
$ads     = Foreplay::spyder()->ads($brandId, $filters);  // CursorPaginator
```

### Swipefile

[](#swipefile)

```
$saved = Foreplay::swipefile()->ads($filters, $offset = 0);
```

### Account

[](#account)

```
$usage = Foreplay::account()->usage();
echo $usage->remaining_credits;
echo $usage->user?->email;
```

Pagination
----------

[](#pagination)

Cursor-paginated endpoints return a `CursorPaginator` that exposes a lazy `Generator`. Pages are fetched on demand, so iteration is memory-safe even across large result sets.

```
foreach (Foreplay::ads()->search('shoes')->cursor() as $ad) {
    // yields every ad across every page
}
```

For bounded results, use `collect($max)`:

```
$first50 = Foreplay::ads()->search('shoes')->collect(50);
```

Endpoints that use offset pagination (`boards.all`, `boards.brands`, `spyder.brands`, `swipefile.ads`) take explicit `$offset` and `$limit`arguments and return a single page per call. The Foreplay API caps `limit`at 10 on those endpoints.

Filtering
---------

[](#filtering)

`AdFiltersData` is the shared filter shape used by every ad-listing endpoint. Dates accept `string`, `DateTimeInterface`, or Carbon and are normalised to `Y-m-d H:i:s` in UTC before being sent. Enum arguments are strictly typed.

```
use Foreplay\LaravelSdk\Data\AdFiltersData;
use Foreplay\LaravelSdk\Enums\DisplayFormat;
use Foreplay\LaravelSdk\Enums\Order;
use Foreplay\LaravelSdk\Enums\PublisherPlatform;

$filters = new AdFiltersData(
    live: true,
    display_format: [DisplayFormat::Video, DisplayFormat::Carousel],
    publisher_platform: [PublisherPlatform::Facebook, PublisherPlatform::Instagram],
    start_date: '2025-01-01',
    end_date: '2025-12-31',
    running_duration_min_days: 30,
    order: Order::LongestRunning,
    limit: 50,
);

$ads = Foreplay::ads()->search('skincare', $filters);
```

All filter fields are nullable; pass only what you care about.

Exception handling
------------------

[](#exception-handling)

Every HTTP failure raises a typed exception that extends `Foreplay\LaravelSdk\Exceptions\ForeplayException`.

StatusException401 / 403`InvalidApiKeyException`404`EndpointNotFoundException`429`RateLimitExceededException`Other 4xx/5xx`ForeplayException````
use Foreplay\LaravelSdk\Exceptions\RateLimitExceededException;

try {
    Foreplay::ads()->search('nike');
} catch (RateLimitExceededException $e) {
    sleep($e->getRetryAfter() ?? 60);
}
```

The original Saloon `Response` is available via `$exception->getResponse()`if you need to inspect headers or the raw body.

Sandbox mode
------------

[](#sandbox-mode)

Sandbox mode answers every request from a pre-recorded JSON fixture shipped with the package. No network call is made and no credits are consumed. Useful during local development, demo recordings, and trial exploration.

Enable it via configuration:

```
FOREPLAY_SANDBOX=true
```

Or instantiate the client directly:

```
use Foreplay\LaravelSdk\ForeplayClient;

$client = ForeplayClient::sandbox();

$ad     = $client->ads()->get('any-id');
$search = $client->ads()->search('nike');
$usage  = $client->account()->usage();
```

The shipped fixtures cover all 17 endpoints. The dataset combines real responses captured against a live account (ads, brands, analytics, usage) with composed playground data for features the public API does not expose for writes (boards, Spyder tracking, swipefile saves).

Testing
-------

[](#testing)

The package includes Pest tests that exercise the connector against Saloon's `MockClient`, covering happy paths, exception mapping, cursor pagination, and filter serialisation.

```
composer install
./vendor/bin/pest
```

Regenerating fixtures
---------------------

[](#regenerating-fixtures)

If you have your own Foreplay API key and want to refresh the sandbox dataset with your account state:

```
FOREPLAY_API_KEY=your_key bash bin/capture-fixtures.sh
python3 bin/build-playground-fixtures.py
```

`capture-fixtures.sh` overwrites fixtures with live responses (PII in `/api/usage` is scrubbed automatically). `build-playground-fixtures.py`composes realistic fixtures from the real captures for any endpoint that came back empty (boards, Spyder, swipefile).

Versioning
----------

[](#versioning)

This package follows semantic versioning. Until the upstream API and this SDK reach `1.0`, minor releases may contain breaking changes; pin with a tilde range (for example `~0.1`) if stability is important.

Issues
------

[](#issues)

Open issues and feature requests at [github.com/yusufgenc34/foreplay-laravel-sdk/issues](https://github.com/yusufgenc34/foreplay-laravel-sdk/issues).

Credits
-------

[](#credits)

- [Saloon](https://github.com/saloonphp/saloon) — HTTP toolkit
- [spatie/laravel-data](https://github.com/spatie/laravel-data) — DTOs
- [Foreplay Inc.](https://foreplay.co) for the underlying data product

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance86

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

2

Last Release

70d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/9165745?v=4)[yusufgenc](/maintainers/yusufgenc)[@yusufgenc](https://github.com/yusufgenc)

---

Tags

laravelsdkadssaloonforeplaycreative-intelligencead-library

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/yusufgenc-foreplay-laravel-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/yusufgenc-foreplay-laravel-sdk/health.svg)](https://phpackages.com/packages/yusufgenc-foreplay-laravel-sdk)
```

###  Alternatives

[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.2k95.4M321](/packages/laravel-horizon)[codebar-ag/laravel-docuware

DocuWare integration with Laravel

1123.7k](/packages/codebar-ag-laravel-docuware)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
