Plaid logo
Docs
ALL DOCS

Link

  • Overview
Platforms
  • Web
  • iOS
  • Android
  • React Native
  • Hosted Link
    • Hosted Link for embedded clients
Core Link functionality
  • OAuth guide
  • Update mode
  • Preventing duplicate Items
  • Data Transparency Messaging migration
  • Returning user experience
Additional Link modes
  • Embedded Link
  • Multi-Item Link
  • Link Recovery (beta)
  • Modular Link (UK/EU only)
Optimizing Link
  • Optimizing Link conversion
  • Link analytics and tracking
  • Pre-Link messaging
  • Customizing Link
  • Choosing when to initialize products
Errors and troubleshooting
  • Troubleshooting
  • Handling an invalid Link Token
  • Institution status in Link
Legacy flows
  • Legacy public key integrations
  • Link Token migration guide
  • Webview integrations
Plaid logo
Docs
Close search modal
Ask Bill!
Ask Bill!
Hi! I'm Bill! You can ask me all about the Plaid API. Try asking questions like:
  • Do access tokens expire?
  • Can you show code for getting transactions in Python?
  • Why is /transactions/sync/ better than /get?
Note: Bill isn't perfect. He's just a robot platypus that reads our docs for fun. You should treat his answers with the same healthy skepticism you might treat any other answer on the internet. This chat may be logged for quality and training purposes. Please don't send Bill any PII -- he's scared of intimacy. All chats with Bill are subject to Plaid's Privacy Policy.
Plaid.com
Log in
Get API Keys
Open nav

Hosted Link

Integrate with Link using a Plaid-hosted frontend

Overview

Hosted Link is the easiest and fastest way to integrate with Plaid. With Hosted Link, Plaid hosts the Link experience. Customers can use this link in web browsers or open it in a secure web context within a mobile app, eliminating the need for front-end implementation work. Hosted Link is especially recommended for any mobile integration that is not using the official Plaid SDK. If your Plaid integration uses webviews, we strongly recommend switching to Hosted Link. Hosted Link can also be used to complement in-person interactions; for example, you can send a Hosted Link session to customers who are in-person at a retail location.

Prefer to learn by watching? Check out this quick video guide to enabling Hosted Link!

With Link Delivery (beta), Hosted Link can also deliver the URL for the Link session to your users via text or email.

Hosted Link is fully compatible with all Plaid products and Link flows (including update mode), except for Plaid Layer. For Identity Verification customers, Hosted Link can optionally be used instead of IDV-specific Verification Links to take advantage of features such as Link Delivery (beta).

Hosted Link is the preferred frontend integration method for all platforms in which Plaid's native mobile or web SDKs can't be used, including webview-based mobile apps and integrations by embedded clients such as PSPs. For details on using Hosted Link as an embedded client, See Hosted Link for embedded clients.

Benefits of using Hosted Link
  • Simplicity: Hosted Link is the easiest way to integrate with Plaid if you are unable to use Plaid's native mobile SDKs. You don't need to build or maintain a front-end component.
  • Integration complexity: Since Hosted Link controls the redirections that are required to support OAuth, it removes one complex step to supporting embedded integrations.
  • SDK size: Since the flow will be hosted by Plaid, there is no added SDK size to your application.
  • Link Recovery: Hosted Link is required to enable Link Recovery (beta). With Link Recovery, users whose Link sessions failed due to temporary institution outages can be automatically notified when the issue has been healed, allowing you to increase Link conversion. For more details, see Link Recovery.

To request access to Link Delivery, contact your Account Manager.

Integration process

Creating a Link token

To start with Hosted Link, call /link/token/create and include a hosted_link object in the request. The hosted_link object can be an empty object {}, or it can contain any of the hosted_link configuration fields. As long as you include the hosted_link object in your request, the hosted_link_url will be present in the response.

Previously, Hosted Link was enabled via Plaid Account Managers; it is no longer necessary to request that your Account Manager enable Hosted Link. If your account was enabled for Hosted Link via your Account Manager, the hosted_link_url will be present in the response for all /link/token/create requests, regardless of whether you include a hosted_link object.

