Configure Velocity Controls
Overview
Spend rule & velocity control results may not be visible for up to 15 seconds after a Transaction Event. See Spend rule latency.
Velocity controls allow time boundary constraints to be applied to a spend rule. The following example explains the difference between velocity controls and spend rules:
The following example explains the difference between velocity controls and spend rules:
- A payment card has a spend rule to decline all authorizations over $1,000.
- For the same payment card, a velocity control is added to decline any authorizations that exceed $1,000 within a calendar week.
- This creates a velocity control that enforces a weekly spending limit of $1,000.
The following graphic shows how a velocity control is created and applied at the card product and payment card levels:
Velocity control windows
You can set velocity control time frames using several time windows. The following table describes available velocity control windows:
| Velocity Rule Window | Description |
|---|---|
| DAILY | One calendar day, 00:00:00 UTC to 23:59:59 UTC |
| WEEKLY | One calendar week, Sunday 00:00:00 UTC to Saturday 23:59:59 UTC |
| MONTHLY | One calendar month, UTC start of month to UTC end of month |
| NINETY_DAYS | 90 calendar days moving window. One calendar day is from 00:00:00 UTC to 23:59:59 UTC |
| QUARTERLY | One calendar quarter, UTC start of quarter to UTC end of quarter |
| Q1: Jan - March, Q2: April - June, Q3: July - September, Q4: October - December | |
| YEARLY | One calendar year, UTC start of year to UTC end of year |
| PER_TRANSACTION | Velocity Rule is evaluated on every transaction individually |
| COOLDOWN_MINUTE | Cooldown period of one minute, e.g., with count rule of 1, cardholder must wait one minute between transactions |
| COOLDOWN_HOUR | Cooldown period of one hour, e.g., with count rule of 1, cardholder must wait one hour between transactions |
The UTC start/end times above are the default. DAILY, WEEKLY, MONTHLY, QUARTERLY, and YEARLY windows can instead measure against a specified time zone — see Velocity control time zones below.
To start a WEEKLY window on Monday instead, see Set a start of week.
Velocity control time zones
By default, every velocity control window measures against UTC. Two optional fields let a velocity control measure against a specified time zone instead.
Both fields appear on every velocity control your organization reads. Only organizations Highnote has enabled can set them, on create or edit. Contact your Highnote representative to request enablement for your organization.
Set a time zone
Pass velocityWindowTimeZone on CreateVelocityRuleInput as a time zone identifier from the IANA time zone database. Use an Area/Location name such as America/New_York where you can; it's the recommended form. A velocity control created without a time zone keeps UTC behavior. This does not change any existing velocity control.
| Accepted | Examples |
|---|---|
| IANA region identifier | America/New_York, Asia/Tokyo, Asia/Kolkata, America/Phoenix |
| Legacy IANA identifier | CET, EET, MET, WET, EST5EDT, CST6CDT, MST7MDT, PST8PDT, US/Eastern |
| UTC | UTC, or leave the field unset |
| Rejected | Examples |
|---|---|
| Fixed offset | +05:00, Etc/GMT+5 |
| Bare abbreviation | EST, MST, HST, PST |
| Empty string | "" |
| Alternate spelling of UTC | Etc/UTC, GMT, Z, Zulu |
Only some velocity rule windows accept a time zone:
| Velocity Rule Window | Accepts a time zone |
|---|---|
DAILY | Yes |
WEEKLY | Yes |
MONTHLY | Yes |
QUARTERLY | Yes |
YEARLY | Yes |
NINETY_DAYS | No — rejected |
PER_TRANSACTION | No — rejected |
COOLDOWN_MINUTE | No — rejected |
COOLDOWN_HOUR | No — rejected |
And only spend velocity controls accept a time zone at all — every other rule family shares the same window options but stays on UTC:
| Velocity Rule Family | Accepts a time zone |
|---|---|
| Spend | Yes |
| Transfer | No — always UTC |
| Inter-financial-account transfer | No — always UTC |
| Check | No — always UTC |
| Dispute | No — always UTC |
| Real-time payment | No — always UTC |
| Risk | No — always UTC |
Set a start of week
Pass velocityWindowStartOfWeek to set which day a WEEKLY window starts, at midnight in velocityWindowTimeZone:
| Value | Week starts |
|---|---|
SUNDAY | Sunday |
MONDAY | Monday |
Whether it's required, optional, or rejected depends on the window and whether a time zone is set:
velocityRuleWindow | Time zone set? | velocityWindowStartOfWeek |
|---|---|---|
WEEKLY | Yes | Required |
WEEKLY | No | Rejected |
| Any other window | Yes or no | Rejected |
A WEEKLY velocity control with no time zone starts its week on Sunday at 00:00:00 UTC. To start the week on Monday and stay on UTC, set velocityWindowTimeZone to UTC and velocityWindowStartOfWeek to MONDAY. Your organization must be enabled to set these fields.
Daylight saving time
A time zone that observes daylight saving keeps the window on the local calendar day, not a fixed 24-hour span. On the day the clock springs forward, that day's window is 23 hours long. On the day it falls back, the window is 25 hours long. Either way, the window still closes at local midnight, and every transaction counts toward exactly one window. A time zone that never observes daylight saving, such as America/Phoenix, keeps a window the same length year-round.
Limits
You can add three spend rules to a velocity control. Additionally, velocity controls have limits at the card product, financial account, and payment card levels:
- Card product: Limit of 10 velocity controls per card product
- Financial account: Limit of 10 velocity controls per financial account
- Payment card: Limit of 10 velocity controls per payment card
Velocity controls for authorized users
To create velocity controls for an authorized user, ensure that the spend rules for that authorized user were created with "userType": "AUTHORIZED_USER". Other than that, there is no difference from the standard velocity control.
Create velocity control
An amount spend rule, or cumulative rule, is required to create a velocity control.
To create a velocity control, you must first create spend rules, one of which must be an amount rule. You can add up to three spend rules to a velocity control. Create the velocity rule with the spend rule IDs. Velocity controls authorize transactions based on whether the associated spend rule's conditions are met within the velocity control window.
The following example uses multiple spend rules to create a velocity control for airline purchases:
- Create an amount limit spend rule for $1000.
- Create a MCC spend rule for airline purchases.
- Add both spend rules to a monthly velocity control.
- Your velocity control will limit only airline purchases to $1000 a month.
Use the following mutation to create a velocity control:
CreateVelocityRule
Query
mutation CreateVelocityRule($input: CreateVelocityRuleInput!) {
createVelocityRule(input: $input) {
__typename
... on VelocityRule {
id
name
version
velocityRuleWindow
cumulativeRule {
id
}
spendRules {
id
}
createdAt
updatedAt
}
... on UserError {
errors {
code
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "name": "My Rule", "velocityRuleWindow": "DAILY", "cumulativeRule": { "id": "<CUMULATIVE_RULE_ID>", "version": "0" }, "spendRules": [ { "id": "<SPEND_RULE_ID>", "version": "0" } ] } }
Result
{
"data": {
"createVelocityRule": {
"__typename": "VelocityRule",
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0",
"cumulativeRule": {
"id": "<CUMULATIVE_RULE_ID>",
"name": "dollar amount rule",
"version": "0"
},
"spendRules": [
{
"id": "<SPEND_RULE_ID>",
"name": "Merchant Rule",
"version": "0"
}
],
"createdAt": "2021-08-12T21:09:25.475Z",
"updatedAt": "2021-08-12T21:09:25.476Z"
}
}
}
Attach velocity control to a card product
Velocity controls can be attached to a card product, a financial account, or an individual payment card. Attaching a velocity control to a card product applies the spend rules and velocity control to all financial accounts and payment cards for your card product.
Use the following mutation to create a velocity control for a card product:
AttachCardProductVelocityRule
Query
mutation AttachCardProductVelocityRule(
$input: AttachCardProductVelocityRuleInput!
) {
attachCardProductVelocityRule(input: $input) {
__typename
... on VelocityRuleAssociation {
velocityRule {
id
name
version
cumulativeRule {
id
name
version
}
createdAt
updatedAt
}
associatedTo {
... on PaymentCard {
id
}
... on CardProduct {
id
}
}
}
... on UserError {
errors {
code
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "cardProductId": "<CARD_PRODUCT_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"attachCardProductVelocityRule": {
"__typename": "VelocityRuleAssociation",
"velocityRule": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0",
"cumulativeRule": {
"id": "<CUMULATIVE_RULE_ID>",
"name": "dollar amount rule",
"version": "0"
},
"createdAt": "2021-08-12T21:09:25.475Z",
"updatedAt": "2021-08-12T21:09:25.476Z"
},
"associatedTo": {
"__typename": "CardProduct",
"id": "<CARD_PRODUCT_ID>"
}
}
}
}
Attach velocity control to a payment card
Velocity controls can be attached to a card product, a financial account, or an individual payment card. Velocity controls attached to a payment card only apply to that specific payment card.
Use the following mutation to attach a velocity control to a payment card:
AttachPaymentCardVelocityRule
Query
mutation AttachPaymentCardVelocityRule(
$input: AttachPaymentCardVelocityRuleInput!
) {
attachPaymentCardVelocityRule(input: $input) {
__typename
... on VelocityRuleAssociation {
velocityRule {
id
name
version
cumulativeRule {
id
name
version
}
createdAt
updatedAt
}
associatedTo {
... on CardProduct {
id
}
... on PaymentCard {
id
}
}
}
... on UserError {
errors {
code
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "paymentCardId": "<PAYMENT_CARD_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"attachPaymentCardVelocityRule": {
"__typename": "VelocityRuleAssociation",
"velocityRule": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0",
"cumulativeRule": {
"id": "<CUMULATIVE_RULE_ID>",
"name": "dollar amount rule",
"version": "0"
},
"createdAt": "2021-08-12T21:09:25.475Z",
"updatedAt": "2021-08-12T21:09:25.476Z"
},
"associatedTo": {
"__typename": "PaymentCard",
"id": "<PAYMENT_CARD_ID>"
}
}
}
}
Attach velocity control to a financial account
Velocity controls can be attached to a card product, a financial account, or an individual payment card. Velocity controls attached to a financial account apply to all payment cards linked to the financial account.
Use the following mutation to attach a velocity control to a financial account:
AttachVelocityRuleToFinancialAccount
Query
mutation AttachVelocityRuleToFinancialAccount(
$input: AttachVelocityRuleToFinancialAccountInput!
) {
attachVelocityRuleToFinancialAccount(input: $input) {
__typename
... on FinancialAccount {
id
attachedVelocityRules {
edges {
node {
id
name
version
}
}
}
}
... on UserError {
errors {
code
path
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "financialAccountId": "<FINANCIAL_ACCOUNT_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"attachVelocityRuleToFinancialAccount": {
"__typename": "FinancialAccount",
"id": "<FINANCIAL_ACCOUNT_ID>",
"attachedVelocityRules": {
"edges": [
{
"node": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0"
}
}
]
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>"
}
}
Detach velocity control from a card product
If you detach and re-attach a velocity, the balance on the "count" and "windows" of the velocity control will reset.
Use the following mutation to detach a velocity control from a card product:
DetachCardProductVelocityRule
Query
mutation DetachCardProductVelocityRule(
$input: DetachCardProductVelocityRuleInput!
) {
detachCardProductVelocityRule(input: $input) {
__typename
... on VelocityRuleAssociation {
velocityRule {
id
name
version
cumulativeRule {
id
name
version
}
createdAt
updatedAt
}
associatedTo {
... on PaymentCard {
id
}
... on CardProduct {
id
}
}
}
... on UserError {
errors {
code
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "cardProductId": "<CARD_PRODUCT_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"detachCardProductVelocityRule": {
"__typename": "VelocityRuleAssociation",
"velocityRule": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0",
"cumulativeRule": {
"id": "<CUMULATIVE_RULE_ID>",
"name": "dollar amount rule",
"version": "0"
},
"createdAt": "2021-08-12T21:09:25.475Z",
"updatedAt": "2021-08-12T21:09:25.476Z"
},
"associatedTo": {
"__typename": "CardProduct",
"id": "<CARD_PRODUCT_ID>"
}
}
}
}
Detach velocity control from a payment card
If you detach and re-attach a velocity, the balance on the "count" and "windows" of the velocity control will reset.
Use the following mutation to detach a velocity control from a payment card:
DetachPaymentCardVelocityRule
Query
mutation DetachPaymentCardVelocityRule(
$input: DetachPaymentCardVelocityRuleInput!
) {
detachPaymentCardVelocityRule(input: $input) {
__typename
... on VelocityRuleAssociation {
velocityRule {
id
name
version
cumulativeRule {
id
name
version
}
createdAt
updatedAt
}
associatedTo {
... on CardProduct {
id
}
... on PaymentCard {
id
}
}
}
... on UserError {
errors {
code
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "paymentCardId": "<PAYMENT_CARD_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"detachPaymentCardVelocityRule": {
"__typename": "VelocityRuleAssociation",
"velocityRule": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0",
"cumulativeRule": {
"id": "<CUMULATIVE_RULE_ID>",
"name": "dollar amount rule",
"version": "0"
},
"createdAt": "2021-08-12T21:09:25.475Z",
"updatedAt": "2021-08-12T21:09:25.476Z"
},
"associatedTo": {
"__typename": "PaymentCard",
"id": "<PAYMENT_CARD_ID>"
}
}
}
}
Detach velocity control from a financial account
If you detach and re-attach a velocity, the balance on the "count" and "windows" of the velocity control will reset.
Use the following mutation to detach a velocity control from a financial account:
DetachVelocityRuleFromFinancialAccount
Query
mutation DetachVelocityRuleFromFinancialAccount(
$input: DetachVelocityRuleFromFinancialAccountInput!
) {
detachVelocityRuleFromFinancialAccount(input: $input) {
__typename
... on FinancialAccount {
id
attachedVelocityRules {
edges {
node {
id
name
version
}
}
}
}
... on UserError {
errors {
code
path
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{ "input": { "financialAccountId": "<FINANCIAL_ACCOUNT_ID>", "velocityRule": { "velocityRuleId": "<VELOCITY_RULE_ID>" } } }
Result
{
"data": {
"detachVelocityRuleFromFinancialAccount": {
"__typename": "FinancialAccount",
"id": "<FINANCIAL_ACCOUNT_ID>",
"attachedVelocityRules": {
"edges": []
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>"
}
}
Edit a velocity control
Editing a velocity control resets its balance, the same as detaching and re-attaching it. This includes changing the limit on one of its spend rules, renaming the velocity control, and changing its time zone or start-of-week day. All of these trigger the reset, even a name-only change with no limit change. Spend already counted in the current window does not carry over.
Use updateAmountLimitSpendRule or updateCountLimitSpendRule to change the limit on a spend rule's cumulative rule. Use updateVelocityRule to rename a velocity control, change its user type, or change its velocityWindowTimeZone and velocityWindowStartOfWeek; it does not accept a limit, but it still resets the balance.
A time zone can't be removed once set. Leaving velocityWindowTimeZone unset on an update keeps the velocity control's current time zone; to move it back to UTC, send UTC explicitly. An empty string is rejected. If the velocity control is WEEKLY and doesn't already have a start of week, you must set velocityWindowStartOfWeek in the same request as velocityWindowTimeZone; if it already has one, you don't need to resend it.
The reset takes effect on the next authorization that evaluates the velocity control, not immediately. A velocity control balance query made right after the edit can still return the pre-edit accumulated amount until that next transaction runs.
List velocity controls
Use the following query to find all velocity controls for your organization:
NodeOrganizationWithVelocityRules
Query
query nodeOrganizationWithVelocityRules($id: ID!, $velocityRulesFirst: Int) {
node(id: $id) {
__typename
... on Organization {
id
velocityRules(first: $velocityRulesFirst) {
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
node {
__typename
... on VelocityRule {
id
name
}
}
}
}
}
}
}
Variables
{
"id": "<ORGANIZATION_ID>",
"velocityRulesFirst": 1
}
Result
{
"node": {
"id": "<ORGANIZATION_ID>",
"velocityRules": {
"pageInfo": {
"hasNextPage": false
},
"edges": [
{
"node": {
"__typename": "VelocityRule",
"id": "<VELOCITY_RULE_ID>",
"name": "My Velocity Rule"
}
}
]
}
}
}
Find velocity control balance
Velocity controls track how much money has been spent within a certain window to help troubleshoot declined transactions. You can check the "balance" of a velocity control for a payment card or financial account. The balance reflects the total amount spent.
Use the following query to find the velocity control balance on a financial account:
NodeFinancialAccountWithVelocityBalance
Query
query nodeFinancialAccountWithVelocityBalance($id: ID!) {
node(id: $id) {
__typename
... on FinancialAccount {
id
velocitySpendRuleBalances {
... on VelocitySpendRuleAmountBalance {
__typename
currentBalance {
currencyCode
value
}
remainingBalance {
currencyCode
value
}
velocityRule {
id
version
name
}
}
}
}
}
}
Variables
{
"id": "<FINANCIAL_ACCOUNT_ID>"
}
Result
{
"node": {
"id": "<FINANCIAL_ACCOUNT_ID>",
"velocitySpendRuleBalances": {
"currentBalance": {
"value": "200",
"currencyCode": "USD"
},
"remainingBalance": {
"value": "400",
"currencyCode": "USD"
},
"velocityRule": {
"id": "<VELOCITY_RULE_ID>",
"name": "My Rule",
"version": "0"
}
}
}
}