Adding and filtering for payment metadata
Usage
As developers, we understand the necessity to associate external metadata to a certain payment. The Breez SDK allows you to easily do so with the set_payment_metadata
method:
sdk.set_payment_metadata("target-payment-hash", r#"{"myCustomValue":true}"#).await?;
try sdk.setPaymentMetadata(hash: "target-payment-hash", metadata: #"{"myCustomValue":true}"#)
try {
sdk.setPaymentMetadata("target-payment-hash", """{"myCustomValue":true}""")
} catch (e: Exception) {
// Handle error
}
await setPaymentMetadata('target-payment-hash', '{"myCustomValue":true}')
await breezSDK.setPaymentMetadata(hash: "target-payment-hash", metadata: '{"myCustomValue":true}');
sdk_services.set_payment_metadata("target-payment-hash", '{"myCustomValue":true}')
sdk.SetPaymentMetadata("target-payment-hash", `{"myCustomValue":true}`)
sdk.SetPaymentMetadata("target-payment-hash", "{\"myCustomValue\":true}");
Once the metadata has been set, you can filter for the specified value using the list_payments
method:
let metadata_filters = vec![
MetadataFilter {
json_path: "myCustomValue".to_string(),
json_value: "true".to_string(),
},
];
sdk.list_payments(ListPaymentsRequest {
metadata_filters,
..Default::default(),
}).await?;
let metadataFilters = [
MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: "true"
)
]
let payments = try? sdk.listPayments(
req: ListPaymentsRequest(
metadataFilters: metadataFilters
)
)
val metadataFilters = listOf(MetadataFilter(
jsonPath = "myCustomValue",
jsonValue = "true"
))
try {
sdk.listPayments(
ListPaymentsRequest(
metadataFilters = metadataFilters
))
} catch (e: Exception) {
// handle error
}
const metadataFilters = [
{
jsonPath: 'myCustomValue',
jsonValue: 'true'
}
]
try {
await listPayments({
metadataFilters
})
} catch (err) {
// handle error
}
List<MetadataFilter> metadataFilters = [
MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: "true",
),
];
await breezSDK.listPayments(
req: ListPaymentsRequest(
metadataFilters: metadataFilters
));
metadata_filters = [
breez_sdk.MetadataFilter("myCustomValue", "true")
]
try:
sdk_services.list_payments(breez_sdk.ListPaymentsRequest(
metadata_filters = metadata_filters
))
except Exception as error:
# handle error
raise
metadataFilters := []breez_sdk.MetadataFilter{
{JsonPath: "myCustomValue", JsonValue: "true"},
}
payments, err := sdk.ListPayments(breez_sdk.ListPaymentsRequest{
MetadataFilters: &metadataFilters,
})
if err != nil {
// handle error
}
try
{
var metadataFilters = new List<MetadataFilter>() {
new MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: "true"
)
};
var payments = sdk.ListPayments(
new ListPaymentsRequest(
metadataFilters: metadataFilters
)
);
}
catch (Exception)
{
// Handle error
}
Caveats
Searching for metadata is flexible, allowing you to search and compare all JSON-supported types (nested ones too, using JSONPath), but with a couple of caveats:
2.1 Filtering for Strings
Since the filter works as a one-to-one comparison to the JSON value, strings must be wrapped in double-quotes in order to be properly filtered:
// Note: The following are equivalent
let metadata_filters = vec![
MetadataFilter {
json_path: "customerName".to_string(),
json_value: r#""Satoshi Nakamoto""#.to_string(),
},
MetadataFilter {
json_path: "customerName".to_string(),
json_value: serde_json::json!("Satoshi Nakamoto").to_string(),
},
];
let metadataFilters = [
MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: #""true""#
)
]
val metadataFilters = listOf(MetadataFilter(
jsonPath = "customerName",
jsonValue = "\"Satoshi Nakamoto\""
))
// Note: These are equivalent
const metadataFilters = [
{
jsonPath: 'customerName',
jsonValue: 'Satoshi Nakamoto'
},
{
jsonPath: 'customerName',
jsonValue: JSON.stringify('Satoshi Nakamoto')
}
]
metadataFilters = [
MetadataFilter(
jsonPath: "customerName",
jsonValue: '"Satoshi Nakamoto"',
),
];
metadata_filters = [
breez_sdk.MetadataFilter("customerName", "\"Satoshi Nakamoto\""),
breez_sdk.MetadataFilter("customerName", json.dumps("Satoshi Nakamoto")),
]
metadataFilters := []breez_sdk.MetadataFilter{
{JsonPath: "customerName", JsonValue: "\"Satoshi Nakamoto\""},
}
jsonValue, _ := json.Marshal("Satoshi Nakamoto")
metadataFilters = []breez_sdk.MetadataFilter{
{
JsonPath: "customerName",
JsonValue: string(jsonValue),
},
}
var metadataFilters = new List<MetadataFilter>() {
new MetadataFilter(
jsonPath: "customerName",
jsonValue: "\"Satoshi Nakamoto\""
),
new MetadataFilter(
jsonPath: "customerName",
jsonValue: JsonSerializer.Serialize("Satoshi Nakamoto")
)
};
2.2 Filtering for Objects/Arrays
You can also compare complex objects against one another, but be careful of whitespaces! Since those are stripped during insertion, passing non-stripped filters will result in improper matching. For example, given the following metadata:
{ "isNested": true, "parent": { "nestedArray": [1, 2, 3] } }
You would filter for payments matching the nested array as follows:
// This will *NOT* work
let metadata_filters = vec![
MetadataFilter {
json_path: "parent.nestedArray".to_string(),
json_value: r#"[1, 2, 3]"#.to_string(),
},
];
// Any of these will work
let metadata_filters = vec![
MetadataFilter {
json_path: "parent.nestedArray".to_string(),
json_value: r#"[1,2,3]"#.to_string(),
},
];
In Rust's case, this check can easily be overcome by using the serde_json crate (which you probably should be using anyway to serialize and insert the metadata):
let metadata_filters = vec![
MetadataFilter {
json_path: "parent.nestedArray".to_string(),
json_value: serde_json::json!(&[1, 2, 3]).to_string(),
},
];
// This will *NOT* work
var metadataFilters = [
MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: #"[1, 2, 3]"#
)
]
// Any of these will work
metadataFilters = [
MetadataFilter(
jsonPath: "myCustomValue",
jsonValue: #"[1,2,3]"#
)
]
// This will *NOT* work
val _metadataFilters = listOf(MetadataFilter(
jsonPath = "parent.nestedArray",
jsonValue = "[1, 2, 3]"
))
// Any of these will work
val metadataFilters = listOf(MetadataFilter(
jsonPath = "parent.nestedArray",
jsonValue = "[1,2,3]"
))
// This will *NOT* work
const _metadataFilters = [
{
jsonPath: 'parent.nestedArray',
jsonValue: '[1, 2, 3]'
}
]
// Any of these will work
const metadataFilters = [
{
jsonPath: 'parent.nestedArray',
jsonValue: '[1,2,3]'
},
{
jsonPath: 'parent.nestedArray',
jsonValue: JSON.stringify([1, 2, 3])
}
]
// This will *NOT* work
metadataFilters = [
MetadataFilter(
jsonPath: "parent.nestedArray",
jsonValue: "[1, 2, 3]",
),
];
// Any of these will work
metadataFilters = [
MetadataFilter(
jsonPath: "parent.nestedArray",
jsonValue: "[1,2,3]",
),
];
# This will *NOT* work
metadata_filters = [
breez_sdk.MetadataFilter("parent.nestedArray", "[1, 2, 3]")
]
# Any of these will work
metadata_filters = [
breez_sdk.MetadataFilter("parent.nestedArray", "[1,2,3]"),
breez_sdk.MetadataFilter("parent.nestedArray", json.dumps([1,2,3], separators=(',', ':'))),
]
// This will *NOT* work
metadataFilters := []breez_sdk.MetadataFilter{
{JsonPath: "parent.nestedArray", JsonValue: "[1, 2, 3]"},
}
// Any of these will work
jsonValue, _ := json.Marshal([]int{1, 2, 3})
metadataFilters = []breez_sdk.MetadataFilter{
{JsonPath: "parent.nestedArray", JsonValue: "[1,2,3]"},
{JsonPath: "parent.nestedArray", JsonValue: string(jsonValue)},
}
// This will *NOT* work
var _metadataFilters = new List<MetadataFilter>() {
new MetadataFilter(
jsonPath: "parent.nestedArray",
jsonValue: "[1, 2, 3]"
)
};
// Any of these will work
var metadataFilters = new List<MetadataFilter>() {
new MetadataFilter(
jsonPath: "parent.nestedArray",
jsonValue: "[1,2,3]"
),
new MetadataFilter(
jsonPath: "parent.nestedArray",
jsonValue: JsonSerializer.Serialize(new int[] {1, 2, 3})
)
};
2.3 Same-key Insertion
In case the same key were to be specified twice during insertion, the last one occurring in the string is taken as valid by default. E.g.
{ "completed": true, "completed": false }
will insert the value as false
.
2.4 Size Limits
Currently, the SDK limits metadata storage per payment to 1,000 UTF-8 encoded characters, and any insertion beyond that will fail.