# Setup Guide

Leverage the power of CloudFactory's AI Data Platform to leverage first class human oversight annotation APIs

This section describes how to use the API and its resources. If you have any questions or issues, please contact the Cloudfactory Support.

## API Reference

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><a href="/pages/Livw9lGaGC4Axkzwkjwz"><strong>API Reference</strong></a><br><br>Learn more about the endpoints you can use from CloudFactory's APIs</td><td></td><td><a href="/pages/Livw9lGaGC4Axkzwkjwz">/pages/Livw9lGaGC4Axkzwkjwz</a></td></tr></tbody></table>

## Authentication & Rate Limiting

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><p><a href="#authentication-and-rate-limiting"><strong>Authentication</strong></a></p><p><br>Create an API access token and authenticate your API requests.</p></td><td></td><td><a href="https://github.com/cloudfactory/gitbook/blob/main/docs/broken-reference/README.md">https://github.com/cloudfactory/gitbook/blob/main/docs/broken-reference/README.md</a></td></tr><tr><td><p><a href="/pages/TlmEfUq0n7Mx4pf5mZHv"><strong>Quota</strong></a>/<a href="/pages/TlmEfUq0n7Mx4pf5mZHv"><strong>Rate Limiting</strong></a></p><p><br>Understand how API requests are rate limited.</p></td><td></td><td><a href="/pages/TlmEfUq0n7Mx4pf5mZHv">/pages/TlmEfUq0n7Mx4pf5mZHv</a></td></tr><tr><td><p><a href="/pages/ZVjAPKKYih82PlW0ivmu"><strong>Webhook</strong></a></p><p><br>Understand how to track progress through webhook</p></td><td></td><td></td></tr></tbody></table>


# Authentication

CloudFactory authenticates the API requests using API keys generated. Please contact our support team to get your API keys.

API keys are unique to the customer and given at workstream/project level.

Authenticate the API requests by sending the key generated in the header of the request as shown below:

```bash
curl -H "x-api-key: YOUR_API_KEY" https://api.cloudfactory.app/v1/tasks
```

{% hint style="warning" %}
Please be sure to keep your API access tokens secure! Do not share them in emails, chat messages, client-side code or publicly accessible sites.

If you have accidentally shared an API access token publicly, you can request to have it revoked.
{% endhint %}


# Webhook

A webhook is a mechanism for one system to send data to another system as soon as a specific event occurs. It's a way to automate data exchange and communication between different software

## WEBHOOK SUPPORT

1. Use the callback\_url provided on a task request
   * Link:<https://developer.cloudfactory.app/cloudfactory-public-api/reference/human-oversight-api/submit-task>
2. Webhook Url Expectations:
   * POST request is supported on the webhook URL and the URL provides 200 as the response code for successful request
   * The webhook URL should not have any authentication in place
3. Retry mechanism:
   * On Webhook fall failure we will retry for 4 times Exponentially backing ( 1Hr, 2Hr, 4Hrs)) off until the 4th retry limit is reached.
4. Request to callback URL will Auto Timeout after 5 seconds\
   \\

## WEBHOOK SECURITY HEADER

For enhanced security and data integrity, CloudFactory employs a robust authentication mechanism for all dispatched webhook events. This mechanism guarantees the authenticity and origin of received data, allowing clients to process information with confidence.

Verification Process:

1. Signature Generation: Each transmitted webhook event includes a unique signature. This signature is derived through a cryptographically secure hashing function (SHA-256) applied to the event payload utilizing a confidential key shared exclusively between CloudFactory and the client’s service.
2. Signature Transmission: The generated signature is appended to the HTTP request headers delivered to the client’s designated webhook URL, specifically within the "X-CF-Signature" header.
3. Signature Verification: Upon receiving a webhook event, it is imperative to independently compute a signature using the identical shared secret key and the received event payload.
4. Authentication Validation: The computed signature is compared against the received "CF-Signature" header value (v1). A successful match conclusively verifies the event's authenticity and confirms its origination from CloudFactory. Conversely, any discrepancy denotes a potential security concern, necessitating the immediate rejection of the event.

