Apply an atomic rule-configuration change set
curl --request POST \
--url https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"preview_token": "<string>",
"request_hash": "<string>"
}
'import requests
url = "https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply"
payload = {
"preview_token": "<string>",
"request_hash": "<string>"
}
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({preview_token: '<string>', request_hash: '<string>'})
};
fetch('https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply', 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/programs/{programId}/rule-configuration/apply",
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([
'preview_token' => '<string>',
'request_hash' => '<string>'
]),
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/programs/{programId}/rule-configuration/apply"
payload := strings.NewReader("{\n \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\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/programs/{programId}/rule-configuration/apply")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply")
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 \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"change_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"rule_configuration": {
"program_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"rule_configuration_version": 4,
"rule_sets": [
{
"rule_set": {
"created_at": "2026-07-16T10:30:00Z",
"id": "550e8400-e29b-41d4-a716-446655440000",
"key": "holiday-promo",
"name": "Holiday Promotion",
"order": 1,
"program_id": "550e8400-e29b-41d4-a716-446655440001",
"rule_configuration_version": 4,
"updated_at": "2026-07-16T10:30:00Z"
},
"rules": [
{
"actions": [
{
"amount": "${{ event.amount * 10 }}",
"asset_id": "550e8400-e29b-41d4-a716-446655440002",
"type": "CREDIT"
}
],
"active_from": "2024-01-01T00:00:00Z",
"active_to": "2024-12-31T23:59:59Z",
"budgets": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"consumed": "4500.00",
"cron_expression": "0 0 1 * *",
"interval": "720h",
"limit": "10000.00",
"next_reset_at": "2026-03-01T00:00:00Z",
"schedule_type": "CRON"
}
],
"condition": "event.type == 'purchase' && event.amount > 0",
"created_at": "2024-01-15T10:30:00Z",
"deleted_at": "2024-06-01T00:00:00Z",
"description": "Awards 10 points per dollar spent",
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Purchase Reward",
"order": 1,
"program_id": "550e8400-e29b-41d4-a716-446655440001",
"rule_configuration_version": 4,
"rule_set_id": "550e8400-e29b-41d4-a716-446655440002",
"status": "ACTIVE",
"stop_after_match": false,
"updated_at": "2024-01-15T10:30:00Z",
"warnings": [
{
"code": "unknown_state_key",
"key": "purchaseCnt",
"kind": "counter",
"message": "unknown counter \"purchaseCnt\" — no rule in this program writes it; did you mean \"purchase_count\"?",
"scope": "participant",
"suggestion": "purchase_count"
}
]
}
]
}
]
}
}{
"code": "bad_request",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource not found"
}{
"code": "conflict",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource already exists or state conflict"
}{
"code": "unsupported_media_type",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Content-Type must be application/json"
}{
"code": "unprocessable",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Business rule violation"
}{
"code": "internal_error",
"message": "An internal error occurred"
}Rule configuration
Apply a rule-configuration change set
Apply the exact server-stored preview plan in one transaction after checking token, request hash, actor, organization, program, expiry, dependency drift, and base configuration version. The version increments exactly once.
POST
/
v1
/
programs
/
{programId}
/
rule-configuration
/
apply
Apply an atomic rule-configuration change set
curl --request POST \
--url https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"preview_token": "<string>",
"request_hash": "<string>"
}
'import requests
url = "https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply"
payload = {
"preview_token": "<string>",
"request_hash": "<string>"
}
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({preview_token: '<string>', request_hash: '<string>'})
};
fetch('https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply', 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/programs/{programId}/rule-configuration/apply",
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([
'preview_token' => '<string>',
'request_hash' => '<string>'
]),
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/programs/{programId}/rule-configuration/apply"
payload := strings.NewReader("{\n \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\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/programs/{programId}/rule-configuration/apply")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/programs/{programId}/rule-configuration/apply")
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 \"preview_token\": \"<string>\",\n \"request_hash\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"change_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"rule_configuration": {
"program_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"rule_configuration_version": 4,
"rule_sets": [
{
"rule_set": {
"created_at": "2026-07-16T10:30:00Z",
"id": "550e8400-e29b-41d4-a716-446655440000",
"key": "holiday-promo",
"name": "Holiday Promotion",
"order": 1,
"program_id": "550e8400-e29b-41d4-a716-446655440001",
"rule_configuration_version": 4,
"updated_at": "2026-07-16T10:30:00Z"
},
"rules": [
{
"actions": [
{
"amount": "${{ event.amount * 10 }}",
"asset_id": "550e8400-e29b-41d4-a716-446655440002",
"type": "CREDIT"
}
],
"active_from": "2024-01-01T00:00:00Z",
"active_to": "2024-12-31T23:59:59Z",
"budgets": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"consumed": "4500.00",
"cron_expression": "0 0 1 * *",
"interval": "720h",
"limit": "10000.00",
"next_reset_at": "2026-03-01T00:00:00Z",
"schedule_type": "CRON"
}
],
"condition": "event.type == 'purchase' && event.amount > 0",
"created_at": "2024-01-15T10:30:00Z",
"deleted_at": "2024-06-01T00:00:00Z",
"description": "Awards 10 points per dollar spent",
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Purchase Reward",
"order": 1,
"program_id": "550e8400-e29b-41d4-a716-446655440001",
"rule_configuration_version": 4,
"rule_set_id": "550e8400-e29b-41d4-a716-446655440002",
"status": "ACTIVE",
"stop_after_match": false,
"updated_at": "2024-01-15T10:30:00Z",
"warnings": [
{
"code": "unknown_state_key",
"key": "purchaseCnt",
"kind": "counter",
"message": "unknown counter \"purchaseCnt\" — no rule in this program writes it; did you mean \"purchase_count\"?",
"scope": "participant",
"suggestion": "purchase_count"
}
]
}
]
}
]
}
}{
"code": "bad_request",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource not found"
}{
"code": "conflict",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource already exists or state conflict"
}{
"code": "unsupported_media_type",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Content-Type must be application/json"
}{
"code": "unprocessable",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Business rule violation"
}{
"code": "internal_error",
"message": "An internal error occurred"
}Applies the exact server-stored plan identified by
preview_token and request_hash. The body cannot replace or modify the proposal.
Scrip verifies the actor, organization, program, expiry, request hash, base version, and referenced dependencies before committing the plan in one transaction. Success increments rule_configuration_version exactly once.
Create a new preview when a token is expired, already applied, based on a stale version, or invalidated by dependency drift.Authorizations
ApiKeyAuthBearerAuth
API key passed in the X-API-Key header.
Path Parameters
Program ID
Body
application/json
Preview capability and integrity hash
⌘I