You can provide the following Hosted Link parameters to /link/token/create:

  • Specify a webhook endpoint where the public_token will be delivered. Webhooks are strongly recommended when using Hosted Link, as the webhook is the primary means of delivering the public_token, as well as of informing you when your user has completed the Link session.
  • To have Plaid deliver the link to your user with Link Delivery (beta), set hosted_link.delivery_method to either sms or email. Plaid will contact the user via the information you provide in the user object of the request. For example, if you selected email, the user object in the request must contain an email_address.
  • To customize the duration of the Hosted Link token lifetime, set hosted_link.url_lifetime_seconds. If you don't set this field, the default lifetime for Hosted Links sent by Plaid via SMS is 24 hours, and for links sent via email, it is 7 days. If Plaid isn't delivering the url, the default lifetime is 30 minutes.
  • To have Plaid redirect the user after they complete the Link flow, set hosted_link.completion_redirect_uri to the destination URI.
  • To indicate that the user will be opening the link in a mobile app in an out-of-process webview (i.e., an AsWebAuthenticationSession / SFSafariViewController or Android Custom Tab), set hosted_link.is_mobile_app to true.

The response from /link/token/create will include a hosted_link_url field. You can send a user to this URL to start the Hosted Link session. Alternatively, if your integration uses both Hosted Link and non-Hosted Link sessions, you can start a non-Hosted Link session using the link_token instead.

In a Hosted Link session, you should also store the link_token value that gets returned, and make sure to associate it with the internal user ID your application is using for this user. This is the only way to make sure the data that gets returned from the Hosted Link session is associated with the right end-user.

1curl -X POST https://production.plaid.com/link/token/create \
2-H 'Content-Type: application/json' \
3-d '{
4 "client_id": "${PLAID_CLIENT_ID}",
5 "secret": "${PLAID_SECRET}",
6 "client_name": "Wonderwallet",
7 "country_codes": ["US"],
8 "redirect_uri": "{{UNIVERSAL_OR_APP_LINK}}",
9 "webhook": "https://wonderwallet.com/webhook_receiver",
10 "language": "en",
11 "user": {
12 "client_user_id": "a57d3304",
13 "phone_number": "+19162255887"
14 },
15 "products": ["auth"],
16 "hosted_link": {
17 "delivery_method": "sms",
18 "completion_redirect_uri": "https://wonderwallet.com/redirect",
19 "is_mobile_app": false,
20 "url_lifetime_seconds": 900
21 }
22}
1{
2 "expiration": "2023-08-18T02:08:03Z",
3 "hosted_link_url": "https://secure.plaid.com/link/lp9o97618r1r6p93oon62nr025950ro4s3",
4 "link_token": "link-production-4b42163e-6e1c-48bb-a17a-e570405eb9f8",
5 "request_id": "kNbPMmLxzBObzpt"
6}
Obtaining a public token

In most other Plaid integration methods, upon completion of the Link flow, your frontend code would receive either an onSuccess or onExit callback. In Hosted Link, there is no frontend integration required (or possible). You will instead receive information about the Link flow (including the public_token) via the SESSION_FINISHED webhook and the /link/token/get endpoint.

Each time a user completes a Link flow, Plaid will fire a SESSION_FINISHED webhook that contains information about what caused the session to end, as well as the public token if the session completed successfully. In flows where Link is re-initialized after an OAuth redirect, this webhook will fire exactly once, after the user completes the entire Link flow.

1{
2 "webhook_type": "LINK",
3 "webhook_code": "SESSION_FINISHED",
4 "status": "SUCCESS",
5 "link_session_id": "356dbb28-7f98-44d1-8e6d-0cec580f3171",
6 "link_token": "link-sandbox-af1a0311-da53-4636-b754-dd15cc058176",
7 "public_tokens": [
8 "public-sandbox-b0e2c4ee-a763-4df5-bfe9-46a46bce993d"
9 ],
10 "environment": "sandbox"
11}

You can also call /link/token/get with the relevant Link token to receive more detailed metadata on sessions started using this Link token. Each Link session includes the time it was started, and (if applicable) the time it finished. Each completed Link session also includes the metadata that would normally be passed to the onSuccess or onExit callbacks, including the public_token for successful sessions.

Detailed session data, including the public token, will also be available from /link/token/get for six hours after the session has completed. In general, it is recommended to use the webhook to obtain the public token, since it will allow you to get the public token more promptly, but you may want to use /link/token/get if your integration does not use webhooks, or as a backup mechanism if your system missed webhooks due to an outage.

In /link/token/get the public_token is present in both the on_success object and the results object. It is recommended to use the results object, as the older on_success object does not support the newer Multi-Item Link option, which allows for multiple public tokens to be returned in a single Link session.

