TrustedTools reseller API

Connect your store to an owner-approved catalog. API orders use your existing main wallet. Purchase access and published products must be enabled by the owner.

Browse the Swagger API reference · Download OpenAPI · Safe Postman collection · Python adapter · Client examples

Use the Reseller API button in your private bot chat to request access. After owner approval, create a key and save it on your server. Never put the key in browser code, screenshots or URLs. The full key is shown once. Keys expire after 90 days and can be revoked in the bot. Creating a new key before revoking the old one allows a planned transition; revoke immediately if a key is exposed.

Your normal bot wallet is the only wallet. There is no transfer to a separate API balance. Read-only keys cannot purchase or read credentials. Purchase keys include quote, order, delivery and claim scopes. Manage keys and one-time portal sign-in links in your private bot chat.

Requests

Use HTTPS at your store's configured public domain. Replace the example host below. These examples are safe reads:

curl https://YOUR_STORE/reseller/v1/me \
  -H "Authorization: Bearer $TRUSTEDTOOLS_API_KEY"
curl https://YOUR_STORE/reseller/v1/wallet \
  -H "Authorization: Bearer $TRUSTEDTOOLS_API_KEY"
curl 'https://YOUR_STORE/reseller/v1/products?after=0' \
  -H "Authorization: Bearer $TRUSTEDTOOLS_API_KEY"

GET /me returns your API account, status and permitted read scopes. GET /wallet returns spendable balance_minor, settled posted_minor and reserved_minor. All amounts are USD cents: 350 means $3.50. Reservations reduce spendable balance without charging it.

GET /products returns up to 50 explicitly published, visible and active products. Pass the returned next_cursor as after on the next request. An empty cursor ends pagination. Changes during traversal can alter results; periodically refresh the complete catalog. Descriptions are untrusted plain text. Prices and stock are informational snapshots. stock_observed_at is when the API observed local stock, not proof of a fresh upstream supplier sync. can_purchase and availability_reason reflect purchasing controls and availability; acceptance revalidates price, funds and stock.

Fetch GET /categories for published hierarchy/counts. Poll GET /catalog/changes?after=0, then continue from the last event cursor. A product event instructs GET /products/ID; remove the item locally when it returns 404. A null product ID instructs a full catalog refresh. Image paths point to protected managed assets: fetch them using the same key, never expose that key in a public image URL.

Purchase safely

One product per order. Use a durable customer reference and one stable retry key. The example below spends real funds if run with an approved purchase key; use /sandbox/orders with synthetic product ID 1 to test first.

POST /reseller/v1/orders
Authorization: Bearer YOUR_PURCHASE_KEY
Idempotency-Key: your-stable-order-request-123
Content-Type: application/json

{"product_id":123,"quantity":1,"client_order_id":"your-customer-order-123","max_total_minor":350}

The server-calculated total must not exceed max_total_minor. Alternatively create POST /quotes with product_id and quantity, then pass its quote_id. Quotes last 60 seconds and reserve price only, never stock or funds. Using both a quote and maximum enforces the maximum too. Exact retries recover the accepted order even after quote expiry or API-key rotation. Changing data with the same key or client reference returns 409; do not replace the key/reference after a timeout.

Read GET /orders/ID after acceptance. Local reusable/pool inventory can deliver immediately. Manual delivery remains awaiting_manual with funds reserved. Supplier work goes through queued and processing. needs_review can mean the supplier already charged; wait for support rather than buying again. Funds are captured only with durable delivery. Definitive no-purchase cancellation releases the hold. Supplier quantities are currently limited to one and automatic products without custom inputs; unsupported/deferred product modes are rejected or returned for review before purchase.

Fetch GET /orders/ID/delivery using delivery:read after delivery becomes available. Responses contain unit numbers, immutable delivery versions and private content. Repeated reads never allocate more stock. Delivery is encrypted at rest. Treat responses as secrets and never include them in logs or public support tickets.

