GoodFunds Gateway API
Secure, RESTful payment processing API
Quick Start
Make your first API call in seconds:
{
"charge_type": "ccauthcapture",
"creditcard": {
"creditcard_number": "4111111111111111",
"creditcard_exp_month": 12,
"creditcard_exp_year": 2025,
"creditcard_cvv": 123
},
"amount": "100.00"
}
Base URLs
https://demo.goodfundsgateway.com/api/
Test Transactions
https://live.goodfundsgateway.com/api/
Live Transactions
Get Started
Don't have an account yet? Request access to our sandbox environment to start testing the API.
Request Sandbox AccessAuthentication
All API requests require authentication via request headers
API Credentials
You must include the following headers in every request:
| Header | Description | Example |
|---|---|---|
svs-api-id |
Your unique API identifier | UPB0W66B96PCIXU45PRI |
svs-api-key |
Your secret API key (keep secure!) | 192QP4J8K4LI5M58P4VDCQN5I2GECDEEHMYPXQKJ |
Authentication Error Example
If authentication fails, you'll receive a 401 error:
{
"status": "error",
"errorMessage": {
"errorCode": 1001,
"message": "Invalid API credentials"
}
}
Testing Guide
Test data for sandbox environment
Credit Card Test Numbers
Use these test credit card numbers in sandbox mode. Different gateways have different test card requirements.
| Card Type | Card Number | Gateway Support | Notes |
|---|---|---|---|
| Visa | 4111111111111111 |
All Gateways | Standard test card |
| Mastercard | 5555555555554444 |
All Gateways | Standard test card |
| Discover | 6011111111111117 |
All Gateways | Standard test card |
| Amex | 378282246310005 |
Converge, Authorize.net | 15-digit Amex test card |
| JCB | 3566002020360505 |
Converge, Authorize.net | JCB test card |
| Diners Club | 30569309025904 |
Converge Only | 14-digit Diners Club test card |
Credit Card Test Scenarios
| Scenario | Card Number | Amount | Expected Response |
|---|---|---|---|
| Approved | 4111111111111111 |
Any | Approved |
| Declined | 4000000000000002 |
Any | Declined - Card declined |
| Insufficient Funds | 4000000000000003 |
Any | Declined - Insufficient funds |
| AVS Mismatch | 4000000000000004 |
Any | AVS mismatch |
| CVV Mismatch | 4000000000000005 |
Any | CVV mismatch |
| Expired Card | 4000000000000006 |
Any | Expired card |
eCheck / ACH Test Accounts
Converge ACH Test Accounts
| Account Type | Routing Number | Account Number | Result |
|---|---|---|---|
| Valid Account | 122105278 |
0000000016 |
Approved |
| Valid Account | 321174851 |
9900000003 |
Approved |
| Invalid Account | 122105278 |
0000000001 |
Declined |
| Invalid Routing | 111111111 |
0000000016 |
Invalid Routing Number |
Linked2Pay (AvidiaPay) ACH Test Accounts
| Account Type | Routing Number | Account Number | Result |
|---|---|---|---|
| Valid Checking | 122105278 |
0000000016 |
Approved |
| Valid Checking | 321174851 |
9900000003 |
Approved |
| Valid Savings | 122105278 |
0000000010 |
Approved |
| Invalid Account | 122105278 |
0000000001 |
Declined |
Jack Henry SmartPay ACH Test Accounts
| Account Type | Routing Number | Account Number | Result |
|---|---|---|---|
| Valid Checking | 111000025 |
56789 |
Approved |
| Valid Checking | 123456789 |
12345678901 |
Approved |
| Declined | 053100244 |
000000000 |
Declined |
| Invalid Routing | 11100002 |
56789 |
Invalid Routing |
Common Test Scenarios by Gateway
| Gateway | Card Test | ACH Test | Notes |
|---|---|---|---|
| Converge | ✓ Full Support | ✓ Full Support | All test cards work. All ACH accounts work. |
| Authorize.net | ✓ Full Support | Limited | Use standard test cards. ACH limited. |
| Linked2Pay (AvidiaPay) | ✓ Full Support | ✓ Full Support | All test cards work. All ACH accounts work. |
| Jack Henry SmartPay | Limited | Limited | Use specific test accounts only |
Credit Card Expiration Dates
Use these expiration dates for testing:
- Future Date:
12/2028or any date in the future - Expired Date:
12/2020- Will trigger expired card response - Current Month: Use current month + 1 year for valid transactions
CVV Test Values
- Valid CVV:
123(Visa/Mastercard/Discover) or1234(Amex) - Invalid CVV:
999- Will trigger CVV mismatch
Payment Methods
Securely store and manage payment methods
/paymentmethod.json
Required
Store a credit card or eCheck for future use. Credit cards are tokenized for security.
Parameters
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
creditcard or echeck |
object | Payment method details | See examples |
customer |
object | Customer information | See examples |
default |
integer | 1 to set as default payment method | 1 |
gateway_id |
integer | Gateway account ID for tokenization | 123 |
customer Optional object
Customer record to attach this payment method to. If customer.internal_id matches an existing customer, that customer is reused; otherwise a new customer is created.
| Field | Type | Description | Example |
|---|---|---|---|
customer.internal_id |
string | Your own identifier for this customer — use this to look the customer back up later via internal_id on other endpoints |
CUST-001 |
customer.first_name |
string | Customer first name | John |
customer.last_name |
string | Customer last name | Doe |
customer.company |
string | Customer company name | Acme Inc. |
customer.email |
string | Customer email address | john@example.com |
customer.phone |
string | Customer phone number | 555-123-4567 |
billto Optional object
Billing address for this payment method. Recommended for AVS matching on credit cards.
| Field | Type | Description | Example |
|---|---|---|---|
billto.address_1 |
string | Street address | 123 Main St |
billto.city |
string | City | San Diego |
billto.state |
string | State / province | CA |
billto.postal_code |
string | ZIP / postal code — this is the field AVS checks against | 92101 |
billto.country |
string | 2-letter country code | US |
creditcard Required for card payment methods
Required when storing a credit card (omit entirely when storing an echeck instead).
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
creditcard.creditcard_number |
string | Yes | Full card number, no spaces or dashes | 4111111111111111 |
creditcard.creditcard_exp_month |
integer | Yes | Expiration month, 1–12 | 12 |
creditcard.creditcard_exp_year |
integer | Yes | 4-digit expiration year | 2028 |
creditcard.creditcard_cvv |
integer | Yes | 3-digit security code (4-digit for Amex) | 123 |
creditcard.creditcard_name |
string | No | Name as it appears on the card | John Doe |
creditcard.creditcard_type |
string | No | Card brand — most gateways detect this automatically from the number if omitted | VISA |
echeck Required for eCheck payment methods
Required when storing a bank account (omit entirely when storing a creditcard instead). Also used for the is_vendor vendor eCheck flow — see the Vendor eCheck example.
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
echeck.echeck_account_number |
string | Yes | Bank account number | 9900000003 |
echeck.echeck_routing_number |
string | Yes | 9-digit ABA routing number | 321174851 |
echeck.echeck_account_type |
integer | Yes | 0 = Business, 1 = Personal |
1 |
echeck.echeck_holder_type |
integer | Yes | 0 = Checking, 1 = Savings |
0 |
echeck.echeck_seccode |
string | Yes | NACHA SEC code — WEB for online-authorized, PPD for prearranged/written authorization (typically used for recurring) |
WEB |
echeck.echeck_name |
string | No | Name on the bank account | Jane Smith |
Vendor eCheck Fields Optional, vendor payment methods only
Use these instead of customer to store an eCheck payment method for a vendor (used for disbursements) rather than a customer. See the Vendor eCheck example tab.
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
is_vendor |
integer | Yes | Set to 1 to create a vendor payment method instead of a customer one |
1 |
vendor_id |
integer | Yes | ID of the vendor (from vendor creation) this payment method belongs to | 1 |
Vendor payment methods only support eCheck — credit card is not available for vendor disbursements. Vendor payment methods don't take customer, billto, or shipto.
Example Requests
{
"gateway_id": 123,
"customer": {
"internal_id": "CUST-001",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "555-123-4567"
},
"billto": {
"address_1": "123 Main St",
"city": "San Diego",
"state": "CA",
"postal_code": "92101",
"country": "US"
},
"shipto": {
"first_name": "John",
"last_name": "Doe",
"address_1": "123 Main St",
"city": "San Diego",
"state": "CA",
"postal_code": "92101",
"country": "US"
},
"creditcard": {
"creditcard_name": "John Doe",
"creditcard_number": "4111111111111111",
"creditcard_type": "VISA",
"creditcard_exp_month": 12,
"creditcard_exp_year": 2025,
"creditcard_cvv": 123
},
"default": 1
}
{
"gateway_id": 456,
"customer": {
"internal_id": "CUST-002",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com"
},
"billto": {
"address_1": "456 Oak Ave",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90001"
},
"echeck": {
"echeck_name": "Jane Smith",
"echeck_account_number": "9900000003",
"echeck_routing_number": "321174851",
"echeck_account_type": 1, // 0 Business 1 Personal
"echeck_holder_type": 0, // 0 Checking 1 Savings
"echeck_seccode": "WEB"
},
"default": 1
}
{
"is_vendor": 1,
"vendor_id": 1,
"default": 1,
"gateway_id": 456,
"echeck": {
"echeck_name": "ABC Supplies Inc.",
"echeck_account_number": "987654321",
"echeck_routing_number": "053100244",
"echeck_account_type": 1, // 0 Business 1 Personal
"echeck_holder_type": 0, // 0 Checking 1 Savings
"echeck_seccode": "WEB"
}
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 700,
"message": {
"payment_method": {
"payment_method_id": 12345,
"card_type": "VISA",
"last_four": "1111"
}
}
}
}
/paymentmethods.json
Optional
List all payment methods for a customer.
Query Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
internal_id |
string | Filter by internal ID | CUST-001 |
method_type |
integer | 1=Credit Card, 2=eCheck | 1 |
vendor_id |
integer | Filter vendor payment methods | 1 |
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/paymentmethods.json?internal_id=123&method_type=1" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
/paymentmethod/{id}.json
Optional
Retrieve a single payment method by its ID.
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/paymentmethod/12345.json" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 706,
"message": {
"payment_method": {
"payment_method_id": 12345,
"card_type": "VISA",
"last_four": "1111"
}
}
}
}
If the payment method doesn't exist, you'll get a 404 with errorCode: 1000.
/paymentmethod/{id}/delete.json
Delete
Permanently delete a stored payment method. This does not affect past charges made with it — only prevents future use.
Example Request
curl -X POST "https://demo.goodfundsgateway.com/api/paymentmethod/12345/delete.json" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 702,
"message": "Payment Method Deleted"
}
}
/paymentmethod/cleardefaults.json
Optional
Clear the default flag across a customer's payment methods — use this before setting a different payment method as the new default.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
customer_id |
integer | Yes | Customer whose default flags should be cleared | 123 |
Example Request
{
"customer_id": 123
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 703,
"message": "Default Payment Methods Cleared"
}
}
Charges
Process credit card and eCheck transactions
/charge.json
Required
Process a single transaction. Supports credit card sales, authorizations, and eCheck processing.
Parameters
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
charge_type |
string | Transaction type | ccauthcapture |
amount |
decimal | Transaction amount | 100.00 |
creditcard or echeck |
object | Payment method details | See examples |
Charge Types
| Type | Description |
|---|---|
ccauthcapture |
Authorize and capture payment immediately |
ccauthorize |
Authorize payment (capture later) |
ccprocesspreauthorize |
Capture a previously authorized transaction |
ecdebit |
Debit from a checking account |
eccredit |
Credit to a checking account |
Authorization Buffer Authorize.net & Converge only
For ccauthorize requests only, on gateway accounts with a buffer configured (contact support to set one up). Not applicable to any other charge_type, and has no effect on other gateways.
The buffer amount/percentage itself is configured on the gateway account, not sent by you per-request. By default, if your gateway account has a buffer configured, it's applied automatically to every ccauthorize. Use is_buffer to control that on a per-request basis:
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
is_buffer |
integer | No | Omit or set to 1 to apply the gateway's configured buffer (this is the default behavior when the gateway has a buffer set up). Set to 0 to authorize the exact amount sent, with no buffer, for this specific request. |
1 |
Example: a gateway configured with a 20% buffer, given amount: 100.00, will actually authorize 120.00 — leaving room to capture up to $120 later via ccprocesspreauthorize without failing. The amount you send is unaffected in the response; check the transaction detail if you need the true authorized amount.
customer Optional object
Customer record to associate with this charge. Omit entirely for a one-off charge with no stored customer.
| Field | Type | Description | Example |
|---|---|---|---|
customer.internal_id |
string | Your own identifier for this customer — use this to look the customer back up later via internal_id on other endpoints |
CUST-001 |
customer.first_name |
string | Customer first name | John |
customer.last_name |
string | Customer last name | Doe |
customer.email |
string | Customer email address | john@example.com |
customer.phone |
string | Customer phone number | 555-123-4567 |
billto Optional object
Billing address for this transaction. Recommended for AVS matching on credit card charges — without it, some gateways will still process the charge but skip AVS verification.
| Field | Type | Description | Example |
|---|---|---|---|
billto.first_name / billto.last_name |
string | Billing contact name | John / Doe |
billto.address_1 |
string | Street address | 123 Main St |
billto.city |
string | City | San Diego |
billto.state |
string | State / province | CA |
billto.postal_code |
string | ZIP / postal code — this is the field AVS checks against | 92101 |
billto.country |
string | 2-letter country code | US |
billto.email / billto.phone |
string | Billing contact email/phone, if different from customer |
— |
creditcard Required for card charge_types
Required when charge_type is ccauthcapture or ccauthorize. Not used for ccprocesspreauthorize (that captures a prior authorization by charge_id) or when charging a stored payment_method_id, where only creditcard.creditcard_cvv is needed for re-verification.
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
creditcard.creditcard_number |
string | Yes | Full card number, no spaces or dashes | 4111111111111111 |
creditcard.creditcard_exp_month |
integer | Yes | Expiration month, 1–12 | 12 |
creditcard.creditcard_exp_year |
integer | Yes | 4-digit expiration year | 2028 |
creditcard.creditcard_cvv |
integer | Yes | 3-digit security code (4-digit for Amex) | 123 |
creditcard.creditcard_name |
string | No | Name as it appears on the card | John Doe |
creditcard.creditcard_type |
string | No | Card brand — most gateways detect this automatically from the number if omitted | VISA |
echeck Required for ACH charge_types
Required when charge_type is ecdebit or eccredit.
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
echeck.echeck_account_number |
string | Yes | Bank account number | 9900000003 |
echeck.echeck_routing_number |
string | Yes | 9-digit ABA routing number | 321174851 |
echeck.echeck_account_type |
integer | Yes | 0 = Business, 1 = Personal |
1 |
echeck.echeck_holder_type |
integer | Yes | 0 = Checking, 1 = Savings |
0 |
echeck.echeck_seccode |
string | Yes | NACHA SEC code — WEB for online-authorized, PPD for prearranged/written authorization (typically used for recurring) |
WEB |
echeck.echeck_name |
string | No | Name on the bank account | Jane Smith |
echeck.echeck_check_number |
string | No | Check number, if applicable | 101 |
echeck.echeck_agree |
integer | No | Set to 1 to confirm the customer authorized this debit — recommended for your own compliance records |
1 |
level2 Optional object
Level 2 processing data — can lower your interchange rate on B2B/commercial cards. Ignored by gateways/card types that don't support it.
| Field | Type | Description | Example |
|---|---|---|---|
level2.invoice_number |
string | Your invoice number for this charge | INV-001 |
level2.salestax |
decimal | Sales tax amount included in amount |
8.50 |
level2.po_number |
string | Customer's purchase order number | PO-12345 |
level2.customer_code |
string | Customer code for the cardholder's own expense tracking | CUST-001 |
Example Requests
{
"charge_type": "ccauthcapture",
"gateway_id": 123,
"customer": {
"internal_id": "CUST-001",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "555-123-4567"
},
"billto": {
"first_name": "John",
"last_name": "Doe",
"address_1": "123 Main St",
"city": "San Diego",
"state": "CA",
"postal_code": "92101",
"country": "US",
"email": "john@example.com",
"phone": "555-123-4567"
},
"shipto": {
"first_name": "John",
"last_name": "Doe",
"address_1": "123 Main St",
"city": "San Diego",
"state": "CA",
"postal_code": "92101",
"country": "US"
},
"level2": {
"invoice_number": "INV-001",
"salestax": "8.50",
"po_number": "PO-12345",
"customer_code": "CUST-001"
},
"creditcard": {
"creditcard_name": "John Doe",
"creditcard_number": "4111111111111111",
"creditcard_type": "VISA",
"creditcard_exp_month": 12,
"creditcard_exp_year": 2025,
"creditcard_cvv": 123
},
"amount": "100.00"
}
{
"charge_type": "ccauthorize",
"gateway_id": 123,
"customer": {
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com"
},
"billto": {
"address_1": "123 Main St",
"city": "San Diego",
"state": "CA",
"postal_code": "92101"
},
"creditcard": {
"creditcard_name": "John Doe",
"creditcard_number": "4111111111111111",
"creditcard_exp_month": 12,
"creditcard_exp_year": 2025,
"creditcard_cvv": 123
},
"amount": "100.00"
}
{
"charge_type": "ccprocesspreauthorize",
"gateway_id": 123,
"amount": "100.00",
"level2": {
"invoice_number": "INV-001"
}
}
{
"charge_type": "ecdebit",
"gateway_id": 456,
"customer": {
"internal_id": "CUST-002",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com"
},
"billto": {
"first_name": "Jane",
"last_name": "Smith",
"address_1": "456 Oak Ave",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90001",
"country": "US"
},
"echeck": {
"echeck_name": "Jane Smith",
"echeck_account_number": "9900000003",
"echeck_routing_number": "321174851",
"echeck_check_number": "101",
"echeck_account_type": 1, // 0 Business 1 Personal
"echeck_holder_type": 0, // 0 Checking 1 Savings
"echeck_seccode": "WEB",
"echeck_agree": 1
},
"amount": "250.00"
}
{
"charge_type": "ccauthcapture",
"gateway_id": 123,
"payment_method_id": 12345,
"amount": "50.00",
"creditcard": {
"creditcard_cvv": 123
},
"level2": {
"invoice_number": "INV-002"
}
}
Responses
{
"status": "success",
"successMessage": {
"response_code": 1,
"message": {
"charge": {
"success": true,
"charge_id": 98765,
"trans_id": "TXN-20260615-ABCDEF",
"approval_code": "ABC123",
"card_number": "411111******1111",
"amount": "100.00",
"raw_data": {
"processor_response": "Approved",
"auth_code": "ABC123"
}
}
}
}
}
A decline is still a 200 OK HTTP response — your request reached the gateway and was processed, it just wasn't approved. Check status and errorMessage.errorCode to detect this, not the HTTP status code.
{
"status": "error",
"errorMessage": {
"errorCode": 106,
"message": {
"success": false,
"reason": "Insufficient funds",
"processor_code": "51",
"processor_message": "Insufficient funds"
}
}
}
Note: the exact fields inside message are the raw response passed through from whichever processor handled the transaction (Converge, Authorize.net, Linked2Pay, Jack Henry, etc.) — they vary by gateway. Branch your integration on errorCode: 106, not on the shape of message.
{
"status": "error",
"errorMessage": {
"errorCode": 5027,
"message": "Credit card number is required"
}
}
See Error Codes for the full list — errorCode is always present on every error response, message is a plain string in most validation errors (not a nested object).
/charges.json
Optional
Search your stored charges. Supports filtering by date range, gateway, customer, and more — use this (or the equivalent GET /transactions.json, which returns identical data under a transactions key) to reconcile activity for a date range instead of looking up charges one at a time.
Query Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
start_date |
date | Include charges on/after this date (YYYY-MM-DD). Compared at midnight — see note below. |
2026-08-01 |
end_date |
date | Include charges on/before this date (YYYY-MM-DD). Compared at midnight of this date — transactions later that same day are excluded. Pass the next day if you need that day fully included. |
2026-08-13 |
charge_date |
date | Exact single-date match instead of a range | 2026-08-05 |
gateway_id |
integer | Filter to one gateway account | 123 |
internal_id |
string | Filter by your internal customer ID | CUST-001 |
payment_type |
string | Filter by payment type | creditcard |
filter[status] |
string | Filter by charge status | OK |
filter[limit] / filter[offset] |
integer | Pagination | 50 / 0 |
filter[sort] / filter[sort_dir] |
string | Sort column and direction (ASC or DESC) |
timestamp / DESC |
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/charges.json?start_date=2026-08-01&end_date=2026-08-14&filter[limit]=50&filter[sort_dir]=DESC" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 706,
"message": {
"charges": [
{ "id": 98765, "gateway_id": 123, "amount": "100.00", "status": "OK", "timestamp": "2026-08-05 10:15:00" }
]
}
}
}
If no charges exist for the given filters, you'll get a 404 with errorCode: 1000.
/charge/{id}.json
Optional
Retrieve one charge by its ID.
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/charge/98765.json" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 707,
"message": {
"charge": { "id": 98765, "gateway_id": 123, "amount": "100.00", "status": "OK" }
}
}
}
If the charge doesn't exist, you'll get a 404 with errorCode: 1000.
Refunds
Process refunds for previous charges
/charge.json
Refund
Process a refund for a previous charge. Automatically voids if settlement hasn't occurred.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ccrefund or ecrefund |
ccrefund |
charge_id |
integer | Yes | ID of the charge to refund | 98765 |
amount |
decimal | No | Amount to refund (defaults to full amount) | 50.00 |
gateway_id |
integer | No | Gateway account ID | 123 |
Example Request
{
"charge_type": "ccrefund",
"gateway_id": 123,
"charge_id": 98765,
"amount": "50.00"
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 1,
"message": {
"charge": {
"response_code": 50,
"response_text": "Transaction refunded.",
"success": true,
"reason": "Transaction refunded successfully"
}
}
}
}
Voids
Process void for previous charge
/charge.json
Void
Process a void for a previous charge.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ccvoid or ecvoid |
ccvoid |
charge_id |
integer | Yes | ID of the charge to void | 98765 |
gateway_id |
integer | No | Gateway account ID | 123 |
Example Request
{
"charge_type": "ccvoid",
"gateway_id": 123,
"charge_id": 98765
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 1,
"message": {
"charge": {
"response_code": 20,
"response_text": "Transaction voided.",
"success": true,
"reason": "Transaction voided successfully"
}
}
}
}
Recurring Payments
Set up and manage automated ACH payments
/setuprecurringcharge.json
Required
Set up a recurring ACH payment schedule.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ecrecurring |
ecrecurring |
gateway_id |
integer | Yes | Gateway account ID to process the recurring charge through | 456 |
amount |
decimal | Yes | Amount for each recurring payment | 100.00 |
schedule |
object | Yes | Recurring schedule details | See example |
echeck |
object | Yes | Bank account details | See example |
customer |
object | No | Customer to attach this recurring schedule to | See example |
billto |
object | No | Billing address | See example |
echeck Required object
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
echeck.echeck_account_number |
string | Yes | Bank account number | 0000000016 |
echeck.echeck_routing_number |
string | Yes | 9-digit ABA routing number | 122105278 |
echeck.echeck_account_type |
integer | Yes | 0 = Business, 1 = Personal |
1 |
echeck.echeck_holder_type |
integer | Yes | 0 = Checking, 1 = Savings |
0 |
echeck.echeck_seccode |
string | Yes | NACHA SEC code — use PPD for recurring (prearranged/written authorization) |
PPD |
echeck.echeck_agree |
integer | Yes | Set to 1 to confirm the customer authorized recurring debits from this account. Required for NACHA compliance on recurring ACH. |
1 |
echeck.echeck_name |
string | No | Name on the bank account | Robert Johnson |
customer Optional object
| Field | Type | Description | Example |
|---|---|---|---|
customer.internal_id |
string | Your own identifier for this customer | CUST-003 |
customer.first_name / customer.last_name |
string | Customer name | Robert / Johnson |
customer.email |
string | Customer email address | robert@example.com |
billto Optional object
| Field | Type | Description | Example |
|---|---|---|---|
billto.first_name / billto.last_name |
string | Billing contact name | Robert / Johnson |
billto.address_1 |
string | Street address | 789 Pine St |
billto.city / billto.state / billto.postal_code |
string | City/state/ZIP | San Francisco / CA / 94101 |
Schedule Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
frequency |
string | monthly, weekly, quarterly, yearly | monthly |
payment_day |
integer | Day of month or day of week (0=Sun...6=Sat) | 15 |
start_date |
date | Start date (YYYY-MM-DD) | 2026-07-01 |
num_payments |
string/integer | "indefinite" or number of payments | indefinite |
enabled |
integer | 1=enabled, 0=disabled | 1 |
description |
string | Description of the recurring payment | Monthly Subscription |
Example Request
{
"charge_type": "ecrecurring",
"gateway_id": 456,
"customer": {
"internal_id": "CUST-003",
"first_name": "Robert",
"last_name": "Johnson",
"email": "robert@example.com"
},
"billto": {
"first_name": "Robert",
"last_name": "Johnson",
"address_1": "789 Pine St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94101"
},
"echeck": {
"echeck_name": "Robert Johnson",
"echeck_account_number": "0000000016",
"echeck_routing_number": "122105278",
"echeck_account_type": 1, // 0 Business 1 Personal
"echeck_holder_type": 0, // 0 Checking 1 Savings
"echeck_seccode": "PPD",
"echeck_agree": 1
},
"schedule": {
"frequency": "monthly",
"payment_day": 15,
"start_date": "2026-07-15",
"num_payments": "indefinite",
"enabled": 1,
"description": "Monthly Subscription Payment"
},
"amount": "100.00"
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 1,
"message": {
"recurring": {
"response_code": 100,
"response_text": "Recurring Payment created.",
"success": true,
"recur_id": 12345,
"amount": "100.00"
}
}
}
}
/stoprecurringcharge.json
Cancel
Cancel an active recurring payment.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ecstoprecurring |
ecstoprecurring |
recur_id |
integer | Yes | Recurring payment ID | 12345 |
reason |
string | No | Reason for cancellation | Customer requested |
Example Request
{
"charge_type": "ecstoprecurring",
"gateway_id": 456,
"recur_id": 12345,
"reason": "Customer requested cancellation"
}
/updaterecurringcharge.json
Update
Update the amount or schedule of an active recurring payment.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ecupdaterecurring |
ecupdaterecurring |
recur_id |
integer | Yes | Recurring payment ID to update | 12345 |
amount |
decimal | No | New amount for future payments | 125.00 |
schedule |
object | No | Any schedule fields you want to change — same shape as setup, only include the fields you're changing | See setup example |
Example Request
{
"charge_type": "ecupdaterecurring",
"gateway_id": 456,
"recur_id": 12345,
"amount": "125.00"
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 102,
"message": {
"recurring": {
"success": true,
"recur_id": 12345,
"amount": "125.00"
}
}
}
}
/enablerecurringcharge.json
Enable
Re-enable a recurring payment that was previously paused with ecdisablerecurring.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ecenablerecurring |
ecenablerecurring |
recur_id |
integer | Yes | Recurring payment ID to enable | 12345 |
Example Request
{
"charge_type": "ecenablerecurring",
"gateway_id": 456,
"recur_id": 12345
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 102,
"message": {
"recurring": {
"success": true,
"recur_id": 12345,
"enabled": 1
}
}
}
}
/disablerecurringcharge.json
Disable
Pause a recurring payment without cancelling it — it can be re-enabled later with ecenablerecurring. If you want to cancel permanently instead, use ecstoprecurring.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
charge_type |
string | Yes | Use ecdisablerecurring |
ecdisablerecurring |
recur_id |
integer | Yes | Recurring payment ID to pause | 12345 |
Example Request
{
"charge_type": "ecdisablerecurring",
"gateway_id": 456,
"recur_id": 12345
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 102,
"message": {
"recurring": {
"success": true,
"recur_id": 12345,
"enabled": 0
}
}
}
}
Webhooks
Get notified in real time when a payment settles or is returned
How It Works
If you're a reseller, GoodFunds Gateway can push payment status events to your own endpoint automatically. This is configured per salescode: when a webhook URL and token are attached to one of your salescodes, every client onboarded under that salescode has their ACH transaction events forwarded to you — you don't need to configure anything per-client.
Ask your account manager to attach a webhook URL to your salescode to get started; this isn't currently self-service via the API.
What Triggers a Webhook
Two event types are sent:
| Topic | When it fires |
|---|---|
transaction.settled |
An ACH debit/credit has cleared successfully |
transaction.returned |
An ACH transaction was returned by the bank (NSF, closed account, unauthorized, etc.) |
Only these two events exist today — this is not a general-purpose event feed for every API action.
Payload Format
Each event is sent as its own individual HTTP POST (not batched):
{
"topic": "transaction.returned",
"charge_id": 27834,
"return_code": "R01",
"return_reason": "Insufficient Funds"
}
return_code and return_reason are null for transaction.settled events. charge_id corresponds to the id you'll see in GET /charges.json / GET /charge/{id}.json — use it to look up full transaction details if you need more than these four fields.
Common ACH Return Codes
| Code | Reason |
|---|---|
R01 |
Insufficient Funds |
R02 |
Account Closed |
R03 |
No Account / Unable to Locate Account |
R04 |
Invalid Account Number |
R05 |
Unauthorized Debit to Consumer Account |
R07 |
Authorization Revoked by Customer |
R08 |
Payment Stopped |
R09 |
Uncollected Funds |
R10 |
Customer Advises Not Authorized |
R16 |
Account Frozen |
R20 |
Non-Transaction Account |
R29 |
Corporate Customer Advises Not Authorized |
Authentication
Every webhook request includes these headers:
| Header | Description |
|---|---|
X-Webhook-Signature |
HMAC-SHA256 signature of the raw request body, using your webhook token |
X-Webhook-Timestamp |
Unix timestamp the webhook was sent — check this is within 5 minutes of your own clock to guard against replay |
X-Client-ID |
Your salescode, not a numeric client ID — despite the header name, this identifies which salescode's subscription the event came from |
X-Webhook-Version |
Currently 2.0 |
Verify like this (same pattern as the RDC webhooks guide):
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(401);
die(json_encode(['error' => 'Invalid timestamp']));
}
$token = 'your-webhook-token-here';
$expected = hash_hmac('sha256', $payload, $token);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
die(json_encode(['error' => 'Invalid signature']));
}
$event = json_decode($payload, true);
// $event['topic'], $event['charge_id'], $event['return_code'], $event['return_reason']
http_response_code(200);
echo json_encode(['success' => true]);
Responding
Respond with a 2xx status to acknowledge. Anything else is treated as a delivery failure and retried.
Retry Behavior
Failed deliveries are retried automatically on our regular delivery schedule, up to 3 attempts total. After the 3rd failed attempt, the event is marked failed and won't be retried further — if you need it resent, contact support with the charge_id and topic.
Vendors
Manage vendor information for disbursements
/vendor.json
Required
Create a new vendor record for ACH disbursements.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
internal_id |
string | Yes | Your unique vendor identifier | VENDOR-001 |
company_name |
string | Yes | Legal business name | ABC Supplies Inc. |
tax_id |
string | No | Tax ID / EIN number | 12-3456789 |
email |
string | No | Vendor email address | billing@abcsupplies.com |
phone |
string | No | Vendor phone number | 555-123-4567 |
status |
string | No | active or inactive | active |
address_1 |
string | No | Street address | 123 Business Road |
address_2 |
string | No | Apt/suite/unit | Suite 200 |
city |
string | No | City | Anywhere |
state |
string | No | State / province | CA |
postal_code |
string | No | ZIP / postal code | 90210 |
country |
string | No | Country code or name — defaults to US if omitted |
USA |
contact_name |
string | No | Name of the individual contact at the vendor, separate from the company itself | John Smith |
contact_email |
string | No | Email address of the individual contact | john@abcsupplies.com |
contact_phone |
string | No | Phone number of the individual contact | 555-123-4568 |
payment_terms |
string | No | Payment terms code — defaults to NET30 if omitted |
NET30 |
Example Request
{
"internal_id": "VENDOR-001",
"company_name": "ABC Supplies Inc.",
"tax_id": "12-3456789",
"email": "billing@abcsupplies.com",
"phone": "555-123-4567",
"address_1": "123 Business Road",
"address_2": "Suite 200",
"city": "Anywhere",
"state": "CA",
"postal_code": "90210",
"country": "USA",
"contact_name": "John Smith",
"contact_email": "john@abcsupplies.com",
"contact_phone": "555-123-4568",
"payment_terms": "NET30",
"status": "active"
}
/vendors.json
Optional
List all vendors with optional filters.
Query Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
internal_id |
string | Filter by internal ID | VENDOR-001 |
company_name |
string | Filter by company name (partial match) | ABC Supplies |
email |
string | Filter by email | @abcsupplies.com |
status |
string | active, inactive, suspended | active |
/vendor.json
Optional
Retrieve a single vendor. Requires at least one lookup parameter below.
Query Parameters
At least one of the following is required:
| Parameter | Type | Description | Example |
|---|---|---|---|
id |
integer | Vendor ID | 1 |
internal_id |
string | Your internal vendor identifier | VENDOR-001 |
email |
string | Vendor email | billing@abcsupplies.com |
tax_id |
string | Vendor tax ID / EIN | 12-3456789 |
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/vendor.json?internal_id=VENDOR-001" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 707,
"message": {
"vendor": {
"id": 1,
"internal_id": "VENDOR-001",
"company_name": "ABC Supplies Inc.",
"status": "active"
}
}
}
}
If no vendor matches, you'll get a 404 with errorCode: 1000.
/vendor.json
Update
Update an existing vendor. Requires id or internal_id to identify the vendor; include any other fields from vendor creation that you want to change.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
id or internal_id |
integer / string | Yes | Identifies which vendor to update | VENDOR-001 |
| any vendor field | — | No | Only the fields you include are changed — see the vendor creation parameter table for the full field list | email, status, etc. |
Example Request
{
"internal_id": "VENDOR-001",
"email": "newbilling@abcsupplies.com",
"status": "inactive"
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 701,
"message": "Vendor Updated"
}
}
/vendor.json
Delete
Delete a vendor record. Requires id or internal_id.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
id or internal_id |
integer / string | Yes | Identifies which vendor to delete | VENDOR-001 |
Example Request
curl -X DELETE "https://demo.goodfundsgateway.com/api/vendor.json?internal_id=VENDOR-001" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 702,
"message": "Vendor Deleted"
}
}
Disbursements
Process vendor payments via ACH credit
/disbursement.json
Required
Create a disbursement (vendor payment) via ACH credit.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
vendor_id |
integer | No | Vendor ID (required if no internal_id) | 1 |
vendor_internal_id |
string | No | Vendor internal ID (required if no vendor_id) | VENDOR-001 |
payment_method_id |
integer | Yes | Vendor eCheck payment method ID | 5 |
amount |
decimal | Yes | Payment amount | 1500.00 |
currency |
string | No | 3-letter currency code — defaults to USD |
USD |
gateway_id |
integer | No | ACH gateway to disburse through — defaults to your account's default ACH gateway if omitted | 456 |
charge_type |
string | No | Defaults to disbursement — you shouldn't need to set this |
disbursement |
internal_id |
string | No | Your own identifier for this disbursement, for later lookup | PO-12345 |
description |
string | No | Payment description | Office supplies - Q4 |
invoice_number |
string | No | Vendor invoice number | INV-2024-001 |
purchase_order |
string | No | Purchase order number | PO-12345 |
memo |
string | No | Internal memo/note, not sent to the vendor | Approved by John |
metadata |
object | No | Arbitrary key/value data to store alongside the disbursement, returned as-is on lookup | {"po_line":"4"} |
scheduled_date |
date | No | Schedule date (YYYY-MM-DD). If omitted, the disbursement processes immediately. | 2026-07-15 |
Example Request
{
"vendor_id": 1,
"payment_method_id": 5,
"amount": "1500.00",
"currency": "USD",
"gateway_id": 456,
"charge_type": "disbursement",
"internal_id": "PO-12345",
"invoice_number": "INV-2024-001",
"purchase_order": "PO-12345",
"description": "Office supplies - Q4",
"memo": "Approved by John",
"scheduled_date": "2026-07-15"
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 700,
"message": {
"disbursement": {
"success": true,
"disbursement_id": 12345,
"transaction_id": "TXN-20260615-ABCDEF",
"status": "pending",
"vendor_id": 1,
"vendor_name": "ABC Supplies Inc.",
"amount": "1500.00"
}
}
}
}
/disbursements.json
Optional
List/search disbursements. Your API credentials automatically scope results to your own account — no client filter needed.
Query Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
vendor_id |
integer | Filter by vendor | 1 |
status |
string | Filter by status | pending |
start_date |
date | Only disbursements created on/after this date (YYYY-MM-DD) | 2026-06-01 |
end_date |
date | Only disbursements created on/before this date (YYYY-MM-DD) | 2026-06-30 |
internal_id |
string | Filter by internal ID (partial match) | PO-12345 |
invoice_number |
string | Filter by invoice number (partial match) | INV-2024 |
limit |
integer | Max results to return — defaults to 50 |
25 |
offset |
integer | Number of results to skip, for pagination — defaults to 0 |
50 |
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/disbursements.json?vendor_id=1&status=pending" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 706,
"message": {
"disbursements": [
{ "disbursement_id": 12345, "vendor_id": 1, "amount": "1500.00", "status": "pending" }
]
}
}
}
If no disbursements exist, you'll get a 404 with errorCode: 1000.
/disbursement/{id}.json
Optional
Retrieve a single disbursement by its ID.
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/disbursement/12345.json" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 707,
"message": {
"disbursement": { "disbursement_id": 12345, "vendor_id": 1, "amount": "1500.00", "status": "pending" }
}
}
}
If the disbursement doesn't exist, you'll get a 404 with errorCode: 1000.
/disbursement/cancel.json
Cancel
Cancel a disbursement. Only succeeds if the disbursement hasn't already been processed — check GET /disbursement/{id}.json first if you're unsure of its current status.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
disbursement_id |
integer | Yes | ID of the disbursement to cancel | 12345 |
Example Request
{
"disbursement_id": 12345
}
Success Response
{
"status": "success",
"successMessage": {
"response_code": 702,
"message": "Disbursement cancelled successfully"
}
}
Transaction Status
Check the status of ACH transactions
/transaction.json
Optional
Check the status of an ACH transaction, including returns and settlements.
Parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
gateway_id |
integer | Yes | Gateway account ID | 456 |
charge_id |
integer | Yes | Charge ID to check | 98765 |
Example Request
curl -X GET "https://demo.goodfundsgateway.com/api/transaction.json/{gateway_id}/{charge_id}" \
-H "svs-api-id: YOUR_API_ID" \
-H "svs-api-key: YOUR_API_KEY"
Success Response
{
"status": "success",
"successMessage": {
"response_code": 707,
"message": {
"transaction": {
"success": true,
"charge_id": 98765,
"trans_id": "TXN-20260615-ABCDEF",
"trans_status": "Returned",
"return_code": "R05",
"return_reason": "Unauthorized debit to consumer account"
}
}
}
}
Common ACH Return Codes
| Return Code | Description | Solution |
|---|---|---|
R01 |
Insufficient Funds | Customer needs to fund account |
R02 |
Account Closed | Customer needs to provide new account |
R03 |
No Account/Unable to Locate | Verify account details |
R04 |
Invalid Account Number | Customer provided wrong account number |
R05 |
Unauthorized Debit | Customer disputes the charge |
R08 |
Payment Stop | Customer placed a stop payment |
R10 |
Customer Advises Not Authorized | Customer disputes authorization |
Error Codes
Real error and success codes returned by the API
status and errorMessage.errorCode in the response body, not just the HTTP status code. The same errorCode can be returned with different HTTP status codes depending on context (this is a known inconsistency in the current API, not something you should rely on) — the codes below are the reliable source of truth.
Error Codes inside errorMessage.errorCode
| Code | Typical HTTP Status | Meaning | Solution |
|---|---|---|---|
1000 |
Varies (400 / 404 / 500) | Generic/catch-all error — by far the most common code, covers "not found," "invalid," and misc. failures across almost every endpoint | Read the message field for the actual detail |
1001 |
401 | Invalid API credentials | Verify your svs-api-id / svs-api-key headers |
1004 |
— | Required fields are missing for this request | Check message for which field |
1010 |
400 | A secure SSL connection is required | Use https://, not http:// |
1011 |
404 | Request body was empty (POST/PUT with no data) | Check your request is sending a JSON body |
1102 |
— | Bank account verification failed (only returned when verifyAccount: 1 was passed on a charge) |
Verify the account/routing number with your customer |
106 |
200 | Transaction declined/failed at the processor — message contains the raw processor response, which varies by gateway |
See the Charges → Responses tab for a worked example |
2 |
— | Charge failed at the gateway | Check message for detail |
3001 |
400 | Gateway ID is required | Include gateway_id in your request |
4001 |
400 | Charge ID is required / invalid | Confirm the charge_id exists on your account |
4002 |
400 | A valid internal_id is required |
Confirm the internal_id matches a stored customer |
4003 |
400 | Transaction could not be found on the gateway | Double check gateway_id and charge_id match |
5004 |
— | Customer information is required | Include a customer object |
5008 |
400 | Invalid payment details — reused for several specific cases (bad routing number, bad card number, missing exp month/year) | Read message for the specific field |
5009 |
— | Invalid amount | Confirm amount is a valid decimal |
5016 |
— | Amount must be greater than 0.00 | — |
5017 |
— | Gateway account is disabled or invalid | Contact support to check gateway status |
5020 |
— | Request/transaction type not supported by this gateway | Check which charge types your gateway supports |
5027 |
— | Credit card number is required | Include creditcard.creditcard_number |
6008 |
400 | A valid payment_method_id is required |
Confirm the payment method exists and belongs to this customer |
Success Codes inside successMessage.response_code
| Code | Meaning |
|---|---|
1 |
Charge/recurring charge processed |
102 |
Recurring charge action processed (update/stop/enable/disable) |
203 |
Merchant info returned (connection/software check) |
700 |
Resource created (payment method, vendor, disbursement) |
701 |
Resource updated |
702 |
Resource deleted / disbursement cancelled |
703 |
Default payment method set/cleared |
706 |
List returned (charges, payment methods, recurrings, disbursements) |
707 |
Single resource returned (charge, payment method, vendor, transaction status) |
errorMessage.errorCode and successMessage.response_code are two different fields on two different response shapes — a response is either "status": "error" with an errorCode, or "status": "success" with a response_code. There is no response_code field inside errorMessage.