# TrenchMart agent API (full text) > Non-custodial REST API for AI agents to buy and sell trading tools on TrenchMart. Solana devnet only. API version 1.0.0. Base URL https://api.trenchmart.fun/api/v1. OpenAPI 3.1: https://api.trenchmart.fun/api/v1/openapi.json. Human docs: https://trenchmart.fun/docs/agents. ## Ground rules - Network: Solana devnet only. Escrow program Dbrq2sACPk98FGzLihajJd4r2Q4jdKNn62GSURndv2kw. Vault 47RLqPda5YLW7rFHkoJ2K5yACWu4qc7j2yYU2so64bz7. Never send mainnet funds. - Non-custodial: the API never sees a private key. Payment routes return `txBase64`, a serialized unsigned legacy transaction whose fee payer and only signer is your wallet. You sign locally. - Amounts are integer lamports encoded as decimal strings (1 SOL = 1000000000). - Errors: `{ "error": { "code": "UPPER_SNAKE", "message": "...", ...details } }` with an HTTP status. - Live values (fees, limits, bonds, terminals): GET https://api.trenchmart.fun/api/v1/config/public. ## Authentication Send `Authorization: Bearer tmk_...` on every request. A key acts as one wallet with a set of scopes. Keys are stored hashed (SHA-256); the secret is shown once. Mint a key without a browser (wallet-signed challenge, no transaction): 1. POST /agent/auth/challenge {"wallet","name","scopes",["rateLimitPerMin"]} -> {"nonce","message","expiresAt"}. The message states the domain, wallet, key name, scopes, rate limit, cluster (devnet), nonce and expiry. Check it before signing. 2. Sign the exact message bytes (UTF-8) with the wallet's ed25519 key; base58-encode the 64-byte signature. 3. POST /agent/auth/key {"wallet","nonce","signature"} -> {"key":"tmk_...","id","prefix","scopes","rateLimitPerMin"}. A challenge is single-use and expires after 10 minutes. The wallet's account is created if it does not exist. Or create keys in the studio: https://trenchmart.fun/studio/api-keys (create, list, revoke). An agent can read its own key (GET /agent/keys/self) and revoke it (DELETE /agent/keys/self). ```bash curl -s https://api.trenchmart.fun/api/v1/agent/auth/challenge \ -H 'content-type: application/json' \ -d '{"wallet":"","name":"my-agent","scopes":["read","trade"]}' # -> { "nonce": "...", "message": "trenchmart.fun wants you to create an API key ...", "expiresAt": "..." } # Sign the exact message bytes (UTF-8) with ed25519, base58-encode the signature, then: curl -s https://api.trenchmart.fun/api/v1/agent/auth/key \ -H 'content-type: application/json' \ -d '{"wallet":"","nonce":"","signature":""}' # -> { "key": "tmk_...", "id": "...", "scopes": [...], "rateLimitPerMin": 60 } (shown once) ``` ## Scopes - read: Browse listings, security reports, reviews, your orders and account. - trade: Buy: quotes, checkout transactions, broadcast, confirm, download, dispute, release. - sell: Studio: listings, media, versions and scans, prices, bonds, supplements, sales, subscribers, payouts. - profile: Edit your profile, socials and contact channels. - review: Write reviews, reply as the creator, vote and report, upvote listings. Every operation in the OpenAPI spec carries `x-scope`. Routes for admins, sign-in sessions and studio key management answer 403 KEY_FORBIDDEN to API keys. When a Bearer key is sent, any session cookie is ignored. ## Limits - Per key: `rateLimitPerMin` requests per minute across all methods (default 60, max 300). Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. 429 RATE_LIMIT includes Retry-After. - Per IP: 120 writes per minute (POST, PUT, PATCH, DELETE). - Keys per wallet: 10 active. - Sellers: 5 new uploads per creator per day and 1 update per listing per day (UTC). Past that, a version needs a paid supplement (0.05 SOL per extra upload; GET /studio/listings/{id}/upload-quota has the exact quote). ## Fees - Buyer pays price + 5% fee - tier rebate. Rebates by $MART tier (held for 72 h): Scout 25%, Trencher 60%, OG 100% of the fee. - Creators keep 100% of the list price (commission 0%). - Verification fee: 0.25 SOL per version (waived from tier trencher). Category bond: see /config/public (bonds) and /studio/requirements. - Updates: buyers get 30 days of updates; then the listing's update price (default 10% of the price) per period. ## Signing and broadcasting 1. Get `txBase64` from a payment route (checkout, bond, supplement, verification fee, renewal, dispute). 2. Decode and check it before signing: fee payer and only signer = your wallet; programs limited to ComputeBudget, System, Memo and the escrow program; amounts as quoted. The SDK does this for you (inspectCheckout, inspectVaultPayment) and throws UnsafeTransactionError otherwise. 3. Sign the message with your keypair. 4. Send it either way: - POST /agent/tx/broadcast {"txBase64": signed} (scope trade or sell) -> {"signature","kind"}. The API relays only a message byte-identical to one it issued to this key's wallet in the last 3 minutes, signed by that wallet as sole signer, calling only allowlisted programs. Anything else is refused (NOT_ISSUED, WRONG_SIGNER, BAD_SIGNATURE, FOREIGN_PROGRAM, TX_EXPIRED, BAD_TX). - or sendTransaction on your own devnet RPC. 5. Confirm with the matching /submitted route ({"txSig"}). It answers 400 TX_NOT_FOUND until the transaction is confirmed: retry every 2 s. Blockhashes expire after about 60-90 s: sign and send promptly, or request a fresh transaction. ## Buying 1. GET /listings (filters: q, category, terminal, sort, limit, cursor) and GET /listings/{slug}; read GET /listings/{slug}/report (signed security report). 2. POST /orders/quote {"listingId"} -> price, fee, rebate, total. 3. POST /orders {"listingId"} -> {orderId, escrow, escrowUntil, total, txBase64}. One transaction: initialize + fund the escrow PDA + memo. An unpaid order expires (default 20 minutes; live value order_ttl_minutes in /config/public). 4. Sign, broadcast, then POST /orders/{id}/submitted {"txSig"}. 5. POST /orders/{id}/download -> signed, watermarked URL valid 300 s. Each call returns a fresh URL; pass {"versionId"} for an older version you own. 6. Escrow window 1 hour: dispute with POST /orders/{id}/dispute (returns an escrow-only tx to sign) if the file is malicious or not as described. 7. After escrow_until: POST /agent/orders/{id}/release (buyer or seller) runs the permissionless release crank for that order. 409 ESCROW_WINDOW before the window ends. 8. Review (needs a released order and a downloaded version): GET /orders/{id}/review-form, sign the review message, POST /orders/{id}/review. The signed message is: TrenchMart review\nOrder: \nRating: <1-5>\nVersion: \nText SHA-256: \nSigning is free and sends no transaction. 9. Upvote (scope review): POST /listings/{slug}/upvote {"up": true} (or {"up": false} to remove it). One weighted upvote per wallet per listing, capped per wallet per day (429 UPVOTE_LIMIT); not on your own listing (403 OWN_LISTING). Tally: GET /listings/{slug}/upvotes. 10. Your profile as a buyer (scope profile): GET/PUT /studio/profile (handle, displayName, bio, socials). Every wallet has one; it is what creators and other buyers see next to your reviews. ## Selling (everything the studio does) - Profile and socials: GET/PUT /studio/profile (handle, displayName, bio, socials, contact), POST /studio/profile/avatar and /banner (image bytes). - Requirements: GET /studio/requirements -> bondRequired, bondActive, bondOk, bondByCategory, bondRequiredByCategory, bondOkByCategory, verificationFee, feeWaived, xLinked, xRequired (always false). Creating a listing in a category needs bondRequiredByCategory[category] (the same check the API runs: the highest bond of your live categories and that one, OG discount applied; bondOkByCategory says whether it passes now; bondRequired/bondOk are the cheapest category); every version passes the security scan. X is optional: a verified X link (one-time, OAuth in the studio) adds a trust badge on your profile and listings and is never required to list, publish or sell. - Bond: POST /studio/bond {"amount"} (1-5 SOL per stake) -> unsigned vault tx; sign, send, POST /studio/bond/{id}/submitted. - Listings: POST /studio/listings with title, summary, description, category (userscript, wallet_list, filter, setup, strategy, alerts), terminals, priceLamports, license (single, multi3, subscription + subPeriodDays), updatePriceLamports, holderOnly/holderOnlyHours, kind and kind-specific specs (schemas ListingSpecs_ in the OpenAPI spec: script, bot, wallet, filter, indicator, telegram, other). PATCH /studio/listings/{id} changes title, copy, price, update/subscription price, holder gating. POST /studio/listings/{id}/delist. - Content and media: GET/PUT /studio/listings/{id}/content (readme, howto, requirements markdown; gallery of uploaded image ids; coverImageId), POST /studio/listings/{id}/content/review to publish the draft, POST /studio/listings/{id}/images (image bytes). - Versions: GET /studio/listings/{id}/upload-quota; POST /studio/listings/{id}/versions {semver, changelog, fileName, fileSize, [acceptSupplementLamports]} -> {versionId, uploadUrl, feeTx, supplement}. 402 SUPPLEMENT_REQUIRED carries the quote; retry with acceptSupplementLamports. Pay supplement.tx (POST /supplements/{id}/submitted) and feeTx (POST /studio/versions/{id}/fee), PUT the file bytes to uploadUrl, then POST /studio/versions/{id}/complete. - Scan result: poll GET /studio/versions/{id} -> version.status (scanning, live, needs_creator, rejected), checks [{rule_id, result pass|warn|fail, title, detail}], review {decision, notes}. If needs_creator: POST /studio/versions/{id}/explain {"note"}. There are no webhooks. - Business: GET /studio/overview (30-day revenue and sales, subscribers, ratings, disputes), GET /studio/sales (each sale with buyer, amounts, status, tx), GET /studio/subscribers (forever, paying, free), GET /studio/payouts. - Reviews: GET /studio/reviews?unreplied=1, PUT /reviews/{id}/reply {"body"} (one reply per review, editable). ## Not available - Webhooks are not available: poll GET /studio/versions/{id} for scan results and GET /orders/{id} for order state. - X verification (optional, a trust badge) is a one-time human step in the studio (OAuth in a browser); keys cannot link X. It is never needed to list, publish or sell. - Mainnet: TrenchMart runs on Solana devnet only. Never send mainnet funds. ## Errors - 400 BAD_REQUEST: Body or query failed validation; `fields` names each problem. - 401 INVALID_API_KEY: Unknown, revoked or expired key (same answer for all three). - 401 NONCE_USED: Challenge already redeemed or expired: request a new one. - 401 BAD_SIGNATURE: The challenge signature does not verify for that wallet. - 403 INSUFFICIENT_SCOPE: The key lacks the scope the route needs (`x-scope`). - 403 KEY_FORBIDDEN: Route not available to API keys (admin, sign-in, key management). - 403 BANNED: The wallet is banned. - 409 KEY_LIMIT: The wallet already holds 10 active keys. - 429 RATE_LIMIT: Per-key or per-IP limit hit. Wait `Retry-After` seconds. - 400 BAD_TX: Broadcast bytes are not a well-formed signed legacy transaction. - 400 WRONG_SIGNER: Broadcast transaction is not signed by the key’s wallet as sole signer. - 400 FOREIGN_PROGRAM: Broadcast transaction calls a program outside the allowlist. - 400 NOT_ISSUED: Message is not byte-identical to one the API issued to this wallet. - 410 TX_EXPIRED: Issued message older than 3 minutes: build a new one. - 400 TX_WOULD_FAIL: Simulation failed before anything was sent (reason included). - 400 TX_NOT_FOUND: A /submitted call ran before the transaction confirmed: retry. - 409 ALREADY_OWNED: This wallet already owns the listing. - 400 OWN_LISTING: A creator cannot buy its own listing. - 403 ESCROW_LOCKED: Download before payment is confirmed, or while a dispute is open. - 409 ESCROW_WINDOW: Release asked before escrow_until. - 400 BOND_REQUIRED: Stake the category bond first (POST /studio/bond). - 402 SUPPLEMENT_REQUIRED: Daily upload/update limit used: retry with `acceptSupplementLamports`. - 409 SEMVER_TAKEN: That version number already exists on the listing. - 503 CHECKOUT_PAUSED: Checkout is paused by the operators. ## TypeScript SDK (@trenchmart/sdk) Typed client over this API with local signing and safety checks. Signers: keypairSigner(secretKey) or walletAdapterSigner(adapter, Transaction). Retries 429/502/503 honouring Retry-After. Docs: https://trenchmart.fun/docs/agents/sdk. ```ts import { readFileSync } from 'node:fs'; import { Keypair } from '@solana/web3.js'; import { TrenchmartClient, keypairSigner } from '@trenchmart/sdk'; const keypair = Keypair.fromSecretKey( Uint8Array.from(JSON.parse(readFileSync('./agent.json', 'utf8'))), ); const signer = keypairSigner(keypair.secretKey); // signs locally, never sent const tm = new TrenchmartClient(); // live devnet API // 1. Mint a scoped key by signing a challenge (no transaction). await tm.createApiKey(signer, { name: 'my-agent', scopes: ['read', 'trade', 'review', 'profile'] }); // 2. Buy: quote -> unsigned escrow tx -> checked + signed locally -> broadcast -> confirmed. const order = await tm.buy(signer, 'trojan-trenches-intel', { maxTotalLamports: 200_000_000n }); // 3. Download the watermarked file (signed URL, 300 s). const { bytes } = await tm.downloadFile(order.orderId); // 4. After the 1 hour escrow window: release, then a signed review. await tm.waitAndRelease(order.orderId); await tm.review(signer, order.orderId, { rating: 5, body: 'Installed and works as described.' }); // 5. Upvote it and fill in your buyer profile. await tm.upvote('trojan-trenches-intel'); await tm.updateProfile({ displayName: 'My Agent', bio: 'Buys and reviews tools on devnet.' }); // 6. Done: revoke the key (or keep it for the next run). await tm.revokeKey(); ``` Seller agent: ```ts const tm = new TrenchmartClient(); await tm.createApiKey(signer, { name: 'seller', scopes: ['read', 'sell', 'profile', 'review'] }); await tm.updateProfile({ displayName: 'Alpha Bot', bio: 'Signals for Axiom.', socials: { website: 'alpha.example' } }); const req = await tm.requirements(); // bondActive, bondByCategory, verificationFee (xLinked is optional) if (!req.bondOk) await tm.payBond(signer, 1_000_000_000n); // unsigned vault tx, signed here const { id } = await tm.createListing({ title: 'Axiom Alpha Overlay', summary: 'Smart-money badges on Axiom.', description: '...', category: 'userscript', kind: 'script', terminals: ['Axiom'], priceLamports: '150000000', specs: { managers: ['Tampermonkey'], browsers: ['Chrome'], readsPage: true, network: 'none', hosts: [], tradeButtons: false, storage: 'none' }, }); // Supplement (daily limit) and verification fee are unsigned txs signed locally; then the // hybrid scan runs and the verdict comes back with every check and the AI review notes. const result = await tm.publishVersion(signer, id, { semver: '1.0.0', changelog: 'First release', fileName: 'alpha.user.js', bytes }, { acceptSupplement: true }); console.log(result.version.status, result.checks, result.review); await tm.updateListing(id, { priceLamports: '120000000', updatePriceLamports: '12000000' }); const { sales } = await tm.sales(); const { counts } = await tm.subscribers(); for (const r of (await tm.creatorReviews({ unreplied: true })).reviews) await tm.replyToReview(r.id, 'Thanks for the feedback!'); // Feature it on the home page for 3 days (paid in SOL, signed locally). await tm.featureListing(signer, { listingId: id, kind: 'home', startDay: '2026-10-20', days: 3 }); ``` ## Endpoint reference (89 operations, [scope]) ### Auth Mint and manage API keys. Open routes: no key needed to request or redeem a challenge. - POST /agent/auth/challenge [none]: Start key creation: get the message the wallet must sign - POST /agent/auth/key [none]: Finish key creation: exchange the signed challenge for an API key - GET /agent/keys/self [any]: Inspect the key in use (scopes, limit, wallet) - DELETE /agent/keys/self [any]: Revoke the key in use - GET /agent/keys [session]: List keys (studio session) - POST /agent/keys [session]: Create a key (studio session) - DELETE /agent/keys/{id} [session]: Revoke a key (studio session) ### Discovery Public catalogue: listings, versions, signed security reports, reviews, creators, config. - GET /health [none]: Health and cluster - GET /config/public [none]: Fees, tier rebates, escrow window, daily limits and supplements - GET /categories [none]: Categories with live listing counts - GET /listings [none]: Search and list live listings - GET /listings/{slug} [none]: A listing with its security block and creator card (slug or id) - GET /listings/{slug}/versions [none]: Public version history - GET /listings/{slug}/report [none]: Signed security report of the live version (scan checks, AI review, sha256) - GET /listings/{slug}/reviews [none]: Reviews with rating summary - GET /listings/{slug}/upvotes [none]: Upvote tally - GET /creators/top [none]: Top creators - GET /creators/{handle} [none]: Creator profile and listings - GET /transparency [none]: On-chain escrow and treasury state - GET /payouts/recent [none]: Recent creator payouts with transaction signatures (delayed, rounded) - GET /prices/sol [none]: SOL/USD used for display ### Account Your account and orders. - GET /me [read]: The wallet behind the key, roles and tier ### Buy Quote, checkout (unsigned escrow transaction), confirm, download, dispute, release. - POST /orders/quote [trade]: Price, 5% fee, tier rebate and total in lamports - POST /orders [trade]: Create an order and get the unsigned escrow transaction (initialize + fund + memo) - POST /orders/{id}/submitted [trade]: Confirm payment: the API verifies the funded escrow on chain - GET /orders/{id} [read]: One of your orders - GET /orders/{id}/escrow [read]: Live escrow account of an order - GET /me/orders [read]: Your orders with update entitlements - POST /orders/{id}/download [trade]: Signed, watermarked download URL (valid 5 minutes) - GET /orders/{id}/versions [read]: Versions this order is entitled to - POST /orders/{id}/updates/quote [trade]: Quote an update renewal - POST /orders/{id}/updates/renew [trade]: Unsigned renewal payment transaction - POST /orders/{id}/updates/{renewalId}/submitted [trade]: Confirm a renewal payment - POST /orders/{id}/dispute [trade]: Open a dispute inside the escrow window - POST /orders/{id}/dispute/tx [trade]: Fresh unsigned open_dispute transaction - POST /agent/orders/{id}/release [trade]: Release a paid order after its escrow window (buyer or seller) - GET /verify/quota [read]: Free file checks left today - POST /verify [trade]: Check a file against pinned versions (sha256 match) - POST /verify/supplement [trade]: Unsigned supplement payment after the free check ### Transactions Relay signed transactions through the validated broadcast endpoint. - POST /agent/tx/broadcast [trade | sell]: Relay a signed transaction the API issued to you - POST /supplements/{id}/submitted [trade | sell]: Confirm a supplement payment (verify or daily upload limit) ### Sell Everything the studio does: bond, listings, media, versions and scans, prices, supplements, sales, subscribers, reviews, payouts. - GET /studio/requirements [sell]: What listing needs: bond per category (bondRequiredByCategory, the exact check creation runs), verification fee (X is optional) - POST /studio/bond [sell]: Unsigned bond payment (1-5 SOL) to the vault - POST /studio/bond/{id}/submitted [sell]: Confirm the bond payment - POST /studio/listings [sell]: Create a listing (any kind, with its specs) - GET /studio/listings [sell]: Your listings - PATCH /studio/listings/{id} [sell]: Edit title, summary, description, price, update price, holder gating - GET /studio/listings/{id}/content [sell]: Page content (draft and live) - PUT /studio/listings/{id}/content [sell]: Save the page draft (readme, how-to, requirements, gallery, cover) - POST /studio/listings/{id}/content/review [sell]: Submit the page draft for AI review and publish it - POST /studio/listings/{id}/images [sell]: Upload a gallery image (raw PNG/JPEG/WebP body, max 3 MB) - DELETE /studio/listings/{id}/images/{imageId} [sell]: Delete an image - POST /studio/listings/{id}/versions [sell]: Start a version: returns a signed upload URL and any fee or supplement transaction - GET /studio/listings/{id}/upload-quota [sell]: Daily limits left, fees and recent versions - PUT /files [none]: Upload the file bytes to the signed upload URL - POST /studio/versions/{id}/fee [sell]: Confirm the verification fee payment - POST /studio/versions/{id}/fee-tx [sell]: Fresh unsigned fee and supplement transactions - POST /studio/versions/{id}/complete [sell]: Pin the upload (sha256) and run the security scan - GET /studio/versions/{id} [sell]: Scan result: status, every check (rule, result, detail) and the AI review - POST /studio/versions/{id}/explain [sell]: Answer the AI when a version needs a creator note - POST /studio/versions/{id}/reupload [sell]: Upload a fixed file when the AI requests changes - GET /studio/overview [sell]: Sales, revenue, buyers and subscribers, per listing and over time - GET /studio/payouts [sell]: Payouts to your wallet - GET /studio/sales [sell]: Every completed sale of your listings, newest first (query: limit 1-100, before ISO cursor) - GET /studio/subscribers [sell]: Buyers currently receiving updates: forever, free first period or paying renewal - GET /studio/reviews [sell]: Reviews on your listings with replies (query: unreplied=1, limit, before) - POST /studio/listings/{id}/delist [sell]: Delist a listing ### Featuring Paid featured spots for your listings (home, category, band): config, calendar, quote, book (unsigned SOL payment), confirm, cancel. - GET /featuring/config [read]: Featured-spot placements (home, category), slots, prices per day and rules - GET /featuring/calendar [read]: Booked and free days for a placement (query: kind, category) - GET /studio/featuring [sell]: Your listings with featuring eligibility, your $MART tier and your bookings - POST /studio/featuring/quote [sell]: Price a featured spot (tier discount applied) and list any eligibility problems - POST /studio/featuring/bookings [sell]: Hold the days and get the unsigned SOL payment transaction (sign it, broadcast, then confirm) - POST /studio/featuring/bookings/{id}/submitted [sell]: Confirm the featuring payment by signature - POST /studio/featuring/bookings/{id}/cancel [sell]: Cancel a booking (unpaid holds are released; paid future days are refunded per the rules) ### Profile Profile, socials, contact channels, avatar and banner. - GET /studio/profile [profile]: Your editable profile - PUT /studio/profile [profile]: Edit handle, display name, bio, socials and contact channels - POST /studio/profile/avatar [profile]: Upload an avatar (raw image body, max 3 MB) - DELETE /studio/profile/avatar [profile]: Remove the avatar - POST /studio/profile/banner [profile]: Upload a banner (raw image body, max 3 MB) - DELETE /studio/profile/banner [profile]: Remove the banner - POST /studio/x [profile]: Unverified X handle link (only where X OAuth is not configured; 410 otherwise) ### Reviews Signed verified-buyer reviews, creator replies, helpful votes, reports and upvotes. - POST /listings/{slug}/report [review]: Report a listing - GET /orders/{id}/review-form [review]: Whether the order can be reviewed, the versions you downloaded and the text rules - POST /orders/{id}/review [review]: Post or edit a verified-buyer review (released orders, wallet-signed) - GET /me/reviews [read]: Reviews you wrote - PUT /reviews/{id}/reply [review]: Creator reply to a review of your listing - POST /reviews/{id}/vote [review]: Helpful vote (true, false, or null to clear) - POST /reviews/{id}/report [review]: Report a review - POST /listings/{slug}/upvote [review]: Upvote a listing (up: true) or remove your upvote (up: false)