Search code examples
c#asp.netfile-uploadpaypal

Paypal Disputes API returns INVALID_EVIDENCE_FILE when posting file


I'm trying to submit a PDF file as dispute evidence in the Paypal sandbox using the /v1/customer/disputes/" + dispute.ID + "/provide-evidence end point. Whatever I try, the error message from Paypal shows as:

INVALID_EVIDENCE_FILE

I've verified that fileBytes is a valid PDF file by saving it to disk just before posting, and it is. I've also tried sending a JPG as well but receive the same error.

The Paypal docs aren't much help for this issue:
https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_provide-evidence

And don't really provide any help as to how the document(s) should be posted. Likely I am not submitting the data properly, any help in pointing out what I might be doing wrong is much appreciated.

using (var httpClient = new HttpClient())
{
    httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {auth.access_token}");

    using (var request = new HttpRequestMessage(HttpMethod.Post, $"{BaseUrl()}" + path))
    {
        var form = new MultipartFormDataContent();

        dynamic p = new
        {
            evidences = new List<object>
            {

            }
        };
        string strData = JsonConvert.SerializeObject(p);

        var jsonPart = new StringContent(strData);
        jsonPart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
        jsonPart.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        form.Add(jsonPart);

        var byteContent = new ByteArrayContent(fileBytes, 0, fileBytes.Length);
        byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        form.Add(byteContent, fileNameWithExtension);

        using (var response = await httpClient.PostAsync(request.RequestUri, form))
        {
            strResponse = await response.Content.ReadAsStringAsync();
            var statusCode = (int)response.StatusCode;
            if (statusCode is < 200 or >= 300)
            {
                throw new PaypalClientException(strResponse);
            }
        }
    }
}

Solution

  • Apparently, the "Evidence file for dispute" in PayPal can be sent in the following ways through the API, which is described separately:

    1- Uploading the file and sending its link in JSON format

    2- Embedding the file inside the "Request" (as mentioned in the question, this method is not described in detail in PayPal's online documentation)

    3- Using "Braintree Control Panel"

    Method 1 (Uploading the file and sending its link in JSON format):

    According to PayPal's documentation about sending "Evidence" for "customer-disputes", I think the information should be sent in the form of a JSON structure similar to the image below. The name and link of the uploaded files should be placed in the "documents" section.

    If that "Evidence" file is not private and that company has a dedicated site and server, and it is possible in terms of security, upload that file somewhere on your server and then put the link that contains the "AccessId" in the "documents" section. For example like below:

    "documents": [
        {
            "name": "Evidence_12.pdf", 
            "url": "https://example.com/PayPalEvidences/?EvidenceId=12&AccessId=3583597257053jjgfr766"
        }
    ]
    

    It should be noted that the content of each document should not exceed 10 MB and the total size of documents should not exceed 50 MB.

    Evidence

    Also, the "documents" section is defined by the following conditions:

    Documents

    Because the practical implementation of sending "Evidence" has different steps, including registering as a developer in PayPal, I haven't tested it myself at the moment, but if I get the practical C# code in the coming days, I will add more details to the answer.

    Method 2 (Embedding the file inside the "Request"):

    Currently, this method is not clearly explained in PayPal's online documentation and the subject is somewhat ambiguous, but based on the question posted in "PayPal-Community" and the answer to that question written in PHP and claimed to work, it seems that if the information is Multipart, it should have something like the following format and embed the contents of the file as "contents" and the name of the file as "name".

    Note:

    Considering that in the other answer of the question written in Java, the content of the file is embedded with a different name, the name of the field that contains the content of the file may be something else. Further investigation is needed.

    Url: "https://api-m.sandbox.paypal.com/v1/customer/disputes/{dispute_id}/provide-evidence"
    Data:
    [
        'headers': [
            'Authorization': 'Bearer {access_token}',
        ],
        'multipart': [
            [
                'name': 'input',
                'contents':
                {
                    "evidences":
                        [
                            {
                                "evidence_type": "~~~~~~~~~~", 
                                "evidence_info":
                                {
                                    "tracking_info":
                                        [
                                            {
                                                "carrier_name": "~~~~~~~~~~",
                                                "tracking_number": "~~~~~~~~~~"
                                            }
                                        ]
                                }, 
                                "notes": "~~~~~~~~~~"
                            }
                        ]
                },
                'headers': [
                    'Content-Type': 'application/json',
                ],
            ],
            'name': 'file.pdf',
            'contents': ~~~~~~~~~~,
        ],
    ]
    

    Method 3 (Using "Braintree Control Panel"):

    By installing the "Braintree" NuGet package and using a code similar to the one described here, the evidence file can probably be sent:

    var documentRequest = new DocumentUploadRequest
    {
        DocumentKind = DocumentUploadKind.EVIDENCE_DOCUMENT,
        File = System.IO.File.Open("local_file.pdf", FileMode.Open)
    };
    
    Result<DocumentUpload> documentResult = gateway.DocumentUpload.Create(documentRequest);
    
    if (documentResult.IsSuccess())
    {
        Result<DisputeEvidence> result = gateway.Dispute
            .AddFileEvidence("a_dispute_id", documentResult.Target.Id);
    }