By adopting this authentication process, CloudFactory safeguards client data integrity and empowers clients to utilize reliable information for optimized decision-making confidently.

## VERIFY WEBHOOK HEADER

As the webhook endpoint is open, clients can verify the request is valid using following mechanism:

Step 1: Extract the timestamp and signatures from the header

Firstly, split the X-CF-Signature header value using the ; character as the separator to get a list of elements. Then split each element using the = character as the separator to get a prefix and value pair. The t corresponds to the timestamp, v1 corresponds to the signature.

Step 2: Prepare signed\_payload

Concatenate the following to create a signed\_payload string:

* the timestamp t
* the character .
* the request body

Step 3: Generate the expected signature

Generate a unique security code (HMAC) using SHA256, where the secret key is the API Key and the signed\_payload string as the message.

Step 4: Compare against the signature

Check if the newly generated security code is the same as the signature (v1) provided, if it matches we can make sure the API webhook is valid.

Example:

```
# import hashlib
# import hmac

# header_string is header ( X-CF-Signature)
# E.g.  "t=1710343835;v1=ce7551796****2ee1"  
# and api key is key used to create the task `X-Api-Token`

def validate_signature(header_string, api_key, response):
  parts = header_string.split(';')
    parsed_data = {}


    for part in parts:
        key, value = part.split('=')
        parsed_data[key] = value


    timestamp = parsed_data.get('t')
    hashed_sign = parsed_data.get('v1')


    if timestamp is None or hashed_sign is None:
        return False


    combined = f"{timestamp}.{response}"
    hmac_obj = hmac.new(api_key.encode('utf-8'), combined.encode('utf-8'), hashlib.sha256)
    calculated_hash = hmac_obj.hexdigest()


    return hashed_sign == calculated_hash
```

## ADDITIONAL TIPS

* Use HTTPS Endpoint: To guarantee secure webhook delivery, exclusively configure callback\_url with https\:// URLs for TLS encryption and verify they point to applications solely under your ownership.
* Prevent Replay Attacks:
  * Check if the timestamp is not too old.
  * Check if the webhook for the task request id has already been acknowledged by the system.

## WEBHOOK WORKFLOW

<figure><img src="https://lh7-us.googleusercontent.com/5lq23qJwq4alZ_ZzxmYO_Lp6m7r8O5X4GZXVak2fn3wehx0ADN0wK7vJPV_ndp_JZCreTtn5axlIymLvRrhqJ3wCJeY_7CAu58G02iVFwUpDJama34edtb8yaVAgkJdwZTrH5LUBvv4X4gy3Q3bdhGA" alt=""><figcaption></figcaption></figure>

## WEBHOOK EVENT CONTRACT

<table><thead><tr><th>Event</th><th>Description</th><th>Sample Payload</th></tr></thead><tbody><tr><td>task.error</td><td>There has been an error processing the task</td><td><pre><code> {
   "uuid": "1b6b786f-403a-459f-8b33-b0b69a437d4b", 
   "event_type":"task.error", 
   "timestamp":"2024-01-29T16:05:00Z", 
   "request_id":"b071b22e-288c-42e6-9a35-cbc4ad924143", 
   "diagnostic": { 
     "workstream_id":"7454a96f-0e30-4569-8ae4-182344728963", 
     "configuration_id":"8eb6edff-bad2-4e16-aba3-759359792f99", 
     "tool_project_id": "a66d2dd4-e742-48e3-b3fc-74ac372c7660" 
   } 
 }
