Origin Docs

Get started

What Origin is

Origin lets a DogeOS app ask Dogecoin a question and use the answer. Does this wallet hold the coin? Does it own a Doginal from this collection? Did this payment confirm?

DogeSoft already indexes every Dogecoin block: DOGE, UTXOs, inscriptions, Doginals, collections and the full DRC-20 ledger. Origin puts that on one front door. You can search it, read it from your server, or use it from a DogeOS contract. When you need to write back to Dogecoin, Origin hands you the request, and your user’s wallet signs it.

Dogecoin L1DogeSoft indexerOriginYour app or contract
New here? You don’t need to run a node or understand inscriptions to start. Open Origin, pick a door, and follow it. Every answer ends with code you can copy.
Going deeper. Origin doesn’t keep its own copy of the chain. Answers resolve against the DogeSoft indexer, using the same fail-closed rules the DogeSoft Bridge uses to mint against L1 deposits. See Trust model.

Get started

Quickstart

Three ways in. Use whichever matches where you are.

1. No code

Go to ø.co, paste a Dogecoin address and type DU$T balance. You get the answer, where it came from, and your plugs.

2. From your server or frontend

Every fact Origin shows can be read straight from the public DogeSoft API. No key needed.

terminal
curl -s 'https://explorer.dogesoft.io/api/wallet/address/DPXjXNN2oiY8UWdGK1U5PgwK6ZV8cstn1s/drc20'
response (trimmed)
{
  "address": "DPXjXNN2oiY8UWdGK1U5PgwK6ZV8cstn1s",
  "balances": [
    { "tick": "DU$T", "balance": "6969", "available": "6969.0", "transferable": "0.0", "decimals": 18 }
  ]
}

3. From a DogeOS contract

Your contract calls Origin, Origin returns the fact. One address, one interface.

HoldersOnly.sol
interface IOrigin {
    function drc20Balance(string calldata dogeAddress, string calldata tick)
        external view returns (uint256 amount, uint64 l1Height, uint64 attestedAt);
}

contract HoldersOnly {
    IOrigin public immutable origin;
    constructor(IOrigin origin_) { origin = origin_; }

    function canEnter(string calldata dogeAddress) external view returns (bool) {
        (uint256 amount, , uint64 attestedAt) = origin.drc20Balance(dogeAddress, "DU$T");
        require(block.timestamp - attestedAt <= 1 hours, "stale");
        return amount >= 1_000_000 * 1e18;
    }
}
Draft. The Origin contract is not deployed yet. The interface above is what we’re building toward. Paths 1 and 2 work today. See What’s live today.

Get started

What’s live today

We only call something live when you can use it right now.

PieceStateWhere
Search and guided pathsLiveø.co · origin.dogesoft.io
Read API (balances, Doginals, collections, txs)Liveexplorer.dogesoft.io/api
Write paths (send a coin, move a Doginal)Liveinscriber.dogesoft.io
Origin, OriginInscriber, OriginPlugs contractsFinal ABI · not deployedABI explorer · DogeOS testnet next
Built on Origin badgeLiveSee badge
Signed facts (attestations)Buildingorigin-attester
Origin ProofPlannedSee Origin Proof
OP_CHECKZKP shadow indexingPlannedSee OP_CHECKZKP

DogeOS itself is still on testnet: Chikyū, chain id 6281971, RPC https://rpc.testnet.dogeos.com.

Get started

Plugs and earning

A plug is one reusable piece of a Dogecoin-powered build. “Holders of this coin get in.” “This Doginal is a playable character.”

How the money moves

99%of every plug license sale goes to the creator.
1%platform fee to DogeSoft, fixed in the OriginPlugs contract.
Fact feesdApps can pay Origin.requestFact for a fresh fact on demand. The plug named in the request earns a share (20% today, capped at 50%). The rest funds attesters and the treasury.
Freereading facts on DogeOS. View calls never cost anything.
Draft. Origin and OriginPlugs are compiled with their final interfaces but not deployed. The marketplace opens when they are.

