Hosted Connect
Hosted Connect is where a member links their Tradovate login and authorizes your application. CrossTrade hosts the consent page; your server exchanges the resulting code for the member token it will use on the Trading and Management APIs. Redirect delivery uses an HTTPS URI registered on your OAuth client.
The link
POST /v1/api/partner/users and /connect-link return a one-time URL under https://app.crosstrade.io/v1/connect/. It is valid for 10 minutes and for one browser:
- Opening the link (
GET) shows a confirmation page and consumes nothing. Link scanners and mail clients that prefetch the URL do not spend it. - The member presses Continue (
POST, same origin) and the link is consumed. CrossTrade records possession of the link as the ownership proof and binds the flow to that browser. Deliver it only to the intended member through your authenticated app or a private message. This is not a separate email-code verification. The browser receives a host-only Connect cookie valid for up to one hour; the flow itself expires one hour after creation. - A second browser, or the same link after it was used, cannot continue. Request a new link.
There is no email code and no CrossTrade sign-in anywhere on the page. A member never logs in to CrossTrade; the link is their access. The page is a standalone portal in your branding (logo, business name, colours; set them under Partner Platform, Settings) with "Powered by CrossTrade" at its foot.
The steps
- Terms. The required CrossTrade agreements and applicable partner connection addendum are shown and accepted with recorded versions. A member who already accepted the currently required documents (on an earlier link, even one they left with "I'll do this later") is not asked again; a later link can start at the broker step.
- Broker. The member can link a Tradovate Demo login, a Tradovate Live login, or both, exactly as on the Brokers tab of a regular CrossTrade account: linking is the member's own account action. Which environments your app may act on is a separate matter, governed by the environments enabled for your partner (the member's
environmentson create records what you asked for). CrossTrade runs the Tradovate OAuth flow and returns to the page; a Tradovate login already linked to a different CrossTrade account cannot be taken over. I'll do this later skips the link for now. - Allow. The member chooses which linked identities your app may use and sees what the requested scopes permit. Allow creates the grant and authorization code. I'll do this later (or Finish without connecting when no login is linked) ends this flow without issuing a new grant or code. You receive
authorization.deniedwithreason: later(redirect delivery getserror=access_denied). Declining a new flow does not revoke an earlier grant or end the funded seat. Send a newauthorizelink when the member is ready or wants to change the identities they share.
A relink flow repairs a broker connection already covered by a standing grant. It does not issue a new code or token pair, and cannot add identities outside that grant. Use authorize for new or changed consent.
To end a connection the member asks you; revoke ends the seat and the grant.
Your redirect URI and how the code reaches you
Every authorization names one of the redirect URIs registered on your API client (Partner Platform, API Keys). Use a callback endpoint in your application, for example https://app.yourcompany.com/oauth/callback. It must exactly match the registered HTTPS URI and the value sent at token exchange. A CrossTrade dashboard page is not your application's callback.
How the one-time authorization code reaches your server depends on the delivery of each authorization: the value in the request, or, when the request omits it, the code delivery set on your API client under API Keys in the Partner Platform dashboard (redirect until you change it):
| Delivery | What the member sees after Allow | Where the code goes | Typical use |
|---|---|---|---|
redirect | Their browser is sent to your redirect URI with code, state and iss | Your page reads code, verifies state, and your server exchanges it for tokens | The member is already using your web app and should land back in it |
pickup | They stay on the portal ("You are connected"), with a button to your return URL if you set one | Your server polls POST /v1/api/partner/users/{external_id}/authorizations/{flow_id}/code with its partner token | Your app has no page for the member to land on, or you created the member from a back office |
With pickup the redirect URI is never visited, but it is still required and checked: OAuth binds the authorization code to it, and the token exchange must send the same value. While you are testing with pickup, any HTTPS page on your own domain will do.
What you receive
delivery: redirect: the browser is sent to yourredirect_uriwithcode,stateandiss. Verify the storedstateand thatissequalshttps://app.crosstrade.io, then exchange the code within 300 seconds.delivery: pickup: pollPOST /v1/api/partner/users/{external_id}/authorizations/{flow_id}/codewith your partner token and no body. The answer ispendinguntil the member allows, then the same code on repeat pickups while it remains valid and unexchanged. After exchange, the answer isexchangedwithout credentials. Expired, denied or revoked flows answer410.
The three pickup answers, in order:
{
"success": true,
"authorization": {
"status": "pending",
"flow_id": "pcf_a1b2c3d4e5f6"
},
"meta": {
"requestId": "preq_1a2b3c4d5e6f7a80"
}
}
{
"success": true,
"authorization": {
"status": "code_ready",
"flow_id": "pcf_a1b2c3d4e5f6",
"code": "xt_ac_...",
"expires": "2026-10-15T14:13:52Z"
},
"meta": {
"requestId": "preq_8f7e6d5c4b3a2910"
}
}
{
"success": true,
"authorization": {
"status": "exchanged",
"flow_id": "pcf_a1b2c3d4e5f6"
},
"meta": {
"requestId": "preq_0a9b8c7d6e5f4a31"
}
}
The first is 202 Accepted, the other two 200 OK. A redirect delivery arrives as https://partner.example/oauth/callback?code=xt_ac_...&state=...&iss=https%3A%2F%2Fapp.crosstrade.io, or with error=access_denied&state=... after a decline.
The events feed carries authorization.granted, authorization.denied and broker.ready as the member progresses.