/link_account

Links a bank account to a verified entity with a Plaid processor token or an MX authorization code

This endpoint accepts an account ID and either an MX authorization code or a Plaid processor token.

Once an account is linked, transaction endpoints should continue to work unless the account is manually removed using /delete_account.

🚧

Required: MX auth code or Plaid processor token

You will need a MX authorization_code or Plaid processor_token before you can link an account to an entity.

See more on MX here and Plaid here.

Plaid vs MX in the Request

Once you have obtained a Plaid processor token or MX authorization code, you can link an end user's account.

Plaid

  • Pass the Plaid processor_token in the provider_token parameter
  • Set the provider as plaid
  • Set provider_token_type as processor

NOTE: Do not link the same account multiple times with a different processor_token. Doing so will create additional payment instruments, and Plaid with invalidate the previous processor_token.

MX

  • Pass the MX authorization_code in the provider_token parameter
  • Set the provider as mx
  • Set provider_token_type as processor.

To verify: You can use the /get_account_balance endpoint and pass "account_name" to verify bank account link.

Request

The account_name key is not required, but can be used to set a custom name to identify the linked checking account. If not provided, the linked account's name will be "default." We recommend specifying a custom name.

Note: user_handles cannot have two linked accounts with the same name.

Authorization / Authentication

Apps using Access Token Authorization

Use a valid access token in an Authorization: Bearer request header.

See Authenticating with an Access Token for more details.

Apps using ECDSA Authentication

Both authsignature and usersignature headers are required for this request. The usersignature header should be generated with a keypair registered to the user (either registered from the /register endpoint or the /register_wallet endpoint).

See the section on ECDSA Authentication for more detail about ECDSA signature generation.

POST /0.2/link_account HTTP/1.1
sandbox.silamoney.com
Content-Type: application/json
// if using OAuth2
Authorization: Bearer [GENERATED JWT TOKEN HERE]
// if using ECDSA
authsignature: [GENERATED AUTHSIGNATURE HEX STRING HERE]
usersignature: [GENERATED USERSIGNATURE HEX STRING HERE]

***Link Account with Plaid 
{
  "header": {
    "created": 1234567890, 
    "app_handle": "handle.silamoney.eth", 
    "user_handle":"user.silamoney.eth", 
    "version": "0.2", 
    "reference": "<your unique id>"
  }, 
  "provider_token": "processor-xxx-xxx", //required
  "provider": "plaid", //required
  "account_name": "Custom Account Name", 
  "selected_account_id": "selected_account_id", 
  "account_type": "Checking", 
  "provider_token_type": "processor"
}

***Link Account with MX
{
  "header": {
    "created": 1234567890, 
    "app_handle": "handle.silamoney.eth", 
    "user_handle":"user.silamoney.eth", 
    "version": "0.2", 
    "reference": "<your unique id>"
  }, 
  "provider_token": "authorization_code-xxx-xxx", //required
  "provider": "mx", //required
  "account_name": "Custom Account Name",
  "provider_token_type": "processor"
}

***

HTTP/1.1  200 OK

{
    "success": true,
    "message": "Bank account successfully linked with status \"processor_token\".",
    "reference": "1727283525",
    "account_name": "<account_name>",
    "account_owner_name": "",
    "payment_instrument_id": "<uuid string>",
    "entity_name": "",
    "match_score": 0.825,
    "provider": "PLAID",
    "web_debit_verified": true,
    "capabilities": {
        "aba_routing_number": "<routing_number>",
        "fednow": {
            "credit_enabled": false,
            "debit_enabled": false
        },
        "rtp": {
            "credit_enabled": true,
            "debit_enabled": true
        }
    },
    "status": "SUCCESS",
    "response_time_ms": "1418"
}

***
Request - /link_account

// Plaid verification flow
const res = await Sila.linkAccount(
  userHandle,
  walletPrivateKey,
  token,
  accountName, // Account Name is not required
  accountId, // Account Id parameters is required,
  plaidTokenType, // Required.'processor,'
);

