Payments
Payments and transfer triggers
A payment is not just money moving. It is an action request. The SDK carries the same standardized { action, metadata } payload inside the transfer memo, so a HIVE transfer and a Hive Engine token transfer trigger application logic exactly the same way.
The idea
Custom JSON operations already carry a standardized payload. Payments extend that same protocol to value transfers: the memo of a native HIVE/HBD transfer, and the memo of a Hive Engine tokens.transfer action, both hold the identical { action, metadata } object. Your application reads one shape, whichever network the money came from.
{
"action": "purchase",
"metadata": { "orderId": "A-1029", "sku": "pro-plan" }
}One payload, many transports
| Parameter | Type | Required | Description |
|---|---|---|---|
| custom_json | json field | No | The original transport — no value attached. |
| HIVE / HBD transfer | memo field | No | Native Layer 1 payment. Final as soon as the block is produced. |
| Hive Engine transfer | contract memo | No | Layer 2 payment inside a custom_json contract action. Execution must be verified. |
The payments namespace
import { HiveClient } from "hivexph-sdk";
const hive = new HiveClient({
accounts: { treasury: { accountEnv: "TREASURY_ACCOUNT", keyEnv: "TREASURY_ACTIVE_KEY" } },
});
// Native HIVE payment carrying a trigger
await hive.payments.hive.transfer({
from: hive.accounts.treasury,
account: "bob",
amount: "10.000",
symbol: "HIVE",
action: "purchase",
metadata: { orderId: "A-1029" },
});
// Hive Engine (Layer 2) payment carrying the same trigger
await hive.payments.engine.transfer({
from: hive.accounts.treasury,
account: "bob",
symbol: "SWAP.HIVE",
quantity: "10",
action: "purchase",
metadata: { orderId: "A-1029" },
});| Parameter | Type | Required | Description |
|---|---|---|---|
| hive | HivePaymentClient | No | Native HIVE / HBD transfers. |
| engine | EnginePaymentClient | No | Hive Engine token transfers. |
| parse(input) | Promise<ParsedPayment[]> | No | Every payment carried by a transaction id. |
| validate(input) | Promise<PaymentValidationResult> | No | Existence + execution + expectation checks. |
| watch(options) | AsyncGenerator<ParsedPayment> | No | Live payment detection as an async iterator over the core block stream. |
Browser flows live under hive.keychain.payments.hive and hive.keychain.payments.engine. Native transfers use Keychain's dedicated transfer request; Layer 2 transfers are signed as active-authority custom_json.
Payment lifecycle
| Parameter | Type | Required | Description |
|---|---|---|---|
| pending | status | No | Execution is not verifiable yet. |
| success | status | No | Transfer happened and, on Layer 2, the contract executed. |
| failed | status | No | The transaction exists but the contract rejected it. |
| invalid | status | No | It executed but does not match your expectations. |
| not_found | status | No | No payment for that id. |
Important
validate() or the stream's execution check can report success: true.Rules the SDK enforces
- Amounts and quantities are decimal strings — never JavaScript numbers.
- Native amounts are normalized to three decimals ("10" becomes "10.000 HIVE").
- A malformed memo never throws in a stream: the trigger is simply null.
- Payloads carry no timestamps — the blockchain is the clock.
- The SDK is stateless: idempotency is your application's job, keyed on
transactionIdplusoperationIndex.
