curl --request POST \
--url https://txengine.bloobank.com/txengine/v1/wallets \
--header 'Content-Type: application/json' \
--header 'X-Access-Key: <api-key>' \
--header 'X-Access-Request-Id: <api-key>' \
--header 'X-Access-Signature: <api-key>' \
--header 'X-Access-Timestamp: <api-key>' \
--data '
{
"name": "production-main",
"status": "ACTIVE"
}
'import requests
url = "https://txengine.bloobank.com/txengine/v1/wallets"
payload = {
"name": "production-main",
"status": "ACTIVE"
}
headers = {
"X-Access-Key": "<api-key>",
"X-Access-Timestamp": "<api-key>",
"X-Access-Request-Id": "<api-key>",
"X-Access-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Access-Key': '<api-key>',
'X-Access-Timestamp': '<api-key>',
'X-Access-Request-Id': '<api-key>',
'X-Access-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({name: 'production-main', status: 'ACTIVE'})
};
fetch('https://txengine.bloobank.com/txengine/v1/wallets', 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://txengine.bloobank.com/txengine/v1/wallets",
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([
'name' => 'production-main',
'status' => 'ACTIVE'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Access-Key: <api-key>",
"X-Access-Request-Id: <api-key>",
"X-Access-Signature: <api-key>",
"X-Access-Timestamp: <api-key>"
],
]);
$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://txengine.bloobank.com/txengine/v1/wallets"
payload := strings.NewReader("{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Access-Key", "<api-key>")
req.Header.Add("X-Access-Timestamp", "<api-key>")
req.Header.Add("X-Access-Request-Id", "<api-key>")
req.Header.Add("X-Access-Signature", "<api-key>")
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://txengine.bloobank.com/txengine/v1/wallets")
.header("X-Access-Key", "<api-key>")
.header("X-Access-Timestamp", "<api-key>")
.header("X-Access-Request-Id", "<api-key>")
.header("X-Access-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://txengine.bloobank.com/txengine/v1/wallets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Access-Key"] = '<api-key>'
request["X-Access-Timestamp"] = '<api-key>'
request["X-Access-Request-Id"] = '<api-key>'
request["X-Access-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}"
response = http.request(request)
puts response.read_body{
"id": "wal_2NhVqRtYbHmRdZ4vG6qAeL",
"kind": "Tenant.Wallet",
"walVersion": 1,
"status": "ACTIVE",
"name": "production-main",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:00.000Z",
"selfName": "wallets/production-main",
"etag": "9f3b2c1d8a7e6f5b4a3c2d1e0f9e8d7c6b5a493827160504e3d2c1b0a9f8e7d6"
}{
"error": {
"code": 400,
"status": "INVALID_ARGUMENT",
"message": "Filter expression references an unsupported field.",
"details": [
{
"reason": "INVALID_ARGUMENT",
"description": "Field `nonexistent` is not allowed for filtering on this endpoint.",
"metadata": {}
}
]
}
}{
"error": {
"code": 401,
"status": "SIGNATURE_INVALID",
"message": "Request signature could not be verified.",
"details": [
{
"reason": "SIGNATURE_INVALID",
"description": "The provided signature does not match the canonical request.",
"metadata": {
"decisionId": "acd_9RmKvTpYzH2wN8qJ5b"
}
}
]
}
}{
"error": {
"code": 403,
"status": "RBAC_DENY",
"message": "The credential is not permitted to perform this action.",
"details": [
{
"reason": "RBAC_DENY",
"description": "Missing required role binding on the target resource.",
"metadata": {
"decisionId": "acd_8PaJvNqLcK3xW5sR4d"
}
}
]
}
}{
"error": {
"code": 409,
"status": "WALLET_ALREADY_EXISTS",
"message": "A wallet with this name already exists.",
"details": [
{
"reason": "WALLET_ALREADY_EXISTS",
"description": "The name `production-main` is already in use.",
"metadata": {}
}
]
}
}{
"error": {
"code": 422,
"status": "PAYMENT_ORDER_NOT_AWAITING_APPROVAL",
"message": "Payment order is not awaiting approval.",
"details": [
{
"reason": "PAYMENT_ORDER_NOT_AWAITING_APPROVAL",
"description": "The payment order must be in AWAITING_APPROVAL for this operation.",
"metadata": {}
}
]
}
}{
"error": {
"code": 429,
"status": "RESOURCE_EXHAUSTED",
"message": "Rate limit exceeded for this credential.",
"details": [
{
"reason": "RESOURCE_EXHAUSTED",
"description": "You have exceeded the request quota for this endpoint.",
"metadata": {
"retry_after_seconds": 12
}
}
]
}
}{
"error": {
"code": 500,
"status": "INTERNAL",
"message": "An unexpected error occurred.",
"details": [
{
"reason": "INTERNAL",
"description": "Internal server error.",
"metadata": {
"id": "exc_5KaHsBxYzW3pM2dV"
}
}
]
}
}{
"error": {
"code": 503,
"status": "PROVIDER_UNAVAILABLE",
"message": "Upstream payment provider is unavailable.",
"details": [
{
"reason": "PROVIDER_UNAVAILABLE",
"description": "The provider returned a transient error or did not respond.",
"metadata": {
"id": "exc_5KaHsBxYzW3pM2dV"
}
}
]
}
}Create wallet
Provisions a new wallet. The name field is an RFC 1035 DNS label
(1-63 lowercase characters), globally unique, and immutable after
creation.
curl --request POST \
--url https://txengine.bloobank.com/txengine/v1/wallets \
--header 'Content-Type: application/json' \
--header 'X-Access-Key: <api-key>' \
--header 'X-Access-Request-Id: <api-key>' \
--header 'X-Access-Signature: <api-key>' \
--header 'X-Access-Timestamp: <api-key>' \
--data '
{
"name": "production-main",
"status": "ACTIVE"
}
'import requests
url = "https://txengine.bloobank.com/txengine/v1/wallets"
payload = {
"name": "production-main",
"status": "ACTIVE"
}
headers = {
"X-Access-Key": "<api-key>",
"X-Access-Timestamp": "<api-key>",
"X-Access-Request-Id": "<api-key>",
"X-Access-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Access-Key': '<api-key>',
'X-Access-Timestamp': '<api-key>',
'X-Access-Request-Id': '<api-key>',
'X-Access-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({name: 'production-main', status: 'ACTIVE'})
};
fetch('https://txengine.bloobank.com/txengine/v1/wallets', 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://txengine.bloobank.com/txengine/v1/wallets",
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([
'name' => 'production-main',
'status' => 'ACTIVE'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Access-Key: <api-key>",
"X-Access-Request-Id: <api-key>",
"X-Access-Signature: <api-key>",
"X-Access-Timestamp: <api-key>"
],
]);
$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://txengine.bloobank.com/txengine/v1/wallets"
payload := strings.NewReader("{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Access-Key", "<api-key>")
req.Header.Add("X-Access-Timestamp", "<api-key>")
req.Header.Add("X-Access-Request-Id", "<api-key>")
req.Header.Add("X-Access-Signature", "<api-key>")
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://txengine.bloobank.com/txengine/v1/wallets")
.header("X-Access-Key", "<api-key>")
.header("X-Access-Timestamp", "<api-key>")
.header("X-Access-Request-Id", "<api-key>")
.header("X-Access-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://txengine.bloobank.com/txengine/v1/wallets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Access-Key"] = '<api-key>'
request["X-Access-Timestamp"] = '<api-key>'
request["X-Access-Request-Id"] = '<api-key>'
request["X-Access-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"production-main\",\n \"status\": \"ACTIVE\"\n}"
response = http.request(request)
puts response.read_body{
"id": "wal_2NhVqRtYbHmRdZ4vG6qAeL",
"kind": "Tenant.Wallet",
"walVersion": 1,
"status": "ACTIVE",
"name": "production-main",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:00.000Z",
"selfName": "wallets/production-main",
"etag": "9f3b2c1d8a7e6f5b4a3c2d1e0f9e8d7c6b5a493827160504e3d2c1b0a9f8e7d6"
}{
"error": {
"code": 400,
"status": "INVALID_ARGUMENT",
"message": "Filter expression references an unsupported field.",
"details": [
{
"reason": "INVALID_ARGUMENT",
"description": "Field `nonexistent` is not allowed for filtering on this endpoint.",
"metadata": {}
}
]
}
}{
"error": {
"code": 401,
"status": "SIGNATURE_INVALID",
"message": "Request signature could not be verified.",
"details": [
{
"reason": "SIGNATURE_INVALID",
"description": "The provided signature does not match the canonical request.",
"metadata": {
"decisionId": "acd_9RmKvTpYzH2wN8qJ5b"
}
}
]
}
}{
"error": {
"code": 403,
"status": "RBAC_DENY",
"message": "The credential is not permitted to perform this action.",
"details": [
{
"reason": "RBAC_DENY",
"description": "Missing required role binding on the target resource.",
"metadata": {
"decisionId": "acd_8PaJvNqLcK3xW5sR4d"
}
}
]
}
}{
"error": {
"code": 409,
"status": "WALLET_ALREADY_EXISTS",
"message": "A wallet with this name already exists.",
"details": [
{
"reason": "WALLET_ALREADY_EXISTS",
"description": "The name `production-main` is already in use.",
"metadata": {}
}
]
}
}{
"error": {
"code": 422,
"status": "PAYMENT_ORDER_NOT_AWAITING_APPROVAL",
"message": "Payment order is not awaiting approval.",
"details": [
{
"reason": "PAYMENT_ORDER_NOT_AWAITING_APPROVAL",
"description": "The payment order must be in AWAITING_APPROVAL for this operation.",
"metadata": {}
}
]
}
}{
"error": {
"code": 429,
"status": "RESOURCE_EXHAUSTED",
"message": "Rate limit exceeded for this credential.",
"details": [
{
"reason": "RESOURCE_EXHAUSTED",
"description": "You have exceeded the request quota for this endpoint.",
"metadata": {
"retry_after_seconds": 12
}
}
]
}
}{
"error": {
"code": 500,
"status": "INTERNAL",
"message": "An unexpected error occurred.",
"details": [
{
"reason": "INTERNAL",
"description": "Internal server error.",
"metadata": {
"id": "exc_5KaHsBxYzW3pM2dV"
}
}
]
}
}{
"error": {
"code": 503,
"status": "PROVIDER_UNAVAILABLE",
"message": "Upstream payment provider is unavailable.",
"details": [
{
"reason": "PROVIDER_UNAVAILABLE",
"description": "The provider returned a transient error or did not respond.",
"metadata": {
"id": "exc_5KaHsBxYzW3pM2dV"
}
}
]
}
}name field is an RFC 1035 DNS label (1–63 lowercase characters), globally unique, and immutable after creation.
name carefully — it cannot be changed. Attempting to update it later returns LABEL_IMMUTABLE. Plan the naming convention for your tenant (e.g., production-main, payroll-2026, escrow-acme) before creating the first wallet.name already exists, the API returns 409 WALLET_ALREADY_EXISTS.
See Wallet overview for the resource model and naming conventions.Authorizations
Opaque credential identifier provisioned during onboarding. See the Integration Guide for the request-signing protocol.
Unix epoch timestamp in UTC milliseconds. See the Integration Guide for skew tolerance.
Unique identifier per request (UUID v4 recommended). The
(accessKey, requestId) tuple must be unique within the replay
window defined by the Integration Guide.
Base64-encoded ECDSA signature of the canonical request, computed
with the private key paired to X-Access-Key. See the Integration
Guide for canonicalization rules and reference implementations.
Body
Response
Wallet created.
A tenant-scoped balance container that isolates payment orders, balances, and ledger transactions.
Server-assigned, immutable identifier.
^wal_[A-Za-z0-9]+$"wal_2NhVqRtYbHmRdZ4vG6qAeL"
Fixed resource-type discriminator; always Tenant.Wallet.
Tenant.Wallet "Tenant.Wallet"
Snapshot version, incremented on every content mutation.
x >= 11
Lifecycle status of a wallet.
ACTIVE, DISABLED RFC 1035 DNS label (1–63 lowercase characters; starts with a letter; ends with an alphanumeric). Globally unique and immutable after creation.
1 - 63^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$"production-main"
Server-assigned creation timestamp (UTC ISO 8601).
"2026-01-15T10:30:00.000Z"
Timestamp of the last content mutation (UTC ISO 8601).
"2026-01-15T10:30:00.000Z"
Canonical relative resource name.
"wallets/production-main"
Hex-encoded content fingerprint of the resource. Reserved for
optimistic concurrency control via the If-Match request header
in a future release; currently exposed for informational and
audit purposes only.
^[a-f0-9]{64,128}$"9f3b2c1d8a7e6f5b4a3c2d1e0f9e8d7c6b5a493827160504e3d2c1b0a9f8e7d6"