Skip to content

Advanced Usage

Most applications only need N8nClient, Webhook, and WebhookRequest. The package also exposes contracts and extension points for cases where your application needs more control.

Custom Webhook Response Resolver

By default, webhook responses are parsed as empty, JSON, or text based on the response body and content type.

If your n8n workflows return a custom shape, implement WebhookResponseResolverContract.

php
use PhpN8n\Client\Contracts\WebhookResponseResolverContract;
use PhpN8n\Client\Executions\ExecutionReference;
use PhpN8n\Client\Webhooks\WebhookResponse;
use PhpN8n\Client\Webhooks\WebhookResponseType;
use Psr\Http\Message\ResponseInterface;

final class CustomWebhookResponseResolver implements WebhookResponseResolverContract
{
    public function resolve(ResponseInterface $response): WebhookResponse
    {
        $payload = json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR);

        return new WebhookResponse(
            response: $response,
            type: WebhookResponseType::Json,
            body: $payload,
            executionReference: isset($payload['id'])
                ? ExecutionReference::fromId($payload['id'])
                : null,
        );
    }
}

Pass it to the client:

php
$client = new N8nClient(
    httpClient: $httpClient,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    webhookResponseResolver: new CustomWebhookResponseResolver(),
);

Custom Triggerer Or Tracker

N8nClient accepts custom implementations of:

Constructor argumentContract
webhookTriggererWebhookTriggererContract
executionTrackerExecutionTrackerContract

This is useful for tests, instrumentation, or application-specific wrappers.

php
$client = new N8nClient(
    httpClient: $httpClient,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    webhookTriggerer: $customWebhookTriggerer,
    executionTracker: $customExecutionTracker,
);

HTTP Client Policy

The package does not own retries, TLS policy, proxies, or connection pooling. Configure those in your PSR-18 client.

With Guzzle:

php
use GuzzleHttp\Client as GuzzleClient;

$httpClient = new GuzzleClient([
    'timeout' => 10,
    'connect_timeout' => 5,
]);

If you need retries, add them through your HTTP client stack or application infrastructure. The core client stays deterministic and small.

Shared Webhook Definitions

Because Webhook is immutable, you can safely define base webhooks and derive specific variants.

php
$baseWebhook = Webhook::fromUri($psr17->createUri($_ENV['N8N_WEBHOOK_URL']))
    ->withHeader('X-App', 'billing')
    ->withQueryParameter('source', 'php');

$productionWebhook = $baseWebhook
    ->withQueryParameter('environment', 'production');

Security Notes

Keep webhook URLs and API keys outside source control.

Use environment variables, your framework's secret management, or your deployment platform's secret store.

php
new ApiConfig(
    apiUri: $psr17->createUri($_ENV['N8N_API_URL']),
    apiKey: $_ENV['N8N_API_KEY'],
);

Do not log full webhook URLs if they contain sensitive tokens.

When To Use Hooks Instead Of Custom Classes

Use hooks when you only need to observe behavior:

  • Log outgoing webhook attempts.
  • Count polling attempts.
  • Record execution status changes.
  • Send errors to your error tracker.

Use custom contracts when you need to change behavior:

  • Parse a non-standard webhook response shape.
  • Replace the execution tracker in tests.
  • Wrap webhook triggering in application-specific rules.

Released under the MIT License.