Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
contact:
email: partner-api@wish.com
x-wish-dev-contact:
assignee: kwei
email: marketplace-external-api@contextlogic.com
description: 'Wish Marketplace V3 API
# General Information
The Wish Marketplace API will be using oAuth to authenticate in order to offer better security for its users
* Learn about oAuth here.'
version: 3.0.65
title: Wish Marketplace V3 Tickets API
servers:
- url: https://merchant.wish.com
description: V3 API endpoint
security:
- OAuth2: []
tags:
- description: For each consumer question or complaint, a ticket is created to manage the dialogue between you, Wish, and the consumer. With this API, you can fetch tickets awaiting your response, fetch a specific ticket, close a ticket, and reply to tickets.
name: Tickets
paths:
/api/v3/tickets/{id}:
put:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Ticket'
description: successfully updated the ticket
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/APIError'
description: failed to update for the ticket
parameters:
- $ref: '#/components/parameters/ticket_id'
tags:
- Tickets
summary: Update a ticket
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateTicket'
security:
- OAuth2:
- tickets:write
operationId: updateTicket
x-code-samples:
- lang: python_requests
source: "import requests\n\nurl = \"https://merchant.wish.com/api/v3/tickets/{id}\"\n\npayload = \"{\\\"state\\\":\\\"CLOSED\\\"}\"\nheaders = {\n 'content-type': \"application/json\",\n 'authorization': \"Bearer REPLACE_BEARER_TOKEN\"\n }\n\nresponse = requests.request(\"PUT\", url, data=payload, headers=headers)\n\nprint(response.text)"
- lang: javascript_jquery
source: "var settings = {\n \"async\": true,\n \"crossDomain\": true,\n \"url\": \"https://merchant.wish.com/api/v3/tickets/{id}\",\n \"method\": \"PUT\",\n \"headers\": {\n \"content-type\": \"application/json\",\n \"authorization\": \"Bearer REPLACE_BEARER_TOKEN\"\n },\n \"processData\": false,\n \"data\": \"{\\\"state\\\":\\\"CLOSED\\\"}\"\n}\n\n$.ajax(settings).done(function (response) {\n console.log(response);\n});"
- lang: java_unirest
source: "HttpResponse<String> response = Unirest.put(\"https://merchant.wish.com/api/v3/tickets/{id}\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer REPLACE_BEARER_TOKEN\")\n .body(\"{\\\"state\\\":\\\"CLOSED\\\"}\")\n .asString();"
- lang: shell_curl
source: "curl --request PUT \\\n --url 'https://merchant.wish.com/api/v3/tickets/{id}' \\\n --header 'authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --header 'content-type: application/json' \\\n --data '{\"state\":\"CLOSED\"}'"
- lang: php_curl
source: "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, array(\n CURLOPT_URL => \"https://merchant.wish.com/api/v3/tickets/{id}\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"PUT\",\n CURLOPT_POSTFIELDS => \"{\\\"state\\\":\\\"CLOSED\\\"}\",\n CURLOPT_HTTPHEADER => array(\n \"authorization: Bearer REPLACE_BEARER_TOKEN\",\n \"content-type: application/json\"\n ),\n));\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
description: Close/re-open a ticket or appeal to Wish support for the ticket.
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Ticket'
description: successfully queried for a ticket
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/APIError'
description: failed to query for the ticket
parameters:
- $ref: '#/components/parameters/ticket_id'
tags:
- Tickets
summary: Get a ticket
security:
- OAuth2:
- tickets:read
operationId: getTicket
x-code-samples:
- lang: python_requests
source: 'import requests
url = "https://merchant.wish.com/api/v3/tickets/{id}"
headers = {''authorization'': ''Bearer REPLACE_BEARER_TOKEN''}
response = requests.request("GET", url, headers=headers)
print(response.text)'
- lang: javascript_jquery
source: "var settings = {\n \"async\": true,\n \"crossDomain\": true,\n \"url\": \"https://merchant.wish.com/api/v3/tickets/{id}\",\n \"method\": \"GET\",\n \"headers\": {\n \"authorization\": \"Bearer REPLACE_BEARER_TOKEN\"\n }\n}\n\n$.ajax(settings).done(function (response) {\n console.log(response);\n});"
- lang: java_unirest
source: "HttpResponse<String> response = Unirest.get(\"https://merchant.wish.com/api/v3/tickets/{id}\")\n .header(\"authorization\", \"Bearer REPLACE_BEARER_TOKEN\")\n .asString();"
- lang: shell_curl
source: "curl --request GET \\\n --url 'https://merchant.wish.com/api/v3/tickets/{id}' \\\n --header 'authorization: Bearer REPLACE_BEARER_TOKEN'"
- lang: php_curl
source: "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, array(\n CURLOPT_URL => \"https://merchant.wish.com/api/v3/tickets/{id}\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"GET\",\n CURLOPT_HTTPHEADER => array(\n \"authorization: Bearer REPLACE_BEARER_TOKEN\"\n ),\n));\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
description: Get a ticket by its ID
/api/v3/tickets/{id}/replies:
post:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Reply'
description: successfully replied for a ticket
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/APIError'
description: failed to reply for the ticket
parameters:
- $ref: '#/components/parameters/ticket_id'
tags:
- Tickets
summary: Reply to a ticket
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ReplyTicket'
security:
- OAuth2:
- tickets:write
operationId: replyTicket
x-code-samples:
- lang: python_requests
source: "import requests\n\nurl = \"https://merchant.wish.com/api/v3/tickets/{id}/replies\"\n\npayload = \"{\\\"message\\\":\\\"string\\\"}\"\nheaders = {\n 'content-type': \"application/json\",\n 'authorization': \"Bearer REPLACE_BEARER_TOKEN\"\n }\n\nresponse = requests.request(\"POST\", url, data=payload, headers=headers)\n\nprint(response.text)"
- lang: javascript_jquery
source: "var settings = {\n \"async\": true,\n \"crossDomain\": true,\n \"url\": \"https://merchant.wish.com/api/v3/tickets/{id}/replies\",\n \"method\": \"POST\",\n \"headers\": {\n \"content-type\": \"application/json\",\n \"authorization\": \"Bearer REPLACE_BEARER_TOKEN\"\n },\n \"processData\": false,\n \"data\": \"{\\\"message\\\":\\\"string\\\"}\"\n}\n\n$.ajax(settings).done(function (response) {\n console.log(response);\n});"
- lang: java_unirest
source: "HttpResponse<String> response = Unirest.post(\"https://merchant.wish.com/api/v3/tickets/{id}/replies\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer REPLACE_BEARER_TOKEN\")\n .body(\"{\\\"message\\\":\\\"string\\\"}\")\n .asString();"
- lang: shell_curl
source: "curl --request POST \\\n --url 'https://merchant.wish.com/api/v3/tickets/{id}/replies' \\\n --header 'authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --header 'content-type: application/json' \\\n --data '{\"message\":\"string\"}'"
- lang: php_curl
source: "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, array(\n CURLOPT_URL => \"https://merchant.wish.com/api/v3/tickets/{id}/replies\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => \"{\\\"message\\\":\\\"string\\\"}\",\n CURLOPT_HTTPHEADER => array(\n \"authorization: Bearer REPLACE_BEARER_TOKEN\",\n \"content-type: application/json\"\n ),\n));\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
description: Reply to a ticket by its ID. Note that you can only reply to a ticket in the AWAITING_MERCHANT state. Our system will automatically update the ticket state after you reply
/api/v3/tickets:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ListTicketsResponse'
description: successfully queried for a list of tickets
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/APIError'
description: failed to query for the list of tickets
parameters:
- $ref: '#/components/parameters/ticket_types'
- $ref: '#/components/parameters/ticket_states'
- $ref: '#/components/parameters/ticket_limit'
- $ref: '#/components/parameters/ticket_sort_by'
- $ref: '#/components/parameters/updated_at_min_param'
- $ref: '#/components/parameters/updated_at_max_param'
tags:
- Tickets
summary: List all tickets
security:
- OAuth2:
- tickets:read
operationId: listTickets
x-code-samples:
- lang: python_requests
source: 'import requests
url = "https://merchant.wish.com/api/v3/tickets"
querystring = {"types":"SOME_ARRAY_VALUE","states":"SOME_ARRAY_VALUE","limit":"SOME_INTEGER_VALUE","sort_by":"SOME_STRING_VALUE","updated_at_min":"SOME_STRING_VALUE","updated_at_max":"SOME_STRING_VALUE"}
headers = {''authorization'': ''Bearer REPLACE_BEARER_TOKEN''}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)'
- lang: javascript_jquery
source: "var settings = {\n \"async\": true,\n \"crossDomain\": true,\n \"url\": \"https://merchant.wish.com/api/v3/tickets?types=SOME_ARRAY_VALUE&states=SOME_ARRAY_VALUE&limit=SOME_INTEGER_VALUE&sort_by=SOME_STRING_VALUE&updated_at_min=SOME_STRING_VALUE&updated_at_max=SOME_STRING_VALUE\",\n \"method\": \"GET\",\n \"headers\": {\n \"authorization\": \"Bearer REPLACE_BEARER_TOKEN\"\n }\n}\n\n$.ajax(settings).done(function (response) {\n console.log(response);\n});"
- lang: java_unirest
source: "HttpResponse<String> response = Unirest.get(\"https://merchant.wish.com/api/v3/tickets?types=SOME_ARRAY_VALUE&states=SOME_ARRAY_VALUE&limit=SOME_INTEGER_VALUE&sort_by=SOME_STRING_VALUE&updated_at_min=SOME_STRING_VALUE&updated_at_max=SOME_STRING_VALUE\")\n .header(\"authorization\", \"Bearer REPLACE_BEARER_TOKEN\")\n .asString();"
- lang: shell_curl
source: "curl --request GET \\\n --url 'https://merchant.wish.com/api/v3/tickets?types=SOME_ARRAY_VALUE&states=SOME_ARRAY_VALUE&limit=SOME_INTEGER_VALUE&sort_by=SOME_STRING_VALUE&updated_at_min=SOME_STRING_VALUE&updated_at_max=SOME_STRING_VALUE' \\\n --header 'authorization: Bearer REPLACE_BEARER_TOKEN'"
- lang: php_curl
source: "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, array(\n CURLOPT_URL => \"https://merchant.wish.com/api/v3/tickets?types=SOME_ARRAY_VALUE&states=SOME_ARRAY_VALUE&limit=SOME_INTEGER_VALUE&sort_by=SOME_STRING_VALUE&updated_at_min=SOME_STRING_VALUE&updated_at_max=SOME_STRING_VALUE\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"GET\",\n CURLOPT_HTTPHEADER => array(\n \"authorization: Bearer REPLACE_BEARER_TOKEN\"\n ),\n));\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
description: Get all tickets
components:
schemas:
ListTicketsResponse:
items:
$ref: '#/components/schemas/Ticket'
type: array
description: List of tickets returned.
TicketProduct:
type: object
properties:
id:
readOnly: true
type: string
description: ID of the product
format: object-id
ReplyTicket:
type: object
properties:
message:
type: string
description: The message you wish to send, with a max of 2000 characters
format: markdown
UpdateTicket:
type: object
properties:
state:
enum:
- CLOSED
- AWAITING_MERCHANT
- AWAITING_WISH
type: string
description: 'State transition rules: (1) To appeal to wish for a ticket, update the state to be AWAITING_WISH. (2) To re-open a CLOSED ticket (if you have permission), update the ticket to AWAITING_MERCHANT state. (3) To close a ticket, update the ticket to CLOSED state.'
Reply:
type: object
properties:
message:
readOnly: true
type: string
description: Contents of the reply
format: markdown
replied_at:
readOnly: true
type: string
description: Time when the reply was sent
format: date-time
sender:
readOnly: true
enum:
- USER
- MERCHANT
- WISH_SUPPORT
- WISH_AUTOMATED_SUPPORT
- LIVE_CHAT
type: string
description: 'Who sent the reply, can be: user, merchant, wish support, wish automated support, live chat'
supporting_files:
items:
$ref: '#/components/schemas/ReplySupportingFile'
readOnly: true
type: array
description: Supporting files provided in the reply. Image links expire after 60 minutes, users can get a new link everytime they request from the API this reply came from.
Ticket:
type: object
properties:
type:
readOnly: true
enum:
- ORDER
- PRE_PURCHASE
- POST_CUSTOMER_SUPPORT
type: string
description: Type of the ticket
sub_label:
readOnly: true
type: string
description: Wish's sub-label for the ticket
updated_at:
readOnly: true
type: string
description: The time that the ticket was last updated at
resolution_info:
type: object
description: State of the ticket
properties:
closed_at:
readOnly: true
type: string
description: The time the ticket was closed (if applicable)
format: date-time
closed_by:
readOnly: true
enum:
- USER
- MERCHANT
- WISH_SUPPORT
- WISH_AUTOMATED_SUPPORT
- LIVE_CHAT
type: string
description: 'Who closed the ticket, can be: USER, MERCHANT, WISH_SUPPORT, WISH_AUTOMATED_SUPPORT or LIVE_CHAT'
orders:
items:
$ref: '#/components/schemas/TicketOrder'
type: array
description: A list of all orders affected by the ticket.
state:
readOnly: true
enum:
- AWAITING_WISH
- AWAITING_USER
- AWAITING_MERCHANT
- CLOSED
- PERMANENTLY_CLOSED
type: string
description: State of the ticket Tickets in PERMANENTLY_CLOSED state can never be re-opened. Tickets in CLOSED state can be re-opened by merchants who have corresponding permissions
products:
items:
$ref: '#/components/schemas/TicketProduct'
type: array
description: A list of all products affected by the ticket.
buyer_info:
type: object
description: The information of the user who created the ticket
properties:
locale:
readOnly: true
type: string
allOf:
- $ref: '#/components/schemas/Locale'
name:
readOnly: true
type: string
description: Name of the buyer
replies:
items:
$ref: '#/components/schemas/Reply'
type: array
description: A list of all replies to the ticket. Each Reply of the ticket includes the message and the Image Urls (If provided).
opened_at:
readOnly: true
type: string
description: The time the ticket was created
format: date-time
merchant_id:
readOnly: true
type: string
description: The merchant the ticket is for
format: object-id
refund_reason:
readOnly: true
enum:
- OTHER
- SHIPPING_TAKING_TOO_LONG
- USER_NO_LONGER_WANTS_ITEM
- ITEM_DOES_NOT_FIT
- ITEM_IS_DAMAGED
- ITEM_DOES_NOT_MATCH_LISTING
- USER_PLACED_ORDER_BY_MISTAKE
- ITEM_IS_COUNTERFEIT
- ITEM_DOES_NOT_WORK_AS_DESCRIBED
- ITEM_NEVER_ARRIVED
- EMPTY_PACKAGE
- RECEIVED_NOTE_FROM_MERCHANT
type: string
description: The reason the order will be refunded for, depends on the label of the ticket
id:
readOnly: true
type: string
description: Ticket ID
format: object-id
subject:
readOnly: true
type: string
description: The subject for the ticket
APIError:
required:
- code
- message
type: object
properties:
message:
type: string
code:
type: integer
format: int32
ReplySupportingFile:
readOnly: true
type: object
description: The file to support reply, can be image url at present
properties:
url:
type: string
description: Url of the file
format: uri
file_name:
type: string
description: The name of the supporting file
Locale:
type: string
description: A language tag (which is sometimes referred to as a 'locale identifier'). This consists of a 2-3 letter base language tag representing the language, optionally followed by additional subtags separated by '-'. The most common extra information is the country or region variant (like 'en-US' or 'fr-CA'). For more information, see specification [BCP 47](https://datatracker.ietf.org/doc/html/bcp47#section-2).
format: BCP 47
TicketOrder:
type: object
properties:
id:
readOnly: true
type: string
description: ID of the order
format: object-id
parameters:
updated_at_max_param:
schema:
type: string
format: date-time
required: false
description: Show tickets updated before the given date time. Default to the date time of the latest updated ticket if not provided
name: updated_at_max
in: query
ticket_sort_by:
schema:
default: updated_at.desc
pattern: ^updated_at(\.(asc|desc))?$
type: string
required: false
description: Sort results by the given attribute. Enabled attributes are `updated_at`. Default order is `desc`, use `asc` to sort in reverse.
name: sort_by
in: query
ticket_types:
schema:
minItems: 1
items:
enum:
- ORDER
- PRE_PURCHASE
- POST_CUSTOMER_SUPPORT
type: string
type: array
required: false
description: Parameter used to choose which type of tickets to retrieve. Default to list all three types if not supplied.
name: types
in: query
ticket_id:
schema:
type: string
format: object-id
required: true
description: Wish's unique identifier for the ticket
name: id
in: path
updated_at_min_param:
schema:
type: string
format: date-time
required: false
description: Show tickets updated after the given date time. Default to the date time of the earliest updated ticket if not provided
name: updated_at_min
in: query
ticket_states:
schema:
minItems: 1
items:
enum:
- AWAITING_WISH
- AWAITING_USER
- AWAITING_MERCHANT
- CLOSED
- PERMANENTLY_CLOSED
type: string
type: array
required: false
description: Parameter used to choose the state of tickets to retrieve. Default to list tickets in all states if not supplied. Tickets in PERMANENTLY_CLOSED state can never be re-opened. Tickets in CLOSED state can be re-opened by merchants who have corresponding permissions
name: states
in: query
ticket_limit:
schema:
default: 50
minimum: 1
type: integer
maximum: 500
required: false
description: A limit on the number of tickets that can be returned. Limit can range from 1 to 500 items and the default is 50
name: limit
in: query
securitySchemes:
OpenID:
type: openIdConnect
openIdConnectUrl: https://merchant.wish.com/oidc/.well-known/openid-configuration
OAuth2:
type: oauth2
flows:
authorizationCode:
scopes:
payments:write: Update payments
tickets:write: Write customer tickets
epc:read: read EPC info
returns:write: Write returns
returns:read: Read returns
fbw:read: Read FBW
products:read: Read products
payments:read: Read payments
fbw:write: Write FBW
merchant:write: Write merchant
products:write: Write products
ratings:read: Read ratings
videos:read: Read videos
compliance:write: Write Compliance
product_boost:read: Read ProductBoost
listing_quality:read: Read listing quality
webhook:write: Write webhook
orders:read: Read orders
compliance:read: Read Compliance
fbs:read: Read FBS
penalties:read: Read penalties
penalties:write: Update penalties
infractions:read: Read infractions
orders:write: Update orders
merchant:read: Read merchant
notifications:write: Write notifications
announcements:read: Read announcements
product_boost:write: Write ProductBoost
notifications:read: Read notifications
webhook:read: Read webhook
qoo10:read: Read Qoo10
wps_parcel:write: Write WishParcel
wps_parcel:read: Read WishParcel
tickets:read: Read customer tickets
infractions:write: Write infractions
videos:write: Write videos
epc:write: write EPC info
tokenUrl: https://merchant.wish.com/api/v3/oauth/access_token
refreshUrl: https://merchant.wish.com/api/v3/oauth/refresh_token
authorizationUrl: https://merchant.wish.com/v3/oauth/authorize
externalDocs:
url: https://merchant.wish.com/documentation/api/v3/explorer
description: API explorer
x-wish-hidden: false