MarkGalloway / wealthsimple-trade

Unofficial API docs for the Wealthsimple Trade API
MIT License
98 stars 14 forks source link

POST /orders on a specific account? #4

Open jaubuchon opened 4 years ago

jaubuchon commented 4 years ago

Hi,

First, thank you for having taking the time to document this API and made it public!

(This is not an issue but a question, not sure how on github we can post question)

Would like to know if you have figure out how to submit an order for a a specific account.

Tried different things but without success (ie: adding "account_id": "xxxxxx" to the request body).

If it can help, by adding "account_id=xxx" to the activity url, this is allowing me to successfully filter activities by account id. Per example: https://trade-service.wealthsimple.com/account/activities?account_id=xxxxxx

Also, would be interested to understand how you were able to reverse engineer this api. Tried with "Burp Suite" (https://blog.haschek.at/2018/reverse-engineering-your-mobile-banking-app.html), but I ended up to the conclusion that Wealthsimple was doing "Certificate pinning", so not possible to do a man-to-the-middle (at least, not without jailbreaking by iphone).

And finally, would be interested to know how to authenticate when 2-factor authentication is enabled.

Thank you!

jaubuchon commented 4 years ago

About the 2FA question, actually I got lucky!

Just need to add "otp" parameter to the request body.

POST: https://trade-service.wealthsimple.com/auth/login

{
    "email": "your_email",
    "password": "your_password_",
    "otp": "your_otp_code"
}
MarkGalloway commented 4 years ago

Unfortunately, I haven't been a user of WST since it first launched in beta. I believe there was only a singular account back then. There is likely a way to do what you want, I'm just not sure.

I wasn't able to get around the certificate pinning and ended up just pulling the endpoints from the app source code.

alexanderMontague commented 4 years ago

@jaubuchon I've been trying to fill out some more endpoints and might have some answers here.

  1. I have not tried a buy yet, but this is what a sell looks like.

    https://trade-service.wealthsimple.com/account/activities?account_id=<ACCT_ID>&limit=20&security_id=<SECURITY_ID>&type=buy&type=dividend&type=sell

    Not sure what's going on with the multiple type query keys, but this works for a SELL. I would try the same for buy, or add on these query params to your BUY POST. I can give you a correct request in a bit once I get set up again.

  2. You are correct in your assumption as they are most definitely using SSL pinning. The way I was able to get around this was by using some proxy agent (I used Charles but any would work), and by using a jailbroken device like you also mentioned. I installed this tweak called "SSLkillswitch" and that worked great.

I hope to have most requests documented soon, but if you have any specific queries let me know!

alexanderMontague commented 4 years ago

So I've verified this now, the above request is actually getting all activities for the specified query. Here is the correct request to buy/sell.

POST: https://trade-service.wealthsimple.com/orders

BUY:

{
    "account_id": <ACCT_ID>,
    "quantity": 1,
    "security_id": <SID>,
    "order_type": "buy_quantity",
    "order_sub_type": "market",
    "time_in_force": "day",
    "limit_price": 0.195
}

SELL:

{
    "account_id": <ACCT_ID>,
    "quantity": 1,
    "security_id": <SID>,
    "order_type": "sell_quantity",
    "order_sub_type": "market",
    "time_in_force": "day"
}
austingreisman commented 4 years ago

I've been able to map a section of the wealthsimple trade web app directory structure using DirBuster. Attached is a log of a "fast scan". Hopefully, some of these help people. DirBusterReport-trade-service.wealthsimple.com-443.txt

phuzybuny commented 4 years ago

About the 2FA question, actually I got lucky!

Just need to add "otp" parameter to the request body.

POST: https://trade-service.wealthsimple.com/auth/login

{
    "email": "your_email",
    "password": "your_password_",
    "otp": "your_otp_code"
}

Thanks for sharing this @jaubuchon. I was fruitlessly trying to include it in the request headers. Hopefully @MarkGalloway would update this wonderful documentation with your finding!