Dogecoin basics

UTXOs in one minute

Dogecoin doesn’t store account balances. It stores coins sitting in outputs.

Every transaction spends some earlier outputs and creates new ones. An output nobody has spent yet is a UTXO (unspent transaction output). A wallet’s DOGE balance is the sum of the UTXOs it can spend.

An output is named by the transaction that created it plus its position: txid:vout. That pair is an outpoint. You’ll see outpoints a lot, because inscriptions live on them.

Coming from Ethereum? There’s no balanceOf on Dogecoin. Think of a wallet as a purse of exact bills. Paying means handing over whole bills and getting change back as a new bill.

Dogecoin basics

Inscriptions and Doginals

An inscription is data written into a Dogecoin transaction. A Doginal is a one-of-a-kind inscription, collected like an NFT.

The data (an image, text, JSON, HTML, audio, video) sits inside an envelope in the transaction. It gets an id like <txid>i0. The inscription then rides on a small output called the carrier. Whoever holds the carrier UTXO owns the inscription. To move it, you spend that output to someone else.

Collections aren’t a chain object. DogeSoft keeps a registry of which inscriptions belong to which collection (298 at last count), and Origin uses it to answer “does this wallet own one of these?”.

Going deeper. Large files are split across many transactions (multipart). The DogeSoft indexer reassembles them and stores a SHA-256 of the full content, which Origin returns as contentHash.

Dogecoin basics

DRC-20 coins

DRC-20 coins are written on Dogecoin with plain-text inscriptions. No contract is involved.

A coin is deployed, minted and moved by inscribing small JSON bodies like {"p":"drc-20","op":"transfer","tick":"DU$T","amt":"10"}. An indexer replays every block to keep the ledger.

Sending a coin is two steps:

  1. Inscribe the transfer to your own address. That amount becomes transferable, meaning locked inside that inscription.
  2. Move the inscription to the recipient. When the move confirms, the ledger debits you and credits them.

That’s why a balance has three numbers. Balance is the total. Available is free to inscribe. Transferable is locked in transfer inscriptions that haven’t moved yet.

Going deeper. Tickers are exact, symbols included (DU$T is not DUST). The only transform DogeSoft applies is lowercase with control characters removed. Amounts in Origin return values are base units: amount × 10^decimals.

Dogecoin basics

Confirmations

A transaction is confirmed once it’s in a block. Each block after that adds a confirmation.

Dogecoin makes a block about every minute. Six confirmations is a common bar for “this won’t change”. Origin defaults to six for payments, and you can ask for more.

DRC-20 is one step behind: the ledger can only settle a block once the DogeSoft indexer has processed it. Origin reports the height the ledger is indexed to, and answers pending for anything newer.

Dogecoin basics

Words we use

CoinA DRC-20 asset. We say coin, not token. It’s inscribed on L1, not issued by a contract.
DoginalA one-of-a-kind inscription.
KoinuSmallest DOGE unit. 1 DOGE = 100,000,000 koinu.
FeeDogecoin charges per byte. There’s no gas.
Commit / revealThe two transactions that write an inscription.
MoveThe transaction that hands an inscription to its recipient.
FactOne thing Origin can tell you, e.g. a coin balance at a block height.
L1 / L2Dogecoin mainnet / DogeOS.

Guide

Reward holders of a coin

Only let people in, airdrop, or unlock a feature if their Dogecoin wallet holds enough of a coin.

  1. On Origin, choose I have a coin → Let DogeOS apps reward my holders, or Building an app → A wallet holds a coin.
  2. Enter the ticker, a wallet to test with, and the minimum.
  3. Copy plug 01 to check it from your server today, or plug 02 for your contract.
