Customers
Read customers, adjust their store credit, grant gift cards, and ban or unban them.
The customers endpoints read a store's customers and act on them: update their details, change their store credit, grant a gift card, and ban or unban them. Field shapes are on the Object reference page.
Throughout this page, {identifier} is a resident's Second Life username or avatar UUID. An identifier that cannot be resolved returns 400 (when it is malformed) or 404 (when no resident matches).
Watch the scopes: the credit endpoints use the credits:* scopes and the gift-card grant uses giftcards:write, even though they live under /customers. Each endpoint lists its own scope below.
Reading customers
List customers
GET /v1/customersReturns a cursor-paginated list of the store's customers. Scope: customers:read. Query parameters limit and cursor are optional; see Pagination and errors.
You can also narrow the list with optional filters:
newsSubscriber(boolean): return only customers who are, or are not, subscribed to the store news kiosk.spentMoreThan(integer): return only customers whose lifetime spend (the same value the Get a customer's spend endpoint returns assum) is strictly greater than this amount inL$. A customer whose spend equals the value is excluded, and a customer with no recorded spend counts as 0, so any value of 0 or more excludes them.
Filters are optional and combine with AND.
curl --fail-with-body "https://integrations.allomancy.net/v1/customers?limit=50" \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"import requests
response = requests.get(
"https://integrations.allomancy.net/v1/customers",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
params={"limit": 50},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers?limit=50",
{
headers: { "X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w" },
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers?limit=50");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;{
"data": [
{
"uuid": "c7d8e9f0-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
"username": "resident.username",
"credit": 120,
"restrictedCredit": 0,
"discount": 5,
"newsSubscriber": true,
"isBanned": false
}
],
"pagination": { "nextCursor": null, "previousCursor": null, "limit": 50 }
}Each row is a CustomerResponse. Status: 200, or 400 for a bad pagination parameter.
Get a customer
GET /v1/customers/{identifier}Returns one customer, including their ban state. Scope: customers:read.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"import requests
response = requests.get(
"https://integrations.allomancy.net/v1/customers/resident.username",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username",
{
headers: { "X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w" },
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;The response is a CustomerResponse. Status: 200, 400, or 404.
Get a customer's credit
GET /v1/customers/{identifier}/creditReturns just the customer's credit balances. Scope: credits:read. These are the raw stored balances, so they can briefly read higher than the customer's spendable credit until an expiry sweep or the customer's next credit change reconciles any lots that have come due.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/credit \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"import requests
response = requests.get(
"https://integrations.allomancy.net/v1/customers/resident.username/credit",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/credit",
{
headers: { "X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w" },
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/credit");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;{
"uuid": "c7d8e9f0-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
"username": "resident.username",
"credit": 120,
"restrictedCredit": 0
}The response is a CustomerCreditResponse. Status: 200, 400, or 404.
Get a customer's spend
GET /v1/customers/{identifier}/spendReturns the customer's lifetime and last-year spend and how many products they own. Scope: customers:read.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/spend \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"import requests
response = requests.get(
"https://integrations.allomancy.net/v1/customers/resident.username/spend",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/spend",
{
headers: { "X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w" },
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/spend");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;{
"uuid": "c7d8e9f0-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
"username": "resident.username",
"sum": 4820,
"lastYearSum": 1310,
"totalOwned": 17
}The response is a CustomerSpendResponse. Status: 200, 400, or 404.
Updating a customer
PUT /v1/customers/{identifier}Updates a customer's per-customer discount and news-kiosk subscription. Scope: customers:write. The body is an UpdateCustomerRequest.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username \
-X PUT \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "discount": 10, "newsSubscriber": true }'import requests
response = requests.put(
"https://integrations.allomancy.net/v1/customers/resident.username",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"discount": 10, "newsSubscriber": True},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username",
{
method: "PUT",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ discount: 10, newsSubscriber: true }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"discount" => 10,
"newsSubscriber" => true,
]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;The response is a CustomerResponse. Status: 200, 400, or 404.
Adjusting store credit
Two pairs of actions change a customer's credit: a set that writes an absolute balance, and an increment that applies a change. Each has a regular and a restricted variant. All four use the credits:write scope and return a CustomerCreditResponse. Store credit is tracked as expiring lots, each with an expiresAt, and that lot model is why set and increment behave differently.
Set is destructive. set-credit and set-restricted-credit write an absolute balance: in one transaction they close every open credit lot of that type (each marked superseded) and rewrite the balance. Pass expiresAt with a positive credit to create one covering lot for the whole new balance; with no expiresAt, the balance becomes permanent unlotted credit with no open lots. The flat response does not report that any lots were closed. To add expiring credit while preserving the customer's existing lots, use increment instead.
Set credit
POST /v1/customers/{identifier}/actions/set-credit
POST /v1/customers/{identifier}/actions/set-restricted-creditWrites the balance to an absolute value. The body is a SetCustomerCreditRequest, where credit is the new balance in L$ and expiresAt is an optional ISO 8601 datetime. Supply expiresAt with a positive credit to place the whole new balance in one covering lot that expires then; omit it to leave the balance as permanent unlotted credit. An expiresAt already in the past is rejected with 400, and the balance is left unchanged. Each variant is scoped to one credit type: setting regular credit does not touch restricted lots, and setting restricted credit does not touch regular lots.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/set-credit \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "credit": 200, "expiresAt": "2026-12-31T23:59:59Z" }'import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/set-credit",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"credit": 200, "expiresAt": "2026-12-31T23:59:59Z"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/set-credit",
{
method: "POST",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ credit: 200, expiresAt: "2026-12-31T23:59:59Z" }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/set-credit");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["credit" => 200, "expiresAt" => "2026-12-31T23:59:59Z"]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;This example sets the balance to L$200 in one lot that expires on 2026-12-31T23:59:59Z; omit expiresAt to leave the balance as permanent unlotted credit.
Status: 200, 400, or 404.
Increment credit
POST /v1/customers/{identifier}/actions/increment-credit
POST /v1/customers/{identifier}/actions/increment-restricted-creditApplies a change to the current balance. The body is an IncrementCustomerCreditRequest, where a positive delta adds credit and a negative delta removes it. Unlike set, increment never closes existing lots. A positive delta with an expiresAt adds one new lot for that amount; a positive delta with no expiresAt adds unlotted credit; a negative delta drains existing lots first-expiring-first. Use increment when you want to add expiring credit without disturbing the customer's current lots. An expiresAt cannot be sent with a negative delta, and doing so returns 400.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "delta": -50 }'import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"delta": -50},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit",
{
method: "POST",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ delta: -50 }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["delta" => -50]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;To add expiring credit as a new lot, send a positive delta with an expiresAt:
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "delta": 100, "expiresAt": "2026-12-31T23:59:59Z" }'import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"delta": 100, "expiresAt": "2026-12-31T23:59:59Z"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit",
{
method: "POST",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ delta: 100, expiresAt: "2026-12-31T23:59:59Z" }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/increment-credit");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["delta" => 100, "expiresAt" => "2026-12-31T23:59:59Z"]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;This adds a new lot of L$100 that expires on 2026-12-31T23:59:59Z, leaving the customer's existing lots untouched.
Status: 200, or 400 (for example when adding would exceed the credit limit, or when removing more than the customer holds), or 404.
Granting a gift card
POST /v1/customers/{identifier}/actions/grant-gift-cardCreates a gift card for the customer. Scope: giftcards:write. The body is a GrantGiftCardRequest, where credit is the gift card balance in L$.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/grant-gift-card \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "credit": 500, "texture": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "transfer": false }'import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/grant-gift-card",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"credit": 500, "texture": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "transfer": False},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/grant-gift-card",
{
method: "POST",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ credit: 500, texture: "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", transfer: false }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/grant-gift-card");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"credit" => 500,
"texture" => "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"transfer" => false,
]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;The response is a GiftCardResponse. Status: 200, 400, or 404. This grant is the only way to create a gift card through the API; see Gift cards for reading and updating one afterward.
Banning and unbanning
POST /v1/customers/{identifier}/actions/ban
POST /v1/customers/{identifier}/actions/unbanBans or unbans a customer. Scope: customers:write. Both return a CustomerBanStateResponse.
The ban action's body is an optional BanCustomerRequest. Send a reason to record one, or omit the body to ban without a reason.
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/ban \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w" \
-H "Content-Type: application/json" \
-d '{ "reason": "Chargeback fraud" }'import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/ban",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
json={"reason": "Chargeback fraud"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/ban",
{
method: "POST",
headers: {
"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type": "application/json",
},
body: JSON.stringify({ reason: "Chargeback fraud" }),
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/ban");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"X-API-Key: allo_live_8Kd2...zQ.Hk9...4w",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["reason" => "Chargeback fraud"]));
$response = curl_exec($ch);
curl_close($ch);
echo $response;{
"uuid": "c7d8e9f0-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
"username": "resident.username",
"isBanned": true
}The unban action takes no body:
curl --fail-with-body https://integrations.allomancy.net/v1/customers/resident.username/actions/unban \
-X POST \
-H "X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"import requests
response = requests.post(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/unban",
headers={"X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w"},
)
print(response.json())const response = await fetch(
"https://integrations.allomancy.net/v1/customers/resident.username/actions/unban",
{
method: "POST",
headers: { "X-API-Key": "allo_live_8Kd2...zQ.Hk9...4w" },
},
);
console.log(await response.json());<?php
$ch = curl_init("https://integrations.allomancy.net/v1/customers/resident.username/actions/unban");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: allo_live_8Kd2...zQ.Hk9...4w"]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Status for both: 200, 400, or 404.
Applying coupons
Coupons can also be applied to or revoked from a customer through actions under /v1/customers/{identifier}/actions/. See Coupons for the apply-coupon and revoke-coupon endpoints.