Ticker
PELUONLINENETSUIESCROWSCANPELUSIUM · LIVE CHAINPELUONLINENETSUIESCROWSCANPELUSIUM · LIVE CHAINPELUONLINENETSUIESCROWSCANPELUSIUM · LIVE CHAINPELUONLINENETSUIESCROWSCANPELUSIUM · LIVE CHAIN

Builder API

Use Pelusium from your own dApp to list collateralized haul jobs, read the open job board, publish partner Cargo Well asks, and share flight numbers (PELU-…) with couriers. Settlement and protocol fees are enforced on-chain when jobs are created and delivered.

This page is for integrators (wallets, marketplaces, companion apps). Player guides live under Introduction.

Overview

LayerRole
@pelusium/sdkBuild Sui Programmable Transaction Blocks (create, accept, pickup, deliver) and call the Pelusium HTTP API.
Pelusium backendIndexes on-chain events, pathfinding for routes, async listing intents, partner listings, and public read APIs.
Move (haul_contract)Escrow, courier bond, treasury fees, and delivery rules.
Your dApp  --sign PTB-->  haul_contract (Sui)
                              |
                              v
                   Pelusium backend  -->  /api/logistics/*
                              |
                              v
                        Cargo Well (market prints)

Base URL

All requests use the Pelusium API host (see the API base URL at the top of the interactive reference). Paths such as /api/logistics/jobs/ are appended to that host.

Install the SDK

npm install @pelusium/sdk @mysten/sui

Package: npmjs.com/package/@pelusium/sdk.

Network defaults: STILLNESS_TESTNET (packageId, protocolConfigId, haulConfigId).

Wallet proofs (write endpoints)

Several POST routes require a wallet proof: the user signs a short UTF-8 message with their Sui wallet. The proof does not move funds; it authorizes an off-chain action (intent creation, confirmation, or partner listing).

Message format (lines must match exactly):

Nebulas Logistics database authorization
Address: 0x…
Action: <action-id>
Issued At: <ISO-8601 timestamp>
Nonce: <unique string>
This signature only authorizes a database write. It cannot move funds.

Send the proof in JSON as:

{
  "proof": {
    "address": "0x…",
    "message": "<full message string>",
    "signature": "<base64 signature>"
  }
}

The SDK exports buildWalletProofMessage and PELIUSIUM_WALLET_PROOF_ACTIONS for the standard action ids.

ActionUsed for
logistics.intent.createPOST /api/logistics/intents/create-haul/
logistics.intent.confirmPOST /api/logistics/intents/{intentId}/confirm/
shop.partnerListing.upsertPOST /api/shop/partner-listings/
shop.partnerListing.cancelPOST /api/shop/partner-listings/{id}/cancel/
logistics.bounty.acceptPOST /api/logistics/flights/{flightNumber}/bounty/

Proofs expire after about 10 minutes. Nonces are single-use.

Public read API

MethodPathDescription
GET/api/logistics/jobs/?status=open&kind=haul&type_id=Open haul jobs (optional filters: limit, max_hops)
GET/api/logistics/prices/?type_id=Implied goods SUI per unit and freight stats (type_id required; cached ~30s, 30/min per IP)
GET/api/logistics/flights/{PELU-…}/Flight detail: route, lifecycle, digests
GET/api/logistics/bounty-board/Jobs where shipper and courier opted into bounty visibility

Jobs with goods_mist > 0 contribute Cargo Well market prints alongside shop listings.

Async haul listing

Recommended flow when you want Pelusium to compute a route before the shipper signs on-chain:

  1. POST /api/logistics/intents/create-haul/ — Body includes proof (logistics.intent.create), wallet, both SSU ids, both solar system ids, cargo typeId, quantity, freightMist, requiredBondMist, optional goodsMist, optional source, optional sellerAllowsBounty. Default generateRoute: true. Returns HTTP 202 with intentId and pollUrl.
  2. GET /api/logistics/intents/{intentId}/ — Poll until status is ready, failed, or expired.
  3. Build the create transaction with SDK buildCreateHaulJobTxFromIntent(ready.buildArgs); user signs and executes on Sui.
  4. POST /api/logistics/intents/{intentId}/confirm/ — Body: digest, wallet, proof (logistics.intent.confirm). Returns flightNumber (PELU-…).

When status is ready, the intent includes buildArgs, route (distanceLy, hopCount, hops, summary), and fee inputs for the PTB.

SDK example

import {
  STILLNESS_TESTNET,
  buildCreateHaulJobTxFromIntent,
  confirmLogisticsIntent,
  createHaulIntent,
  waitForLogisticsIntent,
} from "@pelusium/sdk"

const BACKEND = process.env.PELUSIUM_BACKEND_URL ?? "https://api.pelusium.world"

const pending = await createHaulIntent(BACKEND, {
  proof: createProof,
  wallet,
  characterId,
  pickupSsuId,
  dropoffSsuId,
  pickupSystemId: 101,
  dropoffSystemId: 202,
  typeId: 12345,
  quantity: 10,
  freightMist: 10_000_000,
  requiredBondMist: 5_000_000,
  goodsMist: 50_000_000_000,
  source: "your-app-id",
})

const ready = await waitForLogisticsIntent(BACKEND, pending.intentId)
if (ready.status !== "ready" || !ready.buildArgs) throw new Error(ready.error ?? "Not ready")

const tx = buildCreateHaulJobTxFromIntent(ready.buildArgs)
const { digest } = await signAndExecuteTransaction({ transaction: tx })
const confirmed = await confirmLogisticsIntent(BACKEND, pending.intentId, digest, wallet, confirmProof)
console.log(confirmed.flightNumber)

Direct on-chain create (no intent)

If you already know both SSUs and do not need Pelusium route metadata on the board:

import { STILLNESS_TESTNET, buildCreateHaulJobTx } from "@pelusium/sdk"

const tx = buildCreateHaulJobTx({
  packageId: STILLNESS_TESTNET.packageId,
  protocolConfigId: STILLNESS_TESTNET.protocolConfigId,
  haulConfigId: STILLNESS_TESTNET.haulConfigId,
  freightPaymentMist: 10_000_000n,
  goodsPaymentMist: 0n,
  pickupSsU: "0x…",
  dropoffSsU: "0x…",
  typeId: 12345n,
  quantity: 10,
  slaDurationMs: 86_400_000n,
  requiredBondMist: 5_000_000n,
})

Authorize each SSU once with buildAuthorizePelusiumExtensionTx. Typical courier path after create: buildAcceptHaulJobTx → pickup owner buildApproveHaulPickupTx (may also run while job is still open) → buildExecuteHaulPickupTxbuildExecuteHaulDeliverTx.

Dry run

Set dryRun: true on createHaulIntent (or on partner listing payloads) to validate inputs, routing, and PTB build args without publishing a listing or submitting a transaction. Dry-run intents follow the same poll lifecycle but cannot be confirmed, appear on the job board, or feed Cargo Well. They expire after about 15 minutes (expiresAt in the response).

Grand Exchange (goods + freight books)

Pelusium match mode is goods first, freight rests. Settlement is always create_haul_job (SDK buildCreateHaulJobTx / buildCreateHaulJobTxFromIntent) — there is no separate order-escrow Move module.

ReadMeaning
GET /api/shop/buy-orders/Goods bids. Matchable rows have dropoffSsU and freightMist. ?wallet= lists a shipper’s resting bids.
GET /api/shop/matches/Pending crosses (bid ≥ ask, dest SSU present). fillQty is the partial-fill slice. Nested listing + buy order.
GET /api/shop/freight-asks/Courier standing asks (min freight, optional type / max hops).
GET /api/logistics/jobs/?status=open&shipper=Open hauls that are the freight book after a goods cross.

When a new listing or bid lands, the matcher (match_shop_books) upserts pending crosses. Your dApp can poll GET /api/shop/matches/ (fillQty, nested listing + bid) and deep-link the buyer to Pelusium Prefill haul. The matcher does not call POST /api/logistics/intents/create-haul/ for you (that route still needs the buyer’s wallet proof). If the buyer already has a live signed create-haul intent (same type and dropoff SSU), the matcher binds that intent — pickup, fillQty, freight, listing/bid ids — and re-queues the listing worker. Confirm the signed create as usual.

Partial fills reduce listing and buy-order quantity; one haul per slice. shop.applyListingAfterFreightJobPurchase (wallet proof) can attach buyOrderId and haulJobId after create.

Courier fill of a freight ask is still a signed accept_haul_job when Open-haul freight ≥ the ask (Prefill may set designated courier to the earliest matching ask). After accept, the indexer marks that courier’s matching ask filled.

Partner Cargo Well listings

List cargo in Cargo Well without creating a haul yourself. The seller signs shop.partnerListing.upsert, then:

POST /api/shop/partner-listings/
Content-Type: application/json
{
  "payload": {
    "source": "your-app-id",
    "externalListingId": "listing-123",
    "externalUrl": "https://your.app/listings/123",
    "sellerWallet": "0x…",
    "pickupSsuId": "0x…",
    "pickupSystemId": 300001,
    "pickupSystemName": "Stillness",
    "characterId": "0x…",
    "ownerCapId": "0x…",
    "typeId": 12345,
    "quantity": 10,
    "priceSui": 50,
    "note": "Optional description"
  },
  "proof": { "address": "0x…", "message": "…", "signature": "…" }
}

priceSui is the total for the full quantity. Repeating the same source + externalListingId updates the row. source is your attribution label.

Cancel with POST /api/shop/partner-listings/{pelusiumListingId}/cancel/ and proof action shop.partnerListing.cancel.

SDK helpers: upsertPartnerCargoListing, cancelPartnerCargoListing.

When a buyer uses Pelusium Buy & deliver, a verified on-chain create event with matching seller, pickup, cargo, quantity, and goods escrow can decrement the partner listing.

Pickup and delivery (same rules as the Pelusium UI)

Partner listings and async intents are discovery and routing helpers. They do not move cargo or bypass SSU gates. After a haul job exists on-chain, every integrator—Trinary, a wallet, or Pelusium itself—uses the same Move steps:

StepWho signsSDK helperNotes
Authorize Pelusium on SSUPickup and drop-off owners (once per SSU)buildAuthorizePelusiumExtensionTxRequired before pickup/deliver
Create haul jobShipper (often buyer)buildCreateHaulJobTx or buildCreateHaulJobTxFromIntentLocks freight + optional goods escrow
Accept jobCourierbuildAcceptHaulJobTxLocks bond
Approve pickupPickup SSU OwnerCap holder (seller)buildApproveHaulPickupTxAnti-raid — partner API cannot skip
Execute pickupCourierbuildExecuteHaulPickupTxNeeds freighter character id
Execute deliverCourierbuildExecuteHaulDeliverTxDrop-off SSU must be authorized
Partner listing (HTTP)     →  Cargo Well row only
Buyer Buy & deliver / intent →  create_haul_job (on-chain)
Seller                       →  approve_haul_pickup
Courier                      →  accept → execute_pickup → execute_deliver

Integration patterns:

  • Pelusium-hosted legs — List via API; deep-link buyers to www.pelusium.world for create, approve, pickup, and deliver UX.
  • Embedded SDK — Your app builds and prompts for each PTB; users still need EVE characters and SSU authorization in-game.
  • Hybrid — Partner app for listing + checkout prefills; couriers and sellers use Pelusium Shipping for approve/pickup/deliver.

Goods escrow on create pays the goods_seller wallet you set in the listing or intent—the same wallet that should approve pickup when it owns the pickup SSU.

Bounty board

On create intent, set sellerAllowsBounty. After the courier accepts on-chain, they may opt in:

POST /api/logistics/flights/{flightNumber}/bounty/

Body includes proof action logistics.bounty.accept and the finalized accept transaction digest. The flight appears on /api/logistics/bounty-board/ only when both sides have opted in.

Fees and limits

  • Protocol fees (treasury, goods fee, creation fee) are charged in Move at create/settle time. There is no separate API billing tier.
  • Write endpoints are rate-limited per deployment. Use dry run for integration testing instead of hammering create routes.
  • The insurance HTTP API is reserved for the Pelusium app and is not part of this builder surface.

Prerequisites

  • Sui wallet and network SUI for escrow, bond, and gas
  • Pelusium extension authorized on pickup and drop-off SSUs
  • Correct package / config object ids for your network (STILLNESS_TESTNET on the default Stillness testnet deployment)

Links