-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How should the Balanced API support ACH debits? #3
Comments
Optimistic sounds like it could be open to abuse, +1 for pessimistic. What if there was the concept of a pending balance and an available balance? Debits on ACH initially increment the pending balance and then once cleared, the funds move across to the available balance. Debits would then need some way to show that their funds have not yet cleared but are in a pending state. The create operation would still return a 201. There would also need to be a way to communicate that a Debit has failed which would be similar to how Credits are dealt with. |
I think the optimistic approach will create headaches. General ledgering complications and asynchronous communication are both very hard to understand and implement. Some of the non-obvious limitations of the optimistic approach:
Generally, the main gripe with the optimistic approach is that money should never enter a "working capital" state without any guarantees or risk models. Essentially, what we'd be offering is an unsecured loan. Trying to design for this in the API will be a challenge, and, in my opinion, require too many moving parts. I'm leaning towards +1 for pessimistic. The debit should never be created because there's no actual debit in our system, however, that does not stop another resource creation that essentially monitors the state of the action that was just requested. This makes sense from a resource oriented perspective and is isomorphic to Subbu Allamaraju's RESTful Web Services Cookbook recipe regarding asynchronous tasks. Referencing Chapter 1 Section 10 (How to Use POST for Asynchronous Tasks):
It's important to reflect the state of the system at this point using this new resource: there's a potential for a debit, but it doesn't actually exist. So if the successful completion of this task requires showing the outcome of the task, a debit resource in this case, it follows that there should exist another resource that monitors the state of debit creation - which signfies that money has now entered the system in a "working capital" state by going into the marketplace's escrow balance. For consistency and clarity, I am of the opinion that this monitorable resource CAN NOT be the debit resource. It might involve designing a simple event system or an asynchronous task resource that can operate and support all asynchronous requests for the API Furthermore, I believe that introducing a new balance like @mjallday suggests will have some drawbacks, as it essentially forces marketplaces to update their mental model to account for three balances. There is empirical evidence we've collected that two balances were confusing, adding a 3rd one does not help alleviate this confusion. |
@mahmoudimus, your concerns on optimistic debits are succinct i generally agree. I'm not sure a new resource or system to signify pending debits is a good idea. Given that credits already have a pending state implicitly via the available_at field it would be simple if debits behaved the same way. This lessens the cognitive load on people integrating Balanced. If that is not ideal, then credits should be updated to behave the same way as debits when this change is made. I am positive on the idea of a general system for pending tasks but am cautious due to the additional complexity it may add to the integration process. Asynchronous tasks which create resources may be a more taxing concept to grasp than an existing resource on which the state changes even if it is technically cleaner. On 17/08/2012, at 9:32, Mahmoud Abdelkader notifications@github.com wrote:
|
That sounds like a problem for Balanced and not the marketplace. If Balanced does a poor job approving a marketplace, then theres a ton of other issues to consider as well. @mjallday @mahmoudimus how are the ramifications of an optimistic approach different from a chargeback on a card? Balanced has to pull money back from a marketplace even if the escrow balance is zero. It sounds like there has to be a new resource added to the API no matter what to support ACH debits :'(, which probably means that the debits resource may not have been properly designed and cannot be changed at this point because of breaking changes. What about taking an optimistic approach and adding a ach_rejections (or different name) resource? |
For the record, this issue is discussed thoroughly in The Flow-of Funds Approach to Social Accounting which was published in 1962. Particularly table 1 on page 444 is very useful to understand the issue. |
It's not necessarily marketplace abuse Balanced needs to protect against in this case. With a card there is an instant verification that the card is valid. With an optimistic debit I, as a buyer, could enter in any phony bank account and then you, as the marketplace, will need to either gamble on the account being correct or provide your own system for pending balance until the funds clear. If Balanced makes it pessimistic then we are helping the marketplace by verifying the transfer before clearing the funds. I don't agree there needs to be a new resource for ach debits. Just a way to mark a debit as uncleared. Banks already do this for check deposits with pending and available balances. On 17/08/2012, at 9:59, Matin Tamizi notifications@github.com wrote:
|
@mjallday I re-ask the same question. How is the optimistic approach different from a chargeback process from a marketplace ledger standpoint? Balanced can still provide a method to ensure the debit has completed. The marketplace can decide whether or not to proceed with fulfillment until after the verification. @mahmoudimus pulling out the big guns :-). You're right that it's a standard established process, but it doesn't mean that we can't do it better. For example, businesses previously had to fax in signed documents to apply for a merchant account, but we don't even ask for SSN in most cases. @obfuscat3d what do you think? I know you have an immediate need for ACH debits. |
Funds for chargeback come from marketplace owner account, not the escrow balance right?
A card has to be valid to be charged. The hold ensures that the funds exist before the debit is created. Some sort of pre-validation of the bank account before the debit is made may be required. Something similar to 1c auth for cards. This sounds like internals rather than an API issue.
If we provide a way to ensure the funds have cleared then isn't this now a pessimistic approach?
Balanced should err on the side of caution when telling the marketplace if the funds are cleared. It feels like an optimistic approach is saying fulfill, a pessimistic approach is saying wait until they clear. |
Here's what I have so far:
How about we create a new resource?
There is a risk that Regardless, I agree that the operation should be pessimistic. |
|
What other name do you suggest? Keep in mind that this operation is not funding source independent. It's entirely unique to bank accounts. |
I'd like to see both pending and cleared. I don't like the optimistic approach of conflating them (pretending pending are in fact cleared), and I wouldn't be satisfied with the pessimistic approach if it means I can't see pending debits marked as such. |
@matin - |
We're solving two problems in the same discussion:
Let's solve one problem at a time. I created the ach branch to isolate the conversation to the first issue first. Take a look at the interface for just debits. |
I think the Optimistic method could potentially create too many headaches, especially for a startup like us. We're much more risk-averse when it comes to handling transactions, we'd prefer to make sure the money is cleared from the buyer before giving it to the supplier, because: 1.) We're very averse to chargebacks with regards to our reputation among suppliers |
@whit537 @karthik7 what do you think about this interface? https://github.com/balanced/balanced-api/blob/ach/endpoints.md |
That looks pretty useful, Matin. So, once the initial debit request is On Wed, Aug 22, 2012 at 11:21 AM, Matin Tamizi notifications@github.comwrote:
|
That's an easy way to start until we define how webhooks and events should work in the API. |
Lot of engineering speak going on... What's the current pattern for refunds? As in, how quickly would a buyer request a refund? What is the volume of refunds being processed on e-commerce sites. I ask because everyone is talking about abuse and when is the appropriate time to issue a refund. |
@matin Looks good to me. |
When are you anticipating this going live? |
@femgineer non-engineer speak on #2 |
Optimistic is deceiving to marketplaces and requires them to write more code to handle "weird" cases ... eww :). In my opinion, pessimistic seems to be the way to go. @matin +1 on the resource design. I don't like Either way, good job guys .. this is an awesome feature and can't wait to use it :). |
@khussein it appears everyone agrees on optimistic vs. pessimistic. I'm really happy this discussion is now public.
What about telling a customer when money should have become available in their account?
How would this look? |
In my case, that would be more helpful. But more information about when the status did get updated is always welcome too.
khussein@210464fb7fc7270827acdfdf33718c8b7b0ac737 I can PR it if you would like me to. |
Jumping in on the discussion a bit late... definitely 👍 on the pessimistic approach. As for the actual API, I'd like to think of the solution at a very abstract level by starting with the problem. At that abstract level, there's a buyer, a seller, and a flow of money between the two. A buyer has various funding sources: bank accounts, credit cards, debit cards, etc. Jumping into a bit more of a concrete: a HOLD on a buyer's funding source represents the authorization of funds from that funding source (funds are available). I think that to an API consumer, it should not have to matter whether the HOLD is placed against one funding source or another. Therefore, I would rather implement a state-machine like approach. This approach would be very similar to the one that had been suggested by @mahmoudimus here. The difference, however, is that every transaction would start with a HOLD. What is a HOLD? It is a guarantee that the funds are available for capture. In the case of using a credit card as a funding source, the HOLD is instant, and returns a In the case of a bank account used as a funding source, the HOLD is not instant. In this case the response is a From this simple place, it is possible to later implement various mechanisms for either notifying the marketplace of updates to the state of HOLDs (push notifications) allowing them to be captured or allow the marketplace to poll balanced for updates (this would be the default initially). Thoughts? |
@alexnotov I see where you're going, but I think the concept of a HOLD is hard to grasp for ACH debits. The reason why is that on a credit card, a hold can expire, which is why we have an On an ACH debit, in order to guarantee those funds, we actually NEED to debit those funds, so money has functionally and theoretically entered the system. To reflect this, we must increment the escrow balance of the marketplace. Essentially, what happens is that the HOLD is now automatically transformed into a DEBIT since the money is available. Another side effect is that a HOLD can no longer expire. Does my explanation make sense? |
@matin the @khussein - your pull request essentially suggests something that can be generalized in a task related resource (looks like some generic state on whether the asynchronous task succeeded or failed and what the resulting URI of the created resource is). @whit537 querying for pending debits should be easy, because you would just issue a GET to the URI that comes back from creating that asynchronous task. This GET request should allow you to fetch the state of the asynchronous task. Does this satisfy your requirements? |
Ok I understand. Then yea, 👍 on 'ach_debit' that may maintain a queryable state: 'pending', 'captured', etc. Initially put the querying in the hands of the developer via poll, and then implement optional push/pub-sub mechanisms to allow 'ach_debit' callers to monitor updates to the state of initiated debits. We are currently running a task every 24 hours to capture available holds and disburse captured funds to merchants and to ourselves. I don't see why we would not do the same with checking the state of an 'ach_debit' and disbursing funds when they are available (especially since an 'ach_debit' that is captured is disbursable). On Aug 23, 2012, at 12:07 AM, Mahmoud Abdelkader notifications@github.com wrote:
|
@alexnotov @mahmoudimus +1 for the pessimistic approach. Also I know that most banks have limited overdraft fees and the pessimistic approach suggested would avoid them from being triggered, but is there still a possibility that it could happen? For example, what is if there is a large hold that is debited from a bank, and then a large refund is requested moments later? I know I'm being a stickler about the refund scenario here, but its because I'm anticipating merchants using ACH for large transactions to avoid invoking the transaction fee. |
@mahmoudimus wrote:
I never ruled out the task resource approach, but I wanted to bring up another option. The task resource approach seems to push more work to the client even if it is technically the standard RESTful method. As an exercise, you could write (or at least think about) the docs and client code to support either approach. If I think about it that way, |
+1 for pessimistic They both feel the most intuitive and simple without misleading about state... :) |
@khussein @kieftrav I'll dig into the NACHA specs with @mahmoudimus, so we can be 100% sure about the interaction between us and the ODFI, especially when it comes to receiving confirmations, rejections, and rejection reasons. |
I updated the root description to strike out the optimistic approach as an option |
To me, providing the One additional important feature that I think has only been mentioned by @alexnotov briefly is callbacks for success or failure. If a payment fails, we should be able to specify a URL that will receive a POST with as much info as possible to trigger our own internal alarms. |
@spenczar 🌠 👍 |
From @mahmoudimus:
I think the benefits of consistency and clarity are very important. So I can go either way on task resource pattern vs |
@alexnotov @spenczar @matin For the record, I'm not opposed to having an
Thoughts? |
@mahmoudimus let's go through #37 first. I want to make sure we've outlined all the constraints. |
It seems to me that the main difference is just that you'd like to keep the status as its own, separate task resource, keeping all debits at the same URI, rather than splitting debits into two types. Is that correct? I've really got no problem with that - it makes sense to me. |
@mahmoudimus that's an interesting approach and nice way to make it work in the existing API. I'm interested to see how this will handled by a client lib. Can you write up an example snippet in Ruby and PHP to handle the request for the task resource approach? |
I confirmed that an ACH debit can be confirmed and receive the funds within 1-2 business days (depending on the other party's bank). There is a 60 day dispute window, which act similar to chargebacks. Related to @khussein and @alexnotov point, let me know what you think about #42. I didn't include any timestamp for now. We can add it in if it's explicitly requested. I have for the status: |
I should say this differently. Within 1-2 business days of creating the ACH debit, Balanced will update the status. If the debit clears, the funds will become available. |
what about using |
use status instead of timestamp as discussed in #3
defined milestones and timeline at https://github.com/balanced/balanced-api/issues/milestones |
Spec defined at: https://github.com/balanced/balanced-api/tree/ach Still need to spec out request and response formats (#101) and error codes (#80), but work has already begun to implement the spec. |
changing rev1 json schemas to use jsonapi.org format
Creating an authorization hold on a card is a synchronous operation. Capturing an authorization to charge a card is not a synchronous operation, but the capture is guaranteed given a valid hold. That lends itself well to a REST API.
ACH credits are neither synchronous or guaranteed. Balanced treats credits optimistically (assume it will be successful). It notifies the marketplace if there's a rejection and retries every time the bank account information is updated. The ACH can make bank deposits next business day, but it takes four business days to let the originator know if it was successful or rejected.
There's two ways to treat ACH debits (UPDATE: going to use pessimistic approach. Read comments below for reasoning.):
Optimistic
Just like charging a card, the marketplace will receive the money in their escrow balance immediately and can credit the money out to a merchant. Since the operation is not guaranteed, the money may get pulled back. If there's a rejection, Balanced can pull the money back just a chargeback on a card, but ACH debit rejection are much more likely than a chargeback. This will complicate the marketplaces ledger since they'll have funds that may get pulled back, and they won't know for four business days.Pessimistic
Don't give the money to the marketplace until after the debit is reported to be successful by the bank. Debits are next business day, but this depends on the originating bank, which can take four business days. That complicates the API. The debit isn't technically created, so Balanced can't return a 201. Balanced can notify the marketplace after the fact, but what does that actually look like in the API?
UPDATE: Isolating the conversation to just ACH debits and revisting how it work in the Balanced API. Take a look at the ach branch
The text was updated successfully, but these errors were encountered: