Payments
Hive Engine payments
Layer 2 payments are custom_json operations against the ssc-mainnet-hive sidechain. The transfer memo carries the same standardized trigger as a native payment — but success has to be proven with the sidechain logs.
What gets broadcast
JSON
{
"contractName": "tokens",
"contractAction": "transfer",
"contractPayload": {
"symbol": "SWAP.HIVE",
"to": "bob",
"quantity": "10",
"memo": "{\"action\":\"purchase\",\"metadata\":{\"orderId\":\"A-1029\"}}"
}
}The operation id is ssc-mainnet-hive and it requires the active authority. The trigger lives inside the contract memo, so a single sidechain transfer both moves tokens and requests an action.
Backend transfers
TypeScript
const result = await hive.payments.engine.transfer({
from: hive.accounts.treasury,
account: "bob",
symbol: "SWAP.HIVE",
quantity: "10", // decimal string, Engine precision
action: "purchase",
metadata: { orderId: "A-1029" },
});
// Offline preview — no key, no network
const preview = hive.payments.engine.build({ /* same input */ });
preview.operation; // ["custom_json", { ... }] · preview.json · preview.id| Parameter | Type | Required | Description |
|---|---|---|---|
| from | AccountReference | No | Sender account reference. |
| account | string | No | Recipient Hive account. |
| symbol | string | No | Hive Engine token symbol. |
| quantity | string | No | Decimal string quantity. |
| action | string | No | Trigger action name. |
| metadata | object | null | No | Optional trigger metadata. |
Keychain transfers
TypeScript
await hive.keychain.payments.engine.transfer({
username: "alice",
account: "bob",
symbol: "SWAP.HIVE",
quantity: "10",
action: "purchase",
metadata: { orderId: "A-1029" },
message: "Confirm your purchase",
});Execution is not inclusion
The Layer 2 trap
A Hive block containing your custom_json proves only that the request was broadcast. The sidechain evaluates it afterwards and can reject it — insufficient balance, unknown token, bad quantity. Crediting a user on block inclusion is how Layer 2 integrations lose money.
The SDK asks the Hive Engine RPC for the transaction info and reads its logs. A log with an errors array means the contract failed; a transfer event means it succeeded; no info yet means pending.
TypeScript
const payment = await hive.payments.validate({
transactionId: id, // the network is detected automatically
expected: { account: "bob", symbol: "SWAP.HIVE", quantity: "10", action: "purchase" },
});
if (payment.success === true) fulfilOrder(payment.trigger?.metadata);
if (payment.status === "pending") retryLater();