Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions packages/payments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,23 @@ await payments.wallets.delete(id);

### Transactions

#### Receiving

`transactions.createReceive` generates a Lightning invoice for a wallet. Unlike
sending, the backend mints the invoice on the node itself — no team password or
node macaroon needed, and it works the same for sandbox and live wallets.

```ts
await payments.transactions.createReceive({
wallet_id,
amount,
idempotency_key,
description?,
expires_in?,
const transaction = await payments.transactions.createReceive({
wallet_id: walletId,
amount: '1000', // in the wallet asset's base unit (sats for BTC)
description: 'Order #1234', // optional
expires_in_seconds: 3600, // optional
idempotency_key, // optional
});

transaction.payment_request; // the BOLT11 invoice to share with the payer
transaction.payment_hash;
```

#### Sending
Expand Down
6 changes: 6 additions & 0 deletions packages/payments/examples/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ AMBOSS_API_KEY=
# FEE_LIMIT_SATS=10
# IDEMPOTENCY_KEY=
# TIMEOUT_SECONDS=60

# --- Receive (examples/receive.ts) ----------------------------------------
# Reuses WALLET_ID above. Leave WALLET_ID unset to just list wallets.
# Amount to invoice, in the wallet asset's base unit (sats for BTC). Default 1000.
# RECEIVE_AMOUNT_SATS=1000
# RECEIVE_DESCRIPTION=
15 changes: 15 additions & 0 deletions packages/payments/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,18 @@ Destinations (set one):

The team password is used only to decrypt the node admin macaroon locally; it is
never sent to the API. See `.env.example` for every supported variable.

### `receive.ts` — discovery + mint an invoice

1. **If** `WALLET_ID` is unset, lists your environments and wallets so you can
grab one.
2. **If** `WALLET_ID` is set, mints a Lightning invoice via
`payments.transactions.createReceive` and prints the BOLT11 `payment_request`.

Receiving needs no team password or macaroon and works the same for sandbox and
live wallets. Set `RECEIVE_AMOUNT_SATS` (default `1000`) and optionally
`RECEIVE_DESCRIPTION`.

```bash
node --env-file=examples/.env examples/receive.ts
```
85 changes: 85 additions & 0 deletions packages/payments/examples/receive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Manual smoke test for the @ambosstech/payments SDK receive flow.
*
* Run from packages/payments (Node 24 runs .ts directly):
* node --env-file=examples/.env examples/receive.ts
* or with tsx:
* pnpm exec tsx --env-file=examples/.env examples/receive.ts
*
* Behaviour:
* 1. If WALLET_ID is unset, lists your environments + wallets so you can grab one.
* 2. If WALLET_ID is set, mints a Lightning invoice via transactions.createReceive
* and prints the BOLT11 payment_request to pay.
*
* Unlike sending, receiving needs no team password or macaroon — the backend
* mints the invoice on the node. Works the same for sandbox and live wallets.
*
* Copy examples/.env.example -> examples/.env and fill it in. Do NOT commit .env.
*/
import { Payments, ApiError } from '@ambosstech/payments';

function required(name: string): string {
const value = process.env[name];
if (!value) {
console.error(`Missing required env var: ${name}`);
process.exit(1);
}
return value;
}

async function main(): Promise<void> {
const serviceApiKey = required('AMBOSS_API_KEY'); // the scoped payments service key (amb_live...)
const baseUrl = process.env.AMBOSS_BASE_URL; // optional; defaults to https://rails.amboss.tech/graphql

const payments = new Payments({ serviceApiKey, ...(baseUrl ? { baseUrl } : {}) });

const walletId = process.env.WALLET_ID;

// No wallet chosen yet — list environments + wallets so you can pick one.
if (!walletId) {
console.log('--- environments & wallets ---');
const environments = await payments.environments.list();
if (environments.length === 0) {
console.log('(no environments found for this API key)');
}
for (const environment of environments) {
console.log('environment:', JSON.stringify(environment));
const wallets = await payments.wallets.list({ environmentId: environment.id });
for (const wallet of wallets) {
console.log(' wallet:', JSON.stringify(wallet));
}
}
console.log('\nSet WALLET_ID (and optionally RECEIVE_AMOUNT_SATS) to mint an invoice.');
return;
}

const amount = process.env.RECEIVE_AMOUNT_SATS ?? '1000'; // base unit (sats for BTC)
const description = process.env.RECEIVE_DESCRIPTION;

console.log('\n--- creating receive invoice ---');
console.log('walletId:', walletId, '| amount:', amount);

try {
const transaction = await payments.transactions.createReceive({
wallet_id: walletId,
amount,
...(description ? { description } : {}),
});
console.log('\n✅ invoice created');
console.log('payment_request:', transaction.payment_request);
console.log('payment_hash:', transaction.payment_hash);
console.log('transaction:', JSON.stringify(transaction, null, 2));
} catch (error) {
if (error instanceof ApiError) {
console.error('\n❌ API error:', error.status, error.message, error.graphqlErrors);
} else {
console.error('\n❌ unexpected error:', error);
}
process.exit(1);
}
}

main().catch((error) => {
console.error(error);
process.exit(1);
});
Loading