Cancel queued or awaiting-manual orders using POST /orders/ID/cancel, an empty JSON object and a stable Idempotency-Key. An upstream attempt, delivered order, or review state cannot be cancelled by the reseller. GET /orders?before=ID and GET /claims?before=ID return up to 50 newest records; continue before the last ID.

Claims, replacements and refunds

Open POST /orders/ID/claims with unit, category (access, warranty or other) and a description. One open claim per unit; automatic warranty eligibility uses the coverage configured when the order was accepted and begins at delivery. A display label alone grants no automatic warranty. Support can review general access issues separately.

Read claim details and post follow-ups to /claims/ID/messages. Evidence accepts JPG, PNG and TXT (maximum 80,000 decoded bytes, five files) as base64 JSON at /claims/ID/evidence. Evidence is encrypted, private and downloaded only after ownership checks. Support can replace a unit with a new delivery version or refund it once to the main wallet. A refunded credential never returns to sellable stock. Your refund to your own customer does not automatically authorize a TrustedTools refund.

Sandbox

/sandbox/products, /sandbox/wallet, /sandbox/orders and synthetic order/delivery reads never use real balances, inventory or suppliers. Product ID 1 costs 100 test cents. The fixture balance is fixed at 10,000 test cents; synthetic orders are bounded per account and reset on server restart. Sandbox IDs start with sbx_ and cannot be used as real order IDs. This tests the client contract; it does not simulate every production failure.

Signed webhooks

Configure an optional public HTTPS callback in the reseller workspace, with a separate signing secret shown once. The owner controls global dispatch. Events contain stable IDs, type, order ID, state snapshot, timestamp and schema_version; they never contain delivery credentials. Polling remains authoritative.

Verify X-TrustedTools-Signature: t=TIMESTAMP,v1=HEX using HMAC-SHA256 over the exact bytes TIMESTAMP + "." + raw_body, keyed by the signing secret as its UTF-8 text. Compare in constant time, allow a small timestamp window (for example five minutes), deduplicate the event ID, and tolerate retries/out-of-order events. Fetch the current order/delivery separately. Secret rotation signs future attempts with the new secret.

Callbacks require public HTTPS on port 443. Private/metadata IPs, non-public DNS results, redirects and proxy environment routing are blocked. Each connection resolves and validates its destination before dialing the validated IP. Attempts have bounded time/response limits, exponential backoff, at most 12 tries and a 24-hour event window. Notification failure never repeats or refunds a purchase. Account security and low-wallet changes can also generate events.

Errors and limits

Errors have {"error":{"code":"...","request_id":"..."}}. Every response includes X-Request-ID; provide that ID to support. Never send your API key to support.

HTTPMeaning
401Missing, invalid, expired or revoked key, or inactive account.
403Insufficient scope or purchasing not approved/enabled.
404Unknown/unowned resource or API access disabled.
409State/idempotency conflict, changed price, unavailable stock, insufficient funds or spending/concurrency limit.
415/422JSON required or invalid/ambiguous data. Unknown and duplicate members are rejected.
429Rate limit. Observe Retry-After.
503Temporary unavailability. Retry an accepted purchase using exactly the same request identity.

Read limit: one request per second per account with a burst of ten. Keys for the same account share this limit. A global capacity limit can also return 429. Back off on 429/503; do not loop immediately. The service never returns supplier costs, upstream API keys or delivery credentials in its catalog. Account suspension blocks all keys; closing an account revokes its keys and preserves the ordinary wallet.

API writes are bounded to 128 KB JSON. Account daily spending and concurrent open-order limits persist across restarts and keys. Default account approval is manual; default purchase limit is $100 per UTC day and two open orders, with quantity configurable up to 100 for local products. The owner may lower limits or pause buying without removing order history.

Download the versioned OpenAPI contract. Portal authentication uses a one-time five-minute bot link, then a secure HttpOnly SameSite session with idle/absolute expiry and CSRF protection. Portal cookies do not authorize the machine API or owner panel. For support use your order/request IDs, never your API key or plaintext credentials.