Safely Updating Reactors and Proxies
When you update a Reactor or Proxy, you are deploying code, not saving a setting. Callers reach it by an id, proxy key, or URL, and that reference stays the same when the behavior behind it changes. Everything pointing at it moves to the new version at once: your own application code, scheduled jobs, and partner integrations you may not control.
Treat every change to a Reactor or Proxy as a replacement: create the new version alongside the one serving traffic, validate it in isolation, move callers over, and retire the old one once you are confident. This is the same blue/green approach you would use for an application deploy, and it works here for the same reason. The thing you are changing is live.
This page describes the pattern in general. Migrate from node-bt applies it to one specific change, moving a resource to a Node.js runtime image.
Why editing in place is riskier than it looks
Every caller changes at the same moment. There is no staged rollout and no canary. If the new code is wrong for one caller's payload shape, it is wrong for all of them immediately.
Rollback is another edit. Reverting means writing the previous version back, which assumes you still have it and can reconstruct it correctly while traffic is failing.
Validation happens after go-live. You find out whether the change was right by watching production.
A failed update on a Node.js runtime image is quiet. Updates to a Node.js runtime image are asynchronous. The new function is provisioned in the background while the resource keeps serving requests, so the update itself is not disruptive: invocation continues on the previous active configuration throughout. But if provisioning fails, the resource moves to outdated and carries on serving the previous version. Nothing breaks, no caller sees an error, and nothing announces that the code you deployed is not the code running. Only the resource's state tells you. A replacement makes that impossible to miss, because you validate the new function directly before any caller points at it.
A full PUT replaces the resource with the body you send. If you build that body by hand rather than from the current resource, you can change settings you never intended to touch. Where you do update in place, prefer PATCH, which uses application/merge-patch+json and applies only the fields you supply.
The pattern
- Find every caller. Enumerate everything that references the resource.
- Create the replacement. A new Reactor or Proxy, with the change applied.
- Match the rest of the configuration deliberately. Copy every setting you did not intend to change.
- Validate the replacement in isolation. Invoke it directly, by its own id, key, or URL.
- Move callers over. One at a time if you can.
- Watch production. Include the paths that only appear under real traffic: retries, error handling, partner callbacks.
- Retire the old resource once nothing references it.
Steps 1 and 7 are the easiest to skip, because neither produces something you can watch work. They are also a pair: skipping step 1 means you move the callers you know about while the rest keep hitting the old resource, and those are exactly the callers that break when you delete it. Skipping step 7 leaves a live resource that nothing owns, still holding an application and still invocable.
Reactors
Create a new Reactor with POST /reactors, copying every setting you are not deliberately changing: application, configuration, timeout, synchronous or asynchronous invocation, and for a Node.js runtime image, npm dependencies, permissions, and resource settings.
Name the runtime image explicitly so it cannot drift. A Reactor that names no image is running the legacy node-bt runtime, which is deprecated, so building a replacement is the natural moment to migrate off it.
Invoke the new Reactor directly, by its own id, with POST /reactors/{id}/react or /react-async. Nothing points at it yet, so you can send representative arguments freely and compare against the current Reactor:
- the response shape and status codes your callers depend on
- tokenization behavior: the tokens created, their containers, and their types
- error behavior, including what a downstream failure returns
Once it behaves the way you expect, update the Reactor id everywhere it appears. In practice it hides in more places than expected: application code and configuration files, environment variables, scheduled jobs, webhook and callback configuration, infrastructure as code, dashboards, runbooks, and anything a partner holds on their side.
Once no caller references the old Reactor, delete it.
Pre-Configured Proxies
Create a new Proxy with POST /proxies, again copying what you are not changing: destination_url, require_auth, application, request and response transforms, configuration for code transforms, and any access restrictions the current Proxy relies on. Transform order is part of the behavior, so preserve it.
A new Proxy has its own key and URL, so you can exercise it end to end while the current Proxy keeps serving. Call it with the standard invocation path and compare headers, body shape, status codes, detokenization behavior, transform order, and error handling.
Update callers that use a key or URL
For callers using a Proxy key or Basis Theory-generated Proxy URL, update the key or URL everywhere it appears. This is a configuration change on the caller's side, so you can move callers over at whatever pace you like and point them back if anything looks wrong. The reference hides in the same places a Reactor id does, including anything a partner holds on their side.
Move an existing custom hostname
When to use hostname transfer
Use this procedure when:
- Callers must keep using an existing custom hostname while its assignment moves from the current Proxy to a validated replacement Proxy in the same Tenant.
Do not use this procedure when:
- You need to request or initially configure a custom hostname. To request one, follow Use a Custom Hostname for your Inbound Proxy.
- Callers use only a Proxy key or Basis Theory-generated Proxy URL.
- The source and destination Proxies belong to different Tenants.
- The Proxy that owns the hostname has already been deleted.
Transfer the hostname
Before the transfer:
- Use Get a Proxy to record the source Proxy ID, destination Proxy ID, and the exact existing
proxy_host. - Confirm the destination has no hostname, has passed direct validation, and is
activeif its code transforms run on a Node.js runtime image. - Use a management key with
proxy:updateandproxy:readpermissions.
Move the hostname with Transfer a Custom Hostname. Target the destination Proxy ID and pass the source Proxy's hostname without a scheme or path:
curl --include --request PUT 'https://api.basistheory.com/proxies/<DESTINATION_PROXY_ID>/hostname' \
--header 'BT-API-KEY: <MANAGEMENT_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{"proxy_host":"<CUSTOM_HOSTNAME>"}'
A successful request returns 204 No Content. Hostname-only callers require no URL or DNS change. Callers that use the Proxy key or Basis Theory-generated Proxy URL must still be migrated independently.
Verify the transfer
Verify the destination with Get a Proxy:
curl --request GET 'https://api.basistheory.com/proxies/<DESTINATION_PROXY_ID>' \
--header 'BT-API-KEY: <MANAGEMENT_API_KEY>'
Verify the source separately with Get a Proxy:
curl --request GET 'https://api.basistheory.com/proxies/<SOURCE_PROXY_ID>' \
--header 'BT-API-KEY: <MANAGEMENT_API_KEY>'
Expect the destination's proxy_host to equal the transferred hostname and the source's response to omit proxy_host. Cached record reads and hostname routing may converge after the operation. Send representative requests through the unchanged custom hostname using the callers' normal authentication, paths, headers, and payloads, then verify the replacement's behavior and traffic.
Roll back the transfer
To roll back, call Transfer a Custom Hostname with the original source Proxy ID and the same hostname:
curl --include --request PUT 'https://api.basistheory.com/proxies/<SOURCE_PROXY_ID>/hostname' \
--header 'BT-API-KEY: <MANAGEMENT_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{"proxy_host":"<CUSTOM_HOSTNAME>"}'
The original Proxy must still exist and be eligible to receive the hostname. Recheck both Proxy records and representative traffic after rollback. Keep the original Proxy until hostname traffic is verified, every direct key or URL caller is migrated, and rollback is no longer required.
Rolling back
Rollback needs no rebuild. For Reactors and callers using a Proxy key or Basis Theory-generated Proxy URL, point callers back at the previous resource. For custom-hostname callers, follow the hostname rollback procedure.
Keep the old resource until the new one has handled real traffic, including the error and retry paths you cannot easily simulate. If the original Proxy has a custom hostname that needs to be transferred to the replacement Proxy, transfer it before deleting the original Proxy.
When editing in place is reasonable
Replacement is the default, not a rule. Editing in place is a fair trade when the change carries little risk and the blast radius is small:
- Metadata that does not affect behavior, such as a name.
- A resource with a single caller you control, where you have the current source saved and can absorb the time a revert takes.
- A fix to a resource that is already failing, where there is no working version to protect.
Even then, use PATCH rather than PUT so you only change what you meant to, and save the current source before you overwrite it.
Do not count on an instant revert. Any change that rebuilds the function runs the same provisioning cycle as the change you are undoing, so on a Node.js runtime image the old code is not serving traffic again until that cycle finishes. If the revert itself fails to provision, the resource goes outdated and keeps serving the version you were trying to undo.
Keep credentials out of source
Reactors and Pre-Configured Proxies both accept a configuration object, which is encrypted at rest and injected into your code at invocation time. Read credentials from configuration rather than embedding them in source, so rotating one is a configuration change instead of a code change.
If the change involves rotating a third-party credential, keep the previous credential valid at the provider until you retire the old resource. Revoking it as soon as the replacement is live leaves the old resource unable to reach the provider, removing the rollback path at the point you are most likely to need it.
See Reactors and the Pre-Configured Proxies API for the request shapes, and configuration expressions for referencing configuration from a Proxy.
Checklist
- Every caller of the current resource is identified, including partner-held references
- Replacement created, with runtime, application, configuration, timeouts, and transform order copied deliberately
- Replacement invoked directly and compared against current behavior: response shape, status codes, tokenization, error paths
- Callers moved over; any custom hostname transferred and verified; old resource left running
- Production watched through a full traffic cycle, error paths included
- Old resource ready for deletion or retirement after nothing references it and hostname rollback is no longer required