server, today
const res = await fetch(`https://explorer.dogesoft.io/api/wallet/address/${addr}/drc20`);
const { balances } = await res.json();
const dust = balances.find((b) => b.tick.toLowerCase() === 'du$t');
const ok = Number(dust?.balance ?? 0) >= 1_000_000;
Which wallet is “theirs”? A DogeOS contract sees an EVM address, while the coins sit at a Dogecoin address. Until Origin’s address-link fact ships, have users prove their Dogecoin address with window.dogesoft.signMessage on your site, and check the signature on your server.

Guide

Reward holders of a collection

“Does this wallet own at least one DU$TINAL DOG?”

  1. Choose I have Doginals → Let DogeOS apps reward my holders.
  2. Start typing the collection name. The list fills from DogeSoft’s registry.
  3. Origin counts the Doginals that wallet holds right now and confirms each one against the registry.

The Origin call is collectionCount(dogeAddress, collectionId). Collection ids are slugs like dustinal-dogs.

Going deeper. Ownership means the address holds the carrier UTXO. Today Origin derives the count from the wallet’s UTXOs plus the inscription registry, checking up to 12 items per answer. A single indexer endpoint for this is on the roadmap.

Guide

Verify a coin transfer

Paste a txid and ask “was this DRC-20 transfer valid?”.

Origin uses the same rules as the DogeSoft Bridge. A transfer is valid only when the move settled on the ledger and wasn’t settled by a manual repair or sweep. If the indexer hasn’t reached that block yet, the answer is pending, never yes.

terminal
curl -s 'https://explorer.dogesoft.io/api/explorer/tx/06f8c5cc6c54e94045db7b0fe2ee82f4d95dc8b12a4fcf3d4d5eb85d0d7450ed'
# look at drc20_operations[].data.ledger_settled and .settle_reason

Guide

Confirm a DOGE payment

Ship the order once the payment has enough confirmations.

server
const tx = await fetch(`https://explorer.dogesoft.io/api/tx/${txid}`).then((r) => r.json());
const paid = tx.confirmations >= 6;

On DogeOS the call is txConfirmed(txid, minConfirmations). The txid is passed as bytes32, written exactly as explorers display it. See Encoding rules.

Guide

Check an inscription is real

Paste an inscription id (…i0). Origin tells you whether DogeSoft parsed it from chain, which envelope it uses, its content hash, where it was born and who holds it.

DogeSoft v1 envelope means it carries a registered ACTION tag. Legacy Doginal means a valid inscription made before the standard. Both are real. The label tells you which rules it was written under.

Guide

Send a coin

Move DRC-20 coins with the DogeSoft standard. The user signs. Nobody else holds their keys.

  1. Check. Origin confirms the sender has enough available balance first.
  2. Build. POST /drc20-transfer-draft. DogeSoft pays for and broadcasts the transfer inscription to the sender’s address, using the standard envelope.
  3. Sign the move. Spend the carrier (reveal output 0) and the fee float (output 1) to the recipient.
  4. Broadcast. The DogeSoft wallet’s pushPsbt does it for you. Otherwise use POST /broadcast.
1 · build
curl -s -X POST 'https://inscriber.dogesoft.io/drc20-transfer-draft' \
  -H 'content-type: application/json' \
  -d '{"from_address":"D…sender","recipient":"D…recipient","tick":"DU$T","amount":"10"}'
2 · sign the move with the DogeSoft wallet
const prev = Buffer.from(draft.reveal_raw_hex, 'hex');
const psbt = new bitcoin.Psbt({ network: dogecoin });
psbt.addInput({ hash: draft.reveal_txid, index: 0, nonWitnessUtxo: prev });
psbt.addInput({ hash: draft.reveal_txid, index: draft.fee_float_vout, nonWitnessUtxo: prev });
psbt.addOutput({ address: recipient, value: draft.dust_koinu });

await window.dogesoft.connect();
const { psbtHex } = await window.dogesoft.signPsbt(psbt.toHex(), { autoFinalize: true });
const { txid } = await window.dogesoft.pushPsbt(psbtHex);
Heads up. Step 2 really broadcasts. The transfer inscription is created on Dogecoin as soon as you call it. The draft endpoint refuses if the balance doesn’t cover the amount.

