Paybyte
DevelopersPBE Core 0.0.1 · Protocol 1.0
SERVER-TO-SERVER

Fulfil payments from signed events.

A merchant-controlled PBE node can watch an exact PBE-PAY tuple and deliver HMAC-authenticated events to your backend. Webhooks are optional operational data; they do not change consensus and are disabled by default.

Keep credentials server-sideThe webhook management bearer token and signing secret must never be placed in browser JavaScript, a game client, a mobile application, or a payment URI.

Enable on a merchant node

PHP
'commerce' => [
    'webhooks' => [
        'enabled' => true,
        'manageToken' => 'random-secret-at-least-32-characters',
        'signingSecret' => 'different-random-secret-at-least-32-characters',
        'defaultTtlSeconds' => 86400,
        'maxTtlSeconds' => 604800,
        'allowHttpCallbacks' => false,
        'allowPrivateCallbacks' => false,
    ],
],

When enabled, PBE creates the optional webhook storage tables. Nodes with webhooks disabled do not need those tables.

POST/rpc/commerce/webhooks

Register payment watch

Bearer token

Registers one exact reference + recipient + amount tuple and a callback URL.

Parameters

NameLocation / TypeRequiredDescription
AuthorizationheaderyesBearer <manageToken>.
recipientJSON addressyesExpected merchant address.
amountJSON decimalone of amount / amountBaseUnitsExpected PBE amount.
referenceJSON stringyesExisting merchant order reference.
confirmationsJSON integernoConfirmation target.
callbackUrlJSON HTTPS URLyesMerchant server callback.
ttlSecondsJSON integernoWatch lifetime.

Request body

JSON
{"recipient":"pbe1...","amount":"25","reference":"order_8f42d1","confirmations":12,"callbackUrl":"https://merchant.example/paybyte/webhook","ttlSeconds":86400}

cURL

Shell
curl -X POST https://your-node.example/rpc/commerce/webhooks -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d @watch.json

Example response

JSON
{"ok":true,"subscription":{"id":"pbewh_...","active":true,"reference":"order_8f42d1","recipient":"pbe1...","amount":"2500000000","requiredConfirmations":12,"lastState":"unpaid"}}
GET/rpc/commerce/webhooks/{id}

Inspect payment watch

Bearer token

Reads the current subscription state.

Parameters

NameLocation / TypeRequiredDescription
AuthorizationheaderyesBearer <manageToken>.

cURL

Shell
curl https://your-node.example/rpc/commerce/webhooks/pbewh_... -H "Authorization: Bearer $TOKEN"
POST/rpc/commerce/webhooks/{id}/cancel

Cancel payment watch

Bearer token

Stops a subscription from producing future payment events.

Parameters

NameLocation / TypeRequiredDescription
AuthorizationheaderyesBearer <manageToken>.

cURL

Shell
curl -X POST https://your-node.example/rpc/commerce/webhooks/pbewh_.../cancel -H "Authorization: Bearer $TOKEN"

Events

EventMeaning
payment.pendingMatching transaction entered the node mempool.
payment.confirmingCanonical transaction detected or its confirmation depth changed.
payment.confirmedRequired canonical confirmation depth reached.
payment.reorgedA previously canonical/confirmed observation lost confidence, changed transaction, or dropped confirmation depth.
payment.expiredWatch expired before confirmation.

Verify the callback

PBE sends the exact JSON body with these headers:

HTTP
X-Paybyte-Event: payment.confirmed
X-Paybyte-Event-Id: pbeevt_...
X-Paybyte-Timestamp: 1789168200
X-Paybyte-Signature: v1=<hex-hmac>

Compute HMAC-SHA256 over timestamp + "." + exact_raw_body using the node's signingSecret. Enforce a short timestamp tolerance and compare signatures with a constant-time function.

PHP
$raw = file_get_contents('php://input');
$timestamp = (int)($_SERVER['HTTP_X_PAYBYTE_TIMESTAMP'] ?? 0);
$provided = preg_replace('/^v1=/i', '', $_SERVER['HTTP_X_PAYBYTE_SIGNATURE'] ?? '');
$expected = hash_hmac('sha256', $timestamp . '.' . $raw, $signingSecret);
if (abs(time() - $timestamp) > 300 || !hash_equals($expected, strtolower($provided))) {
    http_response_code(401); exit;
}

Idempotent fulfilment

Webhook delivery is at-least-once. Store event IDs and make the merchant order reference unique. In one database transaction: lock the order, verify reference + recipient + amount + canonical confirmation depth, mark paid, grant the product only if not already granted, and commit.

ReorganizationsDo not treat payment.confirmed as protocol hard finality. Your application should define how payment.reorged affects fulfilment or settlement risk.

Callback security

By default callbacks require HTTPS. Localhost, private and reserved IPs are rejected, redirects are disabled, and delivery pins the validated DNS result to reduce DNS-rebinding/SSRF risk. Relax these controls only on a node you administer and only for a controlled environment.

For a complete working implementation, download the Golden Sword webhook example.