Search by

potibm / phluesky

potibm

An small PHP library for posting messages to the bluesky social network using the AT Protocol.

Package info

github.com/potibm/phluesky

pkg:composer/potibm/phluesky

Statistics

Installs: 34 461

Dependents: 2

Suggesters: 0

Stars: 41

Open Issues: 3

v0.8.0 2026-10-08 22:07 UTC

README

Latest Version Latest Version on Packagist Software License Coverage Status

An small PHP library for Bluesky social using the AT Protocol.

Usage

Install

Installing using composer is suggested

composer require potibm/phluesky

You will need a PSR-7, PSR-17 and PSR-18 client or adapter from this list. For development symfony/http-client and nyholm/psr7 are used.

The HTTP service discovery will do the magic. In most cases no additional steps are required.

Setup and posting a simple message

$api = new \potibm\Bluesky\BlueskyApi('nick.bsky.social', 'abcd-efgh-ijkl-mnop');
$postService = new \potibm\Bluesky\BlueskyPostService($api);

$post = \potibm\Bluesky\Feed\Post::create('✨ example mentioning @atproto.com to share the URL πŸ‘¨β€β€οΈβ€πŸ‘¨ https://en.wikipedia.org/wiki/CBOR.');

$response = $api->createRecord($post);

Adding mentions and links from post text

$post = \potibm\Bluesky\Feed\Post::create('✨ example mentioning @atproto.com to share the URL πŸ‘¨β€β€οΈβ€πŸ‘¨ https://en.wikipedia.org/wiki/CBOR.');
$post = $postService->addFacetsFromMentionsAndLinks($post);

Adding mentions and links and tags from post text

$post = \potibm\Bluesky\Feed\Post::create('✨ example mentioning @atproto.com to share the URL πŸ‘¨β€β€οΈβ€πŸ‘¨ https://en.wikipedia.org/wiki/CBOR. and #HashtagFun');
$post = $postService->addFacetsFromMentionsAndLinksAndTags($post);

Adding images

https://atproto.com/blog/create-post#images-embeds

Images are provided through a MediaSource. Use FileMediaSource to read from disk, or BlobMediaSource to upload binary data already held in memory.

use potibm\Bluesky\Media\FileMediaSource;
use potibm\Bluesky\Media\BlobMediaSource;

$post = \potibm\Bluesky\Feed\Post::create('example post with image attached');

// from a file path
$post = $postService->addImage(
    $post,
    new FileMediaSource('image.jpg'),
    'alt text'
);

// from in-memory binary data
$post = $postService->addImage(
    $post,
    new BlobMediaSource($imageData, 'image/jpeg'),
    'alt text'
);

Passing a file path string (e.g. $postService->addImage($post, 'image.jpg', 'alt text')) is deprecated and will be removed in a future version. Use FileMediaSource instead.

Adding website card embeds

https://atproto.com/blog/create-post#website-card-embeds

use potibm\Bluesky\Media\FileMediaSource;

$post = \potibm\Bluesky\Feed\Post::create('post which embeds an external URL as a card');
$post = $postService->addWebsiteCard(
    $post, 
    'https://example.com', 
    'Example website', 
    'Example website description',
    new FileMediaSource('optionalimage.jpg')
);

Reply to a post

https://atproto.com/blog/create-post#replies

$post = \potibm\Bluesky\Feed\Post::create('example of a reply');
$post = $postService->addReply(
    $post, 
    'at://did:plc:u5cwb2mwiv2bfq53cjufe6yn/app.bsky.feed.post/3k43tv4rft22g'
);

Quote a post

https://atproto.com/blog/create-post#quote-posts

$post = \potibm\Bluesky\Feed\Post::create('example of a quote-post');
$post = $postService->addQuote(
    $post, 
    'at://did:plc:u5cwb2mwiv2bfq53cjufe6yn/app.bsky.feed.post/3k44deefqdk2g'
);

Reusing sessions

By default a new session is created for every BlueskyApi instance. Bluesky rate-limits session creation, so for long-running or repeated use you should reuse sessions. Pass any PSR-16 cache to the constructor; this example uses symfony/cache:

composer require symfony/cache
use potibm\Bluesky\HttpComponentsManager;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;

$cache = new Psr16Cache(new FilesystemAdapter('phluesky', 0, sys_get_temp_dir()));

$api = new \potibm\Bluesky\BlueskyApi(
    'nick.bsky.social',
    'abcd-efgh-ijkl-mnop',
    new HttpComponentsManager(),
    cache: $cache
);

The session (including the refresh token) is stored in the cache and reused by later instances. When an access token expires, the library automatically refreshes the session and retries the request once.

Any implementation listed under psr/simple-cache-implementation works, so you can use whatever cache backend your project already has.

Handling errors

While performing requests using the API, exceptions may be thrown.

The exceptions are of the base type potibm\Bluesky\Exception\Exception. The exception message will contain details from the API.

try {
    $response = $api->createRecord($post);
} catch (\potibm\Bluesky\Exception\HttpRequestException $e) {
    echo 'Error performing request on HTTP level: ' . $e->getMessage();
} catch (\potibm\Bluesky\Exception\AuthenticationErrorException $e) {
    echo 'Unable to authorize: ' . $e->getMessage();
} catch (\potibm\Bluesky\Exception\HttpStatusCodeException $e) {
    echo 'Unable to perform request on API level: ' . $e->getMessage();
} catch (\potibm\Bluesky\Exception\InvalidPayloadException $e) {
    echo 'Received unserializable JSON payload: ' . $e->getMessage();
}

License

The MIT License (MIT). Please see License File for more information.