GoodFunds Gateway API

Secure, RESTful payment processing API

Production Ready v1.6.0 Last Updated: 2026

Quick Start

Make your first API call in seconds:

JSON Request
{
  "charge_type": "ccauthcapture",
  "creditcard": {
    "creditcard_number": "4111111111111111",
    "creditcard_exp_month": 12,
    "creditcard_exp_year": 2025,
    "creditcard_cvv": 123
  },
  "amount": "100.00"
}

Base URLs

Sandbox https://demo.goodfundsgateway.com/api/ Test Transactions
Production 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 Access

Authentication

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
Security Warning: Never expose your API credentials in client-side code or public repositories. Always use server-side code to make API calls.

Authentication Error Example

If authentication fails, you'll receive a 401 error:

JSON Response
{
  "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

Important: Jack Henry requires specific test accounts. Use only these 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/2028 or 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) or 1234 (Amex)
  • Invalid CVV: 999 - Will trigger CVV mismatch

Payment Methods

Securely store and manage payment methods

POST /paymentmethod.json Required

Store a credit card or eCheck for future use. Credit cards are tokenized for security.

Content-Type application/json
Authentication Required
Rate Limit 100 requests/minute

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

JSON Request
{
  "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
}
JSON Request
{
  "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
}
JSON Request
{
  "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

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 700,
    "message": {
      "payment_method": {
        "payment_method_id": 12345,
        "card_type": "VISA",
        "last_four": "1111"
      }
    }
  }
}
GET /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
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"
GET /paymentmethod/{id}.json Optional

Retrieve a single payment method by its ID.

Example Request

cURL
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

200 OK Success
JSON 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.

POST /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
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

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 702,
    "message": "Payment Method Deleted"
  }
}
POST /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

JSON Request
{
  "customer_id": 123
}

Success Response

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 703,
    "message": "Default Payment Methods Cleared"
  }
}

Charges

Process credit card and eCheck transactions

POST /charge.json Required

Process a single transaction. Supports credit card sales, authorizations, and eCheck processing.

Content-Type application/json
Authentication Required
Rate Limit 100 requests/minute

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.

Why this exists: Most gateways won't let you capture more than you authorized. That's a problem for merchants who don't know the exact final amount at auth time — the classic case is a shipping company that authorizes an estimated amount, then needs to capture slightly more once the package is actually weighed. An authorization buffer adds a little headroom to the authorized amount up front (as a flat percentage, or a tiered flat amount based on the order size) so the later capture has room to come in higher without a second authorization.

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

JSON Request
{
  "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"
}
JSON Request
{
  "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"
}
JSON Request
{
  "charge_type": "ccprocesspreauthorize",
  "gateway_id": 123,
  "amount": "100.00",
  "level2": {
    "invoice_number": "INV-001"
  }
}
JSON Request
{
  "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"
}
JSON Request
{
  "charge_type": "ccauthcapture",
  "gateway_id": 123,
  "payment_method_id": 12345,
  "amount": "50.00",
  "creditcard": {
    "creditcard_cvv": 123
  },
  "level2": {
    "invoice_number": "INV-002"
  }
}

Responses

200 OK Success
JSON Response
{
  "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"
        }
      }
    }
  }
}
200 OK Declined

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.

JSON Response
{
  "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.

400 Bad Request Validation Error
JSON Response
{
  "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).

GET /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.

Content-Type application/json
Authentication Required

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

200 OK Success
JSON 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.

GET /charge/{id}.json Optional

Retrieve one charge by its ID.

Example Request

cURL
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

200 OK Success
JSON 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

POST /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

JSON Request
{
  "charge_type": "ccrefund",
  "gateway_id": 123,
  "charge_id": 98765,
  "amount": "50.00"
}

Success Response

200 OK Success
JSON 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

POST /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

JSON Request
{
  "charge_type": "ccvoid",
  "gateway_id": 123,
  "charge_id": 98765
}

Success Response

200 OK Success
JSON 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

Note: Recurring payments are only available for ACH processing with specific gateways. Please contact support to enable recurring payments for your account.
POST /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

JSON 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

200 OK Success
JSON 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"
      }
    }
  }
}
POST /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

JSON Request
{
  "charge_type": "ecstoprecurring",
  "gateway_id": 456,
  "recur_id": 12345,
  "reason": "Customer requested cancellation"
}
POST /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

JSON Request
{
  "charge_type": "ecupdaterecurring",
  "gateway_id": 456,
  "recur_id": 12345,
  "amount": "125.00"
}

Success Response

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 102,
    "message": {
      "recurring": {
        "success": true,
        "recur_id": 12345,
        "amount": "125.00"
      }
    }
  }
}
POST /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

JSON Request
{
  "charge_type": "ecenablerecurring",
  "gateway_id": 456,
  "recur_id": 12345
}

Success Response

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 102,
    "message": {
      "recurring": {
        "success": true,
        "recur_id": 12345,
        "enabled": 1
      }
    }
  }
}
POST /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

JSON Request
{
  "charge_type": "ecdisablerecurring",
  "gateway_id": 456,
  "recur_id": 12345
}

Success Response

200 OK Success
JSON 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

Note: This is separate from the RDC Check Scanning Webhooks, which cover check image processing. This section covers payment/ACH status webhooks for resellers.

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

JSON Payload
{
  "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
<?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.

Unlike the RDC webhooks guide's fixed 1/5/15-minute retry schedule, these retries happen whenever our next scheduled delivery run occurs, not on a fixed per-attempt delay.

Vendors

Manage vendor information for disbursements

POST /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

JSON 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"
}
GET /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
GET /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
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

200 OK Success
JSON 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.

PUT /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

JSON Request
{
  "internal_id": "VENDOR-001",
  "email": "newbilling@abcsupplies.com",
  "status": "inactive"
}

Success Response

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 701,
    "message": "Vendor Updated"
  }
}
DELETE /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
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

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 702,
    "message": "Vendor Deleted"
  }
}

Disbursements

Process vendor payments via ACH credit

POST /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

JSON 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

200 OK Success
JSON 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"
      }
    }
  }
}
GET /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
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

200 OK Success
JSON 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.

GET /disbursement/{id}.json Optional

Retrieve a single disbursement by its ID.

Example Request

cURL
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

200 OK Success
JSON 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.

POST /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

JSON Request
{
  "disbursement_id": 12345
}

Success Response

200 OK Success
JSON Response
{
  "status": "success",
  "successMessage": {
    "response_code": 702,
    "message": "Disbursement cancelled successfully"
  }
}

Transaction Status

Check the status of ACH transactions

GET /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
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

200 OK Success
JSON 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

Always check 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)
Note: 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.