window.dogesoft
Accepting payments
Two ways to get paid through a connected wallet, plus why a self-reported txid isn't proof of payment.
Two ways to get paid through a connected DogeSoft wallet, in order of how fast you can ship them. Both show the user the real destination and amount before anything signs — nothing here bypasses that.
Path 1 — sendDoge(), least work
sendDoge() hands the wallet a plain intent (recipient and amount) and the
wallet builds, signs and broadcasts everything after the user approves. It works the same in the
extension and the mobile app's browser, with no allow-list. See the
sending page.
await dogesoft.connect();
const { txid } = await dogesoft.sendDoge({
to: merchantAddress,
amount: 4.2 // DOGE
});
// record `txid` against your own order, then verify it — don't trust it yet
For DRC-20 payments use sendDrc20({ tick, amount, to }) and verify the
coins arrived with the Explorer API.
Path 2 — signPsbt(), full control
Build the payment transaction yourself on your server (a plain P2PKH output to your address, plus your own inputs, fee and change logic) and hand it to the wallet to sign.
// psbt from your backend (inputs must include nonWitnessUtxo)
const { txHex } = await dogesoft.signPsbt(psbt, { finalize: true });
// send txHex to your server, which broadcasts it via the Explorer API
// (POST /api/tx/broadcast { hex }) and records the txid
This is more work than Path 1: you own UTXO selection, fee estimation and change. See PSBTs.
Verify before you trust it
Either path above ends with a txid the wallet reports back to your page — that's a claim, not proof. Nothing stops a bug, a network hiccup, or a malicious client from reporting a txid that never happened or paid the wrong amount. Confirm it independently against the Explorer API before marking anything paid.
const res = await fetch(
`https://explorer.dogesoft.io/api/wallet/address/${merchantAddress}/history?count=200`
);
const { items } = await res.json();
const paid = items.some((tx) =>
tx.txid === claimedTxid &&
tx.direction === "in" &&
tx.counterparty_address === buyerAddress &&
tx.amount_koinu >= expectedKoinu &&
tx.confirmations >= 1
);
Match on the buyer's own counterparty_address, not amount alone —
flat pricing means two simultaneous buyers can owe the identical amount, and the buyer's address is
already known from DogeSoft Connect for free. Don't
trust a match with zero confirmations — a mempool-only transaction can still be dropped.
Worked example
shop.dogesoft.io runs exactly this pattern end
to end: connect → sendDoge() → record
the claimed txid → independently verify it against Explorer on an interval, whether or not the
customer's page is still open — the same "doesn't need to stay open" property as the
DRC-20 send pipeline. Its order confirmation screen
distinguishes "sent" (broadcast, unconfirmed) from "confirmed" (independently verified) rather than
treating a self-reported txid as final.