Proxy Transforms
Pre-configured proxies support two families of transforms:
- Request transforms run on the inbound request before it is forwarded to the destination. Use them to mutate the request body or headers, tokenize incoming data, or short-circuit the request and return a response without contacting the destination.
- Response transforms run on the response from the destination before it is returned to the caller. Use them to mutate the response body or headers, mask sensitive values, tokenize sensitive data, or append additional content.
Transforms are executed in the order specified in the request_transforms and response_transforms arrays on the proxy.
Request Transforms
| Type | Purpose |
|---|---|
code | Run custom Node.js to mutate the request body or headers, inject configuration secrets, or short-circuit and return a response without forwarding to the destination |
tokenize | Create tokens from request data using plaintext, encrypted JWE, or Liquid expressions |
Code Request Transform
Code request transforms run in Basis Theory's serverless runtime environment. The runtime supports two images: node-bt and node22.
- node-bt
- node22
module.exports = async function (req) {
const { bt, args, configuration } = req;
const { body, headers, method, path, query } = args; // access properties of the http request
const { MY_CONFIG } = configuration; // access any static config defined on the Proxy
// do anything here!
const processedBody = ...; // do something with body
const processedHeaders = ...; // do something with headers
return {
body: processedBody, // transformed request body
headers: processedHeaders // transformed request headers
};
};
module.exports = async function (event) {
const { req, configuration, logger, applicationOptions } = event;
const { body, headers, method, path, query } = req; // access properties of the http request
const { MY_CONFIG } = configuration; // access any static config defined on the Proxy
logger.info("Processing request");
// do anything here!
const processedBody = ...; // do something with body
const processedHeaders = ...; // do something with headers
return {
req: {
body: processedBody, // transformed request body
headers: processedHeaders // transformed request headers
}
};
};
What a Code Request Transform Can and Cannot Change
A code request transform can:
- Mutate the request body.
- Mutate the request headers.
- Short-circuit the request and return a response directly without forwarding to the destination — see Skip Proxy Request.
A code request transform cannot:
- Change the destination URL, hostname, path, or query string. These are read-only — the outbound URL is always
destination_urlwith the inbound path suffix appended. - Change the HTTP method.
node-bt Code Contract
Input
The transform function receives a request object containing the HTTP request properties and configuration:
| Attribute | Type | Description |
|---|---|---|
args | object | HTTP request properties (see below) |
configuration | map<string, string> | Configuration values defined on the proxy |
bt | object | Pre-configured Basis Theory SDK instance for token operations (if application.id is set) |
applicationOptions | object | Configuration information about the associated application (if application.id is set) |
applicationOptions.apiKey | string | The API key of the associated application |
applicationOptions.environment | string | The Basis Theory API URL (e.g., https://api.basistheory.com) |
The args object contains the HTTP request properties:
| Attribute | Type | Description |
|---|---|---|
body | object or string | The request body parsed as a JavaScript object when Content-Type is application/json, or string for other content types. |
headers | object | A JavaScript object containing the headers received on the proxy request |
method | string | The HTTP method of the proxy request (e.g., "GET", "POST", "PUT", "PATCH", "DELETE") |
path | string | The path suffix received on the proxy request after /proxy (e.g., a request to /proxy/sub/path?param=value would result in a path of /sub/path) |
query | string | The unparsed query string that was received on the proxy request (e.g., a request to /proxy/sub/path?param=value would result in a query of ?param=value) |
Output
An object of the following type must be returned by the transform function:
| Attribute | Type | Description |
|---|---|---|
body | object | The transformed request body to forward to the destination |
headers | object | The transformed request headers to forward to the destination |
node22 Code Contract
Input
The transform function receives an event object containing the HTTP request properties and configuration:
| Attribute | Type | Description |
|---|---|---|
req | object | HTTP request properties (see below) |
configuration | map<string, string> | Configuration values defined on the proxy |
logger | object | Logger instance with info(), warn(), error() methods |
applicationOptions | object | Configuration information about the associated application (if application.id is set) |
applicationOptions.apiKey | string | The API key of the associated application |
applicationOptions.environment | string | The Basis Theory API URL (e.g., https://api.basistheory.com) |
The req object contains the HTTP request properties:
| Attribute | Type | Description |
|---|---|---|
body | object or string | The request body parsed as a JavaScript object when Content-Type is application/json, or string for other content types. |
headers | object | A JavaScript object containing the headers received on the proxy request |
method | string | The HTTP method of the proxy request (e.g., "GET", "POST", "PUT", "PATCH", "DELETE") |
path | string | The path suffix received on the proxy request after /proxy (e.g., a request to /proxy/sub/path?param=value would result in a path of /sub/path) |
query | string | The unparsed query string that was received on the proxy request (e.g., a request to /proxy/sub/path?param=value would result in a query of ?param=value) |
Output
To proceed with forwarding the request to the destination, return a req object containing the transformed body and headers. To short-circuit and respond directly without contacting the destination, return a res object instead — see Skip Proxy Request.
| Attribute | Type | Description |
|---|---|---|
req.body | object | The transformed request body to forward to the destination |
req.headers | object | The transformed request headers to forward to the destination |
Skip Proxy Request
A code request transform can skip forwarding to the destination and return a response directly. This is useful for caching, rate limiting, early validation, or authentication checks.
The examples below demonstrate success responses (such as returning cached data). You can also use this approach to return error responses — see Proxy Transform Error Handling.
- node-bt
- node22
Throw CustomHttpResponseError to skip proxying and return a custom response:
const { CustomHttpResponseError } = require('@basis-theory/basis-theory-reactor-formulas-sdk-js');
module.exports = async function (req) {
const { args, configuration } = req;
const cacheKey = args.path;
// Check cache (pseudo-code)
const cachedData = getFromCache(cacheKey);
if (cachedData) {
throw new CustomHttpResponseError({
status: 200,
headers: {
'X-Cache': 'HIT',
'Content-Type': 'application/json'
},
body: cachedData
});
}
// Continue with normal proxy flow
return {
body: args.body,
headers: args.headers
};
};
Return a res object to skip proxying and return a custom response:
module.exports = async function (event) {
const { req, configuration, logger } = event;
const cacheKey = req.path;
// Check cache (pseudo-code)
const cachedData = getFromCache(cacheKey);
if (cachedData) {
logger.info('Cache hit', { key: cacheKey });
return {
res: {
statusCode: 200,
headers: {
'X-Cache': 'HIT',
'Content-Type': 'application/json'
},
body: cachedData
}
};
}
// Continue with normal proxy flow
return {
req: {
body: req.body,
headers: req.headers
}
};
};
Tokenize Request Transform
Creates tokens from request data and makes them available for subsequent transforms via identifiers.
Basic Configuration:
{
"type": "tokenize",
"options": {
"token": {
"type": "token",
"data": "sensitive_value"
},
"identifier": "my_token"
}
}
Data Sources for token.data:
- Plaintext: Static string values
- Encrypted expression:
"{{ encrypted | json: '$.data' }}"- Extract data from the headerBT-ENCRYPTED - Request expressions:
"{{ req.card_number }}"- Extract data from request properties
Token References: Created tokens can be referenced in subsequent transforms or the request body using:
"{{ transform_identifier: 'my_token' }}"- Full token data"{{ transform_identifier: 'my_token' | json: '$.path' }}"- Extract specific data with JSONPath
Response Transforms
2xx status code. Any response with a status code of 300 or higher (including 3xx redirects, 4xx client errors, and 5xx server errors) bypasses all response transforms and is returned to the caller as-is.| Type | Purpose |
|---|---|
code | Run custom Node.js to mutate the response body or headers, tokenize sensitive values returned by the destination, or detokenize values for inbound flows |
mask | Pattern-based masking using regex or predefined matchers |
tokenize | Create tokens from response data using Liquid expressions or plaintext |
append_json | Add JSON properties to the response payload at a JSONPath location |
append_text | Append plain text to the response body |
append_header | Add HTTP headers to the response |
Code Response Transform
Code Response Transform can be used to:
- Transform the body or headers on the HTTP response received from the destination before returning a response from the proxy
- Tokenize sensitive values returned by a third party destination API
- For inbound HTTP requests, tokens returned in responses from your system can be detokenized before sending the response to the third party caller
Code response transforms run in Basis Theory's serverless runtime environment:
- node-bt
- node22
module.exports = async function (req) {
const { bt, args, configuration } = req;
const { body, headers } = args; // access properties of the http response
const { MY_CONFIG } = configuration; // access any static config defined on the Proxy
// do anything here!
const processedBody = ...; // do something to build a transformed body
const processedHeaders = ...; // do something to build transformed headers
return {
body: processedBody, // transformed response body
headers: processedHeaders // transformed request headers
};
};
module.exports = async function (event) {
const { res, configuration, logger, applicationOptions } = event;
const { body, headers } = res; // access properties of the http response
const { MY_CONFIG } = configuration; // access any static config defined on the Proxy
logger.info("Processing response");
// do anything here!
const processedBody = ...; // do something to build a transformed body
const processedHeaders = ...; // do something to build transformed headers
return {
res: {
body: processedBody, // transformed response body
headers: processedHeaders // transformed response headers
}
};
};
What a Code Response Transform Can and Cannot Change
A code response transform can:
- Mutate the response body.
- Mutate the response headers.
- Change the response status code —
node22only. Onnode-bt, the status code is read-only; to return a non-2xxstatus from anode-bttransform, throw an error — see Error Handling.
Response transforms only run when the destination returns a 2xx status code — see the warning at the top of Response Transforms.
node-bt Code Contract
Input
The transform function receives a request object containing the HTTP response properties and configuration:
| Attribute | Type | Description |
|---|---|---|
args | object | HTTP response properties (see below) |
configuration | map<string, string> | Configuration values defined on the proxy |
bt | object | Pre-configured Basis Theory SDK instance for token operations (if application.id is set) |
applicationOptions | object | Configuration information about the associated application (if application.id is set) |
applicationOptions.apiKey | string | The API key of the associated application |
applicationOptions.environment | string | The Basis Theory API URL (e.g., https://api.basistheory.com) |
The args object contains the HTTP response properties:
| Attribute | Type | Description |
|---|---|---|
body | object or string | The response body returned from the destination endpoint, parsed as a JavaScript object when Content-Type is application/json, or string for other content types. |
headers | object | A JavaScript object containing the response headers returned from the destination endpoint |
Output
An object of the following type must be returned by the transform function:
| Attribute | Type | Description |
|---|---|---|
body | object | The transformed response body to return from the proxy |
headers | object | The transformed response headers to return from the proxy |
node22 Code Contract
Input
The transform function receives an event object containing the HTTP response properties and configuration:
| Attribute | Type | Description |
|---|---|---|
res | object | HTTP response properties (see below) |
configuration | map<string, string> | Configuration values defined on the proxy |
logger | object | Logger instance with info(), warn(), error() methods |
applicationOptions | object | Configuration information about the associated application (if application.id is set) |
applicationOptions.apiKey | string | The API key of the associated application |
applicationOptions.environment | string | The Basis Theory API URL (e.g., https://api.basistheory.com) |
The res object contains the HTTP response properties:
| Attribute | Type | Description |
|---|---|---|
body | object or string | The response body returned from the destination endpoint, parsed as a JavaScript object when Content-Type is application/json, or string for other content types. |
headers | object | A JavaScript object containing the response headers returned from the destination endpoint |
Output
An object of the following type must be returned by the transform function:
| Attribute | Type | Description |
|---|---|---|
res.body | object | The transformed response body to return from the proxy |
res.headers | object | The transformed response headers to return from the proxy |
res.statusCode | number | Optional. Override the HTTP status code returned to the caller. |
Mask Response Transform
Mask response transform can be used to transform the body of the response received from the destination before returning a response from the proxy.
The mask transform has two available matcher types, regex and chase_stratus_pan.
Regex Matcher
Mask response transform using the regex matcher is defined using regular expressions and a replacement character.
{
"name": "My masked proxy",
"destination_url": "https://echo.basistheory.com/anything",
"require_auth": false,
"response_transforms": [
{
"type": "mask",
"matcher": "regex",
"replacement": "*",
"expression": "\"accountNumber\":\\s*\"(.*?)\""
}
]
}
The regular expression must contain at least one capture group.
In the example above, the expression will capture the value of an accountNumber attribute of a JSON payload.
Given the proxied service responds with a JSON similar to the following:
Original Response
{
"username": "bsmith1486",
"accountNumber": "56834512"
}
Then the sample proxy will mask the response as:
Transformed Response
{
"username": "bsmith1486",
"accountNumber": "********"
}
When a response body matches the given expression, the matched part of the body will be processed.
During processing, any portion of the matched body section that is equivalent to any value of a capture group defined in the regex will be replaced.
In this case, the matched body section is "accountNumber": "56834512".
The best practice is to limit the match scope to be as narrow as possible. There could be unintended or unexpected side effects if the match string is larger than necessary.
For example, given a regex defined as ^(aa).*?$, a match will occur when the line starts with "aa".
However, since the regular expression uses the beginning, ^, and end $ syntax, the whole string will be matched and eligible for replacements.
Given a response body of aabbccaabbccaa, the entire body will processed during masking.
ALL values that match the capture group value, in this case aa, will be replaced.
The response body will then be masked as **bbcc**bbcc**.
Chase Stratus PAN Matcher
If your proxy is interfacing with the Chase Stratus service, you may be able to take advantage of a default mask.
The chase_stratus_pan matcher will automatically mask PANs from the Chase Stratus Account Verification and Tokenize responses.
{
"name": "My Chase Stratus proxy",
"destination_url": "<REPLACE WITH CHASE STATUS URL>",
"require_auth": false,
"response_transforms": [
{
"type": "mask",
"matcher": "chase_stratus_pan",
"replacement": "*"
}
]
}
This mask will return responses as follows:
Account Verification
T74VKiwuJZ7TYGXD4navTHDLZG104240726tst844 *******************0929VI 000000000000CT01USANNXNNNXY\r
Tokenize
T74VEqMOciR1n8le3BhTVvl3zJ104240726 *******************0329DI 000000000000TI6559909009126557 \r
Tokenize Response Transform
Creates tokens from response data and makes them available for subsequent transforms via identifiers.
Basic Configuration:
{
"type": "tokenize",
"options": {
"token": {
"type": "token",
"data": "{{ res.card_number }}"
},
"identifier": "response_token"
}
}
Data Sources for token.data:
- Plaintext: Static string values
- Encrypted expression:
"{{ encrypted | json: '$.data' }}"- Extract data from the headerBT-ENCRYPTED - Response expressions:
"{{ res.card_number }}"- Extract data from response properties
Append JSON Response Transform
Add JSON properties to response payload at specified locations using JSONPath expressions.
Basic Configuration:
{
"type": "append_json",
"options": {
"value": "{{ transform_identifier: 'response_token' | json: '$.id' }}",
"location": "$.created_token_id"
}
}
Append Text Response Transform
Appends plain text content to the end of response body.
Basic Configuration:
{
"type": "append_text",
"options": {
"value": "Token ID: {{ transform_identifier: 'response_token' | json: '$.id' }}"
}
}
Append Header Response Transform
Add HTTP headers to response with values that can reference tokens from previous transforms.
Basic Configuration:
{
"type": "append_header",
"options": {
"value": "{{ transform_identifier: 'response_token' | json: '$.id' }}",
"location": "X-Token-ID"
}
}
Token References in Response Transforms: All append transforms support referencing tokens created by previous transforms using:
"{{ transform_identifier: 'identifier' }}"- Full token data"{{ transform_identifier: 'identifier' | json: '$.path' }}"- Extract specific data with JSONPath
Tokenizing or Detokenizing
In some situations, you may want to tokenize or detokenize data with Code Request Transform or Code Response Transform. In order to do this,
set the application.id property when creating your Proxy with the id of an
Application that has been granted the desired permissions.
This will inject a Basis Theory JS instance into the transform request
that is pre-configured for this application. For example:
- node-bt
- node22
module.exports = async function (req) {
const token = await req.bt.tokenize({
type: "token",
data: req.args.body.sensitive_value,
});
req.args.body.sensitive_value = token.id;
return {
body: req.args.body,
headers: req.args.headers,
};
};
In the above example, we utilized the injected Basis Theory JS instance to tokenize a property called sensitive_value on our request body
and passed the token back as the updated sensitive_value to be forwarded to the configured destination_url on our Proxy.
const { BasisTheoryClient } = require("@basis-theory/node-sdk");
module.exports = async function (event) {
const { req, applicationOptions, logger } = event;
const client = new BasisTheoryClient({ apiKey: applicationOptions.apiKey });
const token = await client.tokens.create({
type: "token",
data: req.body.sensitive_value
});
logger.info("Token created", { tokenId: token.id });
return {
req: {
headers: req.headers,
body: { ...req.body, sensitive_value: token.id }
}
};
};
For node22, add @basis-theory/node-sdk to your runtime.dependencies and include appropriate permissions in runtime.permissions.
Testing and Dependencies
Testing transforms works the same as testing Reactors.
npm modules
node-bt only supports a curated set of npm modules — see the list of available modules.
node22 has no whitelist. You can install any npm package by specifying it in runtime.dependencies.
For deployment-time and continuous dependency scanning details, see Runtime Vulnerability Scanning.
Error Handling
For information on handling errors in proxy transforms, including error types, response formats, and best practices, see Error Handling.
API Reference
For complete API documentation including all parameters and SDK examples: