Payrix ACH Integration

Process ACH transactions with Payrix including GIACT risk verification

Process ACH (bank account) transactions through Preczn with Payrix as your processor, including optional GIACT risk verification for enhanced fraud prevention.

📘

Prerequisites

Before integrating Payrix ACH, ensure you have:

  • A Payrix processor connection configured on your platform
  • Merchant accounts with Payrix credentials
  • Webhooks configured to receive transaction events

For general ACH concepts and requirements, see ACH Transactions.

Setup

Enable GIACT Verification

GIACT verification provides additional risk assessment for ACH transactions. When enabled, Preczn fetches GIACT decision results from Payrix for transactions that return a generic_error status.

To enable GIACT verification:

  1. Contact Payrix to enable GIACT on your Payrix account. If you want to test GIACT in sandbox, request enablement for both your live and sandbox Payrix accounts.
  2. Enable in Preczn Dashboard:
    • Navigate to ConnectionsPayrix
    • Toggle GIACT Enabled to on
    • Click Save
🚧

GIACT Must Be Enabled on Both Sides

GIACT verification requires enablement at both Payrix and Preczn. If GIACT is not enabled on your Payrix account, transactions will not trigger GIACT verification even if the toggle is enabled in Preczn.

📘

Platform-Level Configuration

GIACT verification is enabled at the platform level, not per-merchant. Once enabled, all ACH verify transactions through your Payrix connection will use GIACT verification when applicable.

Configure Webhooks

To receive GIACT verification results, you must configure webhooks to listen for these events:

EventDescriptionWhen Sent
transaction.pendingTransaction is awaiting GIACT verificationImmediately after initial API response
transaction.erroredTransaction failed with GIACT resultsAfter GIACT verification completes

See Webhooks for configuration instructions.

How ACH Works with Payrix + GIACT

When GIACT is enabled, Payrix ACH verify transactions follow an asynchronous verification flow:

sequenceDiagram
    participant Client
    participant Preczn
    participant Payrix
    participant GIACT

    Client->>Preczn: POST /v1/transactions (verify)
    Preczn->>Payrix: Submit ACH verify
    Payrix-->>Preczn: generic_error (GIACT pending)
    Preczn-->>Client: 200 OK (status: P)
    Preczn->>Client: Webhook: transaction.pending

    Note over Preczn,GIACT: Async GIACT fetch
    Preczn->>Payrix: GET /risk/v2/decision/policy-run-summary
    Payrix->>GIACT: Request decision
    GIACT-->>Payrix: BLOCK/PASS/SKIP
    Payrix-->>Preczn: GIACT results

    Preczn->>Client: Webhook: transaction.errored
❗️

Async Flow Means Two Webhooks

Unlike synchronous processors, Payrix ACH with GIACT may send two webhooks for a single transaction:

  1. transaction.pending - Sent immediately when the transaction enters pending state
  2. transaction.errored - Sent after GIACT verification completes with the final decision

Your integration must handle this asynchronous pattern.

Integration Guide

Required Fields

For Payrix ACH verify transactions, include these fields:

FieldTypeRequiredDescription
merchantIdstringYesPreczn merchant ID (mid_*)
typestringYesMust be verify
payment.bankAccount.accountstringYesBank account number
payment.bankAccount.routingstringYesBank routing number
payment.bankAccount.typestringYesAccount type (see below)
payment.bankAccount.bankCountrystringNoISO 3166-1 alpha-3 country code (default: USA)
firstNamestringYesAccount holder's first name
lastNamestringYesAccount holder's last name

Account Types

ValueDescription
personalCheckingPersonal checking account
personalSavingsPersonal savings account
corporateCheckingBusiness checking account
corporateSavingsBusiness savings account
📘

Corporate Accounts

For corporate account types (corporateChecking, corporateSavings), you can optionally include accountBusinessName to specify the business name associated with the account.

Step 1: Submit ACH Verify Transaction

Submit a verify transaction to validate the bank account:

POST /v1/transactions

{
  "merchantId": "mid_8np2rx4qk6m3wy9jzaht5v7dc",
  "type": "verify",
  "payment": {
    "bankAccount": {
      "account": "1234567890",
      "routing": "011000015",
      "type": "personalChecking",
      "bankCountry": "USA"
    }
  },
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "[email protected]",
  "billingAddress": {
    "address": "123 Main Street",
    "city": "New York",
    "region": "NY",
    "postal": "10001",
    "country": "USA"
  }
}

Step 2: Handle Pending Response

When GIACT is enabled and Payrix returns a generic_error, Preczn returns a Pending status:

{
  "id": "txn_5kx9mw2nq8r7hp4jvbct6y3fa",
  "type": "verify",
  "merchantId": "mid_8np2rx4qk6m3wy9jzaht5v7dc",
  "platformId": "pfm_3dv7ky9m5r2wp8xjqnbt4c6hf",
  "currency": "USD",
  "firstName": "Jane",
  "lastName": "Smith",
  "isGiactEligible": true,
  "authorization": {
    "status": "P",
    "processorCode": "generic_error",
    "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
    "errors": [
      "Transaction processing failed"
    ]
  },
  "payment": {
    "type": "personalChecking",
    "bankCountry": "USA",
    "bin": "011000015",
    "last4": "7890",
    "token": "tkn_4hn8mq2rv6x9kp3jwyct5b7da"
  },
  "processor": {
    "id": "pfmCon_7mx4rk9np2w6hy3jqvbt8c5da",
    "name": "Payrix",
    "routingSource": "direct"
  },
  "createdOn": "2024-01-15T14:30:00Z"
}
👍

Status "P" Means GIACT Verification in Progress

When you receive status: "P" (Pending) with processorCode: "generic_error" and isGiactEligible: true, this indicates Preczn is fetching GIACT verification results. Do not treat this as a failure. Wait for the webhook to receive the final result.

Step 3: Receive Webhook with GIACT Results

After GIACT verification completes, you receive a transaction.errored webhook with the GIACT decision in the errors array:

{
  "id": "what_7c5mm92aes8tkbchfzgf6d3x28",
  "webhookId": "wh_1hatb29w5z8ayb885kc0jj180k",
  "eventType": "transaction.errored",
  "data": {
    "id": "txn_5kx9mw2nq8r7hp4jvbct6y3fa",
    "type": "verify",
    "merchantId": "mid_8np2rx4qk6m3wy9jzaht5v7dc",
    "platformId": "pfm_3dv7ky9m5r2wp8xjqnbt4c6hf",
    "currency": "USD",
    "firstName": "Jane",
    "lastName": "Smith",
    "authorization": {
      "status": "E",
      "processorCode": "generic_error",
      "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
      "errors": [
        "GiactTxnInquiry: BLOCK",
        "Transaction processing failed"
      ]
    },
    "payment": {
      "type": "PERSONAL_CHECKING",
      "bin": "011000015",
      "last4": "7890"
    },
    "processor": {
      "id": "pfmCon_7mx4rk9np2w6hy3jqvbt8c5da",
      "name": "Payrix",
      "routingSource": "direct"
    },
    "createdOn": "2024-01-15T14:30:07Z"
  }
}

GIACT Results

GIACT Decision Codes

The GIACT verification returns one of three decision results:

DecisionMeaningRecommended Action
BLOCKThe transaction data was reviewed with GIACT and has been declined with an assessed feeReject the transaction; display adverse action notice; request a different payment method
PASSThe transaction data was reviewed with GIACT and approved with an assessed feeProceed with the transaction
SKIPThe data submitted did not meet the initial requirements to begin a GIACT reviewReview manually or proceed based on your risk tolerance
❗️

Adverse Action Notice Required for BLOCK

When GIACT returns BLOCK, Payrix requires that you display an adverse action notice to the customer. This notice informs the customer that their transaction was declined based on information obtained from a consumer reporting agency.

For the required notice text and compliance details, see Payrix Adverse Action Notice Requirements.

For more details on GIACT verification, see the Payrix GIACT documentation.

Error Array Format

GIACT results appear in the authorization.errors array with the format:

{decisionType}: {result}

For example:

  • GiactTxnInquiry: BLOCK
  • GiactTxnInquiry: PASS
  • GiactTxnInquiry: SKIP
📘

GIACT Errors Are Prepended

GIACT decision results are prepended to the beginning of the errors array. If there were existing errors from the processor, they appear after the GIACT results.

Example: GIACT BLOCK Response

{
  "authorization": {
    "status": "E",
    "processorCode": "generic_error",
    "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
    "errors": [
      "GiactTxnInquiry: BLOCK",
      "Transaction processing failed"
    ]
  }
}

Example: GIACT PASS Response

{
  "authorization": {
    "status": "E",
    "processorCode": "generic_error",
    "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
    "errors": [
      "GiactTxnInquiry: PASS",
      "Transaction processing failed"
    ]
  }
}
🚧

GIACT PASS Still Results in Error Status

Even when GIACT returns PASS (approved with an assessed fee), the transaction status remains E (Error) because the original Payrix transaction triggered GIACT review. The GIACT result indicates whether the account passed verification, but you should retry the transaction to complete the payment.

Webhook Events

Event Timeline

