File Upload to S3

Step 1 of 2 for adding files to an applicant profile.

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 [email protected] 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 to complete the upload to the applicant.

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)
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
// This has the x-amz-signature, target s3 key and other fields from a presigned upload payload
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);
// You would want to use ReadAsStreamAsync here and pass it directly to XPathDocument but
// this makes it easy to log the response if there was a problem
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", // this is the data key you are uploading the file to
  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; } // data key
  public string S3Key { get; init; } // s3 key
  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; }
}
Language
Credentials
Header
Click Try It! to start a request and see the response here!