Any media_urls (or media_ids) entry can also be an array carrying per-media
alt text (max 1500 chars), delivered to Mastodon, Bluesky, X (photos),
Pinterest, Instagram (images), and LinkedIn (images):
PHP
'media_urls' => [['url' => 'https://example.com/teaser.jpg', 'alt' => 'Red sneaker on a white background']],
Publish immediately:
PHP
$client->posts->createAndPublish([ 'content' => 'Going live right now', 'channels' => ['x', 'bluesky'],]);
// 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']);
Analytics
PHP
// 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']);
Social Inbox
Read and answer DMs, comments and mentions from your connected accounts. The API key
needs the opt-in inbox:read / inbox:write scopes. The lists use cursor pagination
(cursor in, pagination.next_cursor out).
next() hands out the next conversation that still needs an answer, with the thread
and the post it belongs to. On a comment thread, pass message_id so the reply goes
under the comment you answer and not under the newest comment on the post.
PHP
$next = $client->inbox->next();while ($next['data'] !== null) { $message = $next['data']['message']; if (!$next['data']['reply_window']['open']) { // An Instagram/Facebook DM past Meta's 24-hour window: answer it in the app $client->inbox->markRead($message['conversation_id']); $next = $client->inbox->next(); continue; } $reply = $client->inbox->reply($message['conversation_id'], [ 'text' => 'Thanks! DM sent.', 'message_id' => $message['id'], 'include_next' => true, ]); $next = ['data' => $reply['next'] ?? null, 'remaining' => $reply['remaining'] ?? 0];}
See the Social Inbox guide for the platforms, the reply rules and the error
codes.
Pinterest product tags
Tag products on a Pin so people can shop the items in the image. List the product Pins
of the connected Pinterest account, then pass up to 24 of their Pin ids as
product_tags in the pinterest options of the post. Only product Pins of your own
account can be tagged; products of other merchants cannot.
The list answers with HTTP 200 in both cases: products on success, or an error array
(pinterest_not_connected, pinterest_catalog_access_required, platform_error) when
it could not be read. It reads the Pinterest catalog when the connection has catalog
access (given one time in the OmniSocials composer: Pinterest options, Add products,
Connect catalog), else the account's own Pins. The tags are added right after the Pin is
published. A product that Pinterest refuses never fails the post: the post then carries
pinterest.product_tags_result with the tagged and the skipped Pin ids.
$client->pinterest->validateProduct($id) checks one Pin id or Pin link before you
post. On posts->update() the pinterest array replaces the stored one, so leave
product_tags out to remove the tags.
Events: post.scheduled, post.published, post.failed, post.approved and post.rejected.
The two approval events carry data.approval with status, decided_by (the approver's
user id) and reason (null on post.approved). To read the full review of a post (steps,
approvers, the rejection reason and the comment thread), call $client->posts->getApproval($id).
Errors
The base class is OmniSocials\Exception\OmniSocialsException. ApiException
exposes getStatus(), getErrorCode(), getMessage(), and getBody(). Types:
ValidationException (400/422), AuthenticationException (401),
PermissionDeniedException (403), NotFoundException (404), RateLimitException
(429, getRetryAfter()), ServerException (5xx), ApiConnectionException, and
WebhookVerificationException.