Base URLs
| Environment | Base URL |
|---|---|
| Production | https://api.phygitals.com |
| Sandbox | https://api.phygitals.com/_ |
/api/v1/. The sandbox mirrors every production route under /_/api/v1/. For example:
| Production | Sandbox |
|---|---|
GET /api/v1/vm/available | GET /_/api/v1/vm/available |
POST /api/v1/vm/buy/init | POST /_/api/v1/vm/buy/init |
POST /api/v1/vm/buyback | POST /_/api/v1/vm/buyback |
API keys
Two key tiers are issued by Phygitals:Production keys
Identify your partner account and authorize live purchases, sellbacks, and shipments. Contact hello@phygitals.com to request one.
Sandbox keys
Prefixed with
sandbox-. Authorize the sandbox environment at /_/api/v1/*. Do not identify a partner. Never produce real money movement, on-chain transactions, or shipments. Use them to integrate without consuming inventory.401 { "error": "Invalid API key" } is returned for missing, empty, or unrecognized X-API-Key headers on any endpoint, in any environment.
How sandbox differs from production
Read this before integrating. Every behavior below is sandbox-only and must not be relied on in production code paths.State is in-memory and ephemeral
Sandbox state (purchase sessions, simulated inventory, sellbacks, shipping orders) lives in the API server’s memory and is wiped on restart or deploy. Multi-instance deployments do not share state. Treat every sandbox session as fresh.No real fulfillment
The sandbox never touches Alt, PSA, or Fanatics. There are no on-chain transactions, no payment processing, no carrier API calls, and no actual shipping label creation. Every fulfillment is simulated.No row locking on purchases
The same underlying eBay listing can be returned to multiple users from concurrentbuy/init calls. The sandbox does not reserve inventory. Don’t use sandbox to test “two users racing for the same item” scenarios. That’s a production-only behavior.
Synchronous fulfillment
POST /vm/buy/init returns the pulled items immediately. As a result:
POST /vm/buy/statusnever returns the{ "status": "pending" }envelope in sandbox. It returns either the fulfilled{ result: ... }payload or400 { "error": "Transaction failed" }.- Production keeps the polling envelope as-is, so build your client to handle pending. Sandbox just won’t exercise that branch.
No idempotency
CallingPOST /vm/buy/init twice with identical bodies produces two distinct session_ids and stacks the items in inventory. Don’t rely on idempotency keys in sandbox.
No rate limiting
The sandbox never returns429. Rate limits exist in production but are not enforced here.
Frozen pricing on sellback
Theamount returned from POST /vm/buyback equals the buyback_price assigned at buy/init time. Prices are frozen and there is no Alt oracle re-fetch. Production re-prices live at sellback time.
No vouchers
Voucher / promo logic on sellbacks is production-only.Address validation is real; country allow-list is stubbed
destinationis validated end-to-end through the Google Address Validation API.GOOGLE_MAPS_API_KEYmust be configured server-side for/ship/quoteto succeed. When the key is missing, or when Google returns a non-2xx, every quote 400s with{ "error": "Invalid destination address", "details": "Validation failed: internal error" }— the validator fails closed rather than letting bad addresses through. Successful validation returns{ "error": "Invalid destination address", "details": ..., "suggested": ... }for invalid input.countryis also checked separately for length (must be 2 chars). Any 2-character string is accepted, including"ZZ". Production validates against an actual carrier-supported allow-list.
Shipping orders never advance
A successfulship/request in sandbox creates an order with status: "queued" and stays queued. tracking_number, tracking_url, shipped_at, and delivered_at remain null for the lifetime of the sandbox process. Production cycles through queued → processing → label_created → shipped → delivered.
Sandbox is scoped by user_id only
Partner identity is not derived from the API key in sandbox. All sandbox state is isolated by the user_id you submit. In production, scoping is partner-aware.
Production-only features
Don’t integrate against these in sandbox. They’re stubbed or absent and behavior will diverge:429rate-limit responses on/vm/buyback(no concurrency control in sandbox).- The
{ status: "pending" }polling envelope on/vm/buy/status. - The
{ order_id: null, status: "error", error_message }envelope on/ship/request. - Webhook callbacks for shipping status transitions or fulfillment events.
- Voucher / promo logic on sellbacks.
- Real Alt pricing-oracle FMV refresh on sellback.
- Real country allow-list for shipping.
- Real inventory reservation. The same listing can be pulled by multiple users.
- Cross-process / cross-deploy state persistence.