</code></pre></td></tr><tr><td>task.result_available</td><td>Results are now available</td><td><pre><code>{
   "uuid" :"438d3604-bde6-466e-a143-76aec462ebad", 
   "event_type": "task.resultavailable", 
   "timestamp": "2024-01-29T16:05:00Z", 
   "request_id": "b071b22e-288c-42e6-9a35-cbc4ad924143", 
   "diagnostic": { 
     "workstream_id":"7454a96f-0e30-4569-8ae4-182344728963", 
     "configuration_id": "8eb6edff-bad2-4e16-aba3-759359792f99", 
     "tool_project_id": "a66d2dd4-e742-48e3-b3fc-74ac372c7660" 
   } 
 }
</code></pre></td></tr><tr><td>task.result_avalilable</td><td>Results are now available with extra metadata.<br>Note: Configuration change required from CloudFactory personnel</td><td><pre><code>{
   "uuid" :"438d3604-bde6-466e-a143-76aec462ebad", 
   "event_type": "task.resultavailable", 
   "timestamp": "2024-01-29T16:05:00Z", 
   "request_id": "b071b22e-288c-42e6-9a35-cbc4ad924143", 
   "diagnostic": { 
     "workstream_id":"7454a96f-0e30-4569-8ae4-182344728963", 
     "configuration_id": "8eb6edff-bad2-4e16-aba3-759359792f99", 
     "tool_project_id": "a66d2dd4-e742-48e3-b3fc-74ac372c7660" 
   }, 
   "task_details": { 
     "state": "COMPLETED", 
     "updated_tags":[ 
     { 
       "confidence_score": 0, 
        "value": "Left" 
      } 
     ], 
     "existing_tags":[ 
     { 
       "confidence_score": 0, 
        "value": "Left" 
      } 
     ] 
  }, 
  "metadata":[ 
   { 
     "key": "image-0", 
     "value": "url" 
     }
   ]
} 
</code></pre></td></tr></tbody></table>

## Event Object

| Field                         | Type   | Description                                                                    |
| ----------------------------- | ------ | ------------------------------------------------------------------------------ |
| uuid                          | string | A unique identifier for the event.                                             |
| event\_type                   | string | The type of event that occurred. In this case, "task.error"                    |
| timestamp                     | string | The time the event occurred in UTC.                                            |
| task\_id                      | string | The task identifier.                                                           |
| diagnostic                    | array  | An array of key-value pairs containing diagnostic information about the event. |
| diagnostic.workstream\_id     | string | The identifier for the workstream that the event occurred in.                  |
| diagnostic.configuration\_id  | string | The identifier for the configuration that the event occurred in.               |
| diagnostic.tool\_project\_id  | string | The identifier for the tool project that was used when the event occurred.     |
| task\_details                 | object | An object containing internal state of the tasks.                              |
| task\_details.state           | string | The task state at the time of the webhook.                                     |
| task\_details.exisiting\_tags | array  | The tags associated with the task provided by the clients.                     |
| task\_details.updated\_tags   | array  | The tags associated with the task updated by CloudFactory.                     |
| metadata                      | array  | An array of key-value pairs containing client specific data.                   |


# Oversight Mounting Buckets

Oversight's Mounting Buckets (MB) lets you use your own storage and keeps your data private. No uploads needed! MB streamlines data access for a smoother experience.

### Setup

1. Mount your Bucket following the guide here <https://wiki.cloudfactory.com/docs/userdocs/projects/mounting-buckets/mounting-buckets-tutorial>
2. Save the Bucket Credential Id as you will be using this for creating Oversight task.

### Usage

1. When using a mounted bucket for sending tasks to CloudFactory, add the Credential ID to the field bucket ID.
2. Add the Media key within the storage media to the field <mark style="color:blue;">media\_key</mark>

**NOTE**: If Bucket\_id is not provided, it will be assumed that bucket mounting is not being used and media has already been uploaded to CloudFactory through the Upload Media API.

<figure><img src="/files/TkBrBk4zX1qsNyvI6Fhk" alt=""><figcaption></figcaption></figure>


# Rate Limiting

TBD

## Quota