1{
2 {
3 "created_at": "2024-07-29T21:22:13Z",
4 "expiration": "2024-07-29T21:52:13Z",
5 "link_sessions": [
6 {
7 "events": [
8 {
9 "event_id": "c1ccb962-9de0-494c-b85b-e89cdf3b2478",
10 "event_metadata": {
11 "institution_id": "ins_10",
12 "institution_name": "American Express",
13 "request_id": "Z9MB4fuMB2TJqgL"
14 },
15 "event_name": "HANDOFF",
16 "timestamp": "2024-07-29T21:23:03Z"
17 },
18 {
19 "event_id": "ff03f1ff-313b-4c2e-997f-83791c7ec432",
20 "event_metadata": {
21 "institution_id": "ins_10",
22 "institution_name": "American Express",
23 "request_id": "vyPamzbGPPsQucO"
24 },
25 "event_name": "OPEN_OAUTH",
26 "timestamp": "2024-07-29T21:22:34Z"
27 },
28 {
29 "event_id": "0ea6d0df-1bb0-4e4d-bea5-b3731b7536bf",
30 "event_metadata": {
31 "institution_id": "ins_10",
32 "institution_name": "American Express",
33 "request_id": "vyPamzbGPPsQucO"
34 },
35 "event_name": "TRANSITION_VIEW",
36 "timestamp": "2024-07-29T21:22:33Z"
37 },
38 {
39 "event_id": "e14c7b49-82c4-4f0c-a88a-987a62241d34",
40 "event_metadata": {
41 "institution_id": "ins_10",
42 "institution_name": "American Express",
43 "request_id": "0jjsLDlMl1VaVxU"
44 },
45 "event_name": "SELECT_INSTITUTION",
46 "timestamp": "2024-07-29T21:22:32Z"
47 },
48 {
49 "event_id": "b9b9f7ce-52bc-470e-801b-b4fa1da98e59",
50 "event_metadata": {
51 "request_id": "0jjsLDlMl1VaVxU"
52 },
53 "event_name": "TRANSITION_VIEW",
54 "timestamp": "2024-07-29T21:22:23Z"
55 },
56 {
57 "event_id": "e057a92c-eff8-467c-92c2-620109207e87",
58 "event_metadata": {
59 "request_id": "aHnAMiUzk8HrsNn"
60 },
61 "event_name": "SKIP_SUBMIT_PHONE",
62 "timestamp": "2024-07-29T21:22:22Z"
63 },
64 {
65 "event_id": "f1feedc9-61be-4a42-885c-cb67511473d2",
66 "event_metadata": {
67 "request_id": "aHnAMiUzk8HrsNn"
68 },
69 "event_name": "TRANSITION_VIEW",
70 "timestamp": "2024-07-29T21:22:21Z"
71 },
72 {
73 "event_id": "f9b49b0b-4259-4a32-860b-653b55ff8736",
74 "event_metadata": {
75 "request_id": "CGTlWrGRd8WaGa2"
76 },
77 "event_name": "TRANSITION_VIEW",
78 "timestamp": "2024-07-29T21:22:20Z"
79 }
80 ],
81 "finished_at": "2024-07-29T21:23:03.326860787Z",
82 "link_session_id": "f3c3b8fe-16c6-4670-8f2b-e8d797aa6e9f",
83 "on_success": {
84 "metadata": {
85 "accounts": [
86 {
87 "class_type": null,
88 "id": "d1rVJdbe1jCE9jE81wlduPlQQejKXeCJnDzyw",
89 "mask": "3333",
90 "name": "Plaid Credit Card",
91 "subtype": "credit card",
92 "type": "credit",
93 "verification_status": null
94 }
95 ],
96 "institution": {
97 "institution_id": "ins_10",
98 "name": "American Express"
99 },
100 "link_session_id": "f3c3b8fe-16c6-4670-8f2b-e8d797aa6e9f",
101 "transfer_status": null
102 },
103 "public_token": "public-sandbox-d1e64436-f033-4302-a469-b90656edf8c7"
104 },
105 "results": {
106 "item_add_results": [
107 {
108 "accounts": [
109 {
110 "class_type": null,
111 "id": "d1rVJdbe1jCE9jE81wlduPlQQejKXeCJnDzyw",
112 "mask": "3333",
113 "name": "Plaid Credit Card",
114 "subtype": "credit card",
115 "type": "credit",
116 "verification_status": null
117 }
118 ],
119 "institution": {
120 "institution_id": "ins_10",
121 "name": "American Express"
122 },
123 "public_token": "public-sandbox-d1e64436-f033-4302-a469-b90656edf8c7"
124 }
125 ]
126 },
127 "started_at": "2024-07-29T21:22:17.0951134Z"
128 }
129 ],
130 "link_token": "link-sandbox-9b48eb4c-7e1b-44e1-b80d-faa1d71cdf5e",
131 "metadata": {
132 "client_name": "Wonderwallet",
133 "country_codes": [
134 "US"
135 ],
136 "initial_products": [
137 "transactions"
138 ],
139 "language": "en",
140 "redirect_uri": null,
141 "webhook": "https://webhook.site/dc9c138f-75de-4db1-883a-a4add4b7eb7e"
142 },
143 "request_id": "jBBxxNC842EJNqW"
144}

Link session events

To obtain Link session events while using Hosted Link, listen for the EVENTS webhook, or use /link/token/get.

Integrating Hosted Link in native mobile applications

If you are unable to use the Plaid Link SDK in your native mobile app, creating and opening up a Hosted Link is a stable and reliable way of taking users through the Link process. We recommend using a Hosted Link instead of trying to use the Plaid Web SDK in a webview.

When you use a Hosted Link in a native mobile app, you will open the URL inside of an "out of process" webview, such as an ASWebAuthenticationSession in iOS, or an Android Custom Tab. These sessions appear as part of your application, making the process feel more seamless than opening up the URL in a separate browser application.

When the Link session is complete, Plaid will attempt to open a completion_redirect_uri that you specify. This is typically a URI with a custom scheme that automatically closes the web session and allows your application to continue from where you left off.

To use Hosted Link in a native mobile application:

Create a Link token

Call /link/token/create with the following values:

  • hosted_link.is_mobile_app should be set to true
  • hosted_link.completion_redirect_uri should be a URI with a custom scheme.
    • This scheme can be any value you'd like, as long as it isn't a reserved one such as http or tel. By convention, it's often one associated with the name of your application.
    • For example, your app might have something like wonderwallet://hosted-link-complete as a completion redirect URI.
    • Unlike the redirect_uri value, this URI does not need to be registered with the Plaid Dashboard, nor does it need to point to a "real" location.
  • redirect_uri should ideally be a URL that opens up your native mobile application, such as a Universal Link on iOS or an Android App Link on Android.
    • The redirect_uri is used in situations where Plaid opens up another mobile app, like Chase, for app-to-app authentication.
    • When the user is done authenticating with the third party app, the app will attempt to open this URI, which should redirect users back into your app.
    • Plaid cannot use android_package_name to perform the OAuth redirect when using Hosted Link. You must use redirect_uri, even if using an Android app.
    • There is nothing you need to do to handle this incoming redirect_uri. As long as the link opens your application, the Hosted Link session can take it from there.
1curl -X POST https://production.plaid.com/link/token/create \
2-H 'Content-Type: application/json' \
3-d '{
4 ...Other data removed...
5 hosted_link: {
6 completion_redirect_uri: "wonderwallet://hosted-link-complete",
7 is_mobile_app: true
8 },
9 redirect_uri: "https://mysite.com/universal-link/jump-to-my-app.html",
10}'
"Register" your custom URL scheme

You will need to make sure your operating system can handle the completion redirect URI that the Hosted Link session will open when it's complete.

On iOS, all you need to do is pass this URL scheme into the ASWebAuthenticationSession when you initialize it (see Open the Hosted Link URL). There is no need to register this URL scheme in your Xcode project in any other way.

In Android, you should create an Intent Filter for the activity that you want to appear when the user is done with the session.

1<intent-filter>
2 <action android:name="android.intent.action.VIEW" />
3 <category android:name="android.intent.category.DEFAULT" />
4 <category android:name="android.intent.category.BROWSABLE" />
5 <data android:scheme="wonderwallet" android:host="hosted-link-complete" />
6</intent-filter>

If this activity is the same activity that you used to launch Hosted Link in the first place, you may want to give this activity a singleTask or singleTop launch mode, so that the original activity "pops back" to the top of your application, and you're not creating multiple copies of the same activity.

Open the Hosted Link URL

On iOS, create an ASWebAuthenticationSession, using the Hosted Link URL you received from the server and the same custom scheme you used in your completion_redirect_uri.

1@IBAction func connectBankWasPressed(_ sender: Any) {
2 guard let hostedLinkURL = hostedLinkURL else {return}
3 let scheme = "wonderwallet"
4 let session = ASWebAuthenticationSession(url: URL(string: urlToOpen)!, callbackURLScheme: scheme) { callbackURL, error in
5 guard error == nil, let callbackURL = callbackURL else {
6 // The user might have clicked "Cancel" on the session. This will be captured as a 'canceledLogin' error.
7 return
8 }
9 if (callbackURL.absoluteString == "\(scheme)://hosted-link-complete") {
10 self.checkLinkStatus()
11 }
12 }
13 session.presentationContextProvider = self
14 session.start()
15}

