ACH Sale Transaction
Process ACH payments to debit funds from customer bank accounts
ACH Sale Transactions
An ACH Sale transaction debits funds from a customer's bank account. This is the primary method for accepting ACH payments.
Endpoint
POST /v1/transactions
Request Format
Using a Token (Recommended)
If you have an existing ACH token, use it directly:
{
"type": "sale",
"merchantId": "mid_abc123",
"amount": 5000,
"currency": "USD",
"payment": {
"token": "tkn_xyz789"
}
}Token Field Inheritance: If the token was created with
firstName,lastName,accountBusinessName, orachMandate, those values are automatically used for the transaction. You don't need to include them in the request.Overriding Token Fields: If you include
firstName,lastName,accountBusinessName, orachMandatein the request, those values will be used for the transaction and the token will be updated with the new values.
Using Raw Bank Account Details
Alternatively, you can pass bank account details directly:
{
"type": "sale",
"merchantId": "mid_abc123",
"amount": 5000,
"currency": "USD",
"payment": {
"bankAccount": {
"type": "personalChecking",
"account": "123456789",
"routing": "987654321",
"bankCountry": "USA"
}
},
"firstName": "John",
"lastName": "Doe",
"billingAddress": {
"address": "123 Main St",
"city": "New York",
"region": "NY",
"postal": "10001",
"country": "USA"
}
}Request Fields
Required Fields
| Field | Type | Description |
|---|---|---|
type | string | Must be "sale" |
merchantId | string | The merchant processing the payment |
amount | integer | Amount in cents (e.g., 5000 = $50.00) |
currency | string | Must be "USD" for ACH |
payment.token | string | Token from tokenization (preferred) |
payment.bankAccount | object | Raw bank account details (alternative to token) |
Bank Account Fields (when not using token)
| Field | Type | Description |
|---|---|---|
bankAccount.type | string | Account type (see below) |
bankAccount.account | string | Account number (4-17 digits) |
bankAccount.routing | string | Routing number (9 digits) |
bankAccount.bankCountry | string | Must be "USA" |
Account Types
| Value | Description |
|---|---|
personalChecking | Individual checking account |
personalSavings | Individual savings account |
corporateChecking | Business checking account |
corporateSavings | Business savings account |
Customer Information (Required for Personal Accounts)
For personal account types (personalChecking, personalSavings):
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | If not on token | Customer's first name |
lastName | string | If not on token | Customer's last name |
billingAddress.address | string | No | Street address |
billingAddress.city | string | No | City |
billingAddress.region | string | No | State/Province |
billingAddress.postal | string | No | ZIP/Postal code |
billingAddress.country | string | No | ISO 3166-1 alpha-3 country code |
Business Name (Required for Corporate Accounts)
For corporate account types (corporateChecking, corporateSavings):
| Field | Type | Required | Description |
|---|---|---|---|
accountBusinessName | string | If not on token | Business name on the account |
Note: When using a token,
firstName,lastName, andaccountBusinessNameare only required if they weren't provided when the token was created. If included in the request, they will override the token's stored values.
Optional Fields
| Field | Type | Description |
|---|---|---|
fee | integer | Platform fee in cents |
reference | string | Your internal reference ID |
description | string | Transaction description |
achMandate | string | Customer's ACH authorization text (required for some processors if not on token) |
Response Format
Pending Response (Typical for ACH)
{
"id": "txn_01abc123def456",
"type": "sale",
"amount": 5000,
"fee": 0,
"currency": "USD",
"merchantId": "mid_abc123",
"authorization": {
"status": "P",
"processorCode": "00",
"processorMessage": "ACH transaction submitted",
"approvedAmount": 0
},
"payment": {
"type": "personalChecking",
"last4": "6789",
"bin": "987654321"
},
"processor": {
"id": "pfmCon_xyz789",
"name": "Payrix",
"routingSource": "plan"
},
"firstName": "John",
"lastName": "Doe",
"createdOn": "2024-01-15T10:30:00Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique transaction ID |
type | string | Transaction type (sale) |
amount | integer | Amount in cents |
authorization.status | string | Single character status code (P, A, D, E) |
authorization.processorCode | string | Processor-specific code |
authorization.processorMessage | string | Processor message |
authorization.approvedAmount | integer | Amount approved in cents |
payment.type | string | Account type (e.g., personalChecking) |
payment.last4 | string | Last 4 digits of account number |
payment.bin | string | Bank routing number |
processor | object | Processor routing information |
Transaction Statuses
| Status | Code | Description |
|---|---|---|
| Pending | P | Transaction submitted to ACH network |
| Approved | A | Transaction successfully processed |
| Declined | D | Transaction was declined |
| Error | E | An error occurred |
Example: Personal Account Sale
{
"type": "sale",
"merchantId": "mid_abc123",
"amount": 7500,
"currency": "USD",
"payment": {
"bankAccount": {
"type": "personalChecking",
"account": "123456789",
"routing": "987654321",
"bankCountry": "USA"
}
},
"firstName": "Jane",
"lastName": "Smith",
"description": "Monthly subscription",
"reference": "INV-2024-001"
}Example: Corporate Account Sale
{
"type": "sale",
"merchantId": "mid_abc123",
"amount": 150000,
"currency": "USD",
"payment": {
"bankAccount": {
"type": "corporateChecking",
"account": "987654321",
"routing": "123456789",
"bankCountry": "USA"
}
},
"accountBusinessName": "Acme Corporation",
"description": "Q1 Invoice Payment",
"reference": "PO-2024-100"
}Example: Sale with Tokenization
Create a multi-use token for future recurring payments by adding ?tokenize=true to the endpoint:
POST /v1/transactions?tokenize=true
{
"type": "sale",
"merchantId": "mid_abc123",
"amount": 5000,
"currency": "USD",
"payment": {
"bankAccount": {
"type": "personalChecking",
"account": "123456789",
"routing": "987654321",
"bankCountry": "USA"
}
},
"firstName": "John",
"lastName": "Doe"
}The response will include a payment.token field that can be used for future transactions.
Webhooks
ACH transactions go through the ACH network and may take 1-3 business days to settle. Use webhooks to track status changes:
| Event | Description |
|---|---|
transaction.pending | Transaction submitted to ACH network |
transaction.approved | Transaction settled successfully |
transaction.declined | Transaction was declined or returned |
transaction.errored | An error occurred during processing |
Important: Always rely on webhooks for final transaction status. Do not assume a pending ACH transaction will be approved.
Error Messages
These are Preczn API errors returned when a request fails validation or processing. The error and message fields correspond to the API response format documented in the ACH Error Reference.
Bank Account Validation Errors
| Error | Message | Cause | Solution |
|---|---|---|---|
| Bad Request | Routing number is required | Missing routing field | Include the routing field in bankAccount |
| Bad Request | Routing number must be exactly 9 digits | Routing number length incorrect | Verify the routing number is exactly 9 digits |
| Bad Request | Routing number is invalid 'USA' bank routing number | Fails ABA checksum validation | Verify the routing number with customer's bank |
| Bad Request | Account number is required | Missing account field | Include the account field in bankAccount |
| Bad Request | Account number must be between 4 and 17 digits | Account number length invalid | Verify account number is 4-17 digits |
| Bad Request | Account type is required | Missing type field | Include the type field in bankAccount |
| Bad Request | Account type must be one of: PersonalChecking, PersonalSavings, CorporateChecking, CorporateSavings | Invalid account type | Use a valid account type value |
| Bad Request | Bank country is required | Missing bankCountry field | Include bankCountry: "USA" |
| Bad Request | Bank country must be one of: USA | Unsupported country | ACH only supports US bank accounts |
Customer Information Errors
| Error | Message | Cause | Solution |
|---|---|---|---|
| Bad Request | Personal ACH accounts require firstName and lastName | Personal account missing name fields | Include both firstName and lastName fields |
| Bad Request | Corporate ACH accounts require accountBusinessName or firstName and lastName | Corporate account missing identification | Include accountBusinessName or both firstName and lastName |
| Bad Request | ACH mandate is required for Braintree ACH transactions | Braintree requires authorization text | Include achMandate field |
Token Errors
| Error | Message | Cause | Solution |
|---|---|---|---|
| Bad Request | payment.token must be a valid token ID | Invalid or expired token | Verify the token ID is correct and exists |
Transaction Errors
| Error | Message | Cause | Solution |
|---|---|---|---|
| Bad Request | Amount is required | Missing amount field | Include amount in cents |
| Bad Request | Amount must be greater than 0 | Zero or negative amount | Provide a positive amount |
| Bad Request | Currency is required | Missing currency field | Include currency: "USD" |
Configuration Errors
| Error | Message | Cause | Solution |
|---|---|---|---|
| Bad Request | ACH transaction not supported for this Plan | Merchant's plan lacks ACH processor | Contact support to enable ACH |
For a complete list of errors, see the ACH Error Reference.
Updated 2 days ago
