Send a PACT v3 event
curl --request POST \
--url https://{subdomain}.variable.global/api/pact/3/events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/cloudevents+json' \
--data '
{
"specversion": "1.0",
"id": "<string>",
"source": "https://partner.example.com/pact",
"time": "2025-01-01T00:00:00.000Z",
"data": {
"productId": [
"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a"
],
"status": [
"Active"
]
}
}
'import requests
url = "https://{subdomain}.variable.global/api/pact/3/events"
payload = {
"specversion": "1.0",
"id": "<string>",
"source": "https://partner.example.com/pact",
"time": "2025-01-01T00:00:00.000Z",
"data": {
"productId": ["urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a"],
"status": ["Active"]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/cloudevents+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/cloudevents+json'
},
body: JSON.stringify({
specversion: '1.0',
id: '<string>',
source: 'https://partner.example.com/pact',
time: '2025-01-01T00:00:00.000Z',
data: {
productId: ['urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a'],
status: ['Active']
}
})
};
fetch('https://{subdomain}.variable.global/api/pact/3/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{subdomain}.variable.global/api/pact/3/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'specversion' => '1.0',
'id' => '<string>',
'source' => 'https://partner.example.com/pact',
'time' => '2025-01-01T00:00:00.000Z',
'data' => [
'productId' => [
'urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a'
],
'status' => [
'Active'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/cloudevents+json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{subdomain}.variable.global/api/pact/3/events"
payload := strings.NewReader("{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/cloudevents+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{subdomain}.variable.global/api/pact/3/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/cloudevents+json")
.body("{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{subdomain}.variable.global/api/pact/3/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/cloudevents+json'
request.body = "{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "token expired",
"code": "TokenExpired"
}{
"message": "token expired",
"code": "TokenExpired"
}Endpoints
PACT v3 events
Send PACT Action Events, and get PCF requests answered.
POST
/
pact
/
3
/
events
Send a PACT v3 event
curl --request POST \
--url https://{subdomain}.variable.global/api/pact/3/events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/cloudevents+json' \
--data '
{
"specversion": "1.0",
"id": "<string>",
"source": "https://partner.example.com/pact",
"time": "2025-01-01T00:00:00.000Z",
"data": {
"productId": [
"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a"
],
"status": [
"Active"
]
}
}
'import requests
url = "https://{subdomain}.variable.global/api/pact/3/events"
payload = {
"specversion": "1.0",
"id": "<string>",
"source": "https://partner.example.com/pact",
"time": "2025-01-01T00:00:00.000Z",
"data": {
"productId": ["urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a"],
"status": ["Active"]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/cloudevents+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/cloudevents+json'
},
body: JSON.stringify({
specversion: '1.0',
id: '<string>',
source: 'https://partner.example.com/pact',
time: '2025-01-01T00:00:00.000Z',
data: {
productId: ['urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a'],
status: ['Active']
}
})
};
fetch('https://{subdomain}.variable.global/api/pact/3/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{subdomain}.variable.global/api/pact/3/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'specversion' => '1.0',
'id' => '<string>',
'source' => 'https://partner.example.com/pact',
'time' => '2025-01-01T00:00:00.000Z',
'data' => [
'productId' => [
'urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a'
],
'status' => [
'Active'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/cloudevents+json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{subdomain}.variable.global/api/pact/3/events"
payload := strings.NewReader("{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/cloudevents+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{subdomain}.variable.global/api/pact/3/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/cloudevents+json")
.body("{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{subdomain}.variable.global/api/pact/3/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/cloudevents+json'
request.body = "{\n \"specversion\": \"1.0\",\n \"id\": \"<string>\",\n \"source\": \"https://partner.example.com/pact\",\n \"time\": \"2025-01-01T00:00:00.000Z\",\n \"data\": {\n \"productId\": [\n \"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a\"\n ],\n \"status\": [\n \"Active\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "token expired",
"code": "TokenExpired"
}{
"message": "token expired",
"code": "TokenExpired"
}The events endpoint takes a CloudEvent in the PACT v3 format. It needs a token with the
pact:read permission, even when your PACT API is public.
Accepted event types
| Type | What Variable does |
|---|---|
org.wbcsd.pact.ProductFootprint.RequestCreatedEvent.3 | Answers the request, below |
org.wbcsd.pact.ProductFootprint.RequestFulfilledEvent.3 | Accepts it |
org.wbcsd.pact.ProductFootprint.RequestRejectedEvent.3 | Accepts it |
org.wbcsd.pact.ProductFootprint.PublishedEvent.3 | Accepts it |
PCF requests
ARequestCreatedEvent asks for the footprints that match its data, which takes the same criteria as the
footprint filters: productId, companyId, geography, classification,
status, validOn, validAfter and validBefore. A footprint has to match all of them.
Variable answers by sending an event back to the requester’s PACT API, at <source>/3/events, where source is the
request’s own source. It authenticates with the credentials of the PACT data source whose URL matches that source
(see Answering PCF requests). The answer is one of:
RequestFulfilledEventwith the matching footprints inpfs.RequestRejectedEventwith error codeNotFoundwhen no footprint matches, or the request names no criteria.RequestRejectedEventwith error codeBadRequestwhen more than 100 footprints match. Narrow the request, or page throughGET /pact/3/footprints.
requestEventId is the request’s id. A request whose source matches none of the company’s PACT data
sources gets no answer.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/cloudevents+json
A CloudEvent in the PACT v3 format.
Available options:
1.0 Maximum string length:
256The sender's PACT API URL. Variable answers a PCF request at <source>/3/events.
Maximum string length:
1024Example:
"https://partner.example.com/pact"
Example:
"2025-01-01T00:00:00.000Z"
Available options:
org.wbcsd.pact.ProductFootprint.RequestCreatedEvent.3, org.wbcsd.pact.ProductFootprint.RequestFulfilledEvent.3, org.wbcsd.pact.ProductFootprint.RequestRejectedEvent.3, org.wbcsd.pact.ProductFootprint.PublishedEvent.3 For a RequestCreatedEvent, the criteria of the footprints asked for: productId, companyId, geography, classification and status take up to 100 values each; validOn, validAfter and validBefore take one ISO 8601 date.
Example:
{
"productId": [
"urn:uuid:6f8d6c41-6a3c-4c3e-9a51-0b5c4f1e2d7a"
],
"status": ["Active"]
}
Response
The event was accepted