Back to APIs list

Currency API examples & templates

Use these vals as a playground to view and fork Currency API examples and templates on Val Town. Run any example below or find templates that can be used as a pre-built solution.

BTC Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .2) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
}
return btcPrice;
}

A simple bot that will grab the products from a shopify store and check for new products or products in stock. If they are found it will send a pushover alert.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { pushover } from "https://esm.town/v/harper/pushover";
import { ShopifyProductSearch } from "https://esm.town/v/harper/ShopifyProductSearch";
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
async function addProduct(id, title, url, priceAmount, priceCurrencyCode) {
console.debug("Adding product", { id, title, url, priceAmount, priceCurrencyCode });
// Insert the product if it doesn't exist
const res = await sqlite.execute({
sql: `INSERT OR IGNORE INTO products (id, title, url, price_amount, price_currencyCode)
VALUES (:id, :title, :url, :price_amount, :price_currencyCode)`,
args: {
id,
title,
url,
price_amount: priceAmount,
price_currencyCode: priceCurrencyCode,
},
});
const productAdded = res.rowsAffected > 0;
if (productAdded) {
console.debug("Product inserted successfully.");
} else {
console.debug("Product already exists. Skipped insertion.");
}
return productAdded;
}
async function sendNewProductMessage(products) {
if (!products || products.length === 0) {
console.log("No new products to send.");
return;
}
console.log("Sending new product messages...");
const title = "New Products Posted";
let message = `${title}\n\n`;
for (const product of products) {
const { id, title, url, priceAmount, priceCurrencyCode } = product;
message += `${title} for $${priceAmount} ${priceCurrencyCode}\n${url}\n\n`;
}
await pushover({
token: Deno.env.get("PUSHOVER_TOKEN"),
user: Deno.env.get("PUSHOVER_KEY"),
title: title,
message: message,
});
}
export default async function(interval: Interval) {
const brokerId = Deno.env.get("SHOPIFY_STORE_ID");
const first = 30;
// Returns an array of products
const products = await ShopifyProductSearch(brokerId, first);
if (!products) return;
try {
await sqlite.execute(`
CREATE TABLE IF NOT EXISTS products (
id TEXT PRIMARY KEY,
title TEXT,
url TEXT,
price_amount TEXT,
price_currencyCode TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
} catch (error) {
console.error("Error creating products table:", error);
return;
}
const newProducts = [];
for (const product of products) {
const { id, title, url, priceAmount, priceCurrencyCode } = product;
const result = await addProduct(id, title, url, priceAmount, priceCurrencyCode);
if (result) {
newProducts.push(product);
}
}
await sendNewProductMessage(newProducts);
console.log(`Found ${products.length} products. Inserted ${newProducts.length} products.`);
}

A simple endpoint to search a store on shopify for products.

You will have to find the store ID. You can get it from shop.app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetch } from "https://esm.town/v/std/fetch";
export async function ShopifyProductSearch(brokerId, first = 20) {
// The GraphQL endpoint you're going to query
const url = "https://shop.app/web/api/graphql";
// The GraphQL query
const query = `
query ShopProductSearch($brokerId: ID!, $first: Int!, $after: String, $filter: [SearchFilterV2!], $sortBy: ShopProductSearchSortByV2, $query: String) {
shopProductSearch(
brokerId: $brokerId
first: $first
after: $after
filter: $filter
sortBy: $sortBy
query: $query
) {
...ProductSearch
__typename
}
}
fragment ProductSearch on ProductSearchConnection {
nodes {
__typename
id
... on DiscoveryProduct {
id
...ShopWebRelatedProductFragment
__typename
}
}
productFilters {
...ProductFilter
__typename
}
pageInfo {
hasNextPage
endCursor
__typename
}
filter {
network
__typename
}
inferredCategoryFilters
totalCount
totalCountCapped
inferredQueryType
__typename
}
fragment ShopWebRelatedProductFragment on DiscoveryProduct {
id
price {
...MoneyV2Fragment
__typename
}
originalPrice {
...MoneyV2Fragment
__typename
}
title
url
images {
url
altText
sensitive
width
height
__typename
}
offers {
id
... on DiscountOffer {
...DiscountOffer
__typename
}
__typename
}
shopCashOffer {
id
offerHandle
boostMultiplier
totalCashDestinationAmount {
amount
currencyCode
__typename
}
__typename
}
defaultVariantId
inDefaultProductList
shop {
id
websiteUrl
name
defaultHandle
inAppVisibilityStatus
visualTheme {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/** @jsxImportSource npm:hono/jsx */
import { honoMiddleware } from "https://esm.town/v/pomdtr/codeOnValTown";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import * as basicTheme from "https://esm.town/v/pomdtr/invoice_basic_theme";
import {
extractParams,
Invoice,
Language,
schema,
} from "https://esm.town/v/pomdtr/invoice_schema";
import { Editor } from "https://esm.town/v/pomdtr/jsoninvoice_editor";
import { HomePage } from "https://esm.town/v/pomdtr/jsoninvoice_homepage";
import { Hono } from "npm:hono";
import { Base64 } from "npm:js-base64";
const app = new Hono();
const val = extractValInfo(import.meta.url);
app.use(
"/",
honoMiddleware({
val: {
handle: val.author,
name: val.name,
},
})
);
app.get("/", (c) => {
return c.html(<HomePage />);
});
app.get("/editor", (c) => {
return c.html(<Editor />);
});
app.get("/invoice/:code", async (c) => {
try {
const invoice: Invoice = JSON.parse(Base64.decode(c.req.param("code")));
const currencyCode = c.req.query("currency");
const currency = invoice.currencies.find(
(currency) => currency.code == currencyCode
);
if (!currency) {
return new Response(`${currencyCode} not available in currencies array`, {
status: 400,
});
}
const language = c.req.query("language") as Language;
const params = extractParams(invoice, {
currency,
language,
});
const rendered = await basicTheme.render(params);
return c.html(rendered);
} catch (e) {
return new Response(e.stack, {
status: 500,
});
}
});
app.get("/schema.json", () => {
return new Response(JSON.stringify(schema, null, 2), {
headers: {
"Content-Type": "application/json",
},
});
});
app.get("/TODO", (c) => {
return c.text("TODO");
});
export default app.fetch;

Crypto Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 15 min
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
let currency = async (desired, base = "usd", amount = 1) => {
// let { rates } = await fetchJSON(`https://open.er-api.com/v6/latest/${base}`);
// if (rates && rates[desired.toUpperCase()]) return amount * (rates[desired.toUpperCase()]);
// else {
let { rates } = await fetchJSON("https://api.coingecko.com/api/v3/exchange_rates");
return amount * rates[desired.toLowerCase()]?.value / rates[base.toLowerCase()]?.value;
};
async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
console.log(await currency("usd", "btc"));
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .05) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
// await email({
// text: formattedBtcPrice,
// subject: "BTC PRICE ALERT: " + formattedBtcPrice,
// });
}
return btcPrice;
}
async function ethPriceAlert() {
const lastEthPrice: number = await blob.getJSON("lastEthPrice");
let ethPrice = await currency("usd", "eth");
let change = Math.abs(ethPrice - lastEthPrice);
if (change / lastEthPrice > .05) {
await blob.setJSON("lastEthPrice", ethPrice);
let formattedEthPrice = formatAsCurrency(ethPrice);
// await email({
// text: formattedEthPrice,
// subject: "ETH PRICE ALERT: " + formattedEthPrice,
// });
}
return ethPrice;
}
export default async function() {
await Promise.all([btcPriceAlert(), ethPriceAlert()]);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { type Static, Type } from "npm:@sinclair/typebox";
const currencyCode = Type.Union([
Type.Literal("USD"),
Type.Literal("EUR"),
]);
const currency = Type.Object({
code: currencyCode,
rate: Type.Optional(Type.Number()),
});
const language = Type.Union([
Type.Literal("fr-FR"),
Type.Literal("en-US"),
]);
const textfield = Type.Union([
Type.String(),
Type.Object({}, {
additionalProperties: Type.String(),
}),
]);
const entity = Type.Object({
name: textfield,
email: Type.Optional(textfield),
address: Type.Optional(textfield),
phone: Type.Optional(textfield),
website: Type.Optional(textfield),
});
const item = Type.Object({
title: textfield,
quantity: Type.Number(),
price: Type.Number(),
});
export const schema = Type.Object({
id: Type.String(),
issued: Type.String({
format: "date",
}),
due: Type.String({
format: "date",
}),
currencies: Type.Array(currency),
logo: Type.Optional(Type.String({ description: "Your logo." })),
from: entity,
to: entity,
tax: Type.Optional(Type.Number()),
items: Type.Array(item),
note: Type.Optional(textfield),
});
export type Invoice = Static<typeof schema>;
type InvoiceItem = Static<typeof item>;
export type Language = Static<typeof language>;
type Entity = Static<typeof entity>;
export type Currency = Static<typeof currency>;
type RenderParams = {
to: string[];
from: string[];
title: string;
note: string;
details: string[][];
table: Table;
};
type Table = {
columns: string[];
rows: string[][];
summary: string[][];
};
function extractTitle(id: string, lang: Language) {
switch (lang) {
case "fr-FR":
return `Facture ${id}`;
case "en-US":
return `Invoice ${id}`;
}
}
function getTableColumns(lang: Language) {
switch (lang) {
case "fr-FR":
return [];
case "en-US":
return [];
}
}
function formatPrice(price: Number, currency: Currency) {
switch (currency.code) {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { parseArgs } from "jsr:@std/cli/parse-args";
import { Base64 } from "npm:js-base64";
import open from "npm:open";
function printHelp() {
console.log("help");
}
const { _, language, currency } = parseArgs(Deno.args, {
boolean: ["help"],
string: ["language", "currency"],
});
if (_.length == 0 || !language || !currency) {
printHelp();
Deno.exit(1);
}
const content = Deno.readTextFileSync(_[0]);
const url = new URL(`https://jsoninvoice.pomdtr.me/invoice/${Base64.encode(content)}`);
url.searchParams.set("language", language);
url.searchParams.set("currency", currency);
console.log(url.toString());
await open(url.toString());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import { Base64 } from "https://cdn.jsdelivr.net/npm/js-base64@3.7.7/base64.mjs";
import { debounce } from "https://esm.sh/lodash-es";
const editor = document.getElementById("editor");
const preview = document.getElementById("preview") as HTMLIFrameElement;
const printBtn = document.getElementById("print-btn") as HTMLButtonElement;
const copyBtn = document.getElementById("copy-btn") as HTMLButtonElement;
const formatBtn = document.getElementById("format-btn") as HTMLButtonElement;
const languageSelector = document.getElementById("languages") as HTMLSelectElement;
const currencySelector = document.getElementById("currencies") as HTMLSelectElement;
async function updatePreview() {
try {
const code = JSON.parse(editor.code);
const language = languageSelector.value;
const currency = currencySelector.value;
const encoded = Base64.encode(JSON.stringify(code));
preview.src = `${window.location.origin}/invoice/${encoded}?language=${language}&currency=${currency}`;
} catch (_) {
}
}
const debouncedUpdatePreview = debounce(updatePreview, 500, {});
editor.addEventListener("code-change", (e: CustomEvent) => {
debouncedUpdatePreview();
});
currencySelector.addEventListener("change", () => {
debouncedUpdatePreview();
});
languageSelector.addEventListener("change", () => {
debouncedUpdatePreview();
});
printBtn.addEventListener("click", (e: CustomEvent) => {
window.open(preview.src);
});
copyBtn.addEventListener("click", async (e: CustomEvent) => {
await navigator.clipboard.writeText(editor.code);
});
formatBtn.addEventListener("click", async (e: CustomEvent) => {
const invoice = JSON.parse(editor.code);
editor.code = JSON.stringify(invoice, null, 2);
});
updatePreview();

BTC Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .2) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
}
return btcPrice;
}

Donations that people have declared as being on my behalf.

1
2
// set at Mon Apr 08 2024 21:15:15 GMT+0000 (Coordinated Universal Time)
export let donations = {"totalGBP":103.3558,"currencyCount":2,"individual":[{"timestamp":1689933934.276,"amount":"50","currency":"USD"},{"timestamp":1689936862.918,"amount":"62.50","currency":"GBP"},{"timestamp":1708422075.09,"amount":"1.00","currency":"GB

BTC Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .2) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
}
return btcPrice;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { generateInvoicePDF } from "https://esm.town/v/vtdocs/generateInvoicePDF?v=1";
export const examplePDF = async (req: Request) => {
const invoicePDF = await generateInvoicePDF({
invoiceNumber: "001",
date: new Date().toDateString(),
customerName: "Alice Bar",
customerEmail: "alice@bar.com",
items: [{ description: "Arabica Beans 500g", quantity: 2, price: 10 }, {
description: "Robusta Beans 500g",
quantity: 1,
price: 11,
}],
currencySymbol: "$",
});
return new Response(invoicePDF, {
headers: { "Content-Type": "application/pdf" },
});
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import Craftgate from "npm:@craftgate/craftgate";
const craftgate = new Craftgate.Client({
apiKey: "sandbox-YEhueLgomBjqsnvBlWVVuFsVhlvJlMHE",
secretKey: "sandbox-tBdcdKVGmGupzfaWcULcwDLMoglZZvTz",
baseUrl: "https://sandbox-api.craftgate.io",
});
const request = {
price: 100.0,
paidPrice: 100.0,
walletPrice: 0.0,
installment: 1,
conversationId: "456d1297-908e-4bd6-a13b-4be31a6e47d5",
currency: Craftgate.Model.Currency.TRY,
paymentGroup: Craftgate.Model.PaymentGroup.ListingOrSubscription,
card: {
cardHolderName: "Haluk Demir",
cardNumber: "5258640000000001",
expireYear: "2044",
expireMonth: "07",
cvc: "000",
},
items: [
{
name: "Item 1",
price: 30.0,
externalId: "123d1297-839e-4bd6-a13b-4be31a6e12a8",
},
{
name: "Item 2",
price: 50.0,
externalId: "789d1297-839e-4bd6-a13b-4be31a6e13f7",
},
{
name: "Item 3",
price: 20.0,
externalId: "3a1d1297-839e-4bd6-a13b-4be31a6e18e6",
},
],
};
craftgate.payment().createPayment(request)
.then(result => console.info("Payment successful", result))
.catch(err => console.error("Payment failed", err));

BTC Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
console.log(lastBtcPrice, btcPrice);
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .2) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
}
return btcPrice;
}

BTC Price Alert

This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency.

Fork this val to get these notifications on your inbox.

Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency?v=5";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
let change = Math.abs(btcPrice - lastBtcPrice);
if (change / lastBtcPrice > .1) {
await blob.setJSON("lastBtcPrice", btcPrice);
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
}
return btcPrice;
}