#Stamp card types
GET /stamp-card-types
List the stamp card types defined across the organization's loyalty programs. Pass availableAt to get only the ones collectible at a given moment, and include=completionThreshold to see the derived card size.
Requires the loyalty:read permission.
Query Parameters
limitnumberThe number of records to return.
cursorstringA pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.
sortname | -name | createdAt | -createdAtThe sort order. Prefix a field with - to sort descending. Defaults to createdAt.
filterstringA JSON-encoded filter document, for example {"createdAt":{"$gte":"2025-01-01T00:00:00Z"}}. Filterable fields: id, loyaltyProgramId, name, availableFrom, availableTo, createdAt. See Filtering for the syntax.
includestringA comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: completionThreshold.
availableAtstring (date-time)Return only card types that are collectible at this moment in time.
curl \
"https://api.cascade.dev/stamp-card-types" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@cascade-commerce/api/admin/client"
import { getStampCardTypes } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getStampCardTypes()require "net/http"
uri = URI("https://api.cascade.dev/stamp-card-types")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport json
from urllib.request import Request, urlopen
req = Request(
"https://api.cascade.dev/stamp-card-types",
headers={"Authorization": "Bearer sk_YOUR_SECRET_KEY"},
)
with urlopen(req) as res:
print(json.load(res)){
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "...",
"stamps": "..."
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z",
"completionThreshold": 0
}
],
"nextCursor": "string"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the stamp card type."
},
"loyaltyProgramId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The loyalty program the card type belongs to."
},
"name": {
"type": "string",
"description": "The card type's display name, shown to members."
},
"earningType": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerOrder",
"description": "Awards a fixed number of stamps per order."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded for each qualifying order."
}
},
"required": ["type", "stamps"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerSpend",
"description": "Awards stamps in proportion to the amount spent."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded per unit spent."
},
"unitAmountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How much a customer has to spend, in cents, to earn one batch of stamps."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
}
},
"required": ["type", "stamps", "unitAmountCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "custom",
"description": "Stamps are awarded by your own code through `POST /loyalty-stamps` rather than automatically."
}
},
"required": ["type"],
"additionalProperties": false
}
],
"description": "How customers earn stamps on this card."
},
"overflowPolicy": {
"type": "string",
"enum": ["carry", "discard"],
"description": "What happens to stamps earned past the card's completion threshold. `carry` starts the customer's next card with them; `discard` drops them."
},
"allowMultipleOpenCards": {
"type": "boolean",
"description": "Whether a member may hold more than one open card of this type at a time."
},
"availableFrom": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When customers can start collecting on this card. Null means straight away."
},
"availableTo": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When collecting on this card stops. Null means it stays open."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was last changed."
},
"completionThreshold": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The stamp count at which a card of this type is full, derived from the type's highest live `stampsEarned` rule. Null means no rule targets the type, so its cards never complete."
}
},
"required": [
"id",
"loyaltyProgramId",
"name",
"earningType",
"overflowPolicy",
"allowMultipleOpenCards",
"availableFrom",
"availableTo",
"createdAt",
"updatedAt"
],
"additionalProperties": false
},
"description": "The page of records, in the requested sort order."
},
"nextCursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Pass this back as `cursor` to fetch the next page. Null once the last page has been returned."
}
},
"required": ["data", "nextCursor"],
"additionalProperties": false
}POST /stamp-card-types
Create a stamp card type. Cards of the type complete at the threshold set by its highest live stampsEarned rule; without such a rule they collect stamps open-endedly and never complete.
Requires the loyalty:write permission.
Body Parameters
dataobjectrequiredThe stamp card type to create.
curl \
-X POST \
"https://api.cascade.dev/stamp-card-types" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}'import { client } from "@cascade-commerce/api/admin/client"
import { postStampCardTypes } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await postStampCardTypes({
body: {
data: {
loyaltyProgramId: "550e8400-e29b-41d4-a716-446655440000",
name: "string",
earningType: {
type: "stampsPerOrder",
stamps: 0,
},
overflowPolicy: "carry",
allowMultipleOpenCards: true,
availableFrom: "2025-01-15T09:30:00Z",
availableTo: "2025-01-15T09:30:00Z",
},
},
})require "net/http"
uri = URI("https://api.cascade.dev/stamp-card-types")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
req["Content-Type"] = "application/json"
req.body = <<~JSON
{
"data": {
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}
JSON
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport json
from urllib.request import Request, urlopen
body = """{
"data": {
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}"""
req = Request(
"https://api.cascade.dev/stamp-card-types",
data=body.encode(),
headers={
"Authorization": "Bearer sk_YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
)
with urlopen(req) as res:
print(json.load(res)){
"id": "550e8400-e29b-41d4-a716-446655440000",
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the stamp card type."
},
"loyaltyProgramId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The loyalty program the card type belongs to."
},
"name": {
"type": "string",
"description": "The card type's display name, shown to members."
},
"earningType": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerOrder",
"description": "Awards a fixed number of stamps per order."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded for each qualifying order."
}
},
"required": ["type", "stamps"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerSpend",
"description": "Awards stamps in proportion to the amount spent."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded per unit spent."
},
"unitAmountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How much a customer has to spend, in cents, to earn one batch of stamps."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
}
},
"required": ["type", "stamps", "unitAmountCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "custom",
"description": "Stamps are awarded by your own code through `POST /loyalty-stamps` rather than automatically."
}
},
"required": ["type"],
"additionalProperties": false
}
],
"description": "How customers earn stamps on this card."
},
"overflowPolicy": {
"type": "string",
"enum": ["carry", "discard"],
"description": "What happens to stamps earned past the card's completion threshold. `carry` starts the customer's next card with them; `discard` drops them."
},
"allowMultipleOpenCards": {
"type": "boolean",
"description": "Whether a member may hold more than one open card of this type at a time."
},
"availableFrom": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When customers can start collecting on this card. Null means straight away."
},
"availableTo": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When collecting on this card stops. Null means it stays open."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was last changed."
}
},
"required": [
"id",
"loyaltyProgramId",
"name",
"earningType",
"overflowPolicy",
"allowMultipleOpenCards",
"availableFrom",
"availableTo",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The new stamp card type."
}GET /stamp-card-types/{id}
Get a single stamp card type by ID.
Requires the loyalty:read permission.
Path Parameters
idstring (uuid)requiredThe ID of the stamp card type.
Query Parameters
includestringA comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: completionThreshold.
curl \
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@cascade-commerce/api/admin/client"
import { getStampCardTypesById } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getStampCardTypesById({
path: { id: "550e8400-e29b-41d4-a716-446655440000" },
})require "net/http"
uri = URI("https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport json
from urllib.request import Request, urlopen
req = Request(
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000",
headers={"Authorization": "Bearer sk_YOUR_SECRET_KEY"},
)
with urlopen(req) as res:
print(json.load(res)){
"id": "550e8400-e29b-41d4-a716-446655440000",
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z",
"completionThreshold": 0
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the stamp card type."
},
"loyaltyProgramId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The loyalty program the card type belongs to."
},
"name": {
"type": "string",
"description": "The card type's display name, shown to members."
},
"earningType": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerOrder",
"description": "Awards a fixed number of stamps per order."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded for each qualifying order."
}
},
"required": ["type", "stamps"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerSpend",
"description": "Awards stamps in proportion to the amount spent."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded per unit spent."
},
"unitAmountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How much a customer has to spend, in cents, to earn one batch of stamps."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
}
},
"required": ["type", "stamps", "unitAmountCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "custom",
"description": "Stamps are awarded by your own code through `POST /loyalty-stamps` rather than automatically."
}
},
"required": ["type"],
"additionalProperties": false
}
],
"description": "How customers earn stamps on this card."
},
"overflowPolicy": {
"type": "string",
"enum": ["carry", "discard"],
"description": "What happens to stamps earned past the card's completion threshold. `carry` starts the customer's next card with them; `discard` drops them."
},
"allowMultipleOpenCards": {
"type": "boolean",
"description": "Whether a member may hold more than one open card of this type at a time."
},
"availableFrom": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When customers can start collecting on this card. Null means straight away."
},
"availableTo": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When collecting on this card stops. Null means it stays open."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was last changed."
},
"completionThreshold": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The stamp count at which a card of this type is full, derived from the type's highest live `stampsEarned` rule. Null means no rule targets the type, so its cards never complete."
}
},
"required": [
"id",
"loyaltyProgramId",
"name",
"earningType",
"overflowPolicy",
"allowMultipleOpenCards",
"availableFrom",
"availableTo",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The requested stamp card type."
}PUT /stamp-card-types/{id}
Update a stamp card type. The loyalty program it belongs to cannot change.
Requires the loyalty:write permission.
Path Parameters
idstring (uuid)requiredThe ID of the stamp card type to update.
Body Parameters
dataobjectrequiredThe fields to update.
curl \
-X PUT \
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}'import { client } from "@cascade-commerce/api/admin/client"
import { putStampCardTypesById } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await putStampCardTypesById({
path: { id: "550e8400-e29b-41d4-a716-446655440000" },
body: {
data: {
name: "string",
earningType: {
type: "stampsPerOrder",
stamps: 0,
},
overflowPolicy: "carry",
allowMultipleOpenCards: true,
availableFrom: "2025-01-15T09:30:00Z",
availableTo: "2025-01-15T09:30:00Z",
},
},
})require "net/http"
uri = URI("https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
req["Content-Type"] = "application/json"
req.body = <<~JSON
{
"data": {
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}
JSON
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport json
from urllib.request import Request, urlopen
body = """{
"data": {
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z"
}
}"""
req = Request(
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000",
data=body.encode(),
method="PUT",
headers={
"Authorization": "Bearer sk_YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
)
with urlopen(req) as res:
print(json.load(res)){
"id": "550e8400-e29b-41d4-a716-446655440000",
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the stamp card type."
},
"loyaltyProgramId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The loyalty program the card type belongs to."
},
"name": {
"type": "string",
"description": "The card type's display name, shown to members."
},
"earningType": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerOrder",
"description": "Awards a fixed number of stamps per order."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded for each qualifying order."
}
},
"required": ["type", "stamps"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerSpend",
"description": "Awards stamps in proportion to the amount spent."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded per unit spent."
},
"unitAmountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How much a customer has to spend, in cents, to earn one batch of stamps."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
}
},
"required": ["type", "stamps", "unitAmountCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "custom",
"description": "Stamps are awarded by your own code through `POST /loyalty-stamps` rather than automatically."
}
},
"required": ["type"],
"additionalProperties": false
}
],
"description": "How customers earn stamps on this card."
},
"overflowPolicy": {
"type": "string",
"enum": ["carry", "discard"],
"description": "What happens to stamps earned past the card's completion threshold. `carry` starts the customer's next card with them; `discard` drops them."
},
"allowMultipleOpenCards": {
"type": "boolean",
"description": "Whether a member may hold more than one open card of this type at a time."
},
"availableFrom": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When customers can start collecting on this card. Null means straight away."
},
"availableTo": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When collecting on this card stops. Null means it stays open."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was last changed."
}
},
"required": [
"id",
"loyaltyProgramId",
"name",
"earningType",
"overflowPolicy",
"allowMultipleOpenCards",
"availableFrom",
"availableTo",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The updated stamp card type."
}DELETE /stamp-card-types/{id}
Delete a stamp card type. Every card of the type, open or complete, is deleted with it; rewards already earned are kept.
Requires the loyalty:write permission.
Path Parameters
idstring (uuid)requiredThe ID of the stamp card type to delete.
curl \
-X DELETE \
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@cascade-commerce/api/admin/client"
import { deleteStampCardTypesById } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await deleteStampCardTypesById({
path: { id: "550e8400-e29b-41d4-a716-446655440000" },
})require "net/http"
uri = URI("https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport json
from urllib.request import Request, urlopen
req = Request(
"https://api.cascade.dev/stamp-card-types/550e8400-e29b-41d4-a716-446655440000",
method="DELETE",
headers={"Authorization": "Bearer sk_YOUR_SECRET_KEY"},
)
with urlopen(req) as res:
print(json.load(res)){
"id": "550e8400-e29b-41d4-a716-446655440000",
"loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
"name": "string",
"earningType": {
"type": "stampsPerOrder",
"stamps": 0
},
"overflowPolicy": "carry",
"allowMultipleOpenCards": true,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the stamp card type."
},
"loyaltyProgramId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The loyalty program the card type belongs to."
},
"name": {
"type": "string",
"description": "The card type's display name, shown to members."
},
"earningType": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerOrder",
"description": "Awards a fixed number of stamps per order."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded for each qualifying order."
}
},
"required": ["type", "stamps"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "stampsPerSpend",
"description": "Awards stamps in proportion to the amount spent."
},
"stamps": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Stamps awarded per unit spent."
},
"unitAmountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How much a customer has to spend, in cents, to earn one batch of stamps."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
}
},
"required": ["type", "stamps", "unitAmountCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "custom",
"description": "Stamps are awarded by your own code through `POST /loyalty-stamps` rather than automatically."
}
},
"required": ["type"],
"additionalProperties": false
}
],
"description": "How customers earn stamps on this card."
},
"overflowPolicy": {
"type": "string",
"enum": ["carry", "discard"],
"description": "What happens to stamps earned past the card's completion threshold. `carry` starts the customer's next card with them; `discard` drops them."
},
"allowMultipleOpenCards": {
"type": "boolean",
"description": "Whether a member may hold more than one open card of this type at a time."
},
"availableFrom": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When customers can start collecting on this card. Null means straight away."
},
"availableTo": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When collecting on this card stops. Null means it stays open."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the card type was last changed."
}
},
"required": [
"id",
"loyaltyProgramId",
"name",
"earningType",
"overflowPolicy",
"allowMultipleOpenCards",
"availableFrom",
"availableTo",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The deleted stamp card type."
}