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 Required

Forter 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:

📝

The checkpointName can 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 PathTypeDescriptionExampleRequired
customer.externalIdstringYour customer ID (omit for guests)"cust-789"
customer.primaryEmailstringCustomer email"[email protected]"Yes
customer.firstNamestringCustomer first name"John"Yes
customer.lastNamestringCustomer last name"Smith"Yes
customer.primaryPhonestringCustomer phone"+15551234567"
customer.createdAtnumberAccount 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 PathTypeDescriptionExampleRequired
transaction.externalIdstringYour unique order/transaction ID"order-12345"Yes
transaction.merchantDomainstringYour store/site domain"mystore.com"Yes
transaction.amountnumberTotal amount in cents (after discounts)9995 for $99.95Yes
transaction.currencystringCurrency code (defaults to USD)"USD"
transaction.typestringOrder channel/source (see values below). Defaults to "WEB""WEB", "MOBILE"
transaction.authorizationStepstringWhether the Forter decision is pre- or post-authorization"PRE_AUTHORIZATION", "POST_AUTHORIZATION"Yes
transaction.createdAtnumberOrder time as Unix timestamp (seconds). Defaults to current time if not provided.1706644800
transaction.deliveryTypestringOverall delivery type for the order (see values below)"PHYSICAL", "DIGITAL", "HYBRID"
transaction.discountAmountnumberTotal discount amount in cents1000 for $10.00 off
transaction.couponCodestringCoupon/promo code applied"SAVE10"

Transaction Type Values (transaction.type):

ValueDescription
WEBStandard web browser checkout (desktop or mobile web)
MOBILEMobile app checkout (when specific platform is unknown)
IOSiOS app checkout
ANDROIDAndroid app checkout
POSPoint of sale / in-store retail transaction
PHONEPhone/call center order placed by customer speaking to agent
MERCHANT_INITIATEDOrder created by merchant on behalf of customer (draft orders, admin panel)
RECURRINGSubscription renewal or recurring/installment payment
APIHeadless/API integration without standard UI checkout
UNKNOWNUnknown or unidentifiable order source

Delivery Type Values (transaction.deliveryType):

ValueDescription
PHYSICALPhysical goods that require shipping
DIGITALDigital goods, services, or downloads (no shipping)
HYBRIDCombination 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 paymentMethod object at the root level
  • Multiple payments (split tender): Use transaction.paymentMethods array

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 PathTypeDescriptionExampleRequired
paymentMethod.cardBinstringFirst 6-8 digits of card"424242"Yes
paymentMethod.cardLastFourstringLast 4 digits of card"4242"Yes
paymentMethod.cardNetworkstringCard brand"VISA", "MASTERCARD", "AMEX"Yes
paymentMethod.cardHolderNamestringName on card"John Smith"Yes
paymentMethod.cardExpiryMonthnumberExpiration month (1-12)12Yes
paymentMethod.cardExpiryYearnumberExpiration year (4 digits)2025Yes
paymentMethod.typestringPayment method type (see values below)"CARD_CREDIT"
paymentMethod.latestAvsResultCodestringAVS verification result"Y", "N", "A"
paymentMethod.latestCvvResultCodestringCVV verification result"M", "N"
paymentMethod.latestAuthorizationCodestringAuth code from processor"A33244"
paymentMethod.latestProcessorResponseCodestringProcessor response code"00", "02"
paymentMethod.latestProcessorResponseTextstringProcessor response message"APPROVED", "DECLINED"
paymentMethod.gatewaystringPayment gateway name"SHOPIFY_PAYMENTS", "STRIPE"
paymentMethod.latestGatewayTransactionIdstringGateway transaction ID"pi_3abc123def456"
paymentMethod.digitalWalletTypestringDigital wallet type (e.g., "GOOGLE_PAY")"GOOGLE_PAY"
paymentMethod.cardIssuerNamestringIssuing bank name (required for Google Pay)"Chase"
paymentMethod.cardIssuingCountrystringTwo-letter country code (required for Google Pay)"US"
paymentMethod.tokenstringPayment 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 info

