curl --request POST \
--url https://api.scrip.dev/v1/participants \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"external_id": "user_abc123",
"attributes": {
"plan": "premium",
"region": "us-east"
},
"display_name": "Jane Doe",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15551234567",
"program_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "ACTIVE",
"tags": [
"vip"
]
}
'import requests
url = "https://api.scrip.dev/v1/participants"
payload = {
"external_id": "user_abc123",
"attributes": {
"plan": "premium",
"region": "us-east"
},
"display_name": "Jane Doe",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15551234567",
"program_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "ACTIVE",
"tags": ["vip"]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
external_id: 'user_abc123',
attributes: {plan: 'premium', region: 'us-east'},
display_name: 'Jane Doe',
email: 'jane@example.com',
first_name: 'Jane',
last_name: 'Doe',
phone: '+15551234567',
program_id: '550e8400-e29b-41d4-a716-446655440000',
status: 'ACTIVE',
tags: ['vip']
})
};
fetch('https://api.scrip.dev/v1/participants', 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://api.scrip.dev/v1/participants",
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([
'external_id' => 'user_abc123',
'attributes' => [
'plan' => 'premium',
'region' => 'us-east'
],
'display_name' => 'Jane Doe',
'email' => 'jane@example.com',
'first_name' => 'Jane',
'last_name' => 'Doe',
'phone' => '+15551234567',
'program_id' => '550e8400-e29b-41d4-a716-446655440000',
'status' => 'ACTIVE',
'tags' => [
'vip'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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://api.scrip.dev/v1/participants"
payload := strings.NewReader("{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/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://api.scrip.dev/v1/participants")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/participants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"attributes": {
"plan": "premium",
"region": "us-east"
},
"balances": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"available": "1500.00",
"deferred": "0.00",
"held": "200.00"
}
],
"counters": {
"points_earned": "1500",
"purchases": "42"
},
"created_at": "2024-01-15T10:30:00Z",
"display_name": "Jane Doe",
"email": "jane@example.com",
"external_id": "user_123",
"first_name": "Jane",
"id": "550e8400-e29b-41d4-a716-446655440000",
"last_name": "Doe",
"phone": "+15551234567",
"program_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"status": "ACTIVE",
"tags": [
"vip"
],
"tiers": {
"loyalty": {
"level": "gold",
"rank": 2
}
},
"updated_at": "2024-01-15T10:30:00Z"
}{
"attributes": {
"plan": "premium",
"region": "us-east"
},
"balances": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"available": "1500.00",
"deferred": "0.00",
"held": "200.00"
}
],
"counters": {
"points_earned": "1500",
"purchases": "42"
},
"created_at": "2024-01-15T10:30:00Z",
"display_name": "Jane Doe",
"email": "jane@example.com",
"external_id": "user_123",
"first_name": "Jane",
"id": "550e8400-e29b-41d4-a716-446655440000",
"last_name": "Doe",
"phone": "+15551234567",
"program_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"status": "ACTIVE",
"tags": [
"vip"
],
"tiers": {
"loyalty": {
"level": "gold",
"rank": 2
}
},
"updated_at": "2024-01-15T10:30:00Z"
}{
"code": "bad_request",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource not found"
}{
"code": "conflict",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource already exists or state conflict"
}{
"code": "unsupported_media_type",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Content-Type must be application/json"
}{
"code": "internal_error",
"message": "An internal error occurred"
}Create a participant
Create a participant, or update if external_id already exists (upsert).
curl --request POST \
--url https://api.scrip.dev/v1/participants \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"external_id": "user_abc123",
"attributes": {
"plan": "premium",
"region": "us-east"
},
"display_name": "Jane Doe",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15551234567",
"program_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "ACTIVE",
"tags": [
"vip"
]
}
'import requests
url = "https://api.scrip.dev/v1/participants"
payload = {
"external_id": "user_abc123",
"attributes": {
"plan": "premium",
"region": "us-east"
},
"display_name": "Jane Doe",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15551234567",
"program_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "ACTIVE",
"tags": ["vip"]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
external_id: 'user_abc123',
attributes: {plan: 'premium', region: 'us-east'},
display_name: 'Jane Doe',
email: 'jane@example.com',
first_name: 'Jane',
last_name: 'Doe',
phone: '+15551234567',
program_id: '550e8400-e29b-41d4-a716-446655440000',
status: 'ACTIVE',
tags: ['vip']
})
};
fetch('https://api.scrip.dev/v1/participants', 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://api.scrip.dev/v1/participants",
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([
'external_id' => 'user_abc123',
'attributes' => [
'plan' => 'premium',
'region' => 'us-east'
],
'display_name' => 'Jane Doe',
'email' => 'jane@example.com',
'first_name' => 'Jane',
'last_name' => 'Doe',
'phone' => '+15551234567',
'program_id' => '550e8400-e29b-41d4-a716-446655440000',
'status' => 'ACTIVE',
'tags' => [
'vip'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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://api.scrip.dev/v1/participants"
payload := strings.NewReader("{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/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://api.scrip.dev/v1/participants")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/participants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"external_id\": \"user_abc123\",\n \"attributes\": {\n \"plan\": \"premium\",\n \"region\": \"us-east\"\n },\n \"display_name\": \"Jane Doe\",\n \"email\": \"jane@example.com\",\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"phone\": \"+15551234567\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"status\": \"ACTIVE\",\n \"tags\": [\n \"vip\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"attributes": {
"plan": "premium",
"region": "us-east"
},
"balances": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"available": "1500.00",
"deferred": "0.00",
"held": "200.00"
}
],
"counters": {
"points_earned": "1500",
"purchases": "42"
},
"created_at": "2024-01-15T10:30:00Z",
"display_name": "Jane Doe",
"email": "jane@example.com",
"external_id": "user_123",
"first_name": "Jane",
"id": "550e8400-e29b-41d4-a716-446655440000",
"last_name": "Doe",
"phone": "+15551234567",
"program_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"status": "ACTIVE",
"tags": [
"vip"
],
"tiers": {
"loyalty": {
"level": "gold",
"rank": 2
}
},
"updated_at": "2024-01-15T10:30:00Z"
}{
"attributes": {
"plan": "premium",
"region": "us-east"
},
"balances": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"available": "1500.00",
"deferred": "0.00",
"held": "200.00"
}
],
"counters": {
"points_earned": "1500",
"purchases": "42"
},
"created_at": "2024-01-15T10:30:00Z",
"display_name": "Jane Doe",
"email": "jane@example.com",
"external_id": "user_123",
"first_name": "Jane",
"id": "550e8400-e29b-41d4-a716-446655440000",
"last_name": "Doe",
"phone": "+15551234567",
"program_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"status": "ACTIVE",
"tags": [
"vip"
],
"tiers": {
"loyalty": {
"level": "gold",
"rank": 2
}
},
"updated_at": "2024-01-15T10:30:00Z"
}{
"code": "bad_request",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource not found"
}{
"code": "conflict",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource already exists or state conflict"
}{
"code": "unsupported_media_type",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Content-Type must be application/json"
}{
"code": "internal_error",
"message": "An internal error occurred"
}external_id. Tags, attributes, profile fields (email, phone, first_name, last_name, display_name), and initial status can be set in the same call. Status defaults to ACTIVE. Counters and tiers cannot be set at creation. They are managed through their dedicated endpoints or automatically by rules during event processing.
Pass program_id to enroll the participant in a program at creation time. Event ingestion automatically enrolls existing participants in the target program, so pre-enrolling here is optional. If your program’s on_unknown_participant is set to CREATE, new participants are also created automatically on their first event.
If a participant with the same external_id already exists, the call behaves as an upsert and updates the existing record rather than returning an error.
Authorizations
API key passed in the X-API-Key header.
Body
Participant details
Your application's identifier for this user. Upserts if it already exists
1 - 255"user_abc123"
Key-value metadata. Each key is accessible in rules via the participant.attribute. shorthand (null if unset) or get(participant.attributes, "key", "")
Show child attributes
Show child attributes
{ "plan": "premium", "region": "us-east" }
Display name
255"Jane Doe"
Contact email
255"jane@example.com"
First name
255"Jane"
Last name
255"Doe"
Contact phone
50"+15551234567"
Program to enroll this participant in on creation
"550e8400-e29b-41d4-a716-446655440000"
Initial lifecycle state. Defaults to ACTIVE
ACTIVE, SUSPENDED, CLOSED "ACTIVE"
Labels for segmentation, accessible in rules via participant.tag. (true/false) or 'name' in participant.tags
["vip"]
Response
Participant updated (already existed)
Key-value metadata. Each key is accessible in rules via the participant.attribute. shorthand (null if unset) or get(participant.attributes, "key", "")
Show child attributes
Show child attributes
{ "plan": "premium", "region": "us-east" }
Current balances per asset, split by bucket
Show child attributes
Show child attributes
Numeric accumulators, returned as strings for precision
Show child attributes
Show child attributes
{
"points_earned": "1500",
"purchases": "42"
}
When the participant was created
"2024-01-15T10:30:00Z"
Display name
"Jane Doe"
Contact email
"jane@example.com"
Your application's identifier for this user
"user_123"
First name
"Jane"
Participant ID
"550e8400-e29b-41d4-a716-446655440000"
Last name
"Doe"
Contact phone
"+15551234567"
Programs this participant is enrolled in
["550e8400-e29b-41d4-a716-446655440000"]
Lifecycle state
"ACTIVE"
Labels for segmentation, accessible in rules via participant.tag. (true/false) or 'name' in participant.tags
["vip"]
Current tier level per tier type
Show child attributes
Show child attributes
{ "loyalty": { "level": "gold", "rank": 2 } }
When the participant was last modified
"2024-01-15T10:30:00Z"