PhaseEventStatusDescription
1API ResponseP (Pending)Immediate response when GIACT verification is triggered
2transaction.pendingP (Pending)Webhook confirming pending state
3transaction.erroredE (Error)Final webhook with GIACT results

transaction.pending Payload

{
  "id": "what_9m2kx7rn4q8hp5jvbct6y3faw",
  "webhookId": "wh_2jbtc39x6z9byc996ld1kk291l",
  "eventType": "transaction.pending",
  "data": {
    "id": "txn_5kx9mw2nq8r7hp4jvbct6y3fa",
    "type": "verify",
    "merchantId": "mid_8np2rx4qk6m3wy9jzaht5v7dc",
    "platformId": "pfm_3dv7ky9m5r2wp8xjqnbt4c6hf",
    "authorization": {
      "status": "P",
      "processorCode": "generic_error",
      "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
      "errors": [
        "Transaction processing failed"
      ]
    }
  }
}

transaction.errored Payload

{
  "id": "what_7c5mm92aes8tkbchfzgf6d3x28",
  "webhookId": "wh_1hatb29w5z8ayb885kc0jj180k",
  "eventType": "transaction.errored",
  "data": {
    "id": "txn_5kx9mw2nq8r7hp4jvbct6y3fa",
    "type": "verify",
    "merchantId": "mid_8np2rx4qk6m3wy9jzaht5v7dc",
    "platformId": "pfm_3dv7ky9m5r2wp8xjqnbt4c6hf",
    "authorization": {
      "status": "E",
      "processorCode": "generic_error",
      "processorTransactionId": "t1_txn_8a4bc9d21ef753b6c7902e1",
      "errors": [
        "GiactTxnInquiry: BLOCK",
        "Transaction processing failed"
      ]
    }
  }
}

Best Practices for Async Flow

  1. Store transaction ID on initial response - Track the id returned in the API response
  2. Listen for both webhook events - Configure handlers for transaction.pending and transaction.errored
  3. Use transaction ID for correlation - Match webhooks to original requests using the transaction ID
  4. Implement webhook retry handling - Ensure idempotent processing in case of duplicate deliveries
  5. Set appropriate timeouts - GIACT verification typically completes within seconds, but allow for delays

Testing GIACT in Sandbox

To test the GIACT verification flow in sandbox, use the following bank account details to trigger a BLOCK response:

{
  "payment": {
    "bankAccount": {
      "type": "personalChecking",
      "account": "0000000004",
      "routing": "122105278",
      "bankCountry": "USA"
    }
  }
}

This will:

  1. Return an initial P (Pending) status with isGiactEligible: true
  2. Trigger the async GIACT verification flow
  3. Send a transaction.pending webhook
  4. Send a transaction.errored webhook with GiactTxnInquiry: BLOCK in the errors array
📘

Sandbox GIACT Enablement Required

Remember that GIACT must be enabled on your Payrix sandbox account to test this flow. Contact Payrix to enable GIACT for your sandbox environment.

Troubleshooting

Common Scenarios

Transaction Stuck in Pending

Symptom: Transaction remains in P status without receiving transaction.errored webhook.

Possible causes:

  • Webhook endpoint is unreachable
  • Webhook URL is misconfigured
  • GIACT API is experiencing delays

Solution: Check your webhook configuration and logs. Contact support if the issue persists beyond 5 minutes.

No GIACT Results in Errors Array

Symptom: transaction.errored webhook received but errors array is empty or missing GIACT data.

Possible causes:

  • GIACT is not enabled for your platform
  • Transaction was not a verify type
  • Payment method was not ACH

Solution: Verify GIACT is enabled for your Payrix connection and that you're submitting ACH verify transactions.

Immediate Error Response (No Pending State)

Symptom: Transaction returns E status immediately without going through P state.

Possible causes:

  • GIACT is not enabled for your platform
  • Payrix returned an error other than generic_error
  • Transaction validation failed before reaching Payrix

Solution: Check the processorCode value. Only generic_error triggers GIACT verification.

Error Reference

ErrorMeaningSolution
generic_errorPayrix flagged transaction for GIACT verificationWait for webhook with GIACT results
GiactTxnInquiry: BLOCKGIACT reviewed and declined the transaction (fee assessed)Reject transaction; request different payment method
GiactTxnInquiry: PASSGIACT reviewed and approved the transaction (fee assessed)Proceed with the transaction
GiactTxnInquiry: SKIPData did not meet requirements for GIACT reviewReview manually based on risk tolerance

Status Transitions

Normal ACH (no GIACT):
Submit → Approved/Declined/Error

Payrix ACH with GIACT:
Submit → Pending → Error (with GIACT results)

Related Resources