Developers

Accept ACH debits and credits through the PaidYET API.

Embank merchants and partners originate ACH through the PaidYET REST API. One request debits a verified bank account. The same transaction can later be refunded, which sends an ACH credit back to the account holder. A sandbox returns accepted and declined outcomes on demand so your handling can be built before anything is originated in production.

Production
api.paidyet.com/v3

HTTPS only. All paths below are relative to this base.

Sandbox
api.sandbox-paidyet.com/v3

Same paths, mock processor, separate credentials.

Authentication
Bearer token

Exchange your merchant API key at POST /login for a short-lived JWT.

Rate limit
75 / minute

7,000 calls per day. Contact Embank if your volume needs more.

Before you start

Three things you need

ACH is enabled per merchant account. Once Embank has approved the merchant for ACH origination, the integration itself is a small surface: one key, one token exchange, one endpoint.

01

An ACH-approved merchant account

Embank onboards each merchant and enables ACH on the account. Partners integrating a portfolio of merchants go through the partner program, and each merchant still gets its own account.

02

A merchant API key

Generated in the PaidYET dashboard under Settings → Developers. Keys are scoped to one merchant. Partners hold one key per merchant and send the matching key with each request. Rotate keys individually.

03

Sandbox credentials

A separate sandbox account with its own key. Ask Embank and we will arrange it, or email PaidYET support with the subject line “Sandbox Account Request.” Point your integration at the sandbox base URL until you are ready to go live.

Partner-level API keys that acted across many merchants with a merchant UUID have been deprecated by PaidYET. Existing partner keys continue to work, but new integrations should use merchant-level keys.

Conventions

Requests and responses

ItemConvention
TransportHTTPS to the production or sandbox base URL. JSON request and response bodies with Content-Type: application/json.
AuthenticationPOST your API key to /login. The response carries a JWT and its expiry as a Unix timestamp. Send it as Authorization: Bearer <token> on every other call, and log in again when it expires. A 400 with “Expired token” or a 401 means the token needs refreshing.
AmountsDecimal dollars, not cents. 125.00 is one hundred twenty-five dollars. Zero or greater. Do not include surcharge in the amount.
Payment methodExactly one of check, credit_card or emv_data per transaction. ACH always uses check.
IdentifiersPaidYET assigns the numeric transaction id. You may attach your own external_id, order_id and invoice for reconciliation. The API does not offer an idempotency key, so record the returned id before retrying a request that timed out.
TimestampsYYYY-MM-DD HH:MM:SS in UTC on every date_created and search parameter.
EnvelopeEvery response has messages (notice, success, warning and error arrays, each item with a code and content) and payload (type, items, count, pages, page, per_page). A created transaction is payload.items[0].
OutcomesHTTP 400 and 401 are authentication problems. Everything else, including declines, comes back as 200 with the result in the transaction’s status, result and error fields.
POST/login
{
  "key": "YOUR_MERCHANT_API_KEY"
}

// 200 OK
{
  "status": "OK",
  "result": {
    "status": "success",
    "token": "eyJ0eXAiOiJKV1QiLCJh...",
    "exp": "1761700000",
    "message": "Logged in successfully."
  }
}
POST/transaction  ACH debit
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh...

{
  "amount": 1850.00,
  "check": {
    "accountholder": "Dana Ruiz",
    "account": "000123456789",
    "routing": "021000021"
  },
  "email": "[email protected]",
  "invoice": "MAR-RENT-4B",
  "external_id": "rent-4b-2026-03",
  "send_receipt": true
}

// 200 OK (payload.items[0])
{
  "id": 1234567890,
  "amount": 1850.00,
  "type": "sale",
  "status": "approved",
  "result": "OK",
  "date_created": "2026-03-01 15:04:11"
}
Endpoints used for ACH
MethodPathPurpose
POST/loginExchange a merchant API key for a bearer token.
POST/tokenTokenize a bank account for reuse. Returns a token in place of account and routing numbers.
POST/transactionCreate an ACH debit against a bank account or a stored token.
GET/transaction/{id}Retrieve a transaction, including its current ACH status.
GET/transaction/searchList transactions by date, date range, amount, name, status or type.
PUT/transaction/{id}Void a debit that has not yet been sent for origination.
POST/transaction/{id}Refund a funded debit. This originates the ACH credit back to the account holder.

The same API also processes cards, terminals and hosted checkout. Those endpoints and fields are documented in the PaidYET reference and are omitted here. Field names and limits on this page are taken from that reference; where the two differ, the reference governs.

Debits

Collecting from a bank account

