{"openapi":"3.1.0","info":{"title":"SwapR API","version":"1.0.0","description":"REST over HTTPS, JSON in and out. Authenticate with a member-issued key (X-API-Key: sk_\u2026 or Authorization: Bearer sk_\u2026). Keys act as the member who issued them."},"servers":[{"url":"https://www.myswapr.com"}],"paths":{"/api/v1/me":{"get":{"operationId":"getMe","summary":"The account behind the key \u2014 id, name, email, role, verification, market","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"The account behind the key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/listings":{"get":{"operationId":"listListings","summary":"?limit=&offset=&mine=1 \u00b7 public active feed, or only your own listings","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"A page of the active feed, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"mine","in":"query","schema":{"type":"string","enum":["1"]},"description":"Only your own listings"}],"x-required-scope":"listings:read"},"post":{"operationId":"createListing","summary":"JSON body \u00b7 Idempotency-Key supported \u00b7 fires listing.created","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"201":{"description":"The listing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingCreated"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique per request: a retry replays the first response instead of creating a duplicate listing."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingCreate"}}}},"x-required-scope":"listings:write"}},"/api/v1/offers":{"get":{"operationId":"listOffers","summary":"Last 30 offers sent and received, with listing title and status","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Your last 30 sent and received offers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-required-scope":"offers:read"},"post":{"operationId":"createOffer","summary":"Send an offer: listing_id, amount, optional message and kind","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"201":{"description":"The offer was sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCreated"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCreate"}}}},"x-required-scope":"offers:write"}},"/api/v1/offers/{id}/accept":{"post":{"operationId":"acceptOffer","summary":"Seller accepts a pending offer \u2014 creates the escrow order","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"201":{"description":"Accepted \u2014 the escrow order now exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferAccepted"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"404":{"$ref":"#/components/responses/NotFound"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id"}],"x-required-scope":"offers:write"}},"/api/v1/offers/{id}/decline":{"post":{"operationId":"declineOffer","summary":"Seller declines a pending offer","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Declined.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferDeclined"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"404":{"$ref":"#/components/responses/NotFound"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id"}],"x-required-scope":"offers:write"}},"/api/v1/offers/{id}/withdraw":{"post":{"operationId":"withdrawOffer","summary":"Buyer withdraws their own pending offer","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Withdrawn.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferWithdrawn"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"404":{"$ref":"#/components/responses/NotFound"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id"}],"x-required-scope":"offers:write"}},"/api/v1/offers/{id}/counter":{"post":{"operationId":"counterOffer","summary":"Either side counters: amount required, message optional","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Countered \u2014 a new pending offer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCountered"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Offer id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferCounter"}}}},"x-required-scope":"offers:write"}},"/api/v1/orders":{"get":{"operationId":"listOrders","summary":"?limit=&offset= \u00b7 escrow orders where you are buyer or seller","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"A page of escrow orders you are party to.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"x-required-scope":"orders:read"}},"/api/v1/wallet":{"get":{"operationId":"getWallet","summary":"Balances in USD cents \u2014 read-only by design, never moves money","security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Balances in USD cents.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Wallet"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"x-required-scope":"wallet:read"}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"},"bearerAuth":{"type":"http","scheme":"bearer","description":"Authorization: Bearer sk_\u2026"}},"responses":{"Unauthorized":{"description":"Missing, unknown, revoked or expired API key.","headers":[],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account may not act on that resource.","headers":[],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such resource.","headers":[],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"State conflict: plan allowance, idempotency-key reuse, or an offer that is no longer actionable.","headers":[],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unprocessable":{"description":"Validation failed \u2014 see the error message.","headers":[],"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"More than 60 requests/minute for this key; honour the Retry-After header.","headers":{"Retry-After":{"description":"Seconds until one request ages out of the window.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"Payload":{"type":"object","additionalProperties":true},"Me":{"type":"object","description":"The account a key acts as.","required":["id","name","email","username","role","verified","kyc_tier","market","currency","member_since"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"username":{"type":"string"},"role":{"type":"string","enum":["USER","STAFF","ADMIN"]},"verified":{"type":"boolean"},"kyc_tier":{"type":"integer","minimum":0},"market":{"type":"string","enum":["NG","GH","KE","US","GB","AE"]},"currency":{"type":"string"},"member_since":{"type":"string","description":"ISO 8601 UTC."}}},"Listing":{"type":"object","required":["id","title","description","price_cents","currency","condition","type","status","created_at","owner_name","image"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"price_cents":{"type":"integer"},"currency":{"type":"string"},"condition":{"type":"string","enum":["NEW","LIKE_NEW","GOOD","FAIR"]},"type":{"type":"string","enum":["SALE","SWAP","BOTH"]},"status":{"type":"string","enum":["ACTIVE","RESERVED","TRADED","REMOVED"]},"created_at":{"type":"string"},"owner_name":{"type":"string"},"image":{"type":["string","null"],"description":"First image URL, if any."}}},"ListingList":{"type":"object","required":["listings","count","limit","offset"],"properties":{"listings":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"count":{"type":"integer","description":"Rows in this page."},"limit":{"type":"integer"},"offset":{"type":"integer"}}},"ListingCreated":{"type":"object","required":["created","id","url"],"properties":{"created":{"type":"boolean"},"id":{"type":"string"},"url":{"type":"string","description":"Relative listing page."}}},"Offer":{"type":"object","required":["id","status","created_at","title","price_cents","currency"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING","ACCEPTED","DECLINED","WITHDRAWN","COUNTERED"]},"created_at":{"type":"string"},"title":{"type":"string","description":"Title of the listing offered on."},"price_cents":{"type":"integer"},"currency":{"type":"string"}}},"OfferList":{"type":"object","required":["offers","count"],"properties":{"offers":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}},"count":{"type":"integer"}}},"OfferCreated":{"type":"object","required":["created","id","status","kind","listing_id","amount_cents","url"],"properties":{"created":{"type":"boolean"},"id":{"type":"string"},"status":{"type":"string","enum":["PENDING"]},"kind":{"type":"string","enum":["BUY","SWAP"]},"listing_id":{"type":"string"},"amount_cents":{"type":["integer","null"],"description":"Cash top-up; null for a straight swap."},"url":{"type":"string"}}},"OfferAccepted":{"type":"object","required":["offer_id","status","order_id","url"],"properties":{"offer_id":{"type":"string"},"status":{"type":"string","enum":["ACCEPTED"]},"order_id":{"type":"string"},"url":{"type":"string"}}},"OfferDeclined":{"type":"object","required":["offer_id","status"],"properties":{"offer_id":{"type":"string"},"status":{"type":"string","enum":["DECLINED"]}}},"OfferWithdrawn":{"type":"object","required":["offer_id","status"],"properties":{"offer_id":{"type":"string"},"status":{"type":"string","enum":["WITHDRAWN"]}}},"OfferCountered":{"type":"object","required":["id","counter_of","status","amount_cents"],"properties":{"id":{"type":"string","description":"The new counter-offer."},"counter_of":{"type":"string"},"status":{"type":"string","enum":["PENDING"]},"amount_cents":{"type":"integer"}}},"Order":{"type":"object","required":["id","status","is_swap","amount_cents","fee_cents","payout_cents","created_at","seller_shipped_at","buyer_shipped_at","listing_title","side","counterparty"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING_PAYMENT","FUNDED","DISPUTED","RELEASED","CANCELLED","REFUNDED"]},"is_swap":{"type":"integer","enum":[0,1]},"amount_cents":{"type":"integer"},"fee_cents":{"type":"integer"},"payout_cents":{"type":"integer"},"created_at":{"type":"string"},"seller_shipped_at":{"type":["string","null"]},"buyer_shipped_at":{"type":["string","null"]},"listing_title":{"type":"string"},"side":{"type":"string","description":"This key's side of the trade.","enum":["BUY","SELL"]},"counterparty":{"type":"string","description":"The other party's name."}}},"OrderList":{"type":"object","required":["orders","count","limit","offset"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"count":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}},"Wallet":{"type":"object","required":["available_cents","held_cents","currency","note"],"properties":{"available_cents":{"type":"integer"},"held_cents":{"type":"integer","description":"Locked in escrow."},"currency":{"type":"string"},"note":{"type":"string"}}},"ListingCreate":{"type":"object","required":["title","description","price"],"properties":{"title":{"type":"string","maxLength":140},"description":{"type":"string","minLength":10,"maxLength":4000},"price":{"type":"number","exclusiveMinimum":0,"description":"Money units; stored as cents."},"currency":{"type":"string","default":"USD"},"condition":{"type":"string","enum":["NEW","LIKE_NEW","GOOD","FAIR"],"default":"GOOD"},"type":{"type":"string","enum":["SALE","SWAP","BOTH"],"default":"SALE"},"category":{"type":"string","enum":["electronics","fashion","home","collectibles","sports","other"]}}},"OfferCreate":{"type":"object","required":["listing_id"],"properties":{"listing_id":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0,"description":"Money units. Required for BUY offers."},"message":{"type":"string","maxLength":1000},"kind":{"type":"string","enum":["BUY","SWAP"],"default":"BUY"},"swap_listing_id":{"type":"string","description":"Your own active listing \u2014 required when kind=SWAP."}}},"OfferCounter":{"type":"object","required":["amount"],"properties":{"amount":{"type":"number","exclusiveMinimum":0},"message":{"type":"string","maxLength":1000}}}}}}