Add a new bank account to a person. ( STABLE )
curl --request POST \
--url https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"person": {
"first_name": "John",
"last_name": "Doe"
},
"billing_merchant_uuid": "6a8fc154-1a50-483b-a690-fd1dfaf9408b",
"billing_processor_mid": "12345678",
"bank_account": {
"plaid_account_id": "<string>",
"plaid_access_token": "<string>",
"account_number": "9876543210",
"routing_number": "021000021",
"account_name": "John Doe",
"account_type": "checking"
},
"actions": {}
}
'import requests
url = "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts"
payload = {
"person": {
"first_name": "John",
"last_name": "Doe"
},
"billing_merchant_uuid": "6a8fc154-1a50-483b-a690-fd1dfaf9408b",
"billing_processor_mid": "12345678",
"bank_account": {
"plaid_account_id": "<string>",
"plaid_access_token": "<string>",
"account_number": "9876543210",
"routing_number": "021000021",
"account_name": "John Doe",
"account_type": "checking"
},
"actions": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
person: {first_name: 'John', last_name: 'Doe'},
billing_merchant_uuid: '6a8fc154-1a50-483b-a690-fd1dfaf9408b',
billing_processor_mid: '12345678',
bank_account: {
plaid_account_id: '<string>',
plaid_access_token: '<string>',
account_number: '9876543210',
routing_number: '021000021',
account_name: 'John Doe',
account_type: 'checking'
},
actions: {}
})
};
fetch('https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'person' => [
'first_name' => 'John',
'last_name' => 'Doe'
],
'billing_merchant_uuid' => '6a8fc154-1a50-483b-a690-fd1dfaf9408b',
'billing_processor_mid' => '12345678',
'bank_account' => [
'plaid_account_id' => '<string>',
'plaid_access_token' => '<string>',
'account_number' => '9876543210',
'routing_number' => '021000021',
'account_name' => 'John Doe',
'account_type' => 'checking'
],
'actions' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts"
payload := strings.NewReader("{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"message": "This bank account already exists for this person. We have attached it as the default bank account.",
"data": {
"bank_account": {
"aggregator_type": "manual",
"uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6",
"is_default": true,
"account_number": "********1234",
"routing_number": "*****6789",
"account_name": "John Doe",
"account_type": "checking",
"timestamps": {
"created_at": "2024-06-25 13:57:03"
}
},
"account_intelligence": {
"confidence_score": 0.81,
"decisioning_insights": {
"account_duplicate": false,
"days_since_first_seen": -1,
"days_since_last_transaction": -1,
"has_negative_transactions": false,
"has_paid_transactions": false,
"has_positive_transactions": true,
"name_match": "yes",
"phone_number_present": false,
"valid_routing_number": true
},
"version": "v3"
}
},
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": true,
"message": "The bank account was created and attached successfully.",
"data": {
"bank_account": {
"aggregator_type": "manual",
"uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6",
"is_default": true,
"account_number": "********1234",
"routing_number": "*****6789",
"account_name": "John Doe",
"account_type": "checking",
"timestamps": {
"created_at": "2024-06-25 13:57:03"
}
},
"account_intelligence": {
"confidence_score": 0.81,
"decisioning_insights": {
"account_duplicate": false,
"days_since_first_seen": -1,
"days_since_last_transaction": -1,
"has_negative_transactions": false,
"has_paid_transactions": false,
"has_positive_transactions": true,
"name_match": "yes",
"phone_number_present": false,
"valid_routing_number": true
},
"version": "v3"
}
},
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Invalid Parameters Received",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Invalid token.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "This person is not available as they have been scheduled for deletion.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "No person was found matching that UUID.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "The request cannot be executed due to a detected conflict with a duplicate request.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "The given data was invalid.",
"data": null,
"errors": {
"person.first_name": [
"The first name must be a string.",
"The first name may not be greater than 56 characters."
],
"person.last_name": [
"The last name must be a string.",
"The last name may not be greater than 56 characters."
],
"billing_merchant_uuid": [
"The billing merchant UUID must be a valid UUID.",
"The billing merchant UUID does not exist.",
"The billing merchant UUID is deleted and cannot be used for billing purposes."
],
"billing_processor_mid": [
"The billing processor MID must be a string.",
"The billing processor MID does not exist.",
"The billing processor MID is deleted and cannot be used for billing purposes."
],
"bank_account": [
"The bank account field is required.",
"You cannot provide both plaid details and manual bank account fields.",
"This person did not meet the confidence score threshold of 0.5 and has been rejected.",
"Invalid plaid account ID or access token.",
"The bank routing number is not valid."
],
"bank_account.plaid_account_id": [
"The plaid account ID is required when plaid account details is present.",
"The plaid account ID must be a string."
],
"bank_account.plaid_access_token": [
"The plaid access token is required when plaid account details is present.",
"The plaid access token must be a string."
],
"bank_account.account_number": [
"The bank account number is required when any manual bank account field is provided.",
"The bank account number must be a string.",
"The bank account number may not be greater than 17 characters."
],
"bank_account.routing_number": [
"The bank routing number is required when any manual bank account field is provided.",
"The bank routing number must be 9 digits."
],
"bank_account.account_name": [
"The bank account name is required when any manual bank account field is provided.",
"The bank account name must be a string.",
"The bank account name may not be greater than 255 characters."
],
"bank_account.account_type": [
"The bank account type is required when any manual bank account field is provided.",
"The bank account type must be one of the followings: savings, checking"
],
"actions.account_intelligence": [
"The person first and last name are required when name match is true.",
"Name Match is only available when using Account Intelligence Version 3. Please update your request and try again."
],
"actions.account_intelligence.version": [
"The version is required when account intelligence is present.",
"The version must be a string.",
"The version must be one of the followings: v1, v2, v3"
],
"actions.account_intelligence.name_match": [
"The name match field must be true or false."
]
},
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Something went wrong on our side. Please contact support.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}Bank Accounts
Add a new bank account to a person. ( STABLE )
This endpoint allows for adding a new Bank Account to the GrailPay ACH API Ecosystem. The only item that is required is the Bank Account object. When including the bank account, you can pass either Plaid information or account and routing information. You should never pass both.
POST
/
api
/
v3
/
people
/
{uuid}
/
bank-accounts
Add a new bank account to a person. ( STABLE )
curl --request POST \
--url https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"person": {
"first_name": "John",
"last_name": "Doe"
},
"billing_merchant_uuid": "6a8fc154-1a50-483b-a690-fd1dfaf9408b",
"billing_processor_mid": "12345678",
"bank_account": {
"plaid_account_id": "<string>",
"plaid_access_token": "<string>",
"account_number": "9876543210",
"routing_number": "021000021",
"account_name": "John Doe",
"account_type": "checking"
},
"actions": {}
}
'import requests
url = "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts"
payload = {
"person": {
"first_name": "John",
"last_name": "Doe"
},
"billing_merchant_uuid": "6a8fc154-1a50-483b-a690-fd1dfaf9408b",
"billing_processor_mid": "12345678",
"bank_account": {
"plaid_account_id": "<string>",
"plaid_access_token": "<string>",
"account_number": "9876543210",
"routing_number": "021000021",
"account_name": "John Doe",
"account_type": "checking"
},
"actions": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
person: {first_name: 'John', last_name: 'Doe'},
billing_merchant_uuid: '6a8fc154-1a50-483b-a690-fd1dfaf9408b',
billing_processor_mid: '12345678',
bank_account: {
plaid_account_id: '<string>',
plaid_access_token: '<string>',
account_number: '9876543210',
routing_number: '021000021',
account_name: 'John Doe',
account_type: 'checking'
},
actions: {}
})
};
fetch('https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'person' => [
'first_name' => 'John',
'last_name' => 'Doe'
],
'billing_merchant_uuid' => '6a8fc154-1a50-483b-a690-fd1dfaf9408b',
'billing_processor_mid' => '12345678',
'bank_account' => [
'plaid_account_id' => '<string>',
'plaid_access_token' => '<string>',
'account_number' => '9876543210',
'routing_number' => '021000021',
'account_name' => 'John Doe',
'account_type' => 'checking'
],
'actions' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts"
payload := strings.NewReader("{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.grailpay.com/api/v3/people/{uuid}/bank-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"person\": {\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"billing_merchant_uuid\": \"6a8fc154-1a50-483b-a690-fd1dfaf9408b\",\n \"billing_processor_mid\": \"12345678\",\n \"bank_account\": {\n \"plaid_account_id\": \"<string>\",\n \"plaid_access_token\": \"<string>\",\n \"account_number\": \"9876543210\",\n \"routing_number\": \"021000021\",\n \"account_name\": \"John Doe\",\n \"account_type\": \"checking\"\n },\n \"actions\": {}\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"message": "This bank account already exists for this person. We have attached it as the default bank account.",
"data": {
"bank_account": {
"aggregator_type": "manual",
"uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6",
"is_default": true,
"account_number": "********1234",
"routing_number": "*****6789",
"account_name": "John Doe",
"account_type": "checking",
"timestamps": {
"created_at": "2024-06-25 13:57:03"
}
},
"account_intelligence": {
"confidence_score": 0.81,
"decisioning_insights": {
"account_duplicate": false,
"days_since_first_seen": -1,
"days_since_last_transaction": -1,
"has_negative_transactions": false,
"has_paid_transactions": false,
"has_positive_transactions": true,
"name_match": "yes",
"phone_number_present": false,
"valid_routing_number": true
},
"version": "v3"
}
},
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": true,
"message": "The bank account was created and attached successfully.",
"data": {
"bank_account": {
"aggregator_type": "manual",
"uuid": "9b97f121-a449-4b52-9f36-6c55f18394d6",
"is_default": true,
"account_number": "********1234",
"routing_number": "*****6789",
"account_name": "John Doe",
"account_type": "checking",
"timestamps": {
"created_at": "2024-06-25 13:57:03"
}
},
"account_intelligence": {
"confidence_score": 0.81,
"decisioning_insights": {
"account_duplicate": false,
"days_since_first_seen": -1,
"days_since_last_transaction": -1,
"has_negative_transactions": false,
"has_paid_transactions": false,
"has_positive_transactions": true,
"name_match": "yes",
"phone_number_present": false,
"valid_routing_number": true
},
"version": "v3"
}
},
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Invalid Parameters Received",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Invalid token.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "This person is not available as they have been scheduled for deletion.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "No person was found matching that UUID.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "The request cannot be executed due to a detected conflict with a duplicate request.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "The given data was invalid.",
"data": null,
"errors": {
"person.first_name": [
"The first name must be a string.",
"The first name may not be greater than 56 characters."
],
"person.last_name": [
"The last name must be a string.",
"The last name may not be greater than 56 characters."
],
"billing_merchant_uuid": [
"The billing merchant UUID must be a valid UUID.",
"The billing merchant UUID does not exist.",
"The billing merchant UUID is deleted and cannot be used for billing purposes."
],
"billing_processor_mid": [
"The billing processor MID must be a string.",
"The billing processor MID does not exist.",
"The billing processor MID is deleted and cannot be used for billing purposes."
],
"bank_account": [
"The bank account field is required.",
"You cannot provide both plaid details and manual bank account fields.",
"This person did not meet the confidence score threshold of 0.5 and has been rejected.",
"Invalid plaid account ID or access token.",
"The bank routing number is not valid."
],
"bank_account.plaid_account_id": [
"The plaid account ID is required when plaid account details is present.",
"The plaid account ID must be a string."
],
"bank_account.plaid_access_token": [
"The plaid access token is required when plaid account details is present.",
"The plaid access token must be a string."
],
"bank_account.account_number": [
"The bank account number is required when any manual bank account field is provided.",
"The bank account number must be a string.",
"The bank account number may not be greater than 17 characters."
],
"bank_account.routing_number": [
"The bank routing number is required when any manual bank account field is provided.",
"The bank routing number must be 9 digits."
],
"bank_account.account_name": [
"The bank account name is required when any manual bank account field is provided.",
"The bank account name must be a string.",
"The bank account name may not be greater than 255 characters."
],
"bank_account.account_type": [
"The bank account type is required when any manual bank account field is provided.",
"The bank account type must be one of the followings: savings, checking"
],
"actions.account_intelligence": [
"The person first and last name are required when name match is true.",
"Name Match is only available when using Account Intelligence Version 3. Please update your request and try again."
],
"actions.account_intelligence.version": [
"The version is required when account intelligence is present.",
"The version must be a string.",
"The version must be one of the followings: v1, v2, v3"
],
"actions.account_intelligence.name_match": [
"The name match field must be true or false."
]
},
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}{
"status": false,
"message": "Something went wrong on our side. Please contact support.",
"data": null,
"errors": null,
"request_id": "2d6a4c39-8fcf-4d80-9189-b4764eac31f2"
}Authorizations
Token-based authentication using Authorization: Bearer <YOUR_API_KEY> provided by the GrailPay Support Team.
Path Parameters
UUID of the person
Example:
"7c41f6a2-a4b9-4df8-9225-2c1b7312042e"
Body
application/json
Response
The response returned from a successful call to add a bank account.
⌘I
