Risk Intelligence API Changelog
2026.11.2.1
Section titled “2026.11.2.1”What’s new:
Section titled “What’s new:”Every operation in the Risk Intelligence API reference now has a short title, with the fuller explanation moved into the operation’s description.
Why it matters:
Section titled “Why it matters:”The reference reads as a list of operations, such as “Validate account”, “Get access token” and “Create guarantee”, rather than a list of sentences, and the detail that used to sit in the title is still there as the description beneath it.
Highlights:
Section titled “Highlights:”- Titles are a few words long, for example “Validate account”, “Submit account feedback” and “Cancel guarantee”; the previous sentence-length titles become each operation’s description
- The API itself is unchanged: this release touches the OpenAPI document only
2026.10.19.1
Section titled “2026.10.19.1”What’s new:
Section titled “What’s new:”Account Intelligence Lite responses now carry a live flag that tells a live result from a
test one, and Lite and Standard requests are billed separately.
Why it matters:
Section titled “Why it matters:”live shows an integrator whether a result came from the live production path, which a
reserved test routing number or a sandbox call never does, so test traffic can be told apart
from real traffic in the client’s own records. Billing by version means a client is charged
for the version it requests.
Highlights:
Section titled “Highlights:”- Lite
200responses fromPOST /api/v3/accounts/validateincludelive: in production,truefor a real routing number andfalsefor a Lite test number; in the sandbox and every other environment, alwaysfalse. Standard responses and error responses do not include it - Standard requests on v3 and v2 are billed as Standard validations and Lite requests as Lite validations; test routing numbers,
999999999and requests that never reach a data provider are not billed, and name match and taxpayer number match billing is unchanged - The Lite test routing numbers,
999999999and all Standard behavior are unchanged
2026.10.9.1
Section titled “2026.10.9.1”What’s new:
Section titled “What’s new:”POST /api/v3/accounts/validate gains an Account Intelligence Lite version. Sending
actions.version: lite returns a Lite response, a simple valid verdict with supplemental
reason codes, instead of a confidence score and decisioning insights.
Why it matters:
Section titled “Why it matters:”Lite is a lighter validation for integrators that need a likely, unlikely or indeterminate
answer rather than a score and insights. Its test routing numbers work in production as well as
in the sandbox, so an integration can be verified end to end in either environment. Requests
that omit actions.version are unchanged.
Highlights:
Section titled “Highlights:”actions.versionacceptsliteorstandard; omitting it meansstandard, and any other value returns422. A Lite request withactions.name_matchoractions.taxpayer_number_matchset to true returns422- A Lite response carries
valid(likely,unlikelyorindeterminate) andsupplemental_data.codes, an array of{code, description}objects that is empty when no code applies; it never carriesconfidence_scoreordecisioning_insights - Lite test routing numbers, valid in both sandbox and production:
000000100likely;000000101unlikely, invalid input format;000000102unlikely, invalid routing number;000000103unlikely, invalid account number format;000000104unlikely, account number not eligible for ACH;000000106indeterminate, no account information found;000000107unlikely, potential risk indicator;000000108likely, frequently observed active account;999999999simulated service outage - The OpenAPI document shows both the Standard and the Lite response
2026.10.1.1
Section titled “2026.10.1.1”What’s new:
Section titled “What’s new:”POST /api/v3/accounts/validate now honors X-Idempotency-Key per client and per request
body: the first response for a key is stored, a retry with the same key and body returns it,
and the same key with a different body is refused. The guarantee feedback endpoint is now
documented in the OpenAPI document.
Why it matters:
Section titled “Why it matters:”A client that retries an account validation after a timeout receives the original result and
is not billed a second time, including for name match and taxpayer number match, and a key
cannot be reused for a different account by mistake. Generated clients can now be built for
POST /api/v3/guarantees/{guarantee_id}/feedback from the published document.
Highlights:
Section titled “Highlights:”- On
POST /api/v3/accounts/validate, the stored response for anX-Idempotency-Keyis scoped to the authenticated client and the request body; a retry with the same key and body replays the first response and records no additional billing - The same key with a different body returns
409with{"error": "Idempotency key reused with a different request body"}; requests without the header behave as before POST /api/v3/guarantees/{guarantee_id}/feedbackis documented in the OpenAPI document with its request, header and error contract
2026.9.1.1
Section titled “2026.9.1.1”What’s new:
Section titled “What’s new:”The OpenAPI document now describes the Account Intelligence v3 response in full: every
decisioning_insights field is listed with its type, allowed values and an example, and the
request documents the bank_account, actions and location objects clients send.
Why it matters:
Section titled “Why it matters:”Generated clients and validators built from the document will match real
POST /api/v3/accounts/validate responses, where the insights object was previously shown as
empty, and the request schema shows the nested shape the API accepts.
Highlights:
Section titled “Highlights:”- The
200response schema forPOST /api/v3/accounts/validatelists eachdecisioning_insightsfield with types, enums (includingname_matchandtaxpayer_number_match) and example values, alongsideconfidence_score - The request schema documents
bank_account,actionsandlocation(address,ip_addressandgps)
2026.8.26.1
Section titled “2026.8.26.1”What’s new:
Section titled “What’s new:”Guarantee feedback is now submitted against the guarantee’s id:
POST /api/v3/guarantees/{guarantee_id}/feedback replaces
POST /api/v3/transactions/guarantees/feedback, which now returns 404. The body no longer
carries inference_request_id, and the response returns guarantee_id.
Why it matters:
Section titled “Why it matters:”This is a breaking change for feedback integrations, and it completes the move to one identity
for a guarantee: the id from the create response is the key for both cancellation and
feedback. Feedback is accepted for both guarantee and no_guarantee decisions, and a
cancelled guarantee still accepts feedback, since outcome_status: "cancelled" describes the
transaction rather than the guarantee.
Highlights:
Section titled “Highlights:”POST /api/v3/guarantees/{guarantee_id}/feedbacktakes the same event fields as before (client_reference_id,client_originated,client_guarantee_applied,outcome_status,outcome_observed_at,noc_receivedand the conditional return and NOC fields) and a uniqueX-Idempotency-Keyper event;inference_request_idis not accepted in the body200returnsguarantee_id,client_reference_id,status(recordedfor the first event on a guarantee,updatedfor later ones) andreceived_at409for a reusedX-Idempotency-Keyor an event whoseclient_originatedorclient_guarantee_applieddiffers from the first event;404for an unknownguarantee_id, another client’s guarantee or one without a decision;422for validation errors, includingclient_guarantee_applied: trueon ano_guaranteedecisionPOST /api/v3/transactions/guarantees/feedbackreturns404
2026.8.25.1
Section titled “2026.8.25.1”What’s new:
Section titled “What’s new:”The sandbox test routing numbers now work on the receivable guarantee endpoint, and the cancellation endpoint is documented in the OpenAPI document.
Why it matters:
Section titled “Why it matters:”A sandbox integration can obtain a guarantee and a no_guarantee decision deterministically,
and exercise the unavailable path, without depending on live decisioning rules. A guarantee
created with the approved test number has a real id, so cancellation can be tested against
it too. Any other routing number takes the live path, and production never stubs.
Highlights:
Section titled “Highlights:”- In the sandbox,
POST /api/v3/guarantees/receivablewithpayer.bank_account.routing_number000000001returnsdecision: guaranteewith a cancellableid,000000002returnsdecision: no_guarantee, and999999999returns503with the message “Service temporarily unavailable. Guarantee decisioning is currently experiencing a disruption. Please retry your request later.” - The request is validated in full before a test number is matched, and any other valid routing number is evaluated live
POST /api/v3/guarantees/{guarantee_id}/cancelis documented in the OpenAPI document with its200,401,404and409responses
2026.8.24.1
Section titled “2026.8.24.1”What’s new:
Section titled “What’s new:”The guarantee API has a new request contract and new paths. A receivable guarantee is created
with POST /api/v3/guarantees/receivable, the create response returns the guarantee’s id
alongside the decision, and that id is what a cancellation now references:
POST /api/v3/guarantees/{id}/cancel. The former POST /api/v3/transactions/guarantees path
returns 404.
Why it matters:
Section titled “Why it matters:”This is a breaking change for every guarantee integration. The request is reorganized around
payer, payee and transaction with nested bank accounts, tax_id in place of the SSN and
EIN fields, line_1 and postal_code address fields, and the amount in cents; a request in
the old shape is rejected. Clients must store the id from the create response to cancel,
since cancellation by request ID is gone. Feedback continues to work for guarantees created on
the old path.
Highlights:
Section titled “Highlights:”POST /api/v3/guarantees/receivabletakespayer,payeeandtransactionand returns200withid(a UUID) anddecision(guaranteeorno_guarantee)payercarriesbank_account(account_number,routing_number); exactly one ofindividual(first_name,last_name,email,phone;middle_name,prefix,suffixandtax_idoptional) ororganization(name,alternate_name,email,phone;tax_idoptional);locationwithip_addressand anaddress(line_1,city,state,postal_code,country_code;line_2andline_3optional); and the behavioral fieldsaccount_opened_at,user_total_spent_prior(cents),user_transaction_count_prior,is_first_time_user,device_id,source(mobile_app_ios,mobile_app_android,web,subscriptionorother) andas_of_timestamppayeecarriesbank_account,organization(business_name,trading_name,email,phone,tax_id;incorporation_state,industryandbusiness_emailoptional),locationin the same shape as the payer’s, andbeneficial_ownerswith at least one owner (first_name,last_name,email,phone,dob,tax_id,address;middle_name,prefix,suffix,is_account_ownerandis_significant_control_personoptional)transactioncarriesamountin cents (greater than zero),sec_code(WEB,CCDorPPD) andcreated_date;speed(standardorsame_day, defaultstandard) andclient_reference_idare optional. An amount of $10,000.00 or more is answeredno_guaranteePOST /api/v3/guarantees/{id}/cancelcancels a guarantee withdecision: guaranteewithin 15 minutes of issuance;404for an unknownid, another client’s guarantee or ano_guaranteedecision, and409when already cancelled or outside the windowPOST /api/v3/transactions/guaranteesand cancellation by request ID are removed and return404
2026.8.11.1
Section titled “2026.8.11.1”What’s new:
Section titled “What’s new:”Request validation now behaves the same way on every endpoint. A request that fails validation
returns 422 with a message and an errors map keyed by field, and the rules behind it have
been aligned across account validation, account feedback, verify account and routing, the
transaction risk score and the guarantee endpoints. The party object on the transaction risk
score and guarantee requests is payor only, a guarantee can be cancelled only within 15
minutes of being issued, and GET / on the API host now returns a small JSON status payload.
Why it matters:
Section titled “Why it matters:”Integrators that parse validation errors should expect one shape everywhere: HTTP 422, a
top-level message, and errors as an object whose keys are field paths such as
payor.address.zip and whose values are arrays of messages. Malformed values are rejected
before any data provider is called, with the offending field named. The payer spelling is
not accepted as an alias for payor, and a cancellation attempted more than 15 minutes after
the guarantee was issued returns 409.
Highlights:
Section titled “Highlights:”- Validation failures on every endpoint return
422with{"message": "...", "errors": {"field": ["..."]}}; v1 and v2 verify account and routing requests with a non-numeric account number or a routing number that is not exactly 9 digits now fail validation rather than returning a result POST /v1/transactions/score/arandPOST /api/v3/transactions/guaranteesaccept the party object aspayoronly; a body that sendspayeris rejected- Phone numbers must be exactly 10 digits,
ssn9values must be a valid SSN or ITIN, routing numbers exactly 9 digits, and postal codes 5 digits, 9 digits or ZIP+4 (5 digits on the transaction risk score); these are checked before any provider is called POST /api/v3/accounts/validatevalidateslocation.ip_address, requireslocation.gpscoordinates, when present, to fall within the continental United States, and requires anidentity.individualoridentity.organizationobject, when present, to carry its fieldsPOST /api/v3/accounts/feedbackaccepts onlyreturned,unexpected_returnorotherasoutcome_status- On
POST /api/v3/transactions/guarantees,payee.beneficial_ownersis required (it may be empty) and each owner’sssn9is validated as an SSN or ITIN POST /api/v3/transactions/guarantees/feedbackrequiresinference_request_idto be a UUID, requiresoutcome_observed_at,returned_atandnoc_received_atto carry a timezone, and validates the return and NOC fields againstoutcome_statusandnoc_receivedPOST /api/v3/transactions/guarantees/{request_id}/cancelsucceeds only within 15 minutes of the guarantee being issued; later attempts return409GET /on the API host returns{"status": "ok", "documentation": "...", "request_id": "..."}, with the request ID also in theX-RI-Request-IDheader
2026.07.15
Section titled “2026.07.15”What’s new:
Section titled “What’s new:”Transaction guarantees now have a hard amount limit. A guarantee request for a transaction
strictly above $10,000.00 is answered no_guarantee without being sent to the decisioning
service; a transaction of exactly $10,000.00 is still evaluated. Separately, the three
guarantee endpoints have been removed from the public OpenAPI document served at /spec and
/spec-api; they remain available and unchanged.
Why it matters:
Section titled “Why it matters:”Integrators submitting large transactions should expect no_guarantee above the limit rather
than a decision based on the transaction’s risk. The limit is a placeholder that GrailPay
expects to revise. Tooling that reads the OpenAPI document will stop seeing the guarantee,
cancel and feedback endpoints, so generated clients for those endpoints should be kept rather
than regenerated.
Highlights:
Section titled “Highlights:”POST /api/v3/transactions/guaranteesreturnsno_guaranteefor anytransaction.amountstrictly above $10,000.00; the request’s provider data is still collected and retained, and amounts of exactly $10,000.00 are evaluated as before/api/v3/transactions/guarantees,/api/v3/transactions/guarantees/feedbackand/api/v3/transactions/guarantees/{request_id}/canceland their schemas are no longer in the public OpenAPI document; the endpoints themselves are unchanged
2026.07.10
Section titled “2026.07.10”What’s new:
Section titled “What’s new:”The guarantee request’s payer object is now validated strictly: every payer field is
required apart from a few optional identity fields, unknown keys are rejected, and timestamps
must carry a timezone. When a data provider the guarantee depends on is unavailable, the
endpoint answers with an error and no decision. On account validation, the identity details
passed to the matching provider are limited to what the requested actions need, and name
fields are trimmed of surrounding whitespace, with whitespace-only names rejected.
Why it matters:
Section titled “Why it matters:”A guarantee decision depends on a complete, well-formed payer profile, so the contract now
fails loudly on a missing or misspelled field instead of degrading the decision silently.
Integrators calling the guarantee endpoint should check their payloads against the required
list below before upgrading. A 500 from the guarantee endpoint during a provider outage
carries no partial or fabricated decision; the request should be retried later. Account
validation requests that only ask for name_match no longer have their SSN, contact details or
address used for the name check, which makes name_match results depend on the name alone.
Highlights:
Section titled “Highlights:”- On
POST /api/v3/transactions/guarantees,payerrequiresname(2–100 characters),email,phone,account_number,routing_number,address(street_1,street_2,city,state,zip),identity,location(addressandip_address) andmetadatawith all six of its fields; onlyidentity.individual.ssn,middle_name,prefixandsuffixandidentity.organization.einare optional identitymust contain exactly one ofindividual(first_name,last_name,email,phone_number,device_id) ororganization(name,alternate_name,email,phone_number,device_id)- An unknown or misspelled key anywhere in
payerreturns400naming the key;metadata.account_opened_atandmetadata.as_of_timestampmust be ISO-8601 timestamps with an explicit offset - When a required data provider cannot be reached during a guarantee evaluation, the endpoint returns
500with a “service temporarily unavailable, please try again later” message and no decision - For
POST /api/v3/accounts/validate, aname_matchrequest sends only the name to the identity provider;taxpayer_number_matchadds the SSN or EIN; contact details and address are not sent in either case - Leading and trailing whitespace is trimmed from name fields (
payor.name, the individual’sfirst_name,last_name,middle_name,prefixandsuffix, the organization’snameandalternate_name, and the payee’sbusiness_name,trading_nameand beneficial owner names), and a value that is only whitespace is rejected
2026.6.24
Section titled “2026.6.24”What’s new:
Section titled “What’s new:”Authentication failures now return one uniform response, 401 with
{"message": "Unauthorized"}, whether the token is missing, malformed, expired or revoked.
The token endpoints are rate limited per client, every response carries a standard set of
security headers, and provider results used for guarantee decisions are reused for up to 15
days.
Why it matters:
Section titled “Why it matters:”Clients that branch on authentication errors can rely on one status code and one message key:
message is the key every other error on the API uses. POST /v1/auth and
POST /v1/auth/refresh reject bursts of requests with 429 and a Retry-After header, so a
token should be obtained once and reused rather than requested per call. For guarantees, a
repeat request for the same payer within 15 days reuses the provider data gathered the first
time, while account validation keeps its 90-day window.
Highlights:
Section titled “Highlights:”- Every authentication failure returns
401with{"message": "Unauthorized"}; the detailed reason is kept in GrailPay’s logs only POST /v1/authallows 10 requests per minute andPOST /v1/auth/refresh20 per minute from one client address; requests over the limit receive429withRetry-After- Responses include
Strict-Transport-Security,X-Content-Type-Options,Content-Security-Policy,X-Frame-Options,Referrer-Policy,Permissions-Policy,Cross-Origin-Opener-PolicyandCross-Origin-Resource-Policyheaders - Provider results gathered for a guarantee decision are cached for 15 days; results gathered for account validation keep their 90-day cache
2026.6.8
Section titled “2026.6.8”What’s new:
Section titled “What’s new:”Clients can now report what they did with a guarantee decision and how the transaction turned
out. A new POST /api/v3/transactions/guarantees/feedback endpoint records, per guarantee
request, whether the transaction was originated, whether GrailPay’s guarantee was applied, and
the observed outcome, including return and Notification of Change details.
Why it matters:
Section titled “Why it matters:”Feedback closes the loop between a decision and the real-world result, and helps GrailPay measure
and improve its decisions and reconcile billing. A transaction can produce several feedback events
over its life, for example settled and later returned, each sent as its own event. The
original decision is read from GrailPay’s own record of the request, so the client never sends
it. Feedback does not change real-time decisioning.
Highlights:
Section titled “Highlights:”POST /api/v3/transactions/guarantees/feedbackrequires theX-Idempotency-Keyheader, one unique key per feedback event, and a body withinference_request_id(the guarantee request’s ID),client_reference_id,client_originated,client_guarantee_applied,outcome_status,outcome_observed_atandnoc_receivedoutcome_statusis one ofnot_originated,originated,settled,returned,cancelledorfailed_processing; areturnedoutcome also requiresreturn_codeandreturned_at- When
noc_receivedis true,noc_codeandnoc_received_atare required andnoc_reasonis optional 200returnsinference_request_id,client_reference_id,received_atandstatus:recordedfor the first event for a guarantee request,updatedfor each later one400for a validation error, an unknown field, a timestamp without a timezone, or a missing idempotency key;404for a request ID with no prior guarantee by this client;409for a reused idempotency key or a later event that contradicts an earlier one;503if the event could not be stored
2026.5.28
Section titled “2026.5.28”What’s new:
Section titled “What’s new:”The taxpayer_number_match result on Account Intelligence v3 can now be close_match, and a
new sandbox routing number exercises it. The guarantee cancellation response is simplified:
the cancelled guarantee’s ID is returned as cancelled_request_id, and the status field is
removed.
Why it matters:
Section titled “Why it matters:”close_match reports a partial taxpayer identifier match that was previously reported as
not_available, so an integrator that switches on taxpayer_number_match needs a case for
it. The cancellation change is breaking for code that reads request_id or status from the
cancel response body: the per-call request ID is in the X-RI-Request-ID header, and
cancelled: true is the confirmation.
Highlights:
Section titled “Highlights:”decisioning_insights.taxpayer_number_matchonPOST /api/v3/accounts/validateaccepts a fourth value,close_match, alongsideyes,noandnot_available; a value the API does not recognize is reported asnot_available- Sandbox routing number
000000004returns200withconfidence_score: 0.65,taxpayer_number_match: "close_match",name_match: "not_available"andname_match_score: 0.0; the other sandbox numbers are unchanged POST /api/v3/transactions/guarantees/{request_id}/cancelreturnscancelled_request_id,cancelledandcancelled_at; the body does not includerequest_idorstatus
2026.5.22
Section titled “2026.5.22”What’s new:
Section titled “What’s new:”In the sandbox, every transaction guarantee request is now evaluated by the live decisioning
service and returns a real decision; the guarantee endpoint is not stubbed for any routing
number. The sandbox documentation for Account Intelligence v3 now lists the
name_match_score each test routing number returns.
Why it matters:
Section titled “Why it matters:”A sandbox integration of the guarantee endpoint exercises the same decisioning path as production, even when a request uses the account validation test routing numbers, so what a client sees in the sandbox is a genuine decision. The account validation test numbers keep the same outcomes as before, and the score each one returns is now documented.
Highlights:
Section titled “Highlights:”POST /api/v3/transactions/guaranteesis not stubbed in the sandbox: any request with all required fields is routed to the live guarantee decisioning service- Sandbox
name_match_scorevalues forPOST /api/v3/accounts/validate:0.98for000000001,0.0for000000002and0.14for000000003;taxpayer_number_matchfor those numbers isyes,not_availableandno
2026.5.19
Section titled “2026.5.19”What’s new:
Section titled “What’s new:”Transaction guarantees are available on the Risk Intelligence API.
POST /api/v3/transactions/guarantees evaluates a payer, a payee and a transaction and answers
with a single decision, guarantee or no_guarantee, and
POST /api/v3/transactions/guarantees/{request_id}/cancel withdraws a guarantee that was
issued.
Why it matters:
Section titled “Why it matters:”A guarantee decision means GrailPay takes on the balance sheet risk for that transaction,
and cancelling the guarantee removes it. The response is deliberately minimal: it carries no
scores, provider output or decisioning insights, and the request ID an integrator needs for a
later cancellation comes from the X-RI-Request-ID response header rather than the body.
Highlights:
Section titled “Highlights:”POST /api/v3/transactions/guaranteestakespayer,payeeandtransactionobjects and returns200with{ "decision": "guarantee" }or{ "decision": "no_guarantee" }; the request’s ID is in theX-RI-Request-IDheader, and the optionalX-Idempotency-Keyheader is supportedpayerrequiresaccount_numberandrouting_number;name,email,phone(10 digits),address,identity,locationand ametadataobject are optional.metadatacarries client-side signals about the payer:account_opened_at,user_total_spent_prior(in cents),user_transaction_count_prior,is_first_time_user,sourceandas_of_timestamppayeeaccepts an optionalbusiness.email, a business email distinct from the contact emailtransactionrequiresamount(in dollars, a decimal number greater than zero),sec_code(WEB,CCDorPPD),direction(debitorpayout) anddate;speed(standardorsame_day) andclient_reference_idare optional- A validation error returns
400with field-level errors, and503is returned when the decisioning service is unavailable POST /api/v3/transactions/guarantees/{request_id}/cancelreturns200withrequest_id,status: "cancelled",cancelled: trueandcancelled_at; a guarantee that is already cancelled returns409, and an unknown request ID, including one issued to another client, returns404- In the sandbox at this release, a payer routing number of
000000002returns a declined guarantee,999999999returns service unavailable, and any other valid routing number returns an approved guarantee
2026.4.29
Section titled “2026.4.29”What’s new:
Section titled “What’s new:”The sandbox test routing numbers for Account Intelligence v3 now work on the v1 and v2 endpoints as well, returning each version’s own response shape, and they are documented on those endpoints in the OpenAPI document.
Why it matters:
Section titled “Why it matters:”Integrators choose v1, v2 or v3 of Account Intelligence through the Payments API, so the same test numbers now produce a known outcome whichever version is in use, and a sandbox test can cover every supported version consistently.
Highlights:
Section titled “Highlights:”POST /v1/verify-account-routingin the sandbox:000000001returns200withresult: "valid",000000002withresult: "invalid",000000003withresult: "not_validated"; an empty or missingrouting_numberreturns400, and999999999returns503- The v2 verify account and routing endpoint accepts the same numbers:
000000001returns200withrisk_score: 0.90andconfidence_level: "very_high",000000002withrisk_score: 0.55andconfidence_level: "medium",000000003withrisk_score: 0.15andconfidence_level: "very_low"
2026.4.28
Section titled “2026.4.28”What’s new:
Section titled “What’s new:”The Account Intelligence v3 response now includes decisioning_insights.name_match_score, a
normalized name match confidence between 0.0 and 1.0. The API also serves browser-based
clients: cross-origin requests receive CORS headers and preflight OPTIONS requests are
answered, so the API can be called from the OpenAPI document’s “Execute” control and from other
browser-side tooling.
Why it matters:
Section titled “Why it matters:”name_match_score gives the degree of confidence behind the yes, no or not_available in
name_match, so an integrator can apply its own threshold. It is only meaningful when a name
match was requested: otherwise name_match is not_available and the score is 0.0. With
CORS in place, a request made from a browser receives the body, status and headers the same way
a server-side call does.
Highlights:
Section titled “Highlights:”decisioning_insights.name_match_scoreis a float from 0.0 to 1.0, rounded to two decimals; it is0.0when name match was not requested or no score is available, and the OpenAPI document describes itname_matchandname_match_scoreare populated only whenactions.name_matchis requested; otherwisename_matchisnot_available- Preflight
OPTIONSrequests are answered, theAuthorization,Content-TypeandX-Idempotency-Keyrequest headers are allowed, andX-RI-Request-ID,Retry-Afterand the rate limit headers are exposed to browser clients
2026.4.20
Section titled “2026.4.20”What’s new:
Section titled “What’s new:”The Account Intelligence v3 response now reports the taxpayer number match result. A new
decisioning_insights.taxpayer_number_match field uses the same yes, no and
not_available values as name_match, and name_match itself is now limited to those three
values.
Why it matters:
Section titled “Why it matters:”An integrator that requests taxpayer_number_match can read the outcome from the response next
to the name match result, and both fields have a closed set of values to switch on. A match that
was not requested, or for which no data is available, is reported as not_available rather
than omitted, in the sandbox as well as in production.
Highlights:
Section titled “Highlights:”decisioning_insights.taxpayer_number_matchis included in the v3 account validation response, with valuesyes,noornot_availabledecisioning_insights.name_matchis standardized toyes,noornot_available- Both fields are
not_availablewhen the matching data is unavailable - In the sandbox, the test routing numbers return
taxpayer_number_matchofyesfor000000001,not_availablefor000000002andnofor000000003, and a positive match is returned only when the corresponding action was requested
2026.4.14
Section titled “2026.4.14”What’s new:
Section titled “What’s new:”The tin_match action on Account Intelligence v3 is renamed taxpayer_number_match, so that
the name covers Social Security numbers as well as EINs. The OpenAPI document now gives
POST /api/v3/accounts/validate an explicit 429 Too Many Requests response with a
Retry-After header, and shows separate request examples for an individual and for an
organization identity.
Why it matters:
Section titled “Why it matters:”An integration sending actions.tin_match must switch to actions.taxpayer_number_match; the
rest of the request is unchanged, and identity.individual.ssn or identity.organization.ein
is still required when it is true. A rate-limited request should be retried after the interval
in Retry-After, which the API preserves on every 429. The split examples make clear that a
request carries exactly one of identity.individual and identity.organization.
Highlights:
Section titled “Highlights:”actions.tin_matchis replaced byactions.taxpayer_number_matchonPOST /api/v3/accounts/validate;identity.individual.ssnoridentity.organization.einis required when it is truePOST /api/v3/accounts/validatedocuments a429response carryingRetry-AfterandX-RI-Request-ID, and a rate-limited response keeps theRetry-Aftervalue the API sets- The OpenAPI document shows an individual-identity and an organization-identity request example, since only one of the two identity objects may be sent
2026.3.26.1
Section titled “2026.3.26.1”What’s new:
Section titled “What’s new:”The sandbox test routing numbers for POST /api/v3/accounts/validate are now documented in the
OpenAPI document. In the sandbox environment the outcome of a v3 account validation depends on
the bank_account.routing_number sent, so each result can be exercised deliberately.
Why it matters:
Section titled “Why it matters:”A sandbox integration can be tested against a known low-risk, medium-risk and high-risk account, a validation error and an unavailable upstream without guessing which values produce which response, and the name match result for each test number is predictable.
Highlights:
Section titled “Highlights:”000000001: low risk, full match;200withconfidence_score: 0.91anddecisioning_insights.name_match: "yes"000000002: medium risk, name not available;200withconfidence_score: 0.53anddecisioning_insights.name_match: "not_available"000000003: high risk, negative history;200withconfidence_score: 0.12anddecisioning_insights.name_match: "no"- An empty or missing
routing_numberreturns400with validation errors, and999999999returns503for an unavailable upstream
2026.3.5
Section titled “2026.3.5”What’s new:
Section titled “What’s new:”Account Intelligence v3 gains a tin_match action that matches a taxpayer identifier for the
account holder: a Social Security number for an individual, or an EIN for an organization.
Every response now carries an X-RI-Request-ID header, and the OpenAPI document lists the
sandbox and production hosts.
Why it matters:
Section titled “Why it matters:”With tin_match, a single account validation request can confirm that the taxpayer identifier
on file belongs to the account holder, and one billable event is recorded for it whether the
identifier is an SSN or an EIN. The request identifier in X-RI-Request-ID is what to quote
when asking GrailPay about a specific call.
Highlights:
Section titled “Highlights:”POST /api/v3/accounts/validateacceptsactions.tin_match; when it is true,identity.individual.ssnoridentity.organization.einis required, and a request without the identifier is rejected with a validation erroridentity.individual.ssnandidentity.organization.einare new request fields;tin_matchrecords one billable event per request regardless of identifier type, and requests withouttin_matchbehave as before- Every response includes an
X-RI-Request-IDheader identifying the request, now documented in the OpenAPI document, which also lists the sandbox and production server URLs
2026.03.03
Section titled “2026.03.03”What’s new:
Section titled “What’s new:”Account Intelligence v2 and v3 now return a service-unavailable response when the risk model cannot produce a valid confidence score for a request.
Why it matters:
Section titled “Why it matters:”A request that cannot be scored is reported as an error rather than as a result, so an integrator can retry it or route it for manual handling instead of treating an empty score as an outcome.
Highlights:
Section titled “Highlights:”- A missing or non-numeric confidence score from the risk model is answered with a service-unavailable response on the v2 and v3 account validation endpoints
2026.02.25
Section titled “2026.02.25”What’s new:
Section titled “What’s new:”The API’s OpenAPI document, served at /spec, is now OpenAPI 3.0.3.
Why it matters:
Section titled “Why it matters:”Tooling that reads the document, such as client generators and validators, should expect the OpenAPI 3 format. Bearer authentication is declared once, and request and response schemas are defined once as shared components rather than repeated under each endpoint.
Highlights:
Section titled “Highlights:”- The OpenAPI document is OpenAPI 3.0.3, with centralized servers, bearer authentication and shared request and response schema components
2026.1.8
Section titled “2026.1.8”What’s new:
Section titled “What’s new:”The Account Intelligence feedback endpoint now validates account_number and
routing_number with the same rules as the validation endpoints, and the v2 account and routing
verification endpoint reports an invalid account or routing number with a clearer message.
Why it matters:
Section titled “Why it matters:”A feedback submission with an account number longer than 17 characters is rejected, so integrators should send the account number as it was validated. Clients that match on the v2 error text should expect “Invalid account or routing number.”
Highlights:
Section titled “Highlights:”POST /api/v3/accounts/feedbacklimitsaccount_numberto 17 characters and validatesaccount_numberandrouting_numberwith the shared account and routing number rules- The v2 verify account and routing endpoint returns the message “Invalid account or routing number.” for an account or routing number that does not pass validation
2026.01.05
Section titled “2026.01.05”What’s new:
Section titled “What’s new:”Clients can now report the real-world outcome of a transaction whose account received an
acceptable Account Intelligence score. A new POST /api/v3/accounts/feedback endpoint records
the account, the outcome and the return code, linked to the original validation request.
Why it matters:
Section titled “Why it matters:”Feedback closes the loop between a score and what happened afterward. GrailPay uses it to monitor model performance and improve risk accuracy over time; it is used for analytics, evaluation and training, not to change the score already returned. Only clients integrated with the Risk Intelligence API can submit feedback, and each record is tied to the authenticated client.
Highlights:
Section titled “Highlights:”POST /api/v3/accounts/feedbackrequiresaccount_number,routing_number,outcome_status,return_codeandname_match_requested, plus eitherinference_request_id(the UUID GrailPay returned) orinference_timestampto identify the original validation- Optional fields:
returned_at,transaction_initiated_at,sec_code,amountanddirection(creditordebit) outcome_statusacceptsreturned,unexpected_returnorother- A valid submission is answered with
200and a confirmation message; submissions are validated, logged and persisted - The endpoint is documented in the OpenAPI document with its request and response schemas
2025.12.30
Section titled “2025.12.30”What’s new:
Section titled “What’s new:”State-changing requests to the Risk Intelligence API can now be made idempotent. Sending an
X-Idempotency-Key header on a POST request stores the response for about 24 hours, and a
repeat of the same request with the same key returns the stored response instead of being
processed again. The API also now reuses results from its underlying data providers for
repeated identical requests.
Why it matters:
Section titled “Why it matters:”A client that retries after a timeout or a dropped connection can do so safely: the retry returns the original response and does not create a second resource or trigger a second evaluation. Reusing provider results means an identical validation request made again within the retention window is answered from the earlier provider result rather than a new call.
Highlights:
Section titled “Highlights:”- Optional
X-Idempotency-Keyheader onPOSTendpoints such as/api/v3/accounts/validateand/v1/transactions/score/ar; the first response is stored for up to 24 hours and later requests with the same method, path and key receive it without reprocessing - Reusing a key on a different endpoint is rejected with
409 Conflict - Responses larger than 1 MB and
5xxresponses are not stored, so those requests are processed again on retry; only a safe subset of response headers, such asContent-Type, is replayed - A request without the header is processed normally, and a key that has expired is treated as new
- Results from the API’s data providers are cached and reused for identical requests for up to 90 days
- The OpenAPI document describes the idempotency header and the
409response
2025.10.3.1
Section titled “2025.10.3.1”Maintenance Items
Section titled “Maintenance Items”- OpenAPI Documentation Updates: Added all the necessary changes to accurately document the Transaction Intelligence endpoint.
2025.10.2
Section titled “2025.10.2”Maintenance Items
Section titled “Maintenance Items”- OpenAPI Documentation Updates:
- Added all the necessary changes to accurately document the V3 Account Intelligence endpoint.
- Marked all of the V1 and V2 Account Intelligence endpoints as deprecated.
Maintained by EkLine

