| Time | Status | User Agent |  |
| :-- | :-- | :-- | :-- |
| Make a request to see history. |

#### URL Expired

The URL for this request expired after 30 days.

This is part 1 of uploading files to an applicant. In this documentation, you'll be uploading to your account's S3.

> ### Secure data access is required  
> If your call returns with `Secure data access is required`, you'll need to contact [support@fountain.com](mailto:support@fountain.com) to enable your account to access secure data.

Part 2 is to link the file to the applicant. See next article on [Link Applicant to Files in S3](https://developer.fountain.com/reference/link-applicant-documents) to complete the upload to the applicant.

### Python

```python
import json
import xml.etree.ElementTree
import mimetypes
import os
import requests

HOST="api.fountain.com"
API_KEY="K-9NB9DkxU7NdrB9eRBHCA"
APPLICANT="6d0d9434-2817-4b96-9ad4-e33a7f2a0adb"
FILENAME="dog.jpg"
UPLOAD_FILE=(FILENAME, open(FILENAME, 'rb'), mimetypes.guess_type(FILENAME)[0])
UPLOAD_KEY="test"

UPLOAD_URL="https://%s/v2/applicants/%s/secure_documents/upload" % (HOST, APPLICANT)
LINK_UPLOAD_URL="https://%s/v2/applicants/%s/secure_documents/link_upload" % (HOST, APPLICANT)

HEADERS = { 'X-ACCESS-TOKEN': API_KEY }

upload_response = requests.post(UPLOAD_URL, headers=HEADERS)
upload_response_json = json.loads(upload_response.text)
form_data = upload_response_json['form_data']
form_data['Content-type'] = ""

s3_upload_response = requests.post(upload_response_json['url'], data=form_data, files={'file': UPLOAD_FILE})

s3_upload_response_xml = xml.etree.ElementTree.fromstring(s3_upload_response.text)
s3_filename = s3_upload_response_xml.find("Key").text

finish_upload_data = {
    'key': UPLOAD_KEY,
    's3_key': s3_filename,
    'size': os.path.getsize(FILENAME),
}
finish_upload_response = requests.post(LINK_UPLOAD_URL, headers=HEADERS, json=finish_upload_data)
print(finish_upload_response)
```

### C#

```csharp
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using System.Xml.XPath;

var localFilePath = @"/Users/userName/Downloads/the_file.png";
var host = "https://us-2.fountain.com";
var apiKey = "your_api_key";
var applicantId = "29345e1b-6224-467a-964c-da077ebed994";

// Open file stream to the local file on disk
var fileStream = new FileStream(localFilePath, FileMode.Open);

// Create a new HttpClient with default headers for the API key
var hireClient = new HttpClient();
hireClient.DefaultRequestHeaders.Add("X-ACCESS-TOKEN", apiKey);

// Get an upload URL so that the file can be uploaded to the applicant
var urlResponse = await hireClient.PostAsync($"{host}/api/v2/applicants/{applicantId}/secure_documents/upload", null);
var presignedPayload = await urlResponse.Content.ReadFromJsonAsync<Payload>(new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower });

// Upload the file to the presigned URL with a multipart form
var formData = new MultipartFormDataContent();

// Copy the form data from the presignedPayload to the formData
foreach (var item in presignedPayload.FormData)
{
  formData.Add(new StringContent(item.Value), item.Key);
}
formData.Add(new StringContent(""), "Content-Type"); // required due to a content validation rule
formData.Add(new StreamContent(fileStream), "file", Path.GetFileName(localFilePath));

// POST the file to the presigned URL (S3)
var s3Client = new HttpClient();
var uploadResponse = await s3Client.PostAsync(presignedPayload.Url, formData);
var textResponse = await uploadResponse.Content.ReadAsStringAsync();
if (uploadResponse.StatusCode != HttpStatusCode.Created)
{
  Console.WriteLine("Error uploading file");
  Console.WriteLine(textResponse);
  return;
}
var xmlDocument = new XPathDocument(new StringReader(textResponse));
var navigator = xmlDocument.CreateNavigator();
var keyNode = navigator.SelectSingleNode("/PostResponse/Key");
if (keyNode is null) {
  Console.WriteLine("Unexpected response from S3");
  Console.WriteLine(textResponse);
  return;
}

// Now link the uploaded file residing on S3 to the applicant
var linkResponse = await hireClient.PostAsJsonAsync($"{host}/api/v2/applicants/{applicantId}/secure_documents/link_upload", new LinkPayload
{
  Key = "some_file",
  S3Key = keyNode.Value,
  Size = fileStream.Length.ToString()
}, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower });
if (linkResponse.StatusCode != HttpStatusCode.OK)
{
  Console.WriteLine($"Error linking file: {linkResponse.StatusCode}");
  return;
}

public readonly struct LinkPayload
{
  public string Key { get; init; }
  public string S3Key { get; init; }
  public string Size { get; init; }
}

public readonly struct Payload
{
    public string Url { get; init; }
    public string Host { get; init; }
    public Dictionary<string, string> FormData { get; init; }
    public int MinSize { get; init; }
    public int MaxSize { get; init; }
    public bool OnlyImages { get; init; }
    public string Type { get; init; }
}
```

### Curl Example

```curl
curl --request POST \
     --url https://api.fountain.com/v2/applicants/id/secure_documents/upload \
     --header 'accept: application/json' \
     --header 'content-type: application/json'
```
