PHP code example of innis / nostr-client

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

    

innis / nostr-client example snippets


use Innis\Nostr\Client\Infrastructure\Factory\NostrClientFactory;
use Innis\Nostr\Core\Application\Port\EventHandlerInterface;
use Innis\Nostr\Core\Domain\Collection\EventKindCollection;
use Innis\Nostr\Core\Domain\Entity\Event;
use Innis\Nostr\Core\Domain\ValueObject\Content\EventKind;
use Innis\Nostr\Core\Domain\ValueObject\Protocol\Filter;
use Innis\Nostr\Core\Domain\ValueObject\Protocol\RelayUrl;
use Innis\Nostr\Core\Domain\ValueObject\Protocol\SubscriptionId;

$client = NostrClientFactory::create();

$damus = RelayUrl::tryFromString('wss://relay.damus.io')
    ?? throw new InvalidArgumentException('Invalid relay URL');
$nosLol = RelayUrl::tryFromString('wss://nos.lol')
    ?? throw new InvalidArgumentException('Invalid relay URL');

$client->connect($damus);
$client->connect($nosLol);

$handler = new class implements EventHandlerInterface {
    public function handleEvent(Event $event, SubscriptionId $subscriptionId): void
    {
        echo substr((string) $event->getContent(), 0, 100)."\n";
    }

    public function handleEose(SubscriptionId $subscriptionId): void {}
    public function handleClosed(SubscriptionId $subscriptionId, string $message): void {}
    public function handleNotice(RelayUrl $relayUrl, string $message): void {}
};

$filter = new Filter(kinds: EventKindCollection::fromInts([EventKind::TEXT_NOTE]), limit: 10);

$subscriptionId = $client->subscribe($damus, $filter, $handler);

\Amp\delay(5);

$client->unsubscribe($damus, $subscriptionId);
$client->close();

use Innis\Nostr\Core\Domain\Factory\RumourFactory;
use Innis\Nostr\Core\Domain\ValueObject\Identity\KeyPair;
use Innis\Nostr\Core\Infrastructure\Crypto\Secp256k1Signer;

$signer = Secp256k1Signer::create();
$keyPair = KeyPair::generate($signer);
$signedEvent = RumourFactory::createTextNote($keyPair->getPublicKey(), 'Hello Nostr!')
    ->sign($keyPair, $signer);

// publishEvent() returns a Future<PublishResult>. Await it for the relay's verdict,
// or drop it for fire-and-forget.
$result = $client->publishEvent($relay, $signedEvent)->await();

if ($result->isAccepted()) {
    echo "Stored by the relay\n";
} else {
    echo "Rejected: {$result->getMessage()}\n";
}

$results = $client->healthCheck();

foreach ($results as $result) {
    $relayUrl = $result->getRelayUrl();
    if ($result->isHealthy()) {
        echo "{$relayUrl}: reachable\n";
    } else {
        echo "{$relayUrl}: {$result->getErrorMessage()}\n";
    }
}

use Innis\Nostr\Core\Domain\Collection\EventKindCollection;
use Innis\Nostr\Core\Domain\Collection\FilterCollection;

$subscriptionId = $client->subscribeMultiple(
    $relay,
    new FilterCollection([
        new Filter(kinds: EventKindCollection::fromInts([EventKind::TEXT_NOTE]), limit: 10),
        new Filter(kinds: EventKindCollection::fromInts([EventKind::REACTION]), limit: 10),
    ]),
    $handler,
);

use Innis\Nostr\Client\Domain\ValueObject\ConnectionConfig;

$config = new ConnectionConfig(
    connectionTimeoutSeconds: 15,
    headers: ['Authorization' => 'Bearer token'],
    userAgent: 'my-app/1.0',
    autoReconnect: true,
    reconnectInitialDelayMs: 500,
    reconnectMaxDelayMs: 60000,
    reconnectMaxAttempts: 0,
);

$client->connect($relay, $config);

$client->reconnect($relay);
$client->disconnect($relay);
$client->ping($relay);

$state = $client->getConnectionStatus($relay);
$isConnected = $client->isConnected($relay);

$connection = $client->getConnection($relay);
$connected = $client->getConnectedRelays();
$all = $client->getAllConnections();

use Innis\Nostr\Client\Application\Port\ReconnectionListenerInterface;
use Innis\Nostr\Core\Domain\ValueObject\Protocol\RelayUrl;

$listener = new class implements ReconnectionListenerInterface {
    public function onReconnected(RelayUrl $relayUrl): void
    {
        // resubscribe, reauthenticate, etc.
    }
};

$client->setReconnectionListener($listener);

$client->publishEvent($relay, $eventA);
$client->publishEvent($relay, $eventB);
$client->awaitPendingPublishes($relay, timeoutSeconds: 5.0);

use Innis\Nostr\Client\Application\Port\AuthChallengeHandlerInterface;
use Innis\Nostr\Core\Domain\Factory\RumourFactory;
use Innis\Nostr\Core\Domain\Service\SignatureServiceInterface;

$authHandler = new class($keyPair, $signer) implements AuthChallengeHandlerInterface {
    public function __construct(
        private KeyPair $keyPair,
        private SignatureServiceInterface $signer,
    ) {}

    public function handleAuthChallenge(RelayUrl $relayUrl, string $challenge): ?Event
    {
        return RumourFactory::createAuth($this->keyPair->getPublicKey(), $relayUrl, $challenge)
            ->sign($this->keyPair, $this->signer);
    }
};

$client->setAuthHandler($authHandler);

$healthChecker = NostrClientFactory::createHealthChecker();
$relay = RelayUrl::tryFromString('wss://relay.damus.io')
    ?? throw new InvalidArgumentException('Invalid relay URL');
$result = $healthChecker->checkHealth($relay);

try {
    $result = $client->publishEvent($relay, $event)->await();

    if (!$result->isAccepted()) {
        // The relay declined the event — an outcome, not a fault.
        $this->logger->info('Relay rejected the event', [
            'relay' => (string) $relay,
            'reason' => $result->getMessage(),
        ]);
    }
} catch (ConnectionException $e) {
    // The connection broke mid-publish — a fault.
    $this->logger->error('Publish failed', [
        'relay' => (string) $relay,
        'error' => $e->getMessage(),
    ]);
}