// MX verification flow
const res = await sila.linkAccountMX(
    handle,
    walletPrivateKey,
    providerTokenType,
    providerToken,
    accountName,
    selected_account_id
);

Success Response

console.log(res.statusCode); // 200
console.log(res.data.reference); // Random reference number
console.log(res.data.status); // SUCCESS

// Direct account-linking flow (restricted by use-case, contact Sila for approval)
const res = await Sila.linkAccountDirect(
  userHandle,
  walletPrivateKey,
  accountNumber,
  routingNumber,
  accountName,
  accountType
); 
// Account Type and Account Name parameters are not required
// The only permitted account type is "CHECKING"


console.log(res.statusCode); // 200
console.log(res.data.reference); // Random reference number
console.log(res.data.status); // SUCCESS
console.log(res.data.success);
console.log(res.data.message); // Bank account successfully linked
console.log(res.data.account_name);
console.log(res.data.match_score);
console.log(res.data.account_owner_name);
console.log(res.data.entity_name);
console.log(res.data.provider);
console.log(res.data.web_debit_verified); // true/false
### Link Account with MX
payload = {
"user_handle": user_handle,
"provider": "mx",
"provider_token_type": “processor”,
     "provider_token":"<token_id>",
"account_name": 'default_mx',
"selected_account_id": "<account_id>"
}

response = silasdk.User.linkAccount(
app, payload, eth_private_key, False,True)

