PHP code example of omnisocials / omnisocials-php

1. Go to this page and download the library: Download omnisocials/omnisocials-php 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/ */

    

omnisocials / omnisocials-php example snippets


use OmniSocials\Client;

$client = new Client(); // reads OMNISOCIALS_API_KEY from env
$post = $client->posts->create([
    'content' => 'Hello from the SDK',
    'channels' => ['instagram', 'linkedin'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
]);

$client = new Client(apiKey: 'omsk_live_...');

$client = new Client(
    apiKey: 'omsk_live_...',
    baseUrl: 'https://api.omnisocials.com/v1', // default
    timeout: 30.0,   // per-request timeout in seconds (default 30)
    maxRetries: 2,   // automatic retries on 429 / 5xx / network errors (default 2)
);

$response = $client->posts->create([
    'content' => 'New drop this Friday',
    'channels' => ['instagram', 'facebook', 'linkedin'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'media_urls' => ['https://example.com/teaser.jpg'],
]);
echo $response['data']['id'] . ' ' . $response['data']['status'];

$client->posts->create([
    'content' => [
        'default' => 'New drop this Friday',
        'x' => 'New drop this Friday. RT to spread the word',
    ],
    'channels' => ['instagram', 'x'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
]);

$proposal = $client->posts->create([
    'content' => 'Proposed for Friday morning',
    'channels' => ['instagram', 'linkedin'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'draft' => true,
]);
echo $proposal['data']['status'] . ' ' . $proposal['data']['schedule_at']; // draft, the time is kept

// The human agrees: schedule it at the time it already carries
$client->posts->update($proposal['data']['id'], ['draft' => false]);

$post = $client->posts->create([
    'content' => 'Comment GUIDE and I will send you the link',
    'channels' => ['instagram'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'media_urls' => ['https://example.com/guide-cover.jpg'],
    'comment_dm_automation' => [
        'trigger' => ['keywords' => ['guide'], 'match' => 'word'],
        'actions' => [
            'dm' => ['text' => 'Here is the guide: https://example.com/guide'],
            'public_reply' => ['enabled' => true, 'variations' => ['Sent you a DM!', 'Check your inbox']],
        ],
        'limits' => ['max_sends' => 500],
    ],
]);
$automationId = $post['data']['comment_dm_automation']['id'];

// Later: who was answered, and why someone was skipped
$events = $client->automations->listEvents($automationId, ['outcome' => 'sent']);
print_r($events['counts']); // ['sent' => 12, 'skipped' => 3]
foreach ($events['data'] as $event) {
    echo $event['person']['username'] . ' ' . $event['outcome'] . ' ' . $event['reason_label'] . "\n";
}

$client->posts->createAndPublish([
    'content' => 'Going live right now',
    'channels' => ['x', 'bluesky'],
]);

$client->posts->create([
    'content' => 'Sunrise over the harbor',
    'channels' => ['mastodon', 'bluesky'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'media_urls' => [
        [
            'url' => 'https://example.com/harbor.jpg',
            'alt' => 'A small sailboat crossing a calm harbor at sunrise, sky in deep orange',
        ],
    ],
]);

$client->posts->create([
    'content' => 'Behind the scenes of our summer shoot',
    'channels' => ['instagram', 'youtube', 'x'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'media_urls' => ['https://example.com/bts.mp4'],
    'instagram' => ['share_to_feed' => true],
    'youtube' => ['title' => 'Summer shoot BTS', 'privacy' => 'public'],
    'x' => ['reply_settings' => 'following', 'made_with_ai' => false],
    // Not yet released (coming in 0.10.0): a poll on X (the text is the question); also threads.poll and mastodon.poll:
    // 'x' => ['poll' => ['options' => ['Polls', 'Reports'], 'duration_minutes' => 1440]],
]);

$client->posts->create([
    'content' => 'The new collection is live. Tap the button to shop.',
    'channels' => ['telegram'],
    'scheduled_at' => '2026-11-02T09:00:00Z',
    'media_urls' => ['https://example.com/collection.jpg'],
    'telegram' => [
        'silent' => true,
        'pin' => true,
        'buttons' => [['text' => 'Shop now', 'url' => 'https://example.com/shop']],
        'first_comment' => 'Questions? Reply to this message.',
    ],
]);

// A native poll: the text is the question.
$client->posts->create([
    'content' => 'Which day suits the live Q&A?',
    'channels' => ['telegram'],
    'telegram' => ['poll' => ['options' => ['Tuesday', 'Thursday', 'Saturday'], 'open_period' => 86400]],
]);

$client->posts->create([
    'content' => 'How we grew to 10k followers in 90 days',
    'channels' => ['x'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'x' => [
        'thread_parts' => [
            ['text' => 'How we grew to 10k followers in 90 days. A thread:'],
            ['text' => '1. We posted every single day, even when it felt pointless.'],
            ['text' => '2. We replied to every comment within an hour.'],
            ['text' => '3. Full breakdown on our blog. Link in bio.'],
        ],
    ],
]);

// Meta Threads chain with a carousel on the first part
$client->posts->create([
    'content' => 'Behind the scenes of our summer shoot',
    'channels' => ['threads'],
    'threads' => [
        'thread_parts' => [
            ['text' => 'Behind the scenes of our summer shoot. A few highlights:', 'media_urls' => ['https://example.com/shoot-1.jpg', 'https://example.com/shoot-2.jpg']],
            ['text' => 'Day one: scouting locations at sunrise.'],
            ['text' => 'Day two: the full crew, 14 hours, zero regrets.'],
        ],
    ],
]);

$res = $client->posts->create([
    'content' => 'Read the full story: https://example.com/post',
    'channels' => ['x'],
]);
foreach ($res['warnings'] ?? [] as $warning) {
    if ($warning['code'] === 'x_url_post_credits') {
        echo $warning['credits_

use OmniSocials\Exception\ApiException;

try {
    $client->posts->create([
        'content' => 'Read the full story: https://example.com/post',
        'channels' => ['x'],
        'scheduled_at' => '2026-08-15T09:00:00Z',
    ]);
} catch (ApiException $e) {
    if ($e->getErrorCode() === 'x_credits_insufficient') {
        $details = $e->getBody()['error']['details'] ?? [];
        echo "Needs {$details['credits_

$page = $client->posts->list(['status' => 'scheduled', 'limit' => 50]);
$posts = $page['data'];

$one = $client->posts->get($posts[0]['id']);
$client->posts->update($one['data']['id'], ['scheduled_at' => '2026-08-02T10:00:00Z']);
$client->posts->publish($one['data']['id']); // publish a draft/scheduled post now
$client->posts->retry($one['data']['id']);   // retry only the failed platforms of a failed/warning post
$client->posts->delete($one['data']['id']);  // returns null (204)

$client->posts->approve($id);                                    // approve the current approval-workflow step
$client->posts->reject($id, "Wrong CTA link, please fix.");      // reject and stop the workflow (comment optional, or omit / pass null)

$review = $client->posts->getApproval($id)['data'];
if ($review['status'] === 'rejected' && $review['rejection'] !== null) {
    echo "Rejected by {$review['rejection']['by']['name']}: {$review['rejection']['reason']}\n";
}
foreach ($review['steps'] as $step) {
    echo "{$step['order']} {$step['name']} {$step['status']}\n";
}

$recent = $client->posts->recentPlatform(['limit' => 10, 'platforms' => ['instagram', 'x']]);

$upload = $client->media->uploadFromUrl([
    'url' => 'https://example.com/launch-video.mp4',
    'name' => 'launch-video-v2',
    'folder' => 'Campaigns',
]);
echo $upload['data']['id'];
print_r($upload['compatibility']);

// From a path
$client->media->upload(['file' => './photos/product.jpg', 'name' => 'product-hero']);

// Or from raw bytes (pass a filename so the API can detect the type)
$bytes = file_get_contents('./photos/product.jpg');
$client->media->upload(['file' => $bytes, 'filename' => 'product.jpg']);

$client->media->uploadFromBase64([
    'data' => $base64String, // no data URI prefix
    'mime_type' => 'image/png',
    'filename' => 'chart.png',
]);

$pdf = $client->media->uploadFromUrl(['url' => 'https://example.com/deck.pdf']);
$client->posts->create([
    'content' => 'Our Q3 strategy deck',
    'channels' => ['linkedin'],
    'media_ids' => $pdf['media_ids'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
]);

$presigned = $client->media->createUploadUrl();

$ch = curl_init($presigned['upload_url']);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => ['file' => new CURLFile('./big-video.mp4')],
]);
$uploaded = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $uploaded['data']['id'];

$client->media->check(['url' => 'https://example.com/huge.mov']);
$client->media->check(['size_bytes' => 300000000, 'mime' => 'video/quicktime']);

$items = $client->media->list(['search' => 'hero', 'limit' => 20]);
$first = $items['data'][0];

$client->media->update($first['id'], ['name' => 'hero-v2', 'folder_id' => '12']);
$client->media->get($first['id']);
$client->media->delete($first['id']); // 409 media_in_use if attached to a scheduled post

$folders = $client->folders->list(); // flat; build the tree via parent_id
$folder = $client->folders->create(['name' => 'Campaigns']);
$client->folders->update($folder['data']['id'], ['name' => 'Campaigns 2026']);
$client->folders->delete($folder['data']['id']); // files move to root, subfolders move up

$set = $client->hashtagSets->create([
    'name' => 'Launch',
    'hashtags' => ['saas', 'buildinpublic', 'startup'], // or one string: '#saas #buildinpublic #startup'
]);
echo $set['data']['preview']; // "#saas #buildinpublic #startup"

$client->hashtagSets->list();
$client->hashtagSets->get($set['data']['id']);
$client->hashtagSets->update($set['data']['id'], ['hashtags' => ['saas', 'founder']]); // replaces the full list
$client->hashtagSets->delete($set['data']['id']); // returns null (204)

$client->posts->create([
    'content' => 'Launch day!',
    'channels' => ['instagram', 'x'],
    'scheduled_at' => '2026-08-01T09:00:00Z',
    'hashtag_set' => 'Launch',
    'hashtag_placement' => 'first_comment',
    'hashtag_platforms' => ['instagram'],
]);

$accounts = $client->accounts->list();
foreach ($accounts['data'] as $account) {
    echo "{$account['platform']} {$account['username']} {$account['status']}\n";
    if (!empty($account['needs_reconnect'])) {
        echo "{$account['platform']} needs a reconnect: {$account['reauth_reason']}\n";
    }
}
$ig = $client->accounts->get($accounts['data'][0]['id']);

// One post's latest per-platform metrics
$stats = $client->analytics->post('post_id');
print_r($stats['data']['platforms']['instagram']['metrics'] ?? null);

// Batch: up to 100 posts in one call
$batch = $client->analytics->posts(['id1', 'id2', 'id3']);

// Workspace-wide overview
$overview = $client->analytics->overview(['period' => '30d']);
echo $overview['data']['total_impressions'] . ' ' . $overview['data']['total_engagements'];

// Account-level stats (followers etc)
$accountStats = $client->analytics->accounts(['platform' => 'instagram']);

$best = $client->analytics->bestTimes([
    'platform' => 'instagram',
    'timezone' => 'Europe/Amsterdam',
]);
foreach ($best['recommendations'] as $slot) {
    echo "{$slot['day']} {$slot['time']} {$slot['score']}\n";
}

$results = $client->locations->search('Griffith Observatory');
$place = $results['data'][0];

$check = $client->locations->validate($place['id']);
if (!empty($check['valid'])) {
    $client->posts->create([
        'content' => 'Golden hour at the observatory',
        'channels' => ['instagram'],
        'media_urls' => ['https://example.com/observatory.jpg'],
        'location_id' => $place['id'],
        'scheduled_at' => '2026-08-01T18:30:00Z',
    ]);
}

$results = $client->locations->search('Griffith Observatory', ['platform' => 'threads']);
// or around a point instead of a keyword:
$results = $client->locations->search(null, [
    'platform' => 'threads',
    'latitude' => 34.1184,
    'longitude' => -118.3004,
]);
$threadsLocationId = $results['locations'][0]['id'];

$client->posts->create([
    'content' => 'Golden hour at the observatory',
    'channels' => ['threads'],
    'threads' => ['location_id' => $threadsLocationId],
]);

$result = $client->pinterest->listProducts();

if (isset($result['error'])) {
    // HTTP 200 without `products`: pinterest_not_connected,
    // pinterest_catalog_access_
    $client->posts->create([
        'content' => 'Our summer picks',
        'channels' => ['pinterest'],
        'media_urls' => ['https://example.com/summer-look.jpg'],
        'scheduled_at' => '2026-08-01T09:00:00Z',
        'pinterest' => [
            'board_id' => '1234567890',
            'title' => 'Summer picks',
            'product_tags' => $productTags,
        ],
    ]);
}

// List conversations (all filters optional)
$conversations = $client->inbox->listConversations([
    'platform' => 'instagram', // instagram | facebook | linkedin | tiktok | youtube | x | threads
    'type' => 'dm',            // dm | comment | mention
    'unread' => true,
    'limit' => 25,             // 1-100
]);

foreach ($conversations['data'] as $conversation) {
    // Full message history for one conversation.
    // LinkedIn ids contain ":" and "()" - they are URL-encoded for you.
    $messages = $client->inbox->getMessages($conversation['conversation_id']);

    // Mark the whole conversation as read.
    $client->inbox->markRead($conversation['conversation_id']);

    // Reply (text ved_reply_ids).
    $client->inbox->deleteMessage($messages['data'][0]['id']);
}

// Page through with the cursor.
$cursor = $conversations['pagination']['next_cursor'] ?? null;
while ($cursor !== null) {
    $page = $client->inbox->listConversations(['cursor' => $cursor]);
    // ... handle $page['data'] ...
    $cursor = ($page['pagination']['has_more'] ?? false)
        ? $page['pagination']['next_cursor']
        : null;
}

$next = $client->inbox->next(['platform' => 'instagram']);
while ($next['data'] !== null) {
    $message = $next['data']['message'];
    echo "{$next['remaining']} left. {$message['sender']['username']}: {$message['text']}\n";

    if (!$next['data']['reply_window']['open']) {
        // An Instagram/Facebook DM past Meta's 24-hour window: reply() would
        // throw 422 outside_messaging_window. Answer it in the app, or skip it.
        $client->inbox->markRead($message['conversation_id']);
        $next = $client->inbox->next(['platform' => 'instagram']);
        continue;
    }

    $reply = $client->inbox->reply($message['conversation_id'], [
        'text' => 'Thanks! DM sent.',
        'message_id' => $message['id'], // the comment being answered, not the newest one
        '

use OmniSocials\Exception\ApiException;

try {
    $client->inbox->reply($conversation['conversation_id'], ['text' => 'Thanks for the DM!']);
} catch (ApiException $e) {
    if ($e->getErrorCode() === 'insufficient_credits') {
        echo "Balance can't cover the 2-credit send, top up in the dashboard\n";
    } elseif ($e->getErrorCode() === 'x_inbox_suspended') {
        echo "This workspace's X inbox is suspended, top up and re-enable it to resume\n";
    }
}

$webhook = $client->webhooks->create([
    'url' => 'https://example.com/omnisocials/webhook',
    'events' => ['post.published', 'post.failed'],
]);
echo $webhook['data']['secret']; // save it, it is only shown once

$client->webhooks->list();
$client->webhooks->get($webhook['data']['id']);
$client->webhooks->update($webhook['data']['id'], ['is_active' => false]);
$rotated = $client->webhooks->rotateSecret($webhook['data']['id']);
echo $rotated['data']['secret']; // the old secret stops working
$client->webhooks->delete($webhook['data']['id']);



mniSocials\Webhooks;
use OmniSocials\Exception\WebhookVerificationException;

$payload = file_get_contents('php://input'); // the raw body, untouched
$signature = $_SERVER['HTTP_X_OMNISOCIALS_SIGNATURE'] ?? '';

try {
    $event = Webhooks::verifySignature(
        $payload,
        $signature,
        getenv('OMNISOCIALS_WEBHOOK_SECRET'),
        300 // tolerance in seconds (default)
    );
} catch (WebhookVerificationException $e) {
    http_response_code(400);
    exit;
}

switch ($event['type']) {
    case 'post.published':
        error_log('Published: ' . $event['data']['post_id']);
        break;
    case 'post.failed':
        error_log('Failed: ' . $event['data']['post_id']);
        break;
    case 'post.rejected':
        error_log('Rejected: ' . $event['data']['post_id'] . ' ' . ($event['data']['approval']['reason'] ?? ''));
        break;
}

http_response_code(200);

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use OmniSocials\Webhooks;
use OmniSocials\Exception\WebhookVerificationException;

Route::post('/omnisocials/webhook', function (Request $request) {
    try {
        $event = Webhooks::verifySignature(
            $request->getContent(),
            $request->header('X-OmniSocials-Signature', ''),
            config('services.omnisocials.webhook_secret')
        );
    } catch (WebhookVerificationException $e) {
        return response()->json(['error' => 'invalid signature'], 400);
    }

    if ($event['type'] === 'post.published') {
        logger()->info('Post published', $event['data']);
    }

    return response()->noContent();
})->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class]);

$health = $client->health(); // ['status' => 'ok', 'version' => '1.0.0', 'timestamp' => '...']

use OmniSocials\Exception\ApiConnectionException;
use OmniSocials\Exception\ApiException;
use OmniSocials\Exception\RateLimitException;
use OmniSocials\Exception\ValidationException;

try {
    $client->posts->create(['content' => 'Hi', 'channels' => ['instagram']]);
} catch (RateLimitException $e) {
    echo 'Rate limited, retry in ' . $e->getRetryAfter() . "s\n";
} catch (ValidationException $e) {
    echo "Bad request ({$e->getErrorCode()}): {$e->getMessage()}\n";
    print_r($e->getBody());
} catch (ApiConnectionException $e) {
    echo 'Network problem: ' . $e->getMessage() . "\n";
} catch (ApiException $e) {
    echo "API error {$e->getStatus()} ({$e->getErrorCode()}): {$e->getMessage()}\n";
}
bash
composer