For the above code to work, you will also need to make sure the appropriate view controller is set as a proper context provider:

1extension ConnectToBankViewController: ASWebAuthenticationPresentationContextProviding {
2 func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
3 return view.window!
4 }
5}

On Android devices, create a Custom Tab that opens up the Hosted Link URL from within your application:

1import androidx.browser.customtabs.CustomTabsIntent
2import android.net.Uri
3
4private fun openHostedLink(hostedLinkUrl) {
5 val customTabsIntent = CustomTabsIntent.Builder().build()
6 customTabsIntent.launchUrl(this, Uri.parse(hostedLinkUrl))
7}

See the Apple Developer Documentation or Chrome Developer Documentation for more details on these two methods.

Handle the incoming URI

When the user is done with the Hosted Link session, Plaid will attempt to open the completion_redirect_uri you specified when creating the Link token. If your application is set up as described above, this will close the Hosted Link page and bring your application back to the foreground. You will then receive this URI in a callback handler, where you can perform tasks such as refreshing the user's Link Session status.

The completion_redirect_uri is not supported in Identity Verification sessions.

Note that Plaid will call this URI whether the user successfully completed the session, or asked Plaid to exit the connection process, so you cannot assume that receiving this URI means a successful connection. You should listen for the SESSION_FINISHED webhook or call /link/token/get to determine the status of the user's Hosted Link session.

On iOS, you define this handler when you create the ASWebAuthenticationSession

1let scheme = "wonderwallet"
2let session = ASWebAuthenticationSession(url: URL(string: urlToOpen)!, callbackURLScheme: scheme) { callbackURL, error in
3 guard error == nil, let callbackURL = callbackURL else {
4 return
5 }
6 if (callbackURL.absoluteString == "\(scheme)://hosted-link-complete") {
7 self.checkLinkStatus()
8 }
9}

If the user dismisses the window by clicking the Cancel button, this handler will still be called, but with a canceledLogin error instead of a callbackURL.

On Android, you can retrieve this URL in the onNewIntent callback if you are returning to the previous activity. (If you are opening a new activity, you can use the onCreate callback.)

1override fun onNewIntent(intent: Intent?) {
2 super.onNewIntent(intent)
3 intent?.data?.let { uri ->
4 if (uri.scheme == "wonderwallet" && uri.host == "hosted-link-complete") {
5 checkLinkStatus()
6 }
7 }
8 }

If the user dismisses the Custom Tab by tapping the close button, this callback will not be called, but an onResume callback will still be called.

Migrating to Hosted Link from other integrations

First, review the Integration process to understand how to launch the Hosted Link flow and the configuration options available.

If you're currently capturing Link session events, migrate to using /link/token/get to receive Link session events.

If your users will be opening Link sessions inside a native mobile application, launch Hosted Link in an out-of-process webview as described above instead of using an in-process webview.

iFrame based nested integrations

For nested integrations like iFrames in a customer web page within a merchant webview, shift from capturing events through redirects to using backend events via /link/token/get. Your merchants should launch Hosted Link in an out-of-process webview or external browser.

Either you or the merchant must add an extra callback parameter to /link/token/create, allowing Plaid to close the out-of-process webview as needed. You will likely make the /link/token/create call. Merchants must either obtain a callback from the customer or ensure handling of a specified callback in their code.

Next steps

Once you have obtained a public token, you can integrate via the same process as non-Hosted Link integrations, including calling /item/public_token/exchange to exchange the public token for an access token.

Testing Hosted Link

You can test Hosted Link in Production or Sandbox. In the Sandbox environment, Plaid will not provide email or SMS Hosted Link delivery, and update mode sessions will expire after 30 minutes.

Pricing

Hosted Link is free; there is no additional fee to use it. If using Link Delivery to deliver Hosted Link sessions, there is a fee for each link sent. For Link Delivery pricing details, contact Sales or your Account Manager.

Was this helpful?
Developer community
GitHub
GitHub
Stack Overflow
Stack Overflow
YouTube
YouTube
Discord
Discord