An ACH debit is a POST /transaction with an amount and a check object. Supply the account holder’s name with the account and routing numbers, or supply a token from a previous tokenization. A successful request returns status: "approved", which means the debit has been accepted into PaidYET’s system as Processed. It has not yet been originated to the ACH network, and it can still be voided.

The request does not carry an SEC code or an authorization record. Obtaining authorization from the account holder, in the form the Nacha rules require for your entry class, and retaining it for the required period remains your obligation as the originator. See Nacha compliance for what that record must contain.

The check object
FieldDescription
accountholderName of the person or business on the account. Required.
accountBank account number as a string. Required unless a token is supplied.
routingNine-digit ABA routing number as a string. Required unless a token is supplied.
tokenToken from POST /token. Replaces account and routing.
external_idYour own identifier for the account. Optional.
Useful transaction fields
FieldDescription
amountDecimal dollars. Required.
external_idYour reference for the transaction. Searchable from your side; not generated by PaidYET.
invoiceInvoice number shown on the receipt and in the dashboard.
order_idOrder reference.
emailAccount holder’s email. With send_receipt: true, PaidYET emails a receipt.
customerCustomer object with name and contact media. Links the transaction to a stored customer record.
billing_addressStreet, city, two-letter state and ZIP.
commentsFree text stored with the transaction.

Tokenize once, debit repeatedly

For recurring collection, tokenize the account first with POST /token and store the returned token instead of the account and routing numbers. Check tokens hold only the account and routing numbers, and those numbers cannot be read back after tokenization. Tokens are not tied to a single merchant, so a partner can reuse one across the merchants it manages. Attach an external_id at creation if you want to look the token up by your own reference later.

The schedule and recurring options on the transaction endpoint are documented for card payments only. For recurring ACH, schedule the debits on your side and create each one against the stored token.

POST/token
{
  "accountholder": "Dana Ruiz",
  "account": "000123456789",
  "routing": "021000021",
  "external_id": "unit4b"
}

// 200 OK (payload.items[0])
{
  "token": "abcd1234",
  "accountholder": "Dana Ruiz",
  "external_id": "unit4b"
}

// later: debit the token
{
  "amount": 1850.00,
  "check": { "token": "abcd1234" },
  "external_id": "rent-4b-2026-04"
}
Credits

Sending funds back to the account holder

An ACH credit is issued as a refund against a prior debit. Post to the original transaction’s id with type: "refund" and the amount. The credit is originated to the same account the debit was drawn on. For ACH, the refund amount cannot exceed the original debit, and a transaction can only be refunded once it has reached Funded. Until then, a void is the only reversal available, and only while the debit is still Processed.

Credits that are not tied to a prior debit, such as payouts or disbursements, are not available through this endpoint. Contact Embank if your use case needs them.

POST/transaction/1234567890  refund (ACH credit)
{
  "type": "refund",
  "amount": 1850.00
}

// 200 OK: the refund is returned as its own
// transaction with type "refund"
PUT/transaction/1234567890  void
{
  "type": "void"
}

// Only while the debit is Processed. Once it
// has been downloaded for origination the
// void is refused; wait for Funded and refund.
Which reversal applies
Debit statusVoidRefundNote
ProcessedYesNoNothing has left PaidYET. A void leaves no trace on the account holder’s statement.
DownloadedNoNoIn transit to the back office. Wait.
OriginatedNoNoPresented to the Federal Reserve. Wait for settlement.
FundedNoYesRefund up to the original amount. Both the debit and the credit appear on the statement.
Any returnNoNoFunds never settled or have already been pulled back. Handle per the return category below.
Lifecycle

What happens after the debit is accepted

The API answers with approved or declined at submission. The ACH status on the transaction then advances as the entry moves through origination, settlement and the return window. Retrieve the transaction to read it.

Fig. 07 ACH transaction status flow
ACH transaction status flow An accepted debit is Processed, then Downloaded to the back office, then Originated to the Federal Reserve, then Funded to the merchant. A debit that fails back-office processing becomes a BO Exception. A debit returned by the receiving bank moves to one of the return statuses, before or after funding. A funded debit that is refunded becomes Refunded. ACH STATUS ProcessedDownloaded OriginatedFunded Accepted and authenticated.Void is still possible. Pulled into the back office.Temporary status. Validated and presentedto the Federal Reserve. Paid to the merchant.Refund is now possible. BO ExceptionReturnedRefunded Failed back-office checks.Carries an exception code. Invalid, NSF, Chargeback orother. Also possible after Funded. Credit originated backto the account holder. RETURNS AFTER FUNDING CARRY THE IsLateReturn ATTRIBUTE
ACH status
ProcessedAccepted and authenticated. Void is still possible.
DownloadedPulled into the back office. Temporary status.
OriginatedValidated and presented to the Federal Reserve.
FundedPaid to the merchant. Refund is now possible.
From DownloadedBO ExceptionFailed back-office checks. Carries an exception code.
From Originated or FundedReturnedInvalid, NSF, Chargeback or other. Returns after funding carry the IsLateReturn attribute.
From FundedRefundedCredit originated back to the account holder.