Example: 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 PathTypeDescriptionExampleRequired
billingAddress.firstNamestringCardholder first name"John"
billingAddress.lastNamestringCardholder last name"Smith"
billingAddress.line1stringAddress line 1"456 Oak Ave"
billingAddress.line2stringAddress line 2"Suite 200"
billingAddress.citystringCity"New York"
billingAddress.statestringState/region code"NY"
billingAddress.postalCodestringZip/postal code"10001"
billingAddress.countrystringCountry code"US"
billingAddress.phonestringPhone 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 PathTypeDescriptionExampleRequired
transaction.lineItems[*].namestringProduct name"Blue T-Shirt"Yes
transaction.lineItems[*].unitAmountnumberPrice per unit in cents2500Yes
transaction.lineItems[*].numUnitsnumberQuantity2Yes
transaction.lineItems[*].typestring"TANGIBLE" or "NON_TANGIBLE""TANGIBLE"Yes
transaction.lineItems[*].externalIdstringYour product ID/SKU"SKU-12345"
transaction.lineItems[*].categorystringProduct 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 PathTypeDescriptionExampleRequired
transaction.shipments[0].address.firstNamestringRecipient first name"John"
transaction.shipments[0].address.lastNamestringRecipient last name"Smith"
transaction.shipments[0].address.line1stringAddress line 1"123 Main St"
transaction.shipments[0].address.line2stringAddress line 2"Apt 4B"
transaction.shipments[0].address.citystringCity"San Francisco"
transaction.shipments[0].address.statestringState/region code"CA"
transaction.shipments[0].address.postalCodestringZip/postal code"94102"
transaction.shipments[0].address.countrystringCountry code"US"
transaction.shipments[0].address.phonestringPhone 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 PathTypeDescriptionExampleRequired
transaction.shipments[0].shippingTypestringDelivery type: "PHYSICAL", "DIGITAL", or "HYBRID""PHYSICAL"
transaction.shipments[0].methodstringDelivery method chosen by customer"Standard Shipping"
transaction.shipments[0].carrierstringShipping carrier"USPS", "FedEx", "UPS"
transaction.shipments[0].shippingAmountnumberShipping cost in cents599 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 PathTypeDescriptionExampleRequired
device.ipstringCustomer's IP address"203.0.113.42"Yes*
device.browserUserAgentstringBrowser 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 - discountAmount

Option 2: Line items at post-discount prices (preferred)

transaction.amount = Σ(lineItems.unitAmount × lineItems.numUnits) + shippingAmount

When 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.cardBin
  • paymentMethod.cardLastFour
  • paymentMethod.cardNetwork
  • paymentMethod.cardHolderName
  • paymentMethod.cardExpiryMonth
  • paymentMethod.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: 9995

3. "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

  1. Create a checkpoint named SHOPIFY_CREATE_ORDER

    This is a reserved checkpoint name that the Shopify app uses when forwarding orders/create webhooks. 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_ORDER should 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)
  2. Enable "Create Order" in the Shopify App settings

    In the Dodgeball Shopify App settings, check the "Create Order" checkbox to enable the SHOPIFY_CREATE_ORDER checkpoint.

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 SettingEvent KeyWorkflow StepsDescription
Order FulfilledSHOPIFY_ORDER_FULFILLEDShopify Get Order → Forter Update Order StatusNotifies Forter when an order ships
Order CancelledSHOPIFY_ORDER_CANCELLEDShopify Get Order → Decision → Forter Update Order StatusNotifies Forter when an order is cancelled (see note below)
Create Dispute (Chargeback)SHOPIFY_DISPUTE_CREATEShopify Get Order → Forter Chargeback NotificationSends 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:

  1. In the Shopify App settings, check the checkbox for the event you want to enable
  2. Enter the Webhook Lookup Key from the Trust Console (found in the webhook configuration)
  3. 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 OrderShopify Get CustomerForter Get Order Decision.