# Activity API

{% hint style="info" %}
[**Is this page helpful? Give us feedback on our docs ->**](https://village-labs.gitbook.io/coworker-product-and-developer-docs/feedback/village-docs-feedback-form) [ ](https://village-labs.gitbook.io/coworker-product-and-developer-docs/feedback/village-docs-feedback-form)
{% endhint %}

## About the Activity API

The Activity API is Village's most commonly used API.&#x20;

An “Activity” represents something your users do. It is the a basic unit of data that can represent any sort of user activity both online and in the real world. Activities can be anything from completing a transaction, clicking a button, or making a delivery.

Activities are the foundation of most Rule logic. Even with a relatively small number of Activities, you can build incredibly powerful and intricate incentive & segmentation system.&#x20;

We recommend that you log as many Activity types that you can up front to reduce maintenance effort (see [Guides->](https://village-labs.gitbook.io/coworker-product-and-developer-docs/legacy-developer-docs/village-apis-introduction/broken-reference)).&#x20;

## Defining Activities

You can send Activities to the Activity API to be logged on the Village ledger (making them queryable) without adding them first on the Admin Dashboard.&#x20;

However, until they are added, they will not be usable in Program & Rule logic.&#x20;

To be used in [Program & Rule](https://village-labs.gitbook.io/coworker-product-and-developer-docs/legacy-knowledge-base/programs-and-rules) logic, Activities must be added in the Admin Dashboard -> Incentives -> Triggers -> Actions/Sales. Any Admin can complete this action.&#x20;

If an Activity is sent through the Activity API *without* having been defined on the Admin Dashboard, it will still be logged on the Village ledger (and therefore queryable in the future). It will not be usable in Program & Rule logic until it is added, however.&#x20;

**Note there are two types of Activities:** Actions and Sales (learn more [here ->](https://village-labs.gitbook.io/coworker-product-and-developer-docs/legacy-knowledge-base/programs-and-rules/triggers/activities)). However the Activity API is agnostic to the type; any logic based on Actions or Sales will be based on the Activity Short ID field.&#x20;

![](https://3561055466-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fcl1KIMhPQkmG41x5eGvL%2Fuploads%2FxoeYCB5Cy9YRCuD45Gli%2Fimage%20\(31\).png?alt=media\&token=5417e348-6c8d-4793-b871-f070d491519c)

## Endpoint

**`POST`**`/networks/YOUR_NETWORK_ID/activity`&#x20;

Where 'YOUR\_NETWORK\_ID' is replaced with your actual Network ID.&#x20;

## API Field Overview

Every Activity has an amount field, in which you can report the volume of activities (example: 1 checkout, 3 deliveries, 4.45 hours) or the degree of an activity (example: 5 star rating, 3 star rating).&#x20;

When Activities are created as Actions and Sales, they can reference multiple users and include metadata for tracking and reporting.

{% hint style="info" %}
**Pay attention to the amount field:** most of the time, the amount field is going to be set to 1, since 1 event or activity of that type occurred. If you have a rule in Village that pays $50 when a task is completed, the rule will multiply the task activity amount (1) by $50 to calculate the payout. In this case, if you entered 50 in the activity amount field, this would result in a payout of 50 \* $50 = $2500!

The exception to this rule is when you are configuring sales triggers. In this case, the amount field should be the total amount of the transaction or sale, eg. 500 if it was a $500 sale. For example, if a rule pays 1% cash back on each sale, it would multiply the rule amount field (.01) by the sales activity amount field ($500) to get a cash back of $5 for that sale.
{% endhint %}

### Body Fields

<table><thead><tr><th width="138">Field Name</th><th width="236">JSON Key</th><th width="88">Type</th><th width="460">Description</th><th>Required</th></tr></thead><tbody><tr><td>Activity Short ID</td><td><code>activity_short_id</code></td><td>string</td><td>CASE SENSITIVE. A short identifier for the activity. This will match either the Action ID or Sale ID that was set when the Action on Sale trigger type was created.</td><td>Yes</td></tr><tr><td>Amount</td><td><code>amount</code></td><td>string</td><td>The activity amount. For Actions, this is the number of actions. For Sales, this is the sale transaction amount.</td><td>Yes</td></tr><tr><td>Associated Users</td><td><code>users</code></td><td>map</td><td>List of users involved in the activity. This map has two parts, first is one of the pre-set "Associated Users" from the Trigger (e.g. "seller") and the second is the email associated with their Village account (e.g. "bradford@villagelabs.co"). At least one Associated User is required to be submitted with every Activity.</td><td>Yes</td></tr><tr><td>Metadata</td><td><code>metadata</code></td><td>object</td><td>Additional metadata for the activity. See Metadata fields for options.</td><td>No</td></tr></tbody></table>

#### **About Associated Users**

<figure><img src="https://3561055466-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fcl1KIMhPQkmG41x5eGvL%2Fuploads%2FRdsKTTTOOdM9IbJ4UoRZ%2Fimage.png?alt=media&#x26;token=f3384852-cd52-4b7a-80fe-a17287f3d7a3" alt=""><figcaption></figcaption></figure>

### Metadata

<table><thead><tr><th width="149">Field Name</th><th width="225">JSON Key</th><th>Type</th><th width="455">Description</th><th>Required</th></tr></thead><tbody><tr><td>Reference ID</td><td><code>reference_id</code></td><td>string</td><td>An optional identifier that can be used for reporting purposes.</td><td>No</td></tr><tr><td>Activity Timestamp</td><td><code>activity_timestamp</code></td><td>integer</td><td>The Unix timestamp of when the activity occurred (in seconds, not milliseconds). If this is blank, Village will use the timestamp the activity was received via the Village API as the Activity Timestamp.</td><td>No</td></tr><tr><td>Description</td><td><code>description</code></td><td>string</td><td>A description of the activity.</td><td>No</td></tr><tr><td>Enforce Unique Ref ID</td><td><code>enforceUniqueRefId</code></td><td>boolean</td><td>Enforces a unique reference ID to process Activities. </td><td></td></tr></tbody></table>

## Examples

### Body

{% hint style="danger" %}
**Critical note:** The activity\_short\_id is case sensitive, and must exactly match the Trigger created on the dashboard in order to be processed.
{% endhint %}

```
// Example Activity Body
// activity_short_id is case sensitive
// User emails must already exist in Village system to be accepted
// activity_timestamp is Unix timestamp in seconds, not milliseconds

{
    "activity_short_id": "sale", 
    "amount": "3",
    "users": {
        "buyer": "bradford@theroutingcompany.com", 
        "seller": "bradford@villagelabs.co"
    },
    "metadata": {
        "reference_id": "customer_ref_id",
        "activity_timestamp": 12345678910, // Epoch time in seconds 
        "description": "customer description"
    },
    "enforceUniqueRefId": false, // Enforces the the reference_id to be unique, and does not process requests that aren't unique. There is no error message when this activates
}

```

### By Language

{% tabs %}
{% tab title="Python" %}

```python
#Remember to replace 'YOUR_API_KEY' with your actual API key
#Replace 'YOUR_NETWORK_ID' with your actual network ID

import requests
import json

# Define the URL of the User Status API
url = "https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity"

# Define the headers for the API request
headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY' 
}

# Define the data for the API request
data = {
    "activity_short_id": "S1-A",
    "amount": "100.99",
    "users": {
        "seller": "john.buyer@villagelabs.co",
        "buyer": "jane.seller@villagelabs.co"
    },
    "metadata": {
        "reference_id": "dpi_Ylo2Cfr8US8u1JIdAl2eZvKB",
        "activity_timestamp": 1664900628,
        "description": "Especially fancy white shoes."
    }
}

# Convert the data to JSON format
data_json = json.dumps(data)

# Send the request to the API
response = requests.post(url, headers=headers, data=data_json)

# Check the response from the API
if response.status_code == 201:
    print("Successfully sent activity data to the API.")
elif response.status_code == 400:
    print("Bad request. Please check the data you are sending to the API.")
elif response.status_code == 401:
    print("Unauthorized. Please check your API key.")
elif response.status_code == 404:
    print("API not found. Please check your API url.")
elif response.status_code == 500:
    print("Internal Server Error. Please try again later.")
else:
    print(f"Received unexpected status code {response.status_code}.")
    
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
//Remember to replace 'YOUR_API_KEY' with your actual API key
//Replace 'YOUR_NETWORK_ID' with your actual network ID

// Define the URL of the Activity API
let url = "https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity";

// Define the headers for the API request
let headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'  
};

// Define the data for the API request
let data = {
    "activity_short_id": "S1-A",
    "amount": "100.99",
    "users": {
        "seller": "john.buyer@villagelabs.co",
        "buyer": "jane.seller@villagelabs.co"
    },
    "metadata": {
        "reference_id": "dpi_Ylo2Cfr8US8u1JIdAl2eZvKB",
        "activity_timestamp": 1664900628,
        "description": "Especially fancy white shoes."
    }
};

// Send the request to the API
fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(data)  // JavaScript has JSON.stringify() to convert object into JSON
})
.then(response => {
    switch(response.status) {
        case 201:
            console.log("Successfully sent activity data to the API.");
            break;
        case 400:
            console.log("Bad request. Please check the data you are sending to the API.");
            break;
        case 401:
            console.log("Unauthorized. Please check your API key.");
            break;
        case 404:
            console.log("API not found. Please check your API url.");
            break;
        case 500:
            console.log("Internal Server Error. Please try again later.");
            break;
        default:
            console.log(`Received unexpected status code ${response.status}.`);
    }
})
.catch(error => console.error('Error:', error));

```

{% endtab %}

{% tab title="cURL" %}

```json
//Remember to replace 'YOUR_API_KEY' with your actual API key
//Replace 'YOUR_NETWORK_ID' with your actual network ID

curl -X POST https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
    "activity_short_id": "S1-A",
    "amount": "100.99",
    "users": {
        "seller": "john.buyer@villagelabs.co",
        "buyer": "jane.seller@villagelabs.co"
    },
    "metadata": {
        "reference_id": "dpi_Ylo2Cfr8US8u1JIdAl2eZvKB",
        "activity_timestamp": 1664900628,
        "description": "Especially fancy white shoes."
    }
}'
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
#Remember to replace 'YOUR_API_KEY' with your actual API key
#Replace 'YOUR_NETWORK_ID' with your actual network ID

require 'net/http'
require 'uri'
require 'json'

# Define the URL of the Activity API
uri = URI.parse("https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity")

# Define the headers for the API request
headers = {
    'Content-Type' => 'application/json',
    'Accept' => 'application/json',
    'Authorization' => 'Bearer YOUR_API_KEY'  # Replace 'Bearer YOUR_API_KEY' with your actual API key
}

# Define the data for the API request
data = {
    "activity_short_id" => "S1-A",
    "amount" => "100.99",
    "users" => {
        "seller" => "john.buyer@villagelabs.co",
        "buyer" => "jane.seller@villagelabs.co"
    },
    "metadata" => {
        "reference_id" => "dpi_Ylo2Cfr8US8u1JIdAl2eZvKB",
        "activity_timestamp" => 1664900628,
        "description" => "Especially fancy white shoes."
    }
}

# Create a new HTTP request with the headers, data and URL
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, headers)
request.body = data.to_json

# Send the request and capture the response
response = http.request(request)

# Check the response from the API
case response.code.to_i
when 201
  puts "Successfully sent activity data to the API."
when 400
  puts "Bad request. Please check the data you are sending to the API."
when 401
  puts "Unauthorized. Please check your API key."
when 404
  puts "API not found. Please check your API url."
when 500
  puts "Internal Server Error. Please try again later."
else
  puts "Received unexpected status code #{response.code}."
end

```

{% endtab %}

{% tab title="Java" %}

```java
//Remember to replace 'YOUR_API_KEY' with your actual API key
//Replace 'YOUR_NETWORK_ID' with your actual network ID

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {
    public static void main(String[] args) throws Exception {
        String url = "https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity";
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        con.setRequestMethod("POST");

        //add request header
        con.setRequestProperty("Content-Type", "application/json");
        con.setRequestProperty("Accept", "application/json");
        con.setRequestProperty("Authorization", "Bearer YOUR_API_KEY");

        String data = "{\"activity_short_id\":\"S1-A\",\"amount\":\"100.99\",\"users\":{\"seller\":\"john.buyer@villagelabs.co\",\"buyer\":\"jane.seller@villagelabs.co\"},\"metadata\":{\"reference_id\":\"dpi_Ylo2Cfr8US8u1JIdAl2eZvKB\",\"activity_timestamp\":1664900628,\"description\":\"Especially fancy white shoes.\"}}";

        // Send post request
        con.setDoOutput(true);
        OutputStream os = con.getOutputStream();
        os.write(data.getBytes());
        os.flush();
        os.close();

        int responseCode = con.getResponseCode();
        System.out.println("Response Code : " + responseCode);
    }
}

```

{% endtab %}

{% tab title="Go" %}

```go
// Remember to replace 'YOUR_API_KEY' with your actual API key
//Replace 'YOUR_NETWORK_ID' with your actual network ID

package main

import (
	"bytes"
	"net/http"
)

func main() {
	url := "https://api-ledger.villagelabs.net/networks/YOUR_NETWORK_ID/activity"
	var jsonStr = []byte(`{"activity_short_id":"S1-A","amount":"100.99","users":{"seller":"john.buyer@villagelabs.co","buyer":"jane.seller@villagelabs.co"},"metadata":{"reference_id":"dpi_Ylo2Cfr8US8u1JIdAl2eZvKB","activity_timestamp":1664900628,"description":"Especially fancy white shoes."}}`)
	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_API_KEY")

	client := &http.Client{}
	resp, _ := client.Do(req)
	defer resp.Body.Close()

	println("response Status:", resp.Status)
}

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
[**Is this page helpful? Give us feedback on our docs ->**](https://village-labs.gitbook.io/coworker-product-and-developer-docs/feedback/village-docs-feedback-form) [ ](https://village-labs.gitbook.io/coworker-product-and-developer-docs/feedback/village-docs-feedback-form)
{% endhint %}