Status names are PaidYET’s. Back-office exception codes are listed on the B.O. exception codes page. The Nacha return reason codes behind each return category are on the return code reference.

ACH statuses and what to build for each
StatusMeaningHandling to build
ProcessedNewly accepted and authenticated.Record the transaction id. Offer cancellation as a void while this status holds.
DownloadedDownloaded to the back-office system. Temporary.Nothing. Do not attempt a void or refund.
BO ExceptionFailed back-office processing before origination.Alert an operator. Correct the account details or authorization and submit a new debit. Codes are on the exception codes page.
OriginatedValidated and presented to the Federal Reserve.Treat as pending. Funds are not yet yours.
FundedPaid to the merchant.Mark the receivable paid. Refunds become available.
RefundedCredited back to the consumer.Reverse the receivable and keep the refund transaction id with the original.
Invalid ReturnReturned for invalid account information.Stop debiting the account. Re-collect and re-verify account details before trying again.
NSF ReturnReturned for non-sufficient funds.Notify the account holder. Re-present only within the limits the Nacha rules allow, at most two more times.
Chargeback ReturnReturned as unauthorized or authorization revoked.Block further debits to the account. Pull up the authorization record; do not re-present.
ReturnedAny other return type.Read the reason and route it by category. See the return code reference.
IsLateReturnAttribute, not a status. The debit was Funded and then returned.Reverse the payment you already recognized. Watch the rate: late unauthorized returns count toward the Nacha thresholds.
Tracking

Reading status and reconciling

ACH settles and returns over days, not seconds, so status is read rather than pushed. Retrieve a single transaction by id, or search a date or date range to sweep everything that changed. A daily sweep of the previous business day’s debits, plus a second sweep at the end of the standard return window, catches funding and returns without polling every record.

Webhooks are available for batch events: when a batch is created, closed to the settlement platform, or fails to close. They are configured in the PaidYET dashboard under Account → Tools → Access Points. A per-transaction event for ACH returns is not published, so build the sweep regardless.

GET/transaction/search?datetime_start=...&datetime_end=...
// At least one parameter is required.
// date=YYYY-MM-DD  or  datetime_start + datetime_end
// amount, first_name, last_name
// status=approved|declined|scheduled
// type=sale,refund,void

// 200 OK
{
  "payload": {
    "type": "transaction",
    "count": 2,
    "items": [
      { "id": 1234567890, "amount": 1850.00,
        "external_id": "rent-4b-2026-03", ... },
      { "id": 1234567891, "amount": 425.00,
        "external_id": "rent-2a-2026-03", ... }
    ]
  }
}
POSTyour webhook endpoint  batch.closed
{
  "event": "batch.closed",
  "data": [
    {
      "id": 22642,
      "status": "closed",
      "amount": "2275.00",
      "merchant": { "name": "Acme Property Mgmt" },
      "number_transactions": 2,
      "date_opened": "2026-03-01 13:07:39",
      "date_closed": "2026-03-02 16:20:54"
    }
  ]
}

// Other events: batch.created, batch.failed

Transaction-level response codes are reported in the transaction’s error field as a code and message. The format is not guaranteed, so match on the code and log the message rather than parsing the string.

Sandbox

Test accounts

The sandbox runs every request through a mock processor and originates nothing. Use the account and routing numbers below to exercise the accepted and declined paths at submission.

Sandbox ACH test accounts
Account numberRouting numberOutcomeDecline codeHandling to build
111111999999992Accepted—Normal path. Store the id and show the debit as pending.
100999999992Declined100Decline at submission. Surface the message and let the user correct and resubmit.
200999999992Declined200As above, with a different code, to prove you branch on the code.
300999999992Declined300As above.
Any otherAnyError—Unrecognized test account. Treat as a validation failure.

The sandbox does not advance a debit through Originated, Funded or any return status, and it does not send real receipts. Build and unit-test the lifecycle handling above against the status table, then confirm it against the first live transactions with Embank’s support team. Sandbox and production keys are not interchangeable.

Contact

Request credentials

Tell us what you are integrating and we will arrange sandbox access, confirm the merchant’s ACH approval, and put you in contact with the team supporting the API.