Braintree ACH Integration
Process ACH (bank account) transactions through Preczn with Braintree as your processor
PrerequisitesEnsure you've completed Braintree Connection Setup before proceeding.
See also: For general ACH concepts and transaction types, see ACH (Direct Debit).
Setup
Before processing ACH transactions, you must configure Braintree webhooks. This is a one-time setup per merchant.
CriticalYou must complete webhook configuration before processing ACH transactions. Without it, ACH sales will remain in PENDING status indefinitely and you won't receive settlement confirmations.
Get Your Webhook URL
Option A: Via Dashboard
- Navigate to Merchant Connection settings in the Preczn dashboard
- Locate the Braintree processor connection
- Copy the Webhook Consumer API URL
Option B: Via API
GET /v1/merchants/{merchantId}
{
"id": "mid_2zyd88xrnr90xskmjmqpd0x1vj",
"connections": [
{
"processor": "braintree",
"ingressWebhook": {
"url": "https://wc-api.preczn.com/v1/transactions/braintree/platform/{platformId}/merchant/{merchantId}",
"verified": false
}
}
]
}Configure Braintree
In your Braintree Control Panel:
- Click Settings gear → API → Webhooks tab
- Create a new webhook destination using the URL from above
- Subscribe to:
Transaction Settled,Transaction Settlement Declined, and optionallyTransaction Disbursed
Verify the Connection
- Click "Check URL" in Braintree webhook settings
- Braintree sends a test webhook to Preczn
- Verify success:
ingressWebhook.verifiedchanges totrue
{
"connections": [
{
"processor": "braintree",
"ingressWebhook": {
"url": "https://wc-api.preczn.com/v1/transactions/braintree/platform/{platformId}/merchant/{merchantId}",
"verified": true
}
}
]
}
TipIf verification fails, double-check that your Braintree credentials (Merchant ID, Public Key, Secret Key) are correctly configured in Preczn.
How ACH Works with Braintree
ACH transactions follow a verify-then-charge pattern:
- Verify - Tokenize and verify the bank account (required once per token)
- Sale - Charge the verified bank account
- Refund - Return funds after settlement (if needed)
Preczn uses Braintree's Network Check verification method, which instantly validates the routing number, account number, and customer information against banking networks.
Important
- Verification is instant - no micro-deposit waiting period
- Network Check is not supported by all banks - verification may fail with valid accounts in rare cases
- ACH does not support authorization, capture, or void - use
saleandrefundonly
Integration Guide
Required Fields
When verifying ACH bank accounts, you must provide these fields:
ImportantThese fields are validated by Braintree's API. Missing fields cause Braintree to reject the verification.
Always Required
| Field | Description |
|---|---|
achMandate | Customer authorization text (e.g., "I authorize Acme Corp to debit my account...") |
billingAddress.address | Street address |
billingAddress.city | City |
billingAddress.region | State/region (e.g., "TX") |
billingAddress.postal | Postal/ZIP code |
Conditional by Account Type
| Field | Required When | Description |
|---|---|---|
firstName + lastName | Personal accounts | For personalChecking or personalSavings |
accountBusinessName | Corporate accounts | For corporateChecking or corporateSavings |
ACH Mandate
The achMandate contains authorization text the customer agreed to. Example:
"I authorize [Your Company Name] to debit my bank account for the agreed upon amount."
Compliance NoticePreczn passes the
achMandateto Braintree but is not responsible for ACH authorization compliance. See Braintree ACH Client-side Implementation for requirements.
Verify and Charge Flow
This section covers the standard integration pattern for ACH transactions.
RecommendedAlways submit a verify request before charging—Preczn handles both verified and unverified tokens transparently. This eliminates tracking verification status in your system.
Step 1: Verify the Bank Account
Submit a verify request with the token and required fields.
Personal Account:
POST /v1/transactions?tokenize=true
{
"type": "verify",
"merchantId": "mid_2zyd88xrnr90xskmjmqpd0x1vj",
"payment": {
"token": "tkn_SINGLE_USE_TOKEN_FROM_SDK"
},
"firstName": "Jane",
"lastName": "Smith",
"email": "[email protected]",
"achMandate": "I authorize Acme Corp to debit my account for the agreed upon amount.",
"billingAddress": {
"address": "456 Oak Street",
"city": "Austin",
"region": "TX",
"postal": "78702",
"country": "USA"
}
}Corporate Account:
POST /v1/transactions?tokenize=true
{
"type": "verify",
"merchantId": "mid_2zyd88xrnr90xskmjmqpd0x1vj",
"payment": {
"token": "tkn_SINGLE_USE_TOKEN_FROM_SDK"
},
"accountBusinessName": "Johnson Industries LLC",
"email": "[email protected]",
"achMandate": "I authorize Acme Corp to debit the Johnson Industries LLC account for the agreed upon amount.",
"billingAddress": {
"address": "123 Business Park Dr",
"address2": "Suite 400",
"city": "Austin",
"region": "TX",
"postal": "78701",
"country": "USA"
}
}Response:
{
"id": "txn_01h4x5y6z7a8b9c0d1e2f3g4h5",
"type": "verify",
"authorization": {
"status": "A"
},
"payment": {
"token": "tkn_01j2k3l4m5n6o7p8q9r0s1t2u3",
"type": "personalChecking",
"last4": "3210",
"bin": "011000015"
},
"firstName": "Jane",
"lastName": "Smith",
"achMandate": "I authorize Acme Corp to debit my account for the agreed upon amount."
}
Key Points
- Use
?tokenize=trueto receive the multi-use token in the response- Verification is instant (
status: "A"or error) - no pending state- Store the returned
payment.tokenfor future charges
Step 2: Charge the Verified Token
POST /v1/transactions
{
"type": "sale",
"merchantId": "mid_2zyd88xrnr90xskmjmqpd0x1vj",
"amount": 5000,
"currency": "USD",
"payment": {
"token": "tkn_01j2k3l4m5n6o7p8q9r0s1t2u3"
}
}Response:
{
"id": "txn_01y2z3a4b5c6d7e8f9g0h1i2j3",
"type": "sale",
"authorization": {
"status": "P",
"processorTransactionId": "abc123xyz"
},
"amount": 5000,
"currency": "USD",
"payment": {
"token": "tkn_01j2k3l4m5n6o7p8q9r0s1t2u3",
"type": "personalChecking",
"last4": "3210",
"bin": "011000015"
},
"achMandate": "I authorize Acme Corp to debit my account for the agreed upon amount."
}
Pending StatusACH sales return
status: "P"(PENDING) initially. Final status arrives via webhook after 1-3 business days.
Charging Existing Tokens
For tokens already on file, submit a verify request before charging. Preczn handles both scenarios:
- Already verified: Returns success immediately (no-op)
- Not yet verified: Verifies at Braintree, then returns success
This approach eliminates tracking verification status—always verify, then charge.
Direct Charge (Advanced)
If you track verification status externally, you can skip verify for known-verified tokens:
{
"type": "sale",
"merchantId": "mid_2zyd88xrnr90xskmjmqpd0x1vj",
"amount": 10000,
"currency": "USD",
"payment": {
"token": "tkn_VERIFIED_MULTI_USE_TOKEN"
}
}
ImportantIf the token isn't verified, this fails with
400 Bad Request. Use the verify-then-charge pattern for simpler integrations.
Server-Side TokenizationNeed to create tokens from existing bank account data? See Server-Side Bank Account Tokenization for the
POST /v1/tokensendpoint and direct tokenization methods.
Troubleshooting
Error Reference
Validation Errors (400)
| Message | Cause | Solution |
|---|---|---|
ACH mandate is required for Braintree ACH transactions | Missing achMandate | Add achMandate to request |
Personal ACH accounts require firstName and lastName | Personal account missing name | Add firstName and lastName |
Corporate ACH accounts require accountBusinessName or firstName and lastName | Corporate account missing name | Add accountBusinessName |
Routing number must be exactly 9 digits | Invalid routing number | Verify routing number format |
Bank country must be one of: USA | Non-USA bank | ACH is US-only |
Sale Without Verification (400)
{
"message": "ACH bank account not verified. Submit a verify transaction first.",
"error": "Bad Request",
"statusCode": 400
}
SolutionSubmit a
verifytransaction with required fields before the sale:
POST /v1/transactionswithtype: "verify"- Wait for
status: "A"POST /v1/transactionswithtype: "sale"
Status Codes
| Status | Meaning | Action |
|---|---|---|
A | Approved | Success |
P | Pending | Wait for webhook (normal for ACH sales) |
D | Declined | Contact customer for alternative payment |
E | Error | Check error message, retry with corrections |
Refunds
ACH refunds can only be processed after settlement (typically 3 business days). See ACH Refunds for details.
For a complete error list, see ACH Error Reference.
Webhook Events
ACH transactions settle asynchronously. Configure webhooks to receive final status.
ReminderIf webhooks aren't configured, see Setup above.
Event Mapping
| Braintree Event | Preczn Event | Description |
|---|---|---|
transaction_settled | transaction.approved | Settlement succeeded |
transaction_settlement_declined | transaction.declined | Bank declined |
| Sale submitted | transaction.pending | Awaiting settlement |
| Processing error | transaction.errored | Processing failed |
TimelineSettlement typically occurs 1-3 business days after the sale.
Payload Examples
Approved:
{
"id": "evt_01h4x5y6z7a8b9c0d1e2f3g4h5",
"webhookId": "wbh_01a2b3c4d5e6f7g8h9i0j1k2l3",
"eventType": "transaction.approved",
"data": {
"id": "txn_01h4x5y6z7a8b9c0d1e2f3g4h5",
"type": "sale",
"authorization": {
"status": "A",
"processorTransactionId": "abc123xyz"
},
"amount": 5000,
"currency": "USD",
"payment": {
"type": "personalChecking",
"last4": "3210",
"bin": "011000015"
}
}
}Declined:
{
"id": "evt_01h4x5y6z7a8b9c0d1e2f3g4h5",
"webhookId": "wbh_01a2b3c4d5e6f7g8h9i0j1k2l3",
"eventType": "transaction.declined",
"data": {
"id": "txn_01h4x5y6z7a8b9c0d1e2f3g4h5",
"type": "sale",
"authorization": {
"status": "D",
"processorTransactionId": "abc123xyz"
},
"amount": 5000,
"currency": "USD"
}
}Testing
Braintree provides test values for ACH in test mode:
- Test routing numbers - Valid routing numbers for test mode
- Test account numbers - Trigger different verification outcomes
- Test amounts - Trigger different settlement outcomes via webhooks
See Braintree ACH Testing for current test values.
Best Practices
- Always verify before charging - Use the verify-then-charge pattern
- Implement webhook handlers - Essential for final transaction status
- Handle PENDING status - ACH sales don't complete immediately
- Store multi-use tokens - Reuse verified tokens for recurring charges
- Collect complete billing address - Required for Braintree verification
Updated 2 days ago
