tigusigalpa / socialkit-php
A modern, framework-agnostic PHP SDK for the SocialKit API, with first-class Laravel 10, 11, 12 & 13 integration.
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.4
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- illuminate/support: ^10.0 || ^11.0 || ^12.0 || ^13.0
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0 || ^11.0
- phpunit/phpunit: ^10.5 || ^11.0 || ^12.0
Suggests
- illuminate/support: Required to use the Laravel service provider and facade (^10.0 || ^11.0 || ^12.0 || ^13.0).
Provides
None
Conflicts
None
Replaces
None
README
Scrape social media content, transcripts, and stats from YouTube, TikTok, Instagram, Facebook, Twitter/X, and LinkedIn — right where your PHP code lives.
tigusigalpa/socialkit-php is a modern, framework-agnostic PHP SDK for the
SocialKit API. It wraps every endpoint behind a
strongly-typed interface with immutable DTOs, secure key handling, automatic
error mapping, and first-class Laravel 10, 11, 12 & 13 integration.
$transcript = SocialKit::youtube()->transcript(new TranscriptRequest( url: 'https://youtube.com/watch?v=dQw4w9WgXcQ', )); echo $transcript->data->transcript;
Table of Contents
- Requirements
- Installation
- Configuration
- Quick Start
- Service Map
- Method Usage
- Custom Summary Response
- Pagination
- Transient Errors & Retries
- Credits Metadata
- V2 Async Jobs
- Laravel Integration
- Testing
- Compatibility
- Security
- Endpoint Documentation
- Contributing
- License
Requirements
| Requirement | Version |
|---|---|
| PHP | 8.1, 8.2, 8.3, or 8.4 |
| PSR-18 HTTP client | Guzzle ^7.4 ships by default |
| Laravel (optional) | 10.x, 11.x, 12.x, or 13.x |
| SocialKit access key | Get one from your SocialKit dashboard |
Installation
composer require tigusigalpa/socialkit-php
Configuration
Standalone (framework-agnostic)
use Tigusigalpa\SocialKit\SocialKitClient; $client = SocialKitClient::make('YOUR_ACCESS_KEY');
With custom options:
use Tigusigalpa\SocialKit\SocialKitClient; use Tigusigalpa\SocialKit\SocialKitConfig; $config = new SocialKitConfig( accessKey: 'YOUR_ACCESS_KEY', baseUrl: 'https://api.socialkit.dev', timeout: 30.0, retryAttempts: 3, retryDelay: 1.0, ); $client = new SocialKitClient($config);
From environment variables:
$client = new SocialKitClient(SocialKitConfig::fromEnv());
Laravel
Publish the config:
php artisan vendor:publish --tag=socialkit-config
Add to .env:
SOCIALKIT_ACCESS_KEY=your-access-key SOCIALKIT_BASE_URL=https://api.socialkit.dev SOCIALKIT_TIMEOUT=30 SOCIALKIT_RETRY_ATTEMPTS=0 SOCIALKIT_RETRY_DELAY=1
Configuration Reference
Key (config/socialkit.php) |
Env variable | Default | Description |
|---|---|---|---|
access_key |
SOCIALKIT_ACCESS_KEY |
'' |
Sent as x-access-key header. |
base_url |
SOCIALKIT_BASE_URL |
https://api.socialkit.dev |
API root URL. |
timeout |
SOCIALKIT_TIMEOUT |
30 |
Per-request timeout in seconds. |
retry_attempts |
SOCIALKIT_RETRY_ATTEMPTS |
0 |
Auto retries on 429/5xx (0 = no retries). |
retry_delay |
SOCIALKIT_RETRY_DELAY |
1.0 |
Base backoff delay in seconds. |
key_in_query |
SOCIALKIT_KEY_IN_QUERY |
false |
Compatibility: also send key as query/body param. |
user_agent |
— | SocialKit-PHP-SDK/1.0.0 |
User-Agent header. |
Quick Start
use Tigusigalpa\SocialKit\SocialKitClient; use Tigusigalpa\SocialKit\Dto\TranscriptRequest; use Tigusigalpa\SocialKit\Dto\StatsRequest; use Tigusigalpa\SocialKit\Dto\SummaryRequest; $client = SocialKitClient::make('YOUR_ACCESS_KEY'); // 1. Check API status (no key needed) $status = $client->status()->status(); echo $status->data->overall; // "green" // 2. Get YouTube video transcript $transcript = $client->youtube()->transcript(new TranscriptRequest( url: 'https://youtube.com/watch?v=dQw4w9WgXcQ', )); // 3. Get video stats $stats = $client->youtube()->stats(new StatsRequest( url: 'https://youtube.com/watch?v=dQw4w9WgXcQ', )); echo $stats->data->views; // 1000000 // 4. AI summary $summary = $client->youtube()->summarize(new SummaryRequest( url: 'https://youtube.com/watch?v=dQw4w9WgXct', )); echo $summary->data->summary; // 5. Check credits $credits = $client->status()->credits(); echo $credits->data->totalRemaining;
Service Map
| Method | Service | Endpoints |
|---|---|---|
$client->status() |
ServiceService | status, credits |
$client->youtube() |
YouTubeService | transcript, summarize, stats, comments, channelStats, search, videos, download, bulk* |
$client->tiktok() |
TikTokService | transcript, summarize, stats, comments, channelStats, channelVideos, search, hashtagSearch, download, bulk* |
$client->instagram() |
InstagramService | transcript, summarize, stats, comments, channelStats, channelPosts, channelReels, reelsSearch, download, bulk* |
$client->facebook() |
FacebookService | transcript, summarize, stats, comments, channelStats |
$client->twitter() |
TwitterService | profile, tweets, tweet, thread, transcript |
$client->linkedin() |
LinkedInService | profile, company, companyPosts, post, transcript |
$client->video() |
VideoService | transcript, summarize (direct file URLs) |
$client->downloads() |
DownloadsService | start, get, wait (v2 async) |
Method Usage
YouTube
use Tigusigalpa\SocialKit\Dto\TranscriptRequest; use Tigusigalpa\SocialKit\Dto\SummaryRequest; use Tigusigalpa\SocialKit\Dto\StatsRequest; use Tigusigalpa\SocialKit\Dto\CommentsRequest; use Tigusigalpa\SocialKit\Dto\ChannelStatsRequest; use Tigusigalpa\SocialKit\Dto\SearchRequest; use Tigusigalpa\SocialKit\Dto\VideosRequest; use Tigusigalpa\SocialKit\Dto\DownloadRequest; // Transcript $client->youtube()->transcript(new TranscriptRequest(url: '...')); // AI Summary (with custom prompt) $client->youtube()->summarize(new SummaryRequest( url: '...', customPrompt: 'Focus on technical details', )); // Stats $client->youtube()->stats(new StatsRequest(url: '...')); // Comments (limit max 100, sortBy: top|new) $client->youtube()->comments(new CommentsRequest( url: '...', limit: 50, sortBy: 'top', )); // Channel stats $client->youtube()->channelStats(new ChannelStatsRequest(url: '...')); // Search (sortBy: relevance|date|views|rating, uploadDate: hour|today|week|month|year, type: video|shorts) $client->youtube()->search(new SearchRequest( query: 'PHP tutorial', sortBy: 'relevance', uploadDate: 'month', type: 'video', )); // Videos (fullDetails, capped at 30) $client->youtube()->videos(new VideosRequest( url: '...', limit: 30, fullDetails: true, )); // Download (max 10MB, URL expires 1h) $client->youtube()->download(new DownloadRequest( url: '...', format: 'mp4', quality: '720p', ));
TikTok
use Tigusigalpa\SocialKit\Dto\ChannelVideosRequest; use Tigusigalpa\SocialKit\Dto\HashtagSearchRequest; // Channel videos (default 30, max 100, cursor + hasMore) $client->tiktok()->channelVideos(new ChannelVideosRequest( url: 'https://tiktok.com/@user', limit: 30, )); // Hashtag search (without #, max 100) $client->tiktok()->hashtagSearch(new HashtagSearchRequest( hashtag: 'fyp', limit: 50, )); // Download (max 30MB, URL expires 1h) $client->tiktok()->download(new DownloadRequest(url: '...'));
use Tigusigalpa\SocialKit\Dto\ChannelPostsRequest; use Tigusigalpa\SocialKit\Dto\ChannelReelsRequest; use Tigusigalpa\SocialKit\Dto\ReelsSearchRequest; // Channel posts (cursor + hasMore, max 100, 1 credit/20 results) $client->instagram()->channelPosts(new ChannelPostsRequest( url: 'https://instagram.com/test', limit: 20, )); // Channel reels (cursor + hasMore, can take 60s) $client->instagram()->channelReels(new ChannelReelsRequest( url: 'https://instagram.com/test', )); // Reels search (page MUST be 1, hasMore always false) $client->instagram()->reelsSearch(new ReelsSearchRequest( query: 'travel', ));
// Stats (includes reactions[]) $stats = $client->facebook()->stats(new StatsRequest(url: '...')); foreach ($stats->data->reactions as $reaction) { echo $reaction->name . ': ' . $reaction->count; } // No sync download, no bulk endpoints
Twitter/X
use Tigusigalpa\SocialKit\Dto\ProfileRequest; use Tigusigalpa\SocialKit\Dto\TweetsRequest; use Tigusigalpa\SocialKit\Dto\TweetRequest; use Tigusigalpa\SocialKit\Dto\ThreadRequest; // Profile $client->twitter()->profile(new ProfileRequest(url: 'https://twitter.com/elonmusk')); // Tweets (nextCursor nullable) $tweets = $client->twitter()->tweets(new TweetsRequest( url: 'https://twitter.com/elonmusk', limit: 10, )); // Use $tweets->data->nextCursor for next page // Single tweet $client->twitter()->tweet(new TweetRequest(url: '...')); // Thread $client->twitter()->thread(new ThreadRequest(url: '...'));
use Tigusigalpa\SocialKit\Dto\CompanyPostsRequest; use Tigusigalpa\SocialKit\Dto\PostRequest; // Profile (with recentArticles[]) $client->linkedin()->profile(new ProfileRequest(url: '...')); // Company $client->linkedin()->company(new CompanyRequest(url: '...')); // Company posts (max 50) $client->linkedin()->companyPosts(new CompanyPostsRequest( url: '...', limit: 20, )); // Single post $client->linkedin()->post(new PostRequest(url: '...'));
Video (Direct File URLs)
use Tigusigalpa\SocialKit\Dto\VideoTranscriptRequest; use Tigusigalpa\SocialKit\Dto\VideoSummaryRequest; // 5 credits per started minute $client->video()->transcript(new VideoTranscriptRequest( url: 'https://example.com/video.mp4', )); $client->video()->summarize(new VideoSummaryRequest( url: 'https://example.com/video.mp4', ));
Downloads (v2 Async)
use Tigusigalpa\SocialKit\Dto\V2DownloadRequest; use Tigusigalpa\SocialKit\Dto\WaitOptions; // Start a download job $job = $client->downloads()->start(new V2DownloadRequest( url: 'https://youtube.com/watch?v=test', platform: 'youtube', format: 'mp4', quality: '720p', )); // Check status (ALWAYS GET) $job = $client->downloads()->get($job->data->jobId); // Wait for completion (caller-controlled polling) $job = $client->downloads()->wait($job->data->jobId, new WaitOptions( interval: 2.0, timeout: 120.0, )); if ($job->data->isReady()) { echo $job->data->downloadUrl; }
Custom Summary Response
You can provide a custom JSON schema for the summary response:
$client->youtube()->summarize(new SummaryRequest( url: '...', customResponse: '{"sentiment": "string", "confidence": "number"}', )); // Custom fields are available in $response->data->extra echo $response->data->extra['sentiment'];
Pagination
List endpoints use opaque cursor tokens. Pass the cursor from one response to the next request:
$response = $client->youtube()->comments(new CommentsRequest( url: '...', limit: 50, )); if ($response->data->hasMore) { $next = $client->youtube()->comments(new CommentsRequest( url: '...', limit: 50, cursor: $response->data->cursor, )); }
Transient Errors & Retries
By default, the SDK does not retry. To enable conservative retries:
$config = new SocialKitConfig( accessKey: '...', retryAttempts: 3, retryDelay: 1.0, );
- 400, 401, 403, 404 are never retried.
- 429 and 5xx are retried with exponential backoff + jitter.
- The
Retry-Afterheader is always honored. - POST retries require explicit opt-in (
retryAttempts > 0).
Credits Metadata
Every response includes credit and rate-limit metadata:
$response = $client->youtube()->stats(new StatsRequest(url: '...')); echo $response->meta->creditsUsed; echo $response->meta->creditsRemaining; echo $response->meta->rateLimitRemaining;
V2 Async Jobs
V2 download jobs have four states: queued → processing → ready | failed.
The wait() method polls with caller-controlled interval and backoff, respects
timeouts, and never polls infinitely. No auto-resubmit on failure.
Laravel Integration
Facade
use Tigusigalpa\SocialKit\Laravel\Facades\SocialKit; $status = SocialKit::status()->status(); $transcript = SocialKit::youtube()->transcript(new TranscriptRequest(url: '...'));
Dependency Injection
use Tigusigalpa\SocialKit\SocialKitClientInterface; class VideoController { public function __construct( private readonly SocialKitClientInterface $socialkit, ) {} public function show() { return $this->socialkit->youtube()->stats(new StatsRequest(url: '...')); } }
Fake (Testing)
use Tigusigalpa\SocialKit\Laravel\Facades\SocialKit; $fake = SocialKit::fake(); $fake->queueData(['overall' => 'green', 'generated_at' => '2026-01-01']); $response = SocialKit::status()->status(); $fake->assertRequested('/status');
Testing
composer install
composer test
All tests use Guzzle's MockHandler — no real API calls, no network required.
Compatibility
- Authentication:
x-access-keyheader on every authenticated request. SetkeyInQuery: trueto additionally sendaccess_keyas a query/body parameter for compatibility mode. - Request strategy: Protected scrape/read operations default to POST with JSON body (keeps key out of URL). GET is available via explicit method override.
- Always GET:
status(),credits(),downloads.get().
Security
- The access key is never placed in URLs or query strings by default.
- All debug/error output replaces the key with
[REDACTED]. - The key is never logged, serialized, or exposed in exceptions, DTOs, or tests.
- HTTPS is used by default.
See SECURITY.md for the full policy.
Endpoint Documentation
Service & Async Downloads
- Status API —
GET /status - Credits API —
GET /credits - Async Download API v2 —
GET, POST /v2/{platform}/download,GET /v2/downloads/{jobId}
YouTube
- Transcript —
GET, POST /youtube/transcript - Summary —
GET, POST /youtube/summarize - Stats —
GET, POST /youtube/stats - Comments —
GET, POST /youtube/comments - Channel Stats —
GET, POST /youtube/channel-stats - Search —
GET, POST /youtube/search - Videos —
GET, POST /youtube/videos - Download —
GET, POST /youtube/download - Bulk:
POST /youtube/transcript/bulk,POST /youtube/comments/bulk,POST /youtube/stats/bulk,POST /youtube/summarize/bulk— OpenAPI, API Reference
TikTok
- Transcript —
GET, POST /tiktok/transcript - Summary —
GET, POST /tiktok/summarize - Stats —
GET, POST /tiktok/stats - Comments —
GET, POST /tiktok/comments - Channel Stats —
GET, POST /tiktok/channel-stats - Channel Videos —
GET, POST /tiktok/channel-videos - Search —
GET, POST /tiktok/search - Hashtag Search —
GET, POST /tiktok/hashtag-search - Download —
GET, POST /tiktok/download - Bulk:
POST /tiktok/transcript/bulk,POST /tiktok/comments/bulk,POST /tiktok/stats/bulk,POST /tiktok/channel-stats/bulk,POST /tiktok/summarize/bulk— OpenAPI, API Reference
- Transcript —
GET, POST /instagram/transcript - Summary —
GET, POST /instagram/summarize - Stats —
GET, POST /instagram/stats - Comments —
GET, POST /instagram/comments - Channel Stats —
GET, POST /instagram/channel-stats - Channel Posts —
GET, POST /instagram/channel-posts - Channel Reels —
GET, POST /instagram/channel-reels - Reels Search —
GET, POST /instagram/reels-search - Download —
GET, POST /instagram/download - Bulk:
POST /instagram/transcript/bulk,POST /instagram/stats/bulk,POST /instagram/channel-stats/bulk,POST /instagram/summarize/bulk— OpenAPI, API Reference
- Transcript —
GET, POST /facebook/transcript - Summary —
GET, POST /facebook/summarize - Stats —
GET, POST /facebook/stats - Comments —
GET, POST /facebook/comments - Channel Stats —
GET, POST /facebook/channel-stats
Twitter/X
- Profile —
GET, POST /twitter/profile - Tweets —
GET, POST /twitter/tweets - Tweet —
GET, POST /twitter/tweet - Thread —
GET, POST /twitter/thread - Transcript —
GET, POST /twitter/transcript
- Profile —
GET, POST /linkedin/profile - Company —
GET, POST /linkedin/company - Company Posts —
GET, POST /linkedin/company-posts - Post —
GET, POST /linkedin/post - Transcript —
GET, POST /linkedin/transcript
Direct Video
- Transcript —
GET, POST /video/transcript - Summary —
GET, POST /video/summarize
Guides
Contributing
See CONTRIBUTING.md.
License
Released under the MIT License.
Credits
Built and maintained by Igor Sazonov — sovletig@gmail.com.