### Link Account with Plaid
payload = {
"public_token": "public-development-0dc5f214-56a2-4b69-8968-f27202477d3f",  # Required token from plaid
"user_handle": "user.silamoney.eth",                             # Required
    "account_name": "Custom Account Name",                                       # Optional (default value is "default")
    "selected_account_id": "account id",                                        # Optional
    "plaid_token_type": "plaid token type"                                      # Optional}                                         

User.linkAccount(silaApp, payload, user_private_key, plaid=True)

### Link Account with Direct Account Linking
payload={
            "user_handle": "user.silamoney.eth",    # Required
            "account_number": "123456789012",       # Required
            "routing_number": "123456780",          # Required
            "account_type": "CHECKING",             # Optional (default value is CHECKING)
            "account_name": "Custom Account Name"   # Optional (default value is "default"),
        }

User.linkAccount(silaApp,payload,user_private_key)

### Success Response Object
{
    "success": true,
    "account_name": "Gringotts Savings",
    "account_owner_name": "",
    "entity_name": "Postman User",
    "match_score": 0.9
    "message": "Bank account successfully linked.",
    "provider": "MX",
    "reference": "2910ca97-9cb6-4d36-a6fe-591159c61865",
    "response_time_ms": "1262",
    "status": "SUCCESS",
    "web_debit_verified": true
}
// Link account with Plaid
String userHandle = 'user.silamoney.eth';
String accountName = 'plaid'; // Your desired account name
String publicToken = 'public-sandbox-xxx' // Your Plaid token
String userPrivateKey = 'some private key';
String accountId = 'plaid account id'; // Required
String plaidTokenType = "Processor";

ApiResponse response = api.linkAccountPlaidToken(userHandle, userPrivateKey, accountName, publicToken, accountId, plaidTokenType);

// Link account with MX
String provider ="mx";
String providerTokenType ="processor";
String userHandle = "user.silamoney.eth";
String userPrivateKey = "user private key";
String providerToken = "provider token";

ApiResponse response = api.linkAccountMX(userHandle,
     userPrivateKey,providerToken,provider,providerTokenType);

// Link Account directly (restricted by use-case, contact Sila for approval)
String userHandle = 'user.silamoney.eth';
String accountName = 'direct'; // Your desired account name
String accountNumber = '123456789012';
String routingNumber = '123456780';
String accountType = 'CHECKING'; // Currently the only allowed value
String userPrivateKey = 'some private key';

ApiResponse response = api.linkAccount(userHandle, userPrivateKey, accountName, accountNumber, routingNumber, accountType);


// Success Response
System.out.println(response.getStatusCode()); // 200
LinkAccountResponse parsedResponse = (LinkAccountResponse) response.getData();
System.out.println(parsedResponse.getStatus()); // SUCCESS
System.out.println(parsedResponse.getSuccess()); // true
System.out.println(parsedResponse.getReference()); // Reference number
System.out.println(parsedResponse.getMessage()); // Successfully linked
System.out.println(parsedResponse.getAccountName()); // Your desired account name
System.out.println(parsedResponse.getMatchScore()); // Match score
System.out.println(parsedResponse.getAccountOwnerName());
System.out.println(parsedResponse.getEntityName());
System.out.println(parsedResponse.getWebDebitVerified()); // true/false
System.out.println(parsedResponse.getProvider()); // 'plaid' | 'mx'
API Endpoint - /link_account

/**
 * Link with Plaid
 *
 * IMPORTANT! If you do not specify an `$account_id` in `linkAccount()`, the first 
 * account returned by Plaid will be linked by default.
 **/
use Silamoney\Client\Domain\PlaidTokenType;

$userHandle = 'user.silamoney.eth';
$accountName = 'Custom Account Name'; // Defaults to 'default'
$plaidToken = 'public-xxx-xxx'; // A temporary token returned from the Plaid Link plugin. See above for testing.
$accountId = 'string'; // Recommended but not required. See note above.
$userPrivateKey = 'some private key'; // The private key used to register the specified user
$plaidTokenType = PlaidTokenType::Processor(); // Optional.  PROCESSOR

$response = $client->linkAccount($userHandle, $userPrivateKey, $plaidToken, $accountName, $accountId, $plaidTokenType);

/**
 * Link with MX
 **/

$accountName = "defaultMx";
$accountId = "123456780";
$provider = "mx";
$providerTokenType = "processor";

// Making call to API
$response = $client->linkAccountMx(
	$handle,
	$privateKey,
	$provider,
	$providerToken,
	$providerTokenType,
	$accountName
);


/**
 * Link with Direct Account information
 *
 * (Restricted by use-case, contact Sila for approval)
 **/

$userHandle = 'user.silamoney.eth';
$accountName = 'Custom Account Name'; // Defaults to 'default' if not provided. (not required)
$routingNumber = '123456789'; // The routing number. 
$accountNumber = '123456789012'; // The bank account number
$userPrivateKey = 'some private key'; // The private key used to register the specified user
$accountType = 'CHECKING'; // The account type (not required). Only available value is CHECKING

$response = $client->linkAccountDirect($userHandle, $userPrivateKey, $accountNumber, $routingNumber, $accountName, $accountType);

/**
 * Response structure (200 Success)
 **/
echo $response->getStatusCode(); // 200
echo $response->getData()->getStatus(); // SUCCESS
echo $response->getData()->getReference();
echo $response->getData()->getMessage();
echo $response->getData()->getAccountName();
echo $response->getData()->getAccountOwnerName();
echo $response->getData()->getEntityName();
echo $response->getData()->getMatchScore();
echo $response->getData()->getWebDebitVerified();
// Link Account with Plaid
ApiResponse<object> response = api.LinkAccount(userHandle, publicToken, walletPrivateKey, accountName, accountId, plaidTokenType);
// Account Name is not required 
// Account Id is required
// plaidTokenType is not required



// Link Account with MX
ApiResponse<object> response = api.LinkAccountMx(userHandle, userPrivateKey, provider, providerTokenType, providerToken);
// Account Name is not required 
// Account Id is not required 

// Link Account with Direct Account information
ApiResponse<object> response = api.LinkAccountDirect(userHandle, walletPrivateKey, accountNumber, routingNumber, accountType, accountName);
// Account Name is not required 
// Account Type is not required  


// Success Response Object

Console.WriteLine(response.StatusCode); // 200
var parsedResponse = (LinkAccountResponse)response.Data;

Console.WriteLine(parsedResponse.Success); // true
Console.WriteLine(parsedResponse.Status); // SUCCESS
Console.WriteLine(parsedResponse.Reference); // Random reference number
Console.WriteLine(parsedResponse.ResponseTimeMs); // 2345
Console.WriteLine(parsedResponse.Message); // Bank account successfully linked.
Console.WriteLine(parsedResponse.AccountName); // Custom Account Name.
Console.WriteLine(parsedResponse.MatchScore); // 0.825           
Console.WriteLine(parsedResponse.AccountOwnerName); //Sally Smith
Console.WriteLine(parsedResponse.EntityName); //Sally Smith
Console.WriteLine(parsedResponse.WebDebitVerified); //true
Console.WriteLine(parsedResponse.Provider); //'mx' | 'plaid'

The plaid_token and plaid_token_type parameters have been deprecated and are only used prior to SDK version 0.2.49; however, they are still supported for backwards compatibility.

Request Attributes

KeyTypeDescription
headerJSON objectRequired.

Requires these keys in JSON format: created, app_handle, user_handle. See the /check_handle endpoint for the complete list of fields in this object.
provider_tokenStringRequired.

Plaid + Sila Integration:
Pass a processor token obtained from Plaid.
Example: processor-xxx-xxx.
This value shall match the required regex pattern: ^[-a-zA-Z0-9_]+$

MX + Sila Integration:
Pass an authorization_code from MX.
The MX authorization code is a 32 byte string
providerStringRequired.

Plaid: plaid
MX: mx
account_nameStringOptional.

Min length 1, Max length 40, default value if not sent in request is “default”

NOTE- We recommend specifying a custom name here as this is how an account is identified for /issue_sila, /redeem_sila, and /get_transactions.
selected_account_idStringApplicable to Plaid Only

Not required with a Plaid processor token or if the selected_account_id is packaged inside the processor token.

This is the Plaid account ID from list of selected account IDs returned from Plaid Link flow.

If not provided, we will link the first checking account we encounter from the array of selected accounts returned in the metadata object from Plaid Link.
account_typeStringOptional.

"CHECKING"
provider_token_typeStringRequired.

"processor"

Linking multiple accounts at once

Currently, we do not link multiple accounts at once; you will need to send only one account ID.

Responses

Status Codesuccess AttributeDescription
200trueBank account successfully linked.
200falseBank account not successfully linked (public token may have expired; tokens expire in 30 minutes after creation).
202falseBank account linked, but in a frozen state. Requires manual review - contact support for steps to unfreeze this bank account.
400falseCheck validation_details for more information. PRODUCT_NOT_READY indicates the account is waiting to be linked (with microdeposit verification, for instance).
401falseauthsignature or usersignature header was absent or incorrect.

Fuzzy Name Match Algorithm

🚧

Fuzzy Name Match Algorithm

Within the response body of /link_account you may see the error message: "Bank account linked, but in a frozen state. Requires manual review - contact support to unfreeze this bank account."

Read more about the Fuzzy Name Match Algorithm HERE

It is recommended that you wait until an end user passes KYC before you allow them to link an account.

If a user fails KYC, there is a risk that the account that they linked will be frozen and you will get the following error message: "Bank account linked, but in a frozen state. Requires manual review - contact support to unfreeze this bank account."

Legacy Plaid Integration - Link Token & Plaid Public Key

❗️

DEPRECATED: Legacy Plaid Integration - Link Token & Plaid Public Key

If you integrated Plaid through the Sila API before July 2021, you may have a legacy integration.

Per Plaid's request, the Plaid Link token integration was deprecated on May 2022.

Please establish a direct relationship with Plaid, https://plaid.com/docs/auth/partnerships/sila-money/ and begin integration with the Plaid processor token as soon as possible.

Direct Accounts or Manual Account Linking

❗️

Direct Account (manual) linking and Receive Only Entities have been prohibited due to a more restrictive regulatory environment.

  • As of July 2022 direct (manual) account linking was discontinued.
  • As of January 2023 the receive only kyc level was discontinued.

What’s Next

The following are secondary endpoint that can not be used until the primary /link_account endpoint has been successfully called as well as supporting documentation.