Guide

Move a Doginal

No new inscription is needed. You spend the output it sits on.

1 · build
curl -s -X POST 'https://inscriber.dogesoft.io/prepare' \
  -H 'content-type: application/json' \
  -d '{"flow":"doginal_send","inscription_outpoint":"<txid>:<vout>","from_address":"D…owner","recipient":"D…to"}'
2 · sign and broadcast with the DogeSoft wallet
const unsignedHex = [...atob(draft.psbt_base64)]
  .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0')).join('');
await window.dogesoft.connect();
const { psbtHex } = await window.dogesoft.signPsbt(unsignedHex, { autoFinalize: true });
const { txid } = await window.dogesoft.pushPsbt(psbtHex);

Don’t know the outpoint? Origin’s Move a Doginal path looks it up live from the inscription id.

Guide

Inscribe from DogeOS

Your DogeOS contract writes a real inscription to Dogecoin, using the DogeSoft Inscription Standard.

  1. Request. Your contract calls OriginInscriber.requestInscription(action, contentType, metadata, payload, dogeRecipient, plugId) and pays the fee in DOGE. The exact envelope is committed on-chain as envelopeHash.
  2. Inscribe. DogeSoft writes it to Dogecoin with the standard envelope, straight to the recipient’s Dogecoin address.
  3. Receipt. Attesters post a signed receipt. It is accepted only if the inscription on Dogecoin hashes to the same envelope, with enough confirmations, and a reveal output that was never used before.
  4. Done. Your contract can get a callback (onInscribed). If nothing lands before the timeout, the requester reclaims the fee.
MyMint.sol
bytes memory body = inscriber.launchpadMintBody("dustinal-dogs", id, "777");
uint256 fee = inscriber.previewFee("LAUNCHPAD_MINT", body.length);
(uint256 requestId, bytes32 envelopeHash) = inscriber.requestInscription{value: fee}(
    "LAUNCHPAD_MINT", "application/json", new bytes[](0), body, dogeAddress, PLUG_ID
);
// later, anyone can confirm what landed is exactly this:
bool exact = origin.inscriptionMatches(inscriptionId, envelopeHash);
New here? You don’t build the envelope bytes yourself. launchpadMintBody and drc20TransferBody produce the standard JSON byte-for-byte, and encodeEnvelope shows the exact bytes that go to Dogecoin.
Going deeper. envelopeHash = keccak256(OP_FALSE OP_IF "ord" OP_1 <content-type> [<ACTION> <metadata>…] OP_0 <payload in 520-byte pushes> OP_ENDIF). ACTION and metadata are omitted for text/plain DRC-20 bodies, exactly like the Inscriber. The same encoder ships in JavaScript (/shared/js/envelope.js) and is tested byte-for-byte against the contract.
Trust. On the Dogecoin side DogeSoft pays the fees and holds the inscribing key until the inscription reaches the recipient. The byte-exact receipt check is what makes that verifiable.

Guide

Built on Origin badge

Show users your Dogecoin data is verified by DogeSoft’s Origin. One line.

your-site.html
<script src="https://origin.dogesoft.io/shared/badge/origin-badge.js" defer></script>
<origin-badge plug="collection-holder-gate"></origin-badge>

Attributes: plug (links to that plug’s page on Origin Plugs), variant="mark" (logo only), theme="light", size="sm", floating (pinned bottom-right).