The API quota is the maximum number of requests to create task in the system (daily/weekly/monthly). Please contact CloudFactory support to increase the quota.


# Uploading Media Assets

When uploading media to the oversight platform through signed urls, it is crucial to ensure that the `Content-Type` header is included in your request. This header specifies the media type of the resource being uploaded, which helps the oversight platform understand how to process the file.

## Sample Request

Below is a sample `curl` request to upload a media file. Make sure to include the `Content-Type` header in your request with the correct type.

```sh
curl --location --request PUT '{signed_url}' \
--header 'Content-Type: image/jpeg' \
--data-binary '@{file-location}'
```

## Other Content Types

Here are some examples of other `Content-Type` headers you might use depending on the type of file you are uploading:

* For a PNG image:

  ```sh
  --header 'Content-Type: image/png'
  ```
* For a PDF document:

  ```sh
  --header 'Content-Type: application/pdf'
  ```
* For an MP4 video file:

  ```sh
  --header 'Content-Type: video/mp4'
  ```
* For a plain text file:

  ```sh
  --header 'Content-Type: text/plain'
  ```

Always ensure that the `Content-Type` header is included and correctly set to the media type of the file you are uploading.


# API Reference

Here you can find a list of the different endpoints available to use across the CloudFactory API. Click into each card to learn more.

## CloudFactory APIs

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><a href="/pages/Snt6Kj52vUxq5lWikh5j"><strong>WorkStream Performance API</strong></a></td><td></td><td><a href="/pages/Snt6Kj52vUxq5lWikh5j">/pages/Snt6Kj52vUxq5lWikh5j</a></td></tr><tr><td><a href="/pages/X9gBAOaEZpM3pl1O5a9r"><strong>OverSight API</strong></a></td><td></td><td></td></tr></tbody></table>


# WorkStream Performance

These APIs are used to send CloudFactory the performance data related to the individual tasks that CloudWorkers carried out on a WorkStream during a given period of time

### **Step 1: Bulk Upload CSV via URL** <a href="#h_01h92vwdewb127vrspnb50kp77" id="h_01h92vwdewb127vrspnb50kp77"></a>

The [Upload CSV via URL API](/cloudfactory-public-api/reference/workstream-performance-api/send-performance-data-api) is used by clients to generate an upload URL that can then be used to send performance data to our platform via CSV in an agreed format. CloudFactory Platform will then handle the processing of the data as well as automatically sending it for QC and generating throughput and quality reports.

### **Step 2: Throughput API**

The [Throughput API](/cloudfactory-public-api/reference/workstream-performance-api/performance) is used to tell us how many tasks a CloudWorker performed on the WorkStream during the given period. A Client should integrate with the Throughput API if they wish to measure the number of tasks that were completed on a WorkStream and how long they took.

Tasks are broken down into a generic, standardized structure that includes not only **Use Case** and **Task Definition**, but other, custom categories that can be tailored to meet specific Client requirements.

### &#x20;**Step 3: Quality API**

The [Quality API](/cloudfactory-public-api/reference/workstream-performance-api/quality-api) is used to tell us how accurately a CloudWorker performed their tasks on the WorkStream during the given period. A Client should integrate with the Quality API if they have a quality process that allows them to record reviews for tasks completed by CloudWorkers.

The API allows granular information to be stored about the accuracy of each task, including the review score and justification, and by whom these were given.

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td><strong>Secure Upload</strong></td><td></td><td><a href="/pages/yQ6BBZfpc4OHA9ujvsVU">/pages/yQ6BBZfpc4OHA9ujvsVU</a></td></tr><tr><td></td><td><strong>Throughput</strong></td><td></td><td><a href="/pages/0V9yQCyIiQB2Ms2tbif4">/pages/0V9yQCyIiQB2Ms2tbif4</a></td></tr><tr><td></td><td><strong>Quality</strong></td><td></td><td><a href="/pages/8Ya2NYhuKT8JdEbkvdc3">/pages/8Ya2NYhuKT8JdEbkvdc3</a></td></tr></tbody></table>


# Secure Upload

API to be used by the clients to generate the presigned upload URL. Thus generated upload URL can then be used to send performance data to our platform.

{% openapi src="/files/1WseMMKOJqow2NezHF07" path="/v1/workstreams/{workstream\_id}/performance/generate-presigned-url" method="post" %}
[cf-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-a969f6a5d129fc0be2c63beac8c5a59cda1b4ec6%2Fcf-swagger.yaml?alt=media)
{% endopenapi %}


# Throughput

API to be used by the clients to submit task completed info which is used to capture task attributes of completed unit of work across different workstreams.

{% openapi src="/files/1WseMMKOJqow2NezHF07" path="/v1/workstreams/{workstream\_id}/task\_completed" method="post" %}
[cf-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-a969f6a5d129fc0be2c63beac8c5a59cda1b4ec6%2Fcf-swagger.yaml?alt=media)
{% endopenapi %}


# Quality

API to be used by the clients to submit task reviewed info which is used to capture task attributes of reviewed unit of work across different workstreams.

{% openapi src="/files/1WseMMKOJqow2NezHF07" path="/v1/workstreams/{workstream\_id}/task\_reviewed" method="post" %}
[cf-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-a969f6a5d129fc0be2c63beac8c5a59cda1b4ec6%2Fcf-swagger.yaml?alt=media)
{% endopenapi %}


# Oversight

Using the APIs

<figure><img src="/files/PdTMyIi5CyxJ071QN2z0" alt=""><figcaption></figcaption></figure>

### Oversight API Workflow

This workflow describes the process of uploading a media asset and creating a task request.

***NOTE**: Skip **Step 1** and **Step 2** if using Mounted Buckets* Mounted buckets currently only support image assets. For video assets, please use **Step 1** and **Step 2**.

#### Step 1: Upload Media ( Not needed if using Mounted Buckets )

1. Use the Upload Media API to initiate the upload process.
2. Provide:
   * configuration\_id: This should have been passed to you.
3. The API returns a response containing:
   * media\_upload\_url: URL for uploading the actual media content.
   * media\_key: Unique identifier associated with the uploaded media.

#### Step 2: Upload Media Data ( Not needed if using Mounted Buckets )

1. Prepare the media file for upload.
2. Use the media\_upload\_url from the previous step to make a PUT request with the media data.
3. Choose Binary type in body and upload your media file.
4. Ensure the proper content-type is set for your media file in the request header. [Read More](/getting-started/upload-media)

#### Step 3: Create Task Request

1. Use the Create Task API to create a request.
2. Provide:
   * media\_key: The media key obtained in Step 1.
   * (Optional) bucket\_id: Provide the bucket credential Id , if using Mounted Buckets.
   * configuration\_id: The same ID used for media upload.
   * (Optional) callback\_url: URL for receiving notifications about task completion.
3. The API returns a response containing:
   * task\_id: Unique identifier for the created task request.

### Success:

* The media is uploaded to CloudFactory.
* A task is created and media is available in hasty project ready for annotation.

You can use the task\_id to track the progress or retrieve results

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td><strong>Submit Task</strong></td><td></td><td><a href="/pages/fwlZzfeG472M5b6ALDVj">/pages/fwlZzfeG472M5b6ALDVj</a></td></tr><tr><td></td><td><strong>Upload Media</strong></td><td></td><td><a href="/pages/yQ6BBZfpc4OHA9ujvsVU">/pages/yQ6BBZfpc4OHA9ujvsVU</a></td></tr><tr><td></td><td><strong>Task Status</strong></td><td></td><td><a href="/pages/pxSxL0exHtR8q1bX9anw">/pages/pxSxL0exHtR8q1bX9anw</a></td></tr></tbody></table>


# Upload Media

{% openapi src="/files/8hEUdtfFGSUJr2JdW23s" path="/v1/signed-url" method="post" %}
[lma-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-778b09ce02ca17413d9e235a6a831b8b198b31d1%2Flma-swagger.yaml?alt=media)
{% endopenapi %}

For more detailed instructions on uploading media, please refer to the [Getting Started Guide - Uploading Media Assets](/getting-started/upload-media).


# Submit Task

{% openapi src="/files/8hEUdtfFGSUJr2JdW23s" path="/v1/tasks" method="post" %}
[lma-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-778b09ce02ca17413d9e235a6a831b8b198b31d1%2Flma-swagger.yaml?alt=media)
{% endopenapi %}


# Task Status

{% openapi src="/files/8hEUdtfFGSUJr2JdW23s" path="/v1/tasks/{id}" method="get" %}
[lma-swagger.yaml](https://3598919924-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeIDXlxW9gckrh95snvSB%2Fuploads%2Fgit-blob-778b09ce02ca17413d9e235a6a831b8b198b31d1%2Flma-swagger.yaml?alt=media)
{% endopenapi %}


# Snowflake Secure Data Sharing

CloudFactory uses Snowflake, so the easiest way to share datasets would be through a Snowflake to Snowflake secure data sharing.

{% hint style="info" %}

#### <mark style="background-color:green;">`Note`</mark>

<mark style="background-color:green;">`For more information on how secure data sharing works between provider and consumer accounts, refer to the following guide from Snowflake:`</mark> [<mark style="background-color:green;">`Introduction to Secure Data Sharing`</mark>](https://docs.snowflake.com/en/user-guide/data-sharing-intro.html)<mark style="background-color:green;">`.`</mark>
{% endhint %}

Secure Data Sharing enables sharing selected objects in a database in your account with other Snowflake accounts. The following Snowflake database objects can be shared:

1. Tables
2. External tables
3. Secure views
4. Secure materialized views
5. Secure UDFs

Snowflake enables the sharing of databases through shares, which are created by data providers and “imported” by data consumers.&#x20;

<figure><img src="/files/p144Cotg7aKu93AT3wG2" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}

#### <mark style="background-color:green;">`Important`</mark>

<mark style="background-color:green;">`All database objects shared between accounts are read-only (i.e. the objects cannot be modified or deleted, including adding or modifying table data).`</mark>
{% endhint %}

####


# Fivetran and Amazon S3 Data Sharing

If using the Client’s AWS S3:

1. Client controls data security.
2. Client creates a role for CloudFactory’s Fivetran to access their AWS S3 bucket.&#x20;

<figure><img src="/files/wYzXzhw88yYWgonZ5q47" alt=""><figcaption></figcaption></figure>

#### Note <a href="#h_01hxshzb0zvdj5jq6ahmx4cm1d" id="h_01hxshzb0zvdj5jq6ahmx4cm1d"></a>

Follow this setup guide to connect your AWS S3 bucket to Fivetran: [Fivetran S3 Setup Guide](https://fivetran.com/docs/files/aws-s3/setup-guide)

If using CloudFactory’s AWS S3:

1. CloudFactory controls data security.
2. Client sends data to CloudFactory’s AWS S3.&#x20;

<figure><img src="/files/2EtUCyMEEywqWdBumCKT" alt=""><figcaption></figcaption></figure>

#### Overview <a href="#uuid-990d1325-03a8-510f-004b-36e3b218b367_bridgehead-idm4665466328745633174867603492" id="uuid-990d1325-03a8-510f-004b-36e3b218b367_bridgehead-idm4665466328745633174867603492"></a>

1. Create an AWS policy with access to the correct S3 location.
2. Create an AWS role:
   1. Reference the AWS account number and external id (provided by CloudFactory).
   2. Attach the new policy from step 1.
3. Provide the resulting role ARN back to CloudFactory.
4. Provide any file naming conventions to CloudFactory.


