Documentation index for AI agents

GS2-Exchange Transaction Actions

Specification of verify/consume/acquire transaction actions

Combining actions, and concurrency

The background common to every service is collected in Combining Transaction Actions. Read that first; the rest of this section is what GS2-Exchange adds to it.

The transaction actions of GS2-Exchange fall into two groups: those that go through an await, and those that exchange in one go. An await is identified by the combination of namespace, user, and await name.

OperationRepeated in one transactionAcross a nested transactionBoundary that separates targets
Creating an await
CreateAwaitByUserId
Combined at the same exchange rate, and the counts added upFailsnamespace, user, exchange rate
Skipping an await
SkipByUserId
Combined, and the shortened times added upFailsnamespace, user, await
Taking the result of an await
AcquireForceByUserId
Combined into oneFailsnamespace, user, await
Discarding an await
DeleteAwaitByUserId
Combined into oneFailsnamespace, user, await
Exchanging in one go
ExchangeByUserId IncrementalExchangeByUserId
Combined at the same rate, and the counts added upDoes not touch an awaitnamespace, user, exchange rate

Taking the result and discarding both remove an await, and creating adds one, so placing two of those in one transaction collides. Skipping and then taking the result does not work in one transaction either: taking the result is judged against the state at the start of the transaction, so the skip is not yet visible.

ExchangeByUserId and IncrementalExchangeByUserId do not touch an await at all. They work out what to consume and what to acquire and issue those as a transaction of their own, so the restrictions of whichever services those belong to apply, and so does the section below. An incremental exchange also raises the rate as it goes, which is part of what it issues.

Take care with nested transactions

An await created from the inside collides with an await taken or discarded from the outside, and the transaction fails.

If you want to avoid these restrictions

Creating an await, skipping it, taking its result, and exchanging in one go are acquire actions; discarding an await is a consume action. Turning acquireActionUseJobQueue on clears collisions between acquire actions. Turning enableAtomicCommit off clears a collision with a discard, and the discard then runs before the acquire actions.

Concurrency and retries

Where several requests touch the same await at the same time, the one confirmed later returns a conflict (409). Retrying re-evaluates against the latest state, so it succeeds if the await is still there and returns an error if it has already been taken or discarded.

A different await name is a different target, so requests for different awaits do not conflict.


Consume Action

Gs2Exchange:DeleteAwaitByUserId

Delete Exchange Await by User ID

Deletes an exchange await record for the specified user. This cancels the pending exchange, and any rewards that have not yet been acquired are forfeited.

Quantity specification supported: NO

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
awaitNamestring
UUID~ 36 charsExchange Await name
Maintains a unique name for each Exchange Await.
The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await.
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:DeleteAwaitByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "awaitName": "[string]Exchange Await name",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:DeleteAwaitByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  awaitName: "[string]Exchange Await name"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").consume.delete_await_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    awaitName="[string]Exchange Await name",
    timeOffsetToken="[string]Time offset token",
})

Acquire Action

Gs2Exchange:ExchangeByUserId

Perform exchange by User ID

Executes a resource exchange based on the specified Exchange Rate Model for the specified user. Validates the rate model’s timing type: for ‘immediate’ timing, the Namespace must have direct exchange enabled; for ‘await’ timing, the Namespace must have await exchange enabled. A transaction (transaction) is issued to execute the consume/verify/acquire actions defined in the rate model, multiplied by the specified count.

Quantity specification supported: YES

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
rateNamestring
~ 128 charsExchange Rate Model name
Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
countint
1 ~ 1073741821Number of exchanges
configList<Config>[]0 ~ 32 itemsConfiguration values applied to transaction variables
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:ExchangeByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "rateName": "[string]Exchange Rate Model name",
        "userId": "[string]User ID",
        "count": "[int]Number of exchanges",
        "config": [
            {
                "key": "[string]Name",
                "value": "[string]Value"
            }
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:ExchangeByUserId
request:
  namespaceName: "[string]Namespace name"
  rateName: "[string]Exchange Rate Model name"
  userId: "[string]User ID"
  count: "[int]Number of exchanges"
  config: 
    - key: "[string]Name"
      value: "[string]Value"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").acquire.exchange_by_user_id({
    namespaceName="[string]Namespace name",
    rateName="[string]Exchange Rate Model name",
    userId="[string]User ID",
    count="[int]Number of exchanges",
    config={
        {
            key="[string]Name",
            value="[string]Value"
        }
    },
    timeOffsetToken="[string]Time offset token",
})

Gs2Exchange:IncrementalExchangeByUserId

Perform incremental cost exchange by User ID

Executes a resource exchange where the cost increases progressively with each execution, based on the specified Incremental Cost Exchange Rate Model for the specified user. The consume cost is calculated according to the model’s calculation type (linear formula or GS2-Script) and the current exchange count. A transaction (transaction) is issued to execute the consume and acquire actions.

Quantity specification supported: YES

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
rateNamestring
~ 128 charsIncremental Cost Exchange Rate Model name
Unique Incremental Cost Exchange Rate Model name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
countint
1 ~ 1073741821Number of exchanges
configList<Config>[]0 ~ 32 itemsConfiguration values applied to transaction variables
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:IncrementalExchangeByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "rateName": "[string]Incremental Cost Exchange Rate Model name",
        "userId": "[string]User ID",
        "count": "[int]Number of exchanges",
        "config": [
            {
                "key": "[string]Name",
                "value": "[string]Value"
            }
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:IncrementalExchangeByUserId
request:
  namespaceName: "[string]Namespace name"
  rateName: "[string]Incremental Cost Exchange Rate Model name"
  userId: "[string]User ID"
  count: "[int]Number of exchanges"
  config: 
    - key: "[string]Name"
      value: "[string]Value"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").acquire.incremental_exchange_by_user_id({
    namespaceName="[string]Namespace name",
    rateName="[string]Incremental Cost Exchange Rate Model name",
    userId="[string]User ID",
    count="[int]Number of exchanges",
    config={
        {
            key="[string]Name",
            value="[string]Value"
        }
    },
    timeOffsetToken="[string]Time offset token",
})

Gs2Exchange:CreateAwaitByUserId

Create Exchange Await by User ID

Creates a new exchange await record for a time-delayed exchange. The specified rate model must have its timing type set to ‘await’; otherwise the request is rejected. The await starts with zero skip seconds, and the lock time defined in the rate model determines how long the user must wait before acquiring the rewards. Default configuration values can be set at creation time and will be merged with any config provided at acquisition time.

Quantity specification supported: YES

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
rateNamestring
~ 128 charsExchange Rate Model name
Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
countint11 ~ 10000Number of exchanges
The number of times this exchange should be performed. Multiple exchanges can be batched into a single await, multiplying both the cost consumed and the rewards received.
configList<Config>[]0 ~ 32 itemsDefault configuration values applied when obtaining rewards
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:CreateAwaitByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "rateName": "[string]Exchange Rate Model name",
        "count": "[int]Number of exchanges",
        "config": [
            {
                "key": "[string]Name",
                "value": "[string]Value"
            }
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:CreateAwaitByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  rateName: "[string]Exchange Rate Model name"
  count: "[int]Number of exchanges"
  config: 
    - key: "[string]Name"
      value: "[string]Value"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").acquire.create_await_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    rateName="[string]Exchange Rate Model name",
    count="[int]Number of exchanges",
    config={
        {
            key="[string]Name",
            value="[string]Value"
        }
    },
    timeOffsetToken="[string]Time offset token",
})

Gs2Exchange:AcquireForceByUserId

Receive rewards for Exchange Await without waiting for the lock time

Force-acquires the rewards for an exchange await regardless of whether the lock time has elapsed. This bypasses the normal wait time check, allowing immediate reward acquisition. The provided config values are merged with the default config set at await creation time. A transaction (transaction) is issued to execute the acquire actions defined in the rate model.

Quantity specification supported: NO

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
awaitNamestring
UUID~ 36 charsExchange Await name
Maintains a unique name for each Exchange Await.
The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await.
configList<Config>[]0 ~ 32 itemsConfiguration values applied to transaction variables
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:AcquireForceByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "awaitName": "[string]Exchange Await name",
        "config": [
            {
                "key": "[string]Name",
                "value": "[string]Value"
            }
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:AcquireForceByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  awaitName: "[string]Exchange Await name"
  config: 
    - key: "[string]Name"
      value: "[string]Value"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").acquire.acquire_force_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    awaitName="[string]Exchange Await name",
    config={
        {
            key="[string]Name",
            value="[string]Value"
        }
    },
    timeOffsetToken="[string]Time offset token",
})

Gs2Exchange:SkipByUserId

Skip Exchange Await by User ID

Accelerates or skips the waiting time of an exchange await. Supports four skip types: ‘complete’ skips the entire remaining wait, ‘minutes’ adds the specified minutes to skip seconds, ’totalRate’ skips a percentage of the total lock time, and ‘remainRate’ skips a percentage of the remaining wait time. The skip seconds are capped at the total lock time and cannot exceed it.

Quantity specification supported: YES

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
awaitNamestring
UUID~ 36 charsExchange Await name
Maintains a unique name for each Exchange Await.
The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await.
skipTypestring (enum)
enum {
  “complete”,
  “minutes”,
  “totalRate”,
  “remainRate”
}
“complete”Skip type
DefinitionDescription
completeComplete skip
minutesSkip by specifying time(minutes)
totalRateSkip by specifying the percentage of total waiting time
remainRateSkip by specifying the percentage of remaining waiting time
minutesint{skipType} == “minutes”0 ~ 2147483646Minutes to skip
* Enabled only if skipType is “minutes”
ratefloat{skipType} == “totalRate” or {skipType} == “remainRate”0 ~ 1Percentage of time to skip
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Exchange:SkipByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "awaitName": "[string]Exchange Await name",
        "skipType": "[string]Skip type",
        "minutes": "[int]Minutes to skip",
        "rate": "[float]Percentage of time to skip",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Exchange:SkipByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  awaitName: "[string]Exchange Await name"
  skipType: "[string]Skip type"
  minutes: "[int]Minutes to skip"
  rate: "[float]Percentage of time to skip"
  timeOffsetToken: "[string]Time offset token"
transaction.service("exchange").acquire.skip_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    awaitName="[string]Exchange Await name",
    skipType="[string]Skip type",
    minutes="[int]Minutes to skip",
    rate="[float]Percentage of time to skip",
    timeOffsetToken="[string]Time offset token",
})