README.md
[![Built on Origin](https://origin.dogesoft.io/shared/badge/built-on-origin-dark.svg)](https://plugs.dogesoft.io)

Every plug page on Origin Plugs, every finished build on Origin and the Plugs studio hands you this snippet with your plug filled in.

Reference

Read API

Base: https://explorer.dogesoft.io/api. GET, public, JSON. These are the endpoints Origin itself reads.

EndpointGives you
/healthIndexed height, chain tip, DRC-20 ledger height, staleness
/wallet/address/{addr}/balanceDOGE balance in koinu, UTXO count
/wallet/address/{addr}/utxosUTXOs and the inscriptions sitting on them
/wallet/address/{addr}/drc20Coin balances: balance, available, transferable
/wallet/address/{addr}/historyRecent confirmed activity
/tx/{txid}Confirmations, mempool flag, raw hex
/explorer/tx/{txid}Decoded DRC-20 operations and inscriptions
/explorer/drc20/{tick}Coin deploy, supply, holders
/explorer/inscriptions/{id}Owner, location, genesis, content hash, collections
/content/{id}The content, reassembled from chain (no /api prefix)
/explorer/collectionsCollections (max 200 per page, use offset)
/explorer/collections/{id}/itemsItems in a collection
Going deeper. Tickers in paths are case- and symbol-sensitive, so URL-encode them (du%24t). The decoded-tx endpoint can take several seconds on busy transactions, so cache what you can.

Reference

Origin contract Draft

One entry point on DogeOS. Every method is a view, and every answer carries the L1 height it was true at.

The full, compiled interface lives in the ABI explorer (download: Origin.json, OriginPlugs.json). The calls you’ll use most:

IOrigin.sol (excerpt)
function drc20Balance(string calldata dogeAddress, string calldata tick)
    external view returns (uint256 amount, uint64 l1Height, uint64 attestedAt);
function collectionCount(string calldata dogeAddress, string calldata collectionId)
    external view returns (uint256 count, uint64 l1Height, uint64 attestedAt);
function isInscriptionOwner(string calldata inscriptionId, string calldata dogeAddress)
    external view returns (bool);
function inscriptionValid(string calldata inscriptionId)
    external view returns (bool ok, bytes32 contentHash, uint64 l1Height);
function drc20Supply(string calldata tick)
    external view returns (uint256 minted, uint256 maxSupply, uint64 l1Height);
function txConfirmed(bytes32 txid, uint256 minConfirmations)
    external view returns (bool ok, uint64 l1Height);
function drc20TransferValid(bytes32 txid) external view returns (bool ok, uint64 l1Height);
function isLinked(address account, string calldata dogeAddress) external view returns (bool);
function inscriptionHasAction(string calldata inscriptionId, string calldata action) external view returns (bool);
function inscriptionMatches(string calldata inscriptionId, bytes32 envelopeHash) external view returns (bool);
function check(bytes32 factType, bytes32 subject, bytes32 key, uint8 op, uint256 threshold, uint64 maxAge)
    external view returns (bool);
function requestFact(bytes32 factType, bytes32 subject, bytes32 key, uint256 plugId)
    external payable returns (uint256 requestId);

Fact types

FactValue
DOGE_BALANCEkoinu
DRC20_BALANCEbase units (amount × 10^decimals)
COLLECTION_COUNTDoginals held from one collection
INSCRIPTION_OWNERkeccak256(bytes(ownerAddress))
INSCRIPTION_VALIDbool + SHA-256 of content
TX_CONFIRMEDbool
DRC20_TRANSFER_VALIDbool

Freshness

Facts are snapshots. Check attestedAt (or l1Height) against your own limit, e.g. one hour for a gate, and reject anything older.

Security model. Shared with the DogeSoft Bridge: every fact needs M-of-N attester signatures (EIP-712, bound to the chain and contract), proves L1 confirmations and carries a signature expiry; older views can never overwrite newer ones; one fact type can be paused instantly and bad facts quarantined; every parameter, role and attester change goes through a timelock. Tested with 62 checks.
Going deeper. Under the hood, facts arrive as threshold-signed messages bound to the DogeOS chain id and the Origin address, the same pattern the Bridge uses. You can verify one inline (pull) or relay it into storage (push). The entry point sits behind a timelocked proxy, so its address never changes. Method signatures are only ever added, never changed.

Reference

Encoding rules

ThingHow Origin encodes it
Dogecoin addressPassed as string. Hashed as keccak256(bytes(addr)), case-sensitive.
TickerPassed as string, exact. Keyed by keccak256(lowercase(tick)).
Inscription idstring like <txid>i0. Keyed by keccak256(lowercase(id)).
CollectionSlug string, e.g. dustinal-dogs.
txidbytes32 = 0x + the txid as explorers display it (no byte reversal).
Amountsuint256 base units. DOGE in koinu.

Reference

Inscriber API

Base: https://inscriber.dogesoft.io. Builds transactions for the user to sign. It never asks for keys.

EndpointDoes
GET /standardThe live inscription standard: envelope and registered actions
POST /prepareflow: doge_send, doginal_send or drc20_transfer. Returns psbt_base64 + unsigned_tx_hex.
POST /drc20-transfer-draftBalance-checked. Inscribes the transfer to the sender and returns the reveal to move.
POST /broadcast{"signed_tx_hex": "…"}
Calling from a browser? The Inscriber only accepts browser requests from allowlisted sites. Call it from your server, or ask DogeSoft to add your domain.

Reference

Inscription standard

Every DogeSoft inscription is an ord envelope. The spec id is dogesoft_inscription_v1.

envelope
OP_FALSE OP_IF "ord"
  OP_1 [content-type]
  [ACTION]          // omitted for DRC-20 text/plain
  OP_0 [payload]
OP_ENDIF

DRC-20 bodies use the plain positional envelope, byte for byte, so every Dogecoin indexer can read them. Other actions add a registered ACTION tag: TRANSFER, SWAP, ADD_LP, LIST, BUY, LAUNCHPAD_MINT, BRIDGE_L1_DEPOSIT and more. The full list is live at GET /standard. The complete spec is on DogeSoft docs.

Don’t invent tags. If an action isn’t registered, indexers won’t recognise it. Ask DogeSoft to register it instead.

Reference

Answers and failures

AnswerMeans
✓ YesTrue on L1 at the stated height, under DogeSoft’s rules.
✕ NoChecked, and not true.
… PendingNot decided yet: too few confirmations, or the DRC-20 ledger hasn’t reached that block.
Ø InfoContext, not a yes/no fact.

Origin fails closed. When data is ambiguous, missing or slow, it doesn’t guess. It says so.

Trust and roadmap

Trust model

Trust and roadmap

Origin Proof Planned

Prove something about a wallet’s Dogecoin history without showing all of it.

Examples: active for more than two years, used on 100 different days, held a Doginal from a collection since 2024, has created coins. These are activity and Sybil-resistance signals, not identity. A wallet is not a person, and Proof will never claim it is. No KYC, no names, no documents.

Trust and roadmap

OP_CHECKZKP Planned

A draft Dogecoin soft fork (discussion #3869) that would let scripts verify zero-knowledge proofs.

It redefines OP_NOP10 (0xB9) as OP_CHECKZKP, with a Groth16 / BLS12-381 mode and a Halo2-KZG / BN256 mode. It isn’t activated, and Dogecoin Core hasn’t agreed to it.

DogeSoft plans to index it in shadow mode. That means detecting every use from the first block, checking the proofs, and labelling them not consensus-enforced until activation. If it activates, the full history is already there, and Origin can treat a verified proof as a native L1 fact.

Trust and roadmap

FAQ

Do I need an API key?

No. Reads are public and rate-limited.

Does it cost anything?

Reading is free. Writing to Dogecoin costs the normal network fee.

Is there a Dogecoin testnet?

Origin reads Dogecoin mainnet. DogeOS is on testnet (Chikyū) today.

Why does a balance show “transferable”?

Those coins are locked inside a transfer inscription that hasn’t moved yet. See DRC-20 coins.

Can Origin move coins for my users?

No. It builds the request; the user’s wallet signs it.

Something looks wrong.

Every answer links to the raw record it came from. Send that link to DogeSoft.