PHPackages                             cjrasmussen/bluesky-api - 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. cjrasmussen/bluesky-api

ActiveLibrary

cjrasmussen/bluesky-api
=======================

Simple helper for interacting with the Bluesky API/AT protocol

2.3.4(1y ago)3911.8k↓27.8%84MITPHPPHP &gt;=7.4

Since Jul 4Pushed 1y ago6 watchersCompare

[ Source](https://github.com/cjrasmussen/BlueskyApi)[ Packagist](https://packagist.org/packages/cjrasmussen/bluesky-api)[ Docs](https://cjr.dev)[ RSS](/packages/cjrasmussen-bluesky-api/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (24)Used By (4)

BlueskyApi
==========

[](#blueskyapi)

Simple class for making requests to the Bluesky API/AT protocol. Not affiliated with Bluesky.

Usage
-----

[](#usage)

### Starting a session

[](#starting-a-session)

Starting a session requires a handle and password.

```
use cjrasmussen\BlueskyApi\BlueskyApi;

$bluesky = new BlueskyApi();

try {
    $bluesky->auth($handle, $app_password);
} catch (Exception $e) {
    // TODO: Handle the exception however you want
}
```

### Getting a refresh token

[](#getting-a-refresh-token)

If you're running up against rate limits by repeatedly creating a session, you may want to cache a refresh token and use that to refresh your session instead of starting a new one. Cache it however you want for later usage, or see the session helper below.

```
$refresh_token = $bluesky->getRefreshToken();
```

### Refreshing a session

[](#refreshing-a-session)

You can use that cached refresh token later to refresh your session instead of starting a new session.

```
try {
    $bluesky->auth($refresh_token);
} catch (Exception $e) {
    // TODO: Handle the exception however you want
}
```

### Sending a message

[](#sending-a-message)

```
$args = [
	'collection' => 'app.bsky.feed.post',
	'repo' => $bluesky->getAccountDid(),
	'record' => [
		'text' => 'Testing #TestingInProduction',
		'langs' => ['en'],
		'createdAt' => date('c'),
		'$type' => 'app.bsky.feed.post',
	],
];
$data = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
```

### Sending a message with a hashtag

[](#sending-a-message-with-a-hashtag)

The above example has a hashtag in the text, however it will not be rendered as a hashtag. You must explicitly define text as a hashtag when posting via the Bluesky API as the service won't do it for you.

```
$args = [
	'collection' => 'app.bsky.feed.post',
	'repo' => $bluesky->getAccountDid(),
	'record' => [
		'text' => 'Testing #TestingInProduction',
		'facets' => [
			[
				'index' => [
					'byteStart' => 8,
					'byteEnd' => 28,
				],
				'features' => [
					[
						'$type' => 'app.bsky.richtext.facet#tag',
						'tag' => 'TestingInProduction',
					],
				],
			],
		],
		'langs' => ['en'],
		'createdAt' => date('c'),
		'$type' => 'app.bsky.feed.post',
	],
];
$data = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
```

### Sending a message with a link

[](#sending-a-message-with-a-link)

Similarly, you must explicitly define links in text when posting via the Bluesky API.

```
$args = [
	'collection' => 'app.bsky.feed.post',
	'repo' => $bluesky->getAccountDid(),
	'record' => [
		'text' => 'Testing https://cjr.dev',
		'facets' => [
			[
				'index' => [
					'byteStart' => 8,
					'byteEnd' => 23,
				],
				'features' => [
					[
						'$type' => 'app.bsky.richtext.facet#link',
						'uri' => 'https://cjr.dev',
					],
				],
			],
		],
		'langs' => ['en'],
		'createdAt' => date('c'),
		'$type' => 'app.bsky.feed.post',
	],
];
$data = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
```

### Sending a message with an attached image

[](#sending-a-message-with-an-attached-image)

This assumes that your image file is a PNG

```
$body = file_get_contents($file);
$response = $bluesky->request('POST', 'com.atproto.repo.uploadBlob', [], $body, 'image/png');
$image = $response->blob;

$args = [
	'collection' => 'app.bsky.feed.post',
	'repo' => $bluesky->getAccountDid(),
	'record' => [
		'text' => 'Testing with an image #TestingInProduction',
		'langs' => ['en'],
		'createdAt' => date('c'),
		'$type' => 'app.bsky.feed.post',
		'embed' => [
			'$type' => 'app.bsky.embed.images',
			'images' => [
				[
					'alt' => 'A test image',
					'image' => $image,
				],
			],
		],
	],
];
$response = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
```

### Using the session helper to manage refresh token caching

[](#using-the-session-helper-to-manage-refresh-token-caching)

As mentioned above, you can manually cache a session refresh token however you want. The BlueskyApiSessionHelper::auth method is one way of doing that. Provide the path to a file containing a refresh token and the method will refresh your session and update the cache file with the new refresh token. Optionally provide a handle and (app) password to fall back on creating a new session if the refresh token fails.

```
use cjrasmussen\BlueskyApi\BlueskyApi;
use cjrasmussen\BlueskyApi\BlueskyApiSessionHelper;

$blueskyApi = new BlueskyApi();
$blueskyApiSessionHelper = new BlueskyApiSessionHelper($blueskyApi);

try {
    $blueskyApiSessionHelper->auth($refresh_token_path, $handle, $password);
} catch (Exception $e) {
    // TODO: Handle the exception however you want
}
```

### Getting response header for API requests

[](#getting-response-header-for-api-requests)

Bluesky returns data about rate limits in the header of each API request response. The most recent request response header can be accessed as a string as follows:

```
$blueskyApi->getLastResponseHeader();
```

The header can then be parsed as necessary.

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

[](#installation)

Simply add a dependency on cjrasmussen/bluesky-api to your composer.json file if you use [Composer](https://getcomposer.org/) to manage the dependencies of your project:

```
composer require cjrasmussen/bluesky-api
```

Although it's recommended to use Composer, you can actually include the file(s) any way you want.

Further Reference
-----------------

[](#further-reference)

It's not much, but I do have some Bluesky API-related stuff [on my blog](https://cjr.dev/?s=bluesky). Additionally, there's an unofficial "Bluesky API Touchers" Discord (which seems to be invite-only) with a PHP-specific channel.

License
-------

[](#license)

BlueskyApi is [MIT](http://opensource.org/licenses/MIT) licensed.

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance49

Moderate activity, may be stable

Popularity39

Limited adoption so far

Community23

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 93.2% of commits — single point of failure

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 ~31 days

Recently: every ~56 days

Total

23

Last Release

370d ago

Major Versions

1.1.2 → 2.0.02024-01-06

### Community

Maintainers

![](https://www.gravatar.com/avatar/0225f44837a665c8a143afa50a34a406a769c523dba31e4cdf73fd0530dede45?d=identicon)[cjrasmussen](/maintainers/cjrasmussen)

---

Top Contributors

[![cjrasmussen](https://avatars.githubusercontent.com/u/15007730?v=4)](https://github.com/cjrasmussen "cjrasmussen (41 commits)")[![reithose](https://avatars.githubusercontent.com/u/6649052?v=4)](https://github.com/reithose "reithose (2 commits)")[![nemster](https://avatars.githubusercontent.com/u/8384337?v=4)](https://github.com/nemster "nemster (1 commits)")

---

Tags

blueskyat protocol

### Embed Badge

![Health badge](/badges/cjrasmussen-bluesky-api/health.svg)

```
[![Health](https://phpackages.com/badges/cjrasmussen-bluesky-api/health.svg)](https://phpackages.com/packages/cjrasmussen-bluesky-api)
```

###  Alternatives

[revolution/laravel-bluesky

Bluesky(AT Protocol) for Laravel

4317.3k](/packages/revolution-laravel-bluesky)[potibm/phluesky

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

3721.3k2](/packages/potibm-phluesky)[innocenzi/bluesky-notification-channel

Bluesky notification channel for the Laravel framework

3018.4k](/packages/innocenzi-bluesky-notification-channel)

PHPackages © 2026

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