import Shoply from "@shoplygg/node";
const shoply = new Shoply({ apiKey: process.env.SHOPLY_API_KEY });
const result = await shoply.disputes.saveDraft("DISPUTE_ID");
<?php
require 'vendor/autoload.php';
$shoply = new Shoply\Client(['apiKey' => getenv('SHOPLY_API_KEY')]);
$result = $shoply->disputes->saveDraft('DISPUTE_ID');
import shoply
client = shoply.Client() # reads SHOPLY_API_KEY
result = client.disputes.saveDraft("DISPUTE_ID")
curl --request PUT \
--url https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"words": "<string>"
}
'package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft"
payload := strings.NewReader("{\n \"words\": \"<string>\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"words\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"words\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": null,
"code": null,
"data": {
"id": "ae36fc25-3cea-4d17-acaa-4bdb43d84a0e",
"orderId": "71ed606f-3119-4f9f-b7f7-ecd25740e15b",
"email": "mila@example.com",
"provider": "stripe",
"providerName": "Stripe",
"externalId": "dp_1QdZ8x2eZvKYlo2C",
"reason": "fraudulent",
"reasonText": "Says they did not make the payment",
"stage": "chargeback",
"providerStatus": "needs_response",
"status": "needs_response",
"amount": 49,
"currency": "USD",
"dueAt": "2026-10-27T16:20:19Z",
"answer": {
"state": "draft",
"at": null,
"by": "",
"note": ""
},
"answeredFrom": "provider",
"answerPlace": "your Stripe Dashboard",
"accessTaken": false,
"dateCreated": "2026-10-22T16:20:19Z",
"dateClosed": null,
"order": {
"id": "71ed606f-3119-4f9f-b7f7-ecd25740e15b",
"status": "completed",
"amount": 49,
"currency": "USD",
"dateCreated": "2026-10-10T16:20:19Z"
},
"can": {
"edit": true,
"submit": false,
"accept": false,
"markSubmitted": true
},
"records": [
{
"key": "buyer",
"title": "The Buyer",
"facts": [
{
"key": "email",
"name": "Email",
"value": "mila@example.com",
"strong": false
},
{
"key": "name",
"name": "Name",
"value": "Mila Kowalski",
"strong": false
}
]
},
{
"key": "order",
"title": "The Order",
"facts": [
{
"key": "placed",
"name": "Placed",
"value": "Oct 10, 2026, 4:20 PM UTC",
"strong": false
},
{
"key": "paid",
"name": "Paid",
"value": "Oct 10, 2026, 4:20 PM UTC · $49.00 · Credit/Debit Card (Stripe)",
"strong": false
}
]
}
],
"activity": [
"2026-10-19 16:20 UTC · Opened their order (order page) · 203.0.113.42 (the address they paid from) · Germany · Chrome on Windows"
],
"draft": {
"decision": "fight",
"contacted": "no",
"used": "yes",
"words": "The buyer bought a license key and opened their order again from the address they paid from.",
"saved": true,
"statement": "The buyer bought a license key and opened their order again from the address they paid from.\n\nThe buyer did not contact the store before disputing the payment. What they bought was used.\n\nWhat the store's records show:\n- Email: mila@example.com\n- Name: Mila Kowalski\n- Billing Address: Berlin, Germany\n- Checkout From: 203.0.113.42 · Germany · Chrome on Windows\n- Placed: Oct 10, 2026, 4:20 PM UTC\n…"
},
"files": [],
"after": [
{
"key": "blacklist",
"done": false,
"text": "The buyer is not blacklisted"
},
{
"key": "access",
"done": false,
"text": "Their keys and files are shown to them"
}
],
"history": [
{
"at": "2026-10-19T16:20:19Z",
"what": "The buyer opened their order",
"detail": "203.0.113.42, Germany"
}
]
}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}Save a dispute's answer
Keeps the fields named and leaves the rest, while the answer can still change: nothing has been sent or accepted, and the dispute has not ended. Answers 409 not_answerable after that. Sends nothing anywhere.
Needs the disputes.write permission (Answer Disputes).
import Shoply from "@shoplygg/node";
const shoply = new Shoply({ apiKey: process.env.SHOPLY_API_KEY });
const result = await shoply.disputes.saveDraft("DISPUTE_ID");
<?php
require 'vendor/autoload.php';
$shoply = new Shoply\Client(['apiKey' => getenv('SHOPLY_API_KEY')]);
$result = $shoply->disputes->saveDraft('DISPUTE_ID');
import shoply
client = shoply.Client() # reads SHOPLY_API_KEY
result = client.disputes.saveDraft("DISPUTE_ID")
curl --request PUT \
--url https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"words": "<string>"
}
'package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft"
payload := strings.NewReader("{\n \"words\": \"<string>\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"words\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.shoply.gg/v1/stores/{storeId}/disputes/{disputeId}/draft")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"words\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": null,
"code": null,
"data": {
"id": "ae36fc25-3cea-4d17-acaa-4bdb43d84a0e",
"orderId": "71ed606f-3119-4f9f-b7f7-ecd25740e15b",
"email": "mila@example.com",
"provider": "stripe",
"providerName": "Stripe",
"externalId": "dp_1QdZ8x2eZvKYlo2C",
"reason": "fraudulent",
"reasonText": "Says they did not make the payment",
"stage": "chargeback",
"providerStatus": "needs_response",
"status": "needs_response",
"amount": 49,
"currency": "USD",
"dueAt": "2026-10-27T16:20:19Z",
"answer": {
"state": "draft",
"at": null,
"by": "",
"note": ""
},
"answeredFrom": "provider",
"answerPlace": "your Stripe Dashboard",
"accessTaken": false,
"dateCreated": "2026-10-22T16:20:19Z",
"dateClosed": null,
"order": {
"id": "71ed606f-3119-4f9f-b7f7-ecd25740e15b",
"status": "completed",
"amount": 49,
"currency": "USD",
"dateCreated": "2026-10-10T16:20:19Z"
},
"can": {
"edit": true,
"submit": false,
"accept": false,
"markSubmitted": true
},
"records": [
{
"key": "buyer",
"title": "The Buyer",
"facts": [
{
"key": "email",
"name": "Email",
"value": "mila@example.com",
"strong": false
},
{
"key": "name",
"name": "Name",
"value": "Mila Kowalski",
"strong": false
}
]
},
{
"key": "order",
"title": "The Order",
"facts": [
{
"key": "placed",
"name": "Placed",
"value": "Oct 10, 2026, 4:20 PM UTC",
"strong": false
},
{
"key": "paid",
"name": "Paid",
"value": "Oct 10, 2026, 4:20 PM UTC · $49.00 · Credit/Debit Card (Stripe)",
"strong": false
}
]
}
],
"activity": [
"2026-10-19 16:20 UTC · Opened their order (order page) · 203.0.113.42 (the address they paid from) · Germany · Chrome on Windows"
],
"draft": {
"decision": "fight",
"contacted": "no",
"used": "yes",
"words": "The buyer bought a license key and opened their order again from the address they paid from.",
"saved": true,
"statement": "The buyer bought a license key and opened their order again from the address they paid from.\n\nThe buyer did not contact the store before disputing the payment. What they bought was used.\n\nWhat the store's records show:\n- Email: mila@example.com\n- Name: Mila Kowalski\n- Billing Address: Berlin, Germany\n- Checkout From: 203.0.113.42 · Germany · Chrome on Windows\n- Placed: Oct 10, 2026, 4:20 PM UTC\n…"
},
"files": [],
"after": [
{
"key": "blacklist",
"done": false,
"text": "The buyer is not blacklisted"
},
{
"key": "access",
"done": false,
"text": "Their keys and files are shown to them"
}
],
"history": [
{
"at": "2026-10-19T16:20:19Z",
"what": "The buyer opened their order",
"detail": "203.0.113.42, Germany"
}
]
}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}{
"success": false,
"message": "<string>",
"code": "<string>",
"data": null,
"errors": {}
}Authorizations
A secret API key, made under Developers in the dashboard: Authorization: Bearer shoply_sk_...
Headers
A word of your own for this one change, up to 180 letters, digits, dots, dashes, underscores and colons. Sent again with the same key, the request is not carried out twice: the first answer comes back, with Idempotent-Replay: true.
Path Parameters
The store's ID. A key reaches the store it was made in: GET /key answers which.
The dispute, by its ID.
Body
Whether to fight it or accept it.
fight, accept Whether the buyer contacted the store before disputing. Empty when not said.
, yes, no Whether they used what they bought, or unknown. Empty when not said.
, yes, unknown The store's statement in its own words, up to 10,000 characters. Sent apart from what Shoply recorded.

