Payout
Consumers are able to "use my balance" through the consumer mobile and my. web interfaces. Bank Account (ACH), Venmo and Paypal cash transfers are facilitated via Hyperwallet API. Architecture for the payout backend is currently hard-forked per instance as detailed below.
New Architecture 12 APR 2023
Meeting with OBRC dev team and PNDLM determined:
Hyperwallet.Webapproach is unnecessarily complicated and unreliable, and will remain active only for SF for now.- Oregon will be revised to simply call Hyperwallet APIs directly and receive syncronous responses.
- PNDLM will design and develop a mechanism for rate limit queueing/handling to be used by Oregon and 3rdFork.
- Customer service will be given an interface to query Hyperwallet transaction status directly against its API.
Webhook Responses
Early determination from this meeting is that webhook returns are not necessary given the notes below; for now the strategy is to not read webhooks for Oregon or 3rdFork. If necessary later, this is an easily reversible decision especially in 3rdFork through addition of a (much simpler) webhook endpoint.
- Button can be exposed to customer service to follow up on any given transaction using the Hyperwallet API directly!
- Destination bank account will not be invalid, because it has already been verified by the consumer using two initial deposits, unless it has been closed, or frozen, or... [insert niche problem here]
- Venmo and Paypal do not "verify" and so money is sent irrevocably to the addresses the user puts in anyway. Tough beans.
- Insufficient funds on Tenant side are caught synchronously; payout is rejected at time of request.
It should also be noted that Jeff the skeptic verified the lack of necessity of these webhooks through queries with the greatest architect of all time, ChatGPT.
Tenant implementations
3rdFork
PNDLM will lift the internal team's re-written Oregon Hyperwallet code into 3rd fork, update to Hyperwallet V4, and to .NET 6. It will utilize the same new simple architecture.
Oregon
OBRC internal team will rewrite Hyperwallet interface code beginning 13 Apr. It will call Hyperwallet API directly, read the synchronous responses and not utilize webhooks. Not much else to say, because it's pretty freakin simple. BIG IMPROVEMENT, GO TEAM!!
San Francisco
At 12 Apr 2023 meeting with OBRC dev team and PNDLM determined through closer analysis that this architecture is unnecessarily heavy and unreliable. Current decision is to leave it in place until future of SF is decided or SF is simply rolled into 3rdFork.
San Francisco backend calls out to Hyperwallet.Web API which then calls out to Hyperwallet API. Hyperwallet returns responses immediately, but this information is discarded. Instead, Hyperwallet.Web waits for a related webhook response from Hyperwallet, and then attempts to return results to SF backend. Must be restarted nightly.
Hyperwallet API
- Manual group testing on 12 Apr demonstrates that the Hyperwallet API is not as bad as previously feared.
- Does not provide a useful testing environment, confirmed by Garen and Evan independently. Mockerwallet will be finished internally to provide a reasonable test apparatus for ongoing Hyperwallet automated tests.
Sample requests and responses below.
Token Types
Tokens are Hyperwallet side IDs / primary keys for various objects.
prg-Program token is used to identify what Tenant in Hyperwallet we are dealing with. These are listed in Hyperwallet dashboard. We specify program token on request; they respond with it back in confirmation. NOTE that these are different depending on the endpoint !! e.g.prg-413c0f85-9c82-4585-8d5e-1ac794a7bbb0is specified on SF Create Userprg-dfd90ad1-c7e6-4976-bd6c-95cdd3208933is specified on SF Create Payment
usr-User token is primary key for Hyperwallet "User". Note that there is one Hyperwallet User per 3rdFork Linked Account, NOT per 3rdFork User! In other words, many Hyperwallet Users to one 3rdFork User. This was decided back in Johann era and seems to work fine enough, so whatever. Recommended to store this directly onLinkedAccountrecord e.g.hyperwallet_usr_token.trm-Transfer Method token is analgous to 3rdFork Linked Account. Store also directly onLinkedAccountrecord e.g.hyperwallet_trm_token.sts-Status Transition token. Maybe kind of useful for querying Hyperwallet about the transition? I'd consider logging these but probably not worth storing them in the database.pmt-Payment token used to uniquely identify a specific payment. Store these directly on the transaction record in the database e.g.hyperwallet_pmt_token.
Request Information
- Host
api.paylution.com - Basic Authentication (no tokens)
- Accept
application/json - Content-type
application/json- If there is no body to send, DO NOT send empty JSON object
{}as it will cause a 400 error. Send a completely empty body instead with noContent-type.
- If there is no body to send, DO NOT send empty JSON object
Create User V3
Hyperwallet Docs: Create a User
3rdFork is permitted to provide its own key for the Hyperwallet User in clientUserId. This should NOT be the 3rdFork User key (as there is one 3rdFork user to many Hyperwallet user, so this will not be unique) but perhaps the 3rdFork Linked Account ID instead. PNDLM recommends to omit (or generate random key if absolutely required) and instead store Hyperwallet's returned usr- token as the key for communication with Hyperwallet about this Hyperwallet user going forward.
// POST /rest/v3/users
{
"clientUserId": "3rdForkLinkedAccountIdGoesHereIfYouWant",
"profileType": "INDIVIDUAL",
"firstName": "John",
"lastName": "Smith",
"dateOfBirth": "1980-01-01",
"email": "john@company.com",
"addressLine1": "123 Main Street",
"city": "New York",
"stateProvince": "NY",
"country": "US",
"postalCode": "10016",
"programToken": "prg-413c0f85-9c82-4585-8d5e-1ac794a7bbb0"
}
// 201 Created
{
"token": "usr-c0b21a9d-6a9b-41f7-9889-203b28305637",
"status": "PRE_ACTIVATED",
"verificationStatus": "NOT_REQUIRED",
"taxVerificationStatus": "NOT_REQUIRED",
"createdOn": "2023-04-12T23:05:49",
"clientUserId": "3rdForkLinkedAccountIdGoesHereIfYouWant",
"profileType": "INDIVIDUAL",
"firstName": "John",
"lastName": "Smith",
"dateOfBirth": "1980-01-01",
"email": "john@company.com",
"addressLine1": "123 Main Street",
"city": "New York",
"stateProvince": "NY",
"country": "US",
"postalCode": "10016",
"language": "en",
"timeZone": "GMT",
"programToken": "prg-413c0f85-9c82-4585-8d5e-1ac794a7bbb0",
"links": [
{
"params": {
"rel": "self"
},
"href": "https://api.paylution.com/rest/v3/users/usr-c0b21a9d-6a9b-41f7-9889-203b28305637"
}
]
}
Create Transfer Method V3
The below examples use Venmo, but expected to maintain same shape for ACH and Paypal.
Hyperwallet Docs: Create a Venmo Account
// POST /rest/v3/users/{usr-token}/venmo-accounts
{
"type": "VENMO_ACCOUNT",
"transferMethodCountry": "US",
"transferMethodCurrency": "USD",
"accountId": "3609219277"
}
// 201 Created
{
"token" : "trm-957a5449-fd42-4832-b3f7-10baa49e671a",
"type" : "VENMO_ACCOUNT",
"status" : "ACTIVATED",
"createdOn" : "2023-04-12T23:06:17",
"transferMethodCountry" : "US",
"transferMethodCurrency" : "USD",
"accountId" : "3609219277",
"userToken" : "usr-c0b21a9d-6a9b-41f7-9889-203b28305637",
"links" : [ {
"params" : {
"rel" : "self"
},
"href" : "https://api.paylution.com/rest/v3/users/usr-c0b21a9d-6a9b-41f7-9889-203b28305637/venmo-accounts/trm-957a5449-fd42-4832-b3f7-10baa49e671a"
} ]
}
Deactivate Transfer Method V3
Hyperwallet Docs: Status Transitions
// POST /rest/v3/users/{usr-token}/venmo-accounts/{trm-token}/status-transitions
{
"transition": "DE_ACTIVATED",
"notes": "Meh... We don't really need this."
}
// 201 Created
{
"token": "sts-1aede385-7840-44ec-881e-50ac1036e510",
"createdOn": "2023-04-12T22:30:52",
"transition": "DE_ACTIVATED",
"fromStatus": "ACTIVATED",
"toStatus": "DE_ACTIVATED",
"notes": "Meh... We don't really need this.",
"links": [
{
"params": {
"rel": "self"
},
"href": "https://api.paylution.com/rest/v3/users/usr-1b473243-4c51-49be-af24-f0bdbd0a9b4b/venmo-accounts/trm-fc51d6c0-5209-46ab-b50b-e927003ab838/status-transitions/sts-1aede385-7840-44ec-881e-50ac1036e510"
}
]
}
Reactivate Transfer Method V3
Hyperwallet Docs: Status Transitions
// POST /rest/v3/users/{usr-token}/venmo-accounts/{trm-token}/status-transitions
{
"transition": "ACTIVATED",
"notes": "Meh... We don't really need this."
}
// 201 Created
{
"token": "sts-f921b5f6-80f1-40fa-9e19-3d5a3b342542",
"createdOn": "2023-04-12T22:34:33",
"transition": "ACTIVATED",
"fromStatus": "DE_ACTIVATED",
"toStatus": "ACTIVATED",
"notes": "Meh... We don't really need this.",
"links": [
{
"params": {
"rel": "self"
},
"href": "https://api.paylution.com/rest/v3/users/usr-1b473243-4c51-49be-af24-f0bdbd0a9b4b/venmo-accounts/trm-fc51d6c0-5209-46ab-b50b-e927003ab838/status-transitions/sts-f921b5f6-80f1-40fa-9e19-3d5a3b342542"
}
]
}
Create Payment (Payout) V3
Hyperwallet Docs: Create a Payment
The destinationToken is the Transfer Method to transfer to. NOTE that despite what the Hyperwallet documentation says, it should always be the trm- token in our case.
NOTE also that the programToken here is different than the one for Create User; see notes on Token Types above. Be sure to store the returned pmt- token so that customer service can query it later if a consumer calls in.
// POST /rest/v3/payments
{
"amount": "1.00",
"clientPaymentId": "3rdForkTransactionIdGoesHereIfYouWant",
"currency": "USD",
"destinationToken": "trm-957a5449-fd42-4832-b3f7-10baa49e671a",
"programToken": "prg-dfd90ad1-c7e6-4976-bd6c-95cdd3208933",
"purpose": "OTHER"
}
// 201 Created
{
"token": "pmt-e2184620-faf9-4390-93cb-5a08a02aae74",
"status": "PENDING_TRANSACTION_VERIFICATION",
"createdOn": "2023-04-12T23:09:21",
"amount": "1.00",
"currency": "USD",
"clientPaymentId": "3rdForkTransactionIdGoesHereIfYouWant",
"purpose": "OTHER",
"expiresOn": "2023-10-09T23:09:21",
"destinationToken": "trm-957a5449-fd42-4832-b3f7-10baa49e671a",
"programToken": "prg-dfd90ad1-c7e6-4976-bd6c-95cdd3208933",
"links": [
{
"params": {
"rel": "self"
},
"href": "https://api.paylution.com/rest/v3/payments/pmt-e2184620-faf9-4390-93cb-5a08a02aae74"
}
]
}
Retrieve Payment (Payout) V3
Hyperwallet Docs: Retrieve a Payment
This endpoint to be used by Smiling Hill to provide transaction information to customer service.
// GET /rest/v3/payments/{pmt-token}
// EMPTY REQUEST BODY
// 200 OK
{
"token": "pmt-e2184620-faf9-4390-93cb-5a08a02aae74",
"status": "COMPLETED",
"createdOn": "2023-04-12T23:09:21",
"amount": "1.00",
"currency": "USD",
"clientPaymentId": "3rdForkTransactionIdGoesHereIfYouWant",
"purpose": "OTHER",
"expiresOn": "2023-10-09T23:09:21",
"destinationToken": "trm-957a5449-fd42-4832-b3f7-10baa49e671a",
"programToken": "prg-dfd90ad1-c7e6-4976-bd6c-95cdd3208933",
"links": [
{
"params": {
"rel": "self"
},
"href": "https://api.paylution.com/rest/v3/payments/pmt-e2184620-faf9-4390-93cb-5a08a02aae74"
}
]
}
PNDLM TODO
Updated 17 Apr
- Verify one more time that the Sandbox really doesn't work
- Rate limit handling
- Mockerwallet revisions based on real request/response
- Customer service transaction button via Smiling Hill initial release
- Decide to proxy mobile app through 3rdFork for April release, or connect to Oregon directly
- Clean up 3rdFork repo and prepare for use by OBRC team this week!