Forter
Connect and configure Forter with Dodgeball for fraud detection, and optimize your event data for accurate risk decisions.
Forter Get Order Decision: Customer Integration Guide
This guide explains how to structure your event data so that Forter receives complete transaction information for fraud decisioning.
Important: Client SDK RequiredForter requires the Dodgeball Client SDK to be installed on your frontend. The Client SDK collects device fingerprinting data that Forter uses for fraud detection. Without it, Forter cannot make accurate decisions.
Quick Start
When you call a Dodgeball checkpoint, you send event data that maps to vocabulary paths. Here's the minimum you need:
ThecheckpointNamecan be whatever you want (e.g.,ORDER_FRAUD_CHECK,PAYMENT,CHECKOUT). Just make sure it matches the checkpoint name configured in your Dodgeball workflow.
const checkpointResponse = await dodgeball.checkpoint({
checkpointName: "ORDER_FRAUD_CHECK", // Use any name you want
event: {
ip: req.ip, // Customer's IP address
data: {
transaction: {
externalId: "order-12345", // Your order ID
merchantDomain: "mystore.com", // Your store domain
amount: 9995, // $99.95 in cents
currency: "USD",
authorizationStep: "PRE_AUTHORIZATION", // or "POST_AUTHORIZATION"
lineItems: [
{
name: "Blue T-Shirt",
unitAmount: 2500, // $25.00 in cents
numUnits: 2,
type: "TANGIBLE"
}
]
},
customer: {
externalId: "cust-789",
primaryEmail: "[email protected]",
firstName: "John",
lastName: "Smith"
},
paymentMethod: {
cardBin: "424242",
cardLastFour: "4242",
cardNetwork: "VISA",
cardHolderName: "John Smith",
cardExpiryMonth: 12,
cardExpiryYear: 2025
}
}
},
sourceToken: sourceToken, // From Dodgeball Client SDK
sessionId: sessionId,
userId: "cust-789" // Optional
});Customer Data
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
customer.externalId | string | Your customer ID (omit for guests) | "cust-789" | |
customer.primaryEmail | string | Customer email | "[email protected]" | Yes |
customer.firstName | string | Customer first name | "John" | Yes |
customer.lastName | string | Customer last name | "Smith" | Yes |
customer.primaryPhone | string | Customer phone | "+15551234567" | |
customer.createdAt | number | Account creation time (Unix seconds) | 1609459200 |
Example:
customer: {
externalId: "cust-789",
primaryEmail: "[email protected]",
firstName: "John",
lastName: "Smith",
primaryPhone: "+15551234567",
createdAt: 1609459200
}Transaction Data
Core transaction information.
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
transaction.externalId | string | Your unique order/transaction ID | "order-12345" | Yes |
transaction.merchantDomain | string | Your store/site domain | "mystore.com" | Yes |
transaction.amount | number | Total amount in cents (after discounts) | 9995 for $99.95 | Yes |
transaction.currency | string | Currency code (defaults to USD) | "USD" | |
transaction.type | string | Order channel/source (see values below). Defaults to "WEB" | "WEB", "MOBILE" | |
transaction.authorizationStep | string | Whether the Forter decision is pre- or post-authorization | "PRE_AUTHORIZATION", "POST_AUTHORIZATION" | Yes |
transaction.createdAt | number | Order time as Unix timestamp (seconds). Defaults to current time if not provided. | 1706644800 | |
transaction.deliveryType | string | Overall delivery type for the order (see values below) | "PHYSICAL", "DIGITAL", "HYBRID" | |
transaction.discountAmount | number | Total discount amount in cents | 1000 for $10.00 off | |
transaction.couponCode | string | Coupon/promo code applied | "SAVE10" |
Transaction Type Values (transaction.type):
| Value | Description |
|---|---|
WEB | Standard web browser checkout (desktop or mobile web) |
MOBILE | Mobile app checkout (when specific platform is unknown) |
IOS | iOS app checkout |
ANDROID | Android app checkout |
POS | Point of sale / in-store retail transaction |
PHONE | Phone/call center order placed by customer speaking to agent |
MERCHANT_INITIATED | Order created by merchant on behalf of customer (draft orders, admin panel) |
RECURRING | Subscription renewal or recurring/installment payment |
API | Headless/API integration without standard UI checkout |
UNKNOWN | Unknown or unidentifiable order source |
Delivery Type Values (transaction.deliveryType):
| Value | Description |
|---|---|
PHYSICAL | Physical goods that require shipping |
DIGITAL | Digital goods, services, or downloads (no shipping) |
HYBRID | Combination of physical and digital items |
Note on Amounts: Always send monetary values in the smallest currency unit (cents for USD). $99.95 should be sent as 9995.
Note on Merchant Domain: Forter uses the merchant domain to identify the site where the order originated. If using Shopify Get Order, this is automatically populated from your Shopify store domain.
Note on Authorization Step: The authorizationStep field tells Forter whether the transaction is sent before or after payment authorization:
"PRE_AUTHORIZATION"- Forter decision requested before charging the card. Use this when you want Forter's decision to determine whether to proceed with payment."POST_AUTHORIZATION"- Forter decision requested after the card has been authorized/charged. Use this when you've already processed payment and want Forter's assessment for fulfillment decisions.
When using Shopify Get Order, this is typically set to "POST_AUTHORIZATION" since Shopify orders are created after payment is processed.
Payment Method Data
Payment method data tells Forter how the customer is paying. The structure depends on the payment type:
- Single payment: Use
paymentMethodobject at the root level - Multiple payments (split tender): Use
transaction.paymentMethodsarray
Payment Method Fields
These fields apply to all card-based payment types (credit, debit, prepaid).
The first 6 fields below are required for card data to be sent. If any of these is missing, only the transaction amount is sent without card details.
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
paymentMethod.cardBin | string | First 6-8 digits of card | "424242" | Yes |
paymentMethod.cardLastFour | string | Last 4 digits of card | "4242" | Yes |
paymentMethod.cardNetwork | string | Card brand | "VISA", "MASTERCARD", "AMEX" | Yes |
paymentMethod.cardHolderName | string | Name on card | "John Smith" | Yes |
paymentMethod.cardExpiryMonth | number | Expiration month (1-12) | 12 | Yes |
paymentMethod.cardExpiryYear | number | Expiration year (4 digits) | 2025 | Yes |
paymentMethod.type | string | Payment method type (see values below) | "CARD_CREDIT" | |
paymentMethod.latestAvsResultCode | string | AVS verification result | "Y", "N", "A" | |
paymentMethod.latestCvvResultCode | string | CVV verification result | "M", "N" | |
paymentMethod.latestAuthorizationCode | string | Auth code from processor | "A33244" | |
paymentMethod.latestProcessorResponseCode | string | Processor response code | "00", "02" | |
paymentMethod.latestProcessorResponseText | string | Processor response message | "APPROVED", "DECLINED" | |
paymentMethod.gateway | string | Payment gateway name | "SHOPIFY_PAYMENTS", "STRIPE" | |
paymentMethod.latestGatewayTransactionId | string | Gateway transaction ID | "pi_3abc123def456" | |
paymentMethod.digitalWalletType | string | Digital wallet type (e.g., "GOOGLE_PAY") | "GOOGLE_PAY" | |
paymentMethod.cardIssuerName | string | Issuing bank name (required for Google Pay) | "Chase" | |
paymentMethod.cardIssuingCountry | string | Two-letter country code (required for Google Pay) | "US" | |
paymentMethod.token | string | Payment method token (required for Google Pay) | "tkn-77620..." |
paymentMethod.type values:
"CARD_CREDIT"- Credit card"CARD_DEBIT"- Debit card"CARD_PREPAID"- Prepaid card"CARD_GIFT"- Gift card"OTHER"- Other payment type
Example: Credit Card
paymentMethod: {
cardBin: "424242",
cardLastFour: "4242",
cardNetwork: "VISA",
cardHolderName: "John Smith",
cardExpiryMonth: 12,
cardExpiryYear: 2025,
type: "CARD_CREDIT",
gateway: "STRIPE",
latestGatewayTransactionId: "pi_3abc123def456"
}What happens if a required field is missing:
// ❌ Missing cardHolderName - card details will NOT be sent
paymentMethod: {
cardBin: "424242",
cardLastFour: "4242",
cardNetwork: "VISA",
// cardHolderName: missing!
cardExpiryMonth: 12,
cardExpiryYear: 2025
}
// Result: Only the transaction amount is sent, no card infoExample: Gift Card
Gift cards only require type and amount:
paymentMethod: {
type: "CARD_GIFT",
amount: 2500 // $25.00 in cents
}Example: Split Payments (Multiple Payment Methods)
For orders paid with multiple methods (e.g., credit card + gift card), use the transaction.paymentMethods array:
transaction: {
externalId: "order-12345",
merchantDomain: "mystore.com",
amount: 10000, // Total: $100.00
paymentMethods: [
{
type: "CARD_CREDIT",
amount: 7500, // $75.00 on card
cardBin: "424242",
cardLastFour: "4242",
cardNetwork: "VISA",
cardHolderName: "John Smith",
cardExpiryMonth: 12,
cardExpiryYear: 2025
},
{
type: "CARD_GIFT",
amount: 2500 // $25.00 gift card
}
]
}Example: Google Pay
For payments made through Google Pay, include digitalWalletType: "GOOGLE_PAY" along with the underlying card details. Forter maps Google Pay to the androidPay object.
Additional fields required for Google Pay: digitalWalletType, cardIssuerName, cardIssuingCountry, and token (see Payment Method Fields table above).
paymentMethod: {
// Required: Set to "GOOGLE_PAY" to trigger androidPay mapping in Forter
digitalWalletType: "GOOGLE_PAY",
// Standard card fields (same as credit card)
cardBin: "424242",
cardLastFour: "4242",
cardNetwork: "VISA",
cardHolderName: "John Smith",
cardExpiryMonth: 12,
cardExpiryYear: 2025,
type: "CARD_CREDIT",
// Required for Google Pay - maps to Forter's androidPay object
cardIssuerName: "Chase", // → androidPay.cardBank
cardIssuingCountry: "US", // → androidPay.countryOfIssuance
token: "tkn-77620...", // → androidPay.token
// Post-authorization verification results → androidPay.verificationResults
latestAuthorizationCode: "065696",
latestProcessorResponseCode: "00",
latestProcessorResponseText: "APPROVED"
}Billing Address
Include the billing address associated with the payment method. This is important for AVS (Address Verification Service) matching and fraud detection.
Note: At least one of line1, city, or postalCode must be provided for billing address to be sent.
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
billingAddress.firstName | string | Cardholder first name | "John" | |
billingAddress.lastName | string | Cardholder last name | "Smith" | |
billingAddress.line1 | string | Address line 1 | "456 Oak Ave" | |
billingAddress.line2 | string | Address line 2 | "Suite 200" | |
billingAddress.city | string | City | "New York" | |
billingAddress.state | string | State/region code | "NY" | |
billingAddress.postalCode | string | Zip/postal code | "10001" | |
billingAddress.country | string | Country code | "US" | |
billingAddress.phone | string | Phone in E.164 format | "+12125551234" |
Example:
billingAddress: {
firstName: "John",
lastName: "Smith",
line1: "456 Oak Ave",
line2: "Suite 200",
city: "New York",
state: "NY",
postalCode: "10001",
country: "US",
phone: "+12125551234"
}Why billing address matters:
- Billing/shipping address mismatches can be a fraud signal
- AVS verification compares the billing address against the card issuer's records
- Different billing and shipping addresses are common for gift purchases but can also indicate potential fraud
Cart Items (Line Items)
Each product in the order should be included in transaction.lineItems:
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
transaction.lineItems[*].name | string | Product name | "Blue T-Shirt" | Yes |
transaction.lineItems[*].unitAmount | number | Price per unit in cents | 2500 | Yes |
transaction.lineItems[*].numUnits | number | Quantity | 2 | Yes |
transaction.lineItems[*].type | string | "TANGIBLE" or "NON_TANGIBLE" | "TANGIBLE" | Yes |
transaction.lineItems[*].externalId | string | Your product ID/SKU | "SKU-12345" | |
transaction.lineItems[*].category | string | Product category | "Apparel" |
Example:
transaction: {
lineItems: [
{
name: "Blue T-Shirt",
unitAmount: 2500, // $25.00 each
numUnits: 2, // Quantity: 2
type: "TANGIBLE", // Physical product
externalId: "SKU-12345",
category: "Apparel"
},
{
name: "Digital Download - Album",
unitAmount: 999, // $9.99
numUnits: 1,
type: "NON_TANGIBLE" // Digital product
}
]
}Product Types:
"TANGIBLE"- Physical products that ship"NON_TANGIBLE"- Digital goods, services, subscriptions
Shipping Data
For physical orders, include shipping address and delivery information. All shipping data is part of the transaction.shipments array.
Note: Forter's API only supports a single primaryDeliveryDetails and primaryRecipient, so only the first shipment (shipments[0]) is sent. If your order has multiple shipments, only the first will be included in the Forter request.
Shipping Address
The shipping address is nested inside an address object within each shipment.
Important: For digital-only orders, you must still include a shipment with shippingType: "DIGITAL". If omitted, Forter defaults to "PHYSICAL" which is incorrect.
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
transaction.shipments[0].address.firstName | string | Recipient first name | "John" | |
transaction.shipments[0].address.lastName | string | Recipient last name | "Smith" | |
transaction.shipments[0].address.line1 | string | Address line 1 | "123 Main St" | |
transaction.shipments[0].address.line2 | string | Address line 2 | "Apt 4B" | |
transaction.shipments[0].address.city | string | City | "San Francisco" | |
transaction.shipments[0].address.state | string | State/region code | "CA" | |
transaction.shipments[0].address.postalCode | string | Zip/postal code | "94102" | |
transaction.shipments[0].address.country | string | Country code | "US" | |
transaction.shipments[0].address.phone | string | Phone in E.164 format | "+14155551234" |
Example:
transaction: {
// ... other transaction fields ...
shipments: [{
address: {
firstName: "John",
lastName: "Smith",
line1: "123 Main St",
line2: "Apt 4B",
city: "San Francisco",
state: "CA",
postalCode: "94102",
country: "US",
phone: "+14155551234"
}
}]
}Delivery Information
Delivery details are at the shipment level (not inside the address object).
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
transaction.shipments[0].shippingType | string | Delivery type: "PHYSICAL", "DIGITAL", or "HYBRID" | "PHYSICAL" | |
transaction.shipments[0].method | string | Delivery method chosen by customer | "Standard Shipping" | |
transaction.shipments[0].carrier | string | Shipping carrier | "USPS", "FedEx", "UPS" | |
transaction.shipments[0].shippingAmount | number | Shipping cost in cents | 599 for $5.99 |
Delivery Types:
"PHYSICAL"- Shipped goods (default if not specified)"DIGITAL"- Non-shipped goods (services, gift cards, downloads)"HYBRID"- Combination of both physical and digital items
Complete shipment example (address + delivery):
transaction: {
// ... other transaction fields ...
shipments: [{
address: {
firstName: "John",
lastName: "Smith",
line1: "123 Main St",
city: "San Francisco",
state: "CA",
postalCode: "94102",
country: "US"
},
shippingType: "PHYSICAL",
method: "Standard Shipping",
carrier: "USPS",
shippingAmount: 599 // $5.99 in cents
}]
}Note: If shippingType is not provided, it defaults to "PHYSICAL". For digital-only orders, explicitly set shippingType: "DIGITAL". When using Shopify Get Order, this field is automatically populated based on the order's fulfillment requirements.
Device Data
Device data is captured automatically by the Dodgeball Client SDK. These fields are required by Forter but are typically auto-collected.
| Vocabulary Path | Type | Description | Example | Required |
|---|---|---|---|---|
device.ip | string | Customer's IP address | "203.0.113.42" | Yes* |
device.browserUserAgent | string | Browser user agent | "Mozilla/5.0..." | Yes* |
*Auto-collected by the Client SDK; only provide if manually overriding.
Note on IP Address: The Quick Start example shows event.ip which is the default way to pass the customer's IP. If you need to override or explicitly set the IP, use device.ip in the event.data object instead.
Amount Reconciliation
For accurate fraud detection, ensure your amounts are consistent:
Option 1: Line items at pre-discount prices
transaction.amount = Σ(lineItems.unitAmount × lineItems.numUnits) + shippingAmount - discountAmountOption 2: Line items at post-discount prices (preferred)
transaction.amount = Σ(lineItems.unitAmount × lineItems.numUnits) + shippingAmountWhen using post-discount prices, discountAmount is informational only (for coupon tracking).
Split payments
If using multiple payment methods, the sum of payment method amounts should equal the transaction total:
transaction.amount = Σ(paymentMethods[*].amount)Example with discount and split payment:
{
transaction: {
amount: 9500, // $95.00 final total
discountAmount: 1000, // $10.00 discount applied
couponCode: "SAVE10",
lineItems: [
{ unitAmount: 4250, numUnits: 2 } // $42.50 × 2 = $85.00 (post-discount)
],
shipments: [{
shippingAmount: 1000 // $10.00 shipping
}],
// $85 (items after discount) + $10 (shipping) = $95 total
// For split payments, amounts must also sum to total:
paymentMethods: [
{ type: "CARD_CREDIT", amount: 7000 }, // $70 on card
{ type: "CARD_GIFT", amount: 2500 } // $25 gift card
]
// $70 + $25 = $95 total
}
}Why this matters: Amount consistency is important for accurate fraud detection. Mismatched totals may indicate data quality issues or manipulation attempts.
Complete Example Payloads
The examples below show just the event.data portion. See Quick Start for the full checkpoint call structure. Each example is minimal and focuses on the specific scenario being tested.
Web Checkout
Standard web checkout with browser user agent.
{
"transaction": {
"externalId": "web-checkout-001",
"merchantDomain": "mystore.com",
"amount": 2999,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "T-Shirt", "unitAmount": 2999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "John", "lastName": "Smith", "line1": "123 Main St", "city": "Austin", "state": "TX", "postalCode": "78701", "country": "US" } }]
},
"customer": { "externalId": "cust-001", "primaryEmail": "[email protected]", "firstName": "John", "lastName": "Smith" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "John Smith", "cardExpiryMonth": 12, "cardExpiryYear": 2026 },
"device": { "browserUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" }
}Phone Checkout
Phone/call center order placed by customer speaking to agent. Note: transaction.type: "PHONE" sets the Forter orderType to PHONE.
{
"transaction": {
"externalId": "phone-checkout-001",
"merchantDomain": "mystore.com",
"amount": 4999,
"currency": "USD",
"type": "PHONE",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "Wireless Earbuds", "unitAmount": 4999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Jane", "lastName": "Doe", "line1": "456 Oak Ave", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } }]
},
"customer": { "externalId": "cust-002", "primaryEmail": "[email protected]", "firstName": "Jane", "lastName": "Doe" },
"paymentMethod": { "cardBin": "555555", "cardLastFour": "4444", "cardNetwork": "MASTERCARD", "cardHolderName": "Jane Doe", "cardExpiryMonth": 6, "cardExpiryYear": 2025 }
}Guest Checkout
No customer.externalId for guest users.
{
"transaction": {
"externalId": "guest-checkout-001",
"merchantDomain": "mystore.com",
"amount": 1999,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "Book", "unitAmount": 1999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Guest", "lastName": "User", "line1": "789 Elm St", "city": "Denver", "state": "CO", "postalCode": "80201", "country": "US" } }]
},
"customer": { "primaryEmail": "[email protected]", "firstName": "Guest", "lastName": "User" },
"paymentMethod": { "cardBin": "378282", "cardLastFour": "0005", "cardNetwork": "AMEX", "cardHolderName": "Guest User", "cardExpiryMonth": 3, "cardExpiryYear": 2027 }
}Digital Item Only
Important: Must include shippingType: "DIGITAL" and method (e.g., "Email"). No shipping address needed.
{
"transaction": {
"externalId": "digital-only-001",
"merchantDomain": "mystore.com",
"amount": 999,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"deliveryType": "DIGITAL",
"lineItems": [{ "name": "E-Book Download", "unitAmount": 999, "numUnits": 1, "type": "NON_TANGIBLE" }],
"shipments": [{ "shippingType": "DIGITAL", "method": "Email" }]
},
"customer": { "externalId": "cust-003", "primaryEmail": "[email protected]", "firstName": "Alex", "lastName": "Reader" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Alex Reader", "cardExpiryMonth": 9, "cardExpiryYear": 2026 }
}Multiple Physical Items
Multiple line items with quantities.
{
"transaction": {
"externalId": "multi-physical-001",
"merchantDomain": "mystore.com",
"amount": 8997,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [
{ "name": "T-Shirt (Blue)", "unitAmount": 2499, "numUnits": 2, "type": "TANGIBLE" },
{ "name": "Baseball Cap", "unitAmount": 1999, "numUnits": 1, "type": "TANGIBLE" },
{ "name": "Socks (3-pack)", "unitAmount": 1500, "numUnits": 1, "type": "TANGIBLE" }
],
"shipments": [{ "shippingType": "PHYSICAL", "method": "Ground", "carrier": "UPS", "shippingAmount": 599, "address": { "firstName": "Mike", "lastName": "Jones", "line1": "321 Pine St", "city": "Portland", "state": "OR", "postalCode": "97201", "country": "US" } }]
},
"customer": { "externalId": "cust-004", "primaryEmail": "[email protected]", "firstName": "Mike", "lastName": "Jones" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Mike Jones", "cardExpiryMonth": 11, "cardExpiryYear": 2025 }
}Digital and Physical Item (Hybrid)
Mixed order with shippingType: "HYBRID".
{
"transaction": {
"externalId": "hybrid-order-001",
"merchantDomain": "mystore.com",
"amount": 7998,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"deliveryType": "HYBRID",
"lineItems": [
{ "name": "Laptop Stand", "unitAmount": 4999, "numUnits": 1, "type": "TANGIBLE" },
{ "name": "Software License", "unitAmount": 2999, "numUnits": 1, "type": "NON_TANGIBLE" }
],
"shipments": [{ "shippingType": "HYBRID", "method": "Standard Shipping", "carrier": "FedEx", "shippingAmount": 0, "address": { "firstName": "Sam", "lastName": "Tech", "line1": "555 Tech Blvd", "city": "San Jose", "state": "CA", "postalCode": "95101", "country": "US" } }]
},
"customer": { "externalId": "cust-005", "primaryEmail": "[email protected]", "firstName": "Sam", "lastName": "Tech" },
"paymentMethod": { "cardBin": "555555", "cardLastFour": "4444", "cardNetwork": "MASTERCARD", "cardHolderName": "Sam Tech", "cardExpiryMonth": 4, "cardExpiryYear": 2027 }
}Gateway Data
Order with payment gateway information. This example uses POST_AUTHORIZATION since the payment has already been processed through the gateway.
{
"transaction": {
"externalId": "gateway-data-001",
"merchantDomain": "mystore.com",
"amount": 5999,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"lineItems": [{ "name": "Keyboard", "unitAmount": 5999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Taylor", "lastName": "Dev", "line1": "700 Gateway Blvd", "city": "San Jose", "state": "CA", "postalCode": "95101", "country": "US" } }]
},
"customer": { "externalId": "cust-012", "primaryEmail": "[email protected]", "firstName": "Taylor", "lastName": "Dev" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Taylor Dev", "cardExpiryMonth": 10, "cardExpiryYear": 2026, "type": "CARD_CREDIT", "gateway": "STRIPE", "latestGatewayTransactionId": "pi_3MqJvBLkdIwHu7ix0EXAMPLE" }
}Gift Card Payment
Using type: "CARD_GIFT" for gift card payments.
{
"transaction": {
"externalId": "gift-card-001",
"merchantDomain": "mystore.com",
"amount": 2500,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "Coffee Mug", "unitAmount": 2500, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Gift", "lastName": "Recipient", "line1": "100 Gift Lane", "city": "Chicago", "state": "IL", "postalCode": "60601", "country": "US" } }]
},
"customer": { "externalId": "cust-006", "primaryEmail": "[email protected]", "firstName": "Gift", "lastName": "Giver" },
"paymentMethod": { "type": "CARD_GIFT", "amount": 2500 }
}Discount Applied
Order with discount and coupon code.
{
"transaction": {
"externalId": "discount-order-001",
"merchantDomain": "mystore.com",
"amount": 4499,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"discountAmount": 500,
"couponCode": "SAVE5",
"lineItems": [{ "name": "Jacket", "unitAmount": 4999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Dana", "lastName": "Saver", "line1": "200 Discount Dr", "city": "Phoenix", "state": "AZ", "postalCode": "85001", "country": "US" } }]
},
"customer": { "externalId": "cust-007", "primaryEmail": "[email protected]", "firstName": "Dana", "lastName": "Saver" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Dana Saver", "cardExpiryMonth": 8, "cardExpiryYear": 2026 }
}Successful Credit Card Auth
Order with successful authorization details. Uses POST_AUTHORIZATION since the card has been authorized.
{
"transaction": {
"externalId": "good-auth-001",
"merchantDomain": "mystore.com",
"amount": 9999,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"lineItems": [{ "name": "Watch", "unitAmount": 9999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Chris", "lastName": "Buyer", "line1": "300 Auth Ave", "city": "Miami", "state": "FL", "postalCode": "33101", "country": "US" } }]
},
"customer": { "externalId": "cust-008", "primaryEmail": "[email protected]", "firstName": "Chris", "lastName": "Buyer" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Chris Buyer", "cardExpiryMonth": 7, "cardExpiryYear": 2027, "latestAvsResultCode": "Y", "latestCvvResultCode": "M", "latestAuthorizationCode": "A12345" }
}Failed Credit Card Auth
Order where authorization was declined by the payment processor. This is a post-authorization flow where the gateway response indicates failure. Includes processor response codes to provide context for the decline.
{
"transaction": {
"externalId": "bad-auth-001",
"merchantDomain": "mystore.com",
"amount": 15000,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"lineItems": [{ "name": "Expensive Item", "unitAmount": 15000, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Test", "lastName": "Decline", "line1": "400 Decline St", "city": "Boston", "state": "MA", "postalCode": "02101", "country": "US" } }]
},
"customer": { "externalId": "cust-009", "primaryEmail": "[email protected]", "firstName": "Test", "lastName": "Decline" },
"paymentMethod": { "cardBin": "400000", "cardLastFour": "0002", "cardNetwork": "VISA", "cardHolderName": "Test Decline", "cardExpiryMonth": 1, "cardExpiryYear": 2025, "type": "CARD_CREDIT", "latestAuthorizationCode": "DEC001", "latestProcessorResponseCode": "02", "latestProcessorResponseText": "DECLINED" }
}Good CVV Match
Order with CVV match result "M" (match).
{
"transaction": {
"externalId": "good-cvv-001",
"merchantDomain": "mystore.com",
"amount": 3999,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "Bluetooth Speaker", "unitAmount": 3999, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Pat", "lastName": "Secure", "line1": "500 CVV Lane", "city": "Atlanta", "state": "GA", "postalCode": "30301", "country": "US" } }]
},
"customer": { "externalId": "cust-010", "primaryEmail": "[email protected]", "firstName": "Pat", "lastName": "Secure" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Pat Secure", "cardExpiryMonth": 5, "cardExpiryYear": 2026, "latestCvvResultCode": "M" }
}Bad CVV (No Match)
Order with CVV mismatch result "N".
{
"transaction": {
"externalId": "bad-cvv-001",
"merchantDomain": "mystore.com",
"amount": 2499,
"currency": "USD",
"authorizationStep": "PRE_AUTHORIZATION",
"lineItems": [{ "name": "Headphones", "unitAmount": 2499, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Robin", "lastName": "Risk", "line1": "600 CVV Fail Rd", "city": "Dallas", "state": "TX", "postalCode": "75201", "country": "US" } }]
},
"customer": { "externalId": "cust-011", "primaryEmail": "[email protected]", "firstName": "Robin", "lastName": "Risk" },
"paymentMethod": { "cardBin": "411111", "cardLastFour": "1111", "cardNetwork": "VISA", "cardHolderName": "Robin Risk", "cardExpiryMonth": 2, "cardExpiryYear": 2026, "latestCvvResultCode": "N" }
}Google Pay Payment
Order paid with Google Pay. For post-authorization flows, the payment gateway response must be included in the verificationResults. Forter maps Google Pay to the androidPay object in the payment array.
{
"transaction": {
"externalId": "googlepay-order-001",
"merchantDomain": "mystore.com",
"amount": 9995,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"lineItems": [{ "name": "Premium Headphones", "unitAmount": 9995, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{ "shippingType": "PHYSICAL", "address": { "firstName": "Alex", "lastName": "Wallet", "line1": "123 Google St", "city": "Mountain View", "state": "CA", "postalCode": "94043", "country": "US" } }]
},
"customer": { "externalId": "cust-googlepay-001", "primaryEmail": "[email protected]", "firstName": "Alex", "lastName": "Wallet" },
"paymentMethod": {
"digitalWalletType": "GOOGLE_PAY",
"cardBin": "424242",
"cardLastFour": "4242",
"cardNetwork": "VISA",
"cardHolderName": "Alex Wallet",
"cardExpiryMonth": 12,
"cardExpiryYear": 2026,
"type": "CARD_CREDIT",
"cardIssuerName": "Chase",
"cardIssuingCountry": "US",
"token": "tkn-77620C360132856A103477D2959967AB",
"latestAuthorizationCode": "065696",
"latestProcessorResponseCode": "00",
"latestProcessorResponseText": "APPROVED"
}
}Google Pay Declined Payment
Order paid with Google Pay where the transaction was declined by the payment processor. For post-authorization flows, the payment gateway's declined response must be included in the verificationResults. This test verifies that when a Google Pay transaction is rejected, your API request includes the failed response from the payment gateway.
{
"transaction": {
"externalId": "googlepay-declined-001",
"merchantDomain": "mystore.com",
"amount": 9995,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"lineItems": [{ "name": "Premium Headphones", "unitAmount": 9995, "numUnits": 1, "type": "TANGIBLE" }],
"shipments": [{
"shippingType": "PHYSICAL",
"address": {
"firstName": "Alex",
"lastName": "Wallet",
"line1": "123 Google St",
"city": "Mountain View",
"state": "CA",
"postalCode": "94043",
"country": "US"
}
}]
},
"customer": {
"externalId": "cust-googlepay-declined-001",
"primaryEmail": "[email protected]",
"firstName": "Alex",
"lastName": "Wallet"
},
"paymentMethod": {
"digitalWalletType": "GOOGLE_PAY",
"cardBin": "424242",
"cardLastFour": "4242",
"cardNetwork": "VISA",
"cardHolderName": "Alex Wallet",
"cardExpiryMonth": 12,
"cardExpiryYear": 2026,
"type": "CARD_CREDIT",
"cardIssuerName": "Chase",
"cardIssuingCountry": "US",
"token": "tkn-77620C360132856A103477D2959967AB",
"latestAuthorizationCode": "85825A",
"latestProcessorResponseCode": "02",
"latestProcessorResponseText": "DECLINED"
}
}Complex Payload
Full example with multiple items, multiple payment methods, verification results, and gateway data. All payment data is in transaction.paymentMethods array.
{
"transaction": {
"externalId": "complex-order-001",
"merchantDomain": "mystore.com",
"amount": 24997,
"currency": "USD",
"authorizationStep": "POST_AUTHORIZATION",
"deliveryType": "HYBRID",
"discountAmount": 2500,
"couponCode": "VIP25",
"lineItems": [
{ "name": "Premium Headphones", "unitAmount": 14999, "numUnits": 1, "type": "TANGIBLE", "category": "Electronics" },
{ "name": "Carrying Case", "unitAmount": 2999, "numUnits": 1, "type": "TANGIBLE", "category": "Accessories" },
{ "name": "Extended Warranty", "unitAmount": 1999, "numUnits": 1, "type": "NON_TANGIBLE", "category": "Services" },
{ "name": "Music Subscription (1yr)", "unitAmount": 9999, "numUnits": 1, "type": "NON_TANGIBLE", "category": "Subscription" }
],
"shipments": [{
"shippingType": "HYBRID",
"method": "Express Shipping",
"carrier": "FedEx",
"shippingAmount": 1499,
"address": {
"firstName": "Jordan",
"lastName": "Premium",
"line1": "1000 Luxury Blvd",
"line2": "Suite 500",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102",
"country": "US",
"phone": "+14155551234"
}
}],
"paymentMethods": [
{
"type": "CARD_CREDIT",
"amount": 19997,
"cardBin": "411111",
"cardLastFour": "1111",
"cardNetwork": "VISA",
"cardHolderName": "Jordan Premium",
"cardExpiryMonth": 12,
"cardExpiryYear": 2027,
"latestAvsResultCode": "Y",
"latestCvvResultCode": "M",
"latestAuthorizationCode": "AUTH789",
"gateway": "STRIPE",
"latestGatewayTransactionId": "pi_3abc123def456"
},
{ "type": "CARD_GIFT", "amount": 5000 }
]
},
"billingAddress": {
"firstName": "Jordan",
"lastName": "Premium",
"line1": "1000 Luxury Blvd",
"line2": "Suite 500",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102",
"country": "US"
},
"customer": {
"externalId": "vip-customer-001",
"primaryEmail": "[email protected]",
"firstName": "Jordan",
"lastName": "Premium",
"primaryPhone": "+14155551234",
"createdAt": 1609459200
}
}Common Issues & Solutions
1. "Card data isn't being sent"
Cause: One or more required card fields is missing.
Check these fields are ALL present:
paymentMethod.cardBinpaymentMethod.cardLastFourpaymentMethod.cardNetworkpaymentMethod.cardHolderNamepaymentMethod.cardExpiryMonthpaymentMethod.cardExpiryYear
2. "Amount seems wrong"
Cause: Sending amounts in dollars instead of cents.
Fix: Always use minor currency units:
// ❌ Wrong
amount: 99.95
// ✅ Correct
amount: 99953. "Customer appears as unknown"
Cause: Missing customer.primaryEmail or customer.firstName.
Fix: Ensure these required fields are present:
customer: {
primaryEmail: "[email protected]", // Required
firstName: "Required" // Required
}4. "Shipping address not showing"
Cause: Missing or malformed shipping address fields in the transaction.shipments array.
Fix: Include shipping address in transaction.shipments[0].address:
// ❌ Wrong - address fields flat on shipment
transaction: {
shipments: [{
firstName: "John",
line1: "123 Main St"
}]
}
// ✅ Correct - address nested inside shipment
transaction: {
shipments: [{
address: {
firstName: "John",
lastName: "Smith",
line1: "123 Main St",
city: "San Francisco",
state: "CA",
postalCode: "94102",
country: "US"
}
}]
}5. "Billing address not being sent"
Cause: Missing billingAddress object or using wrong field names.
Fix: Include the billingAddress object with proper structure:
// ❌ Wrong - using payment method for address
paymentMethod: {
address: "456 Oak Ave" // Won't work
}
// ✅ Correct - use separate billingAddress object
billingAddress: {
firstName: "John",
lastName: "Smith",
line1: "456 Oak Ave",
city: "New York",
state: "NY",
postalCode: "10001",
country: "US"
}Note: Billing address is separate from shipping address. For fraud detection, billing address is compared against card issuer records and mismatches with shipping address can be a fraud signal.
Shopify Integration
Using the Dodgeball Shopify App
If you use the Dodgeball Shopify App, the app handles webhook routing and data extraction automatically. However, you must set up the corresponding checkpoints in Dodgeball:
Required Setup
-
Create a checkpoint named
SHOPIFY_CREATE_ORDERThis is a reserved checkpoint name that the Shopify app uses when forwarding
orders/createwebhooks. When a new order is placed in Shopify, the app triggers this checkpoint with all order data pre-populated.Your workflow attached to
SHOPIFY_CREATE_ORDERshould include:- Shopify Get Order (to enrich with full order details)
- Shopify Get Customer (to get customer history)
- Forter Get Order Decision (or other fraud detection step)
-
Enable "Create Order" in the Shopify App settings
In the Dodgeball Shopify App settings, check the "Create Order" checkbox to enable the
SHOPIFY_CREATE_ORDERcheckpoint.
Other Supported Shopify Webhooks
The Shopify app can also forward these webhook types. These webhooks provide the order ID, so you'll typically use the Shopify Get Order step to fetch the full order details before calling Forter:
| Shopify App Setting | Event Key | Workflow Steps | Description |
|---|---|---|---|
| Order Fulfilled | SHOPIFY_ORDER_FULFILLED | Shopify Get Order → Forter Update Order Status | Notifies Forter when an order ships |
| Order Cancelled | SHOPIFY_ORDER_CANCELLED | Shopify Get Order → Decision → Forter Update Order Status | Notifies Forter when an order is cancelled (see note below) |
| Create Dispute (Chargeback) | SHOPIFY_DISPUTE_CREATE | Shopify Get Order → Forter Chargeback Notification | Sends chargeback data to Forter for model training |
Note on Order Cancelled: Forter requires a cancellation reason (MERCHANT_CANCELLED or CUSTOMER_CANCELLED). You'll need a decision step in your workflow to map the Shopify cancel_reason (e.g., customer, fraud, inventory, declined, other) to the appropriate Forter reason before calling Forter Update Order Status.
To enable these webhooks:
- In the Shopify App settings, check the checkbox for the event you want to enable
- Enter the Webhook Lookup Key from the Trust Console (found in the webhook configuration)
- Create a workflow in the Trust Console that:
- Listens for that webhook
- Runs Shopify Get Order to fetch full order details
- Runs the appropriate Forter step
Manual Shopify Integration (Without the Shopify App)
If you're calling checkpoints manually from a custom Shopify integration: You can simplify your payload significantly. Send the Shopify order ID and use the Shopify Get Order and Shopify Get Customer workflow steps before the Forter step.
These steps will automatically populate:
- Full order details (line items, amounts, shipping)
- Payment method data (card BIN, last 4, network, etc.)
- Customer history (order count, total spent, account creation date)
- Shipping and billing addresses
Minimal event.data for Shopify:
// event.data - just pass the Shopify order ID
{
shopifyOrder: {
externalId: "shopify-order-id-here" // The Shopify order ID (numeric)
}
}Then configure your workflow to run Shopify Get Order → Shopify Get Customer → Forter Get Order Decision.
Updated about 2 hours ago
