> DOCUMENTATION
> Getting Started
Welcome to the BIP47 documentation. Here you'll find everything you need to understand and implement reusable payment codes, Auth47 authentication, and PayNym identity services.
What is BIP47?
BIP47 defines a protocol for reusable payment codes in Bitcoin. Unlike traditional addresses that should only be used once, payment codes allow you to share a single identifier that others can use to generate unlimited unique payment addresses for you.
What is Auth47?
Auth47 is an authentication protocol built on top of BIP47. It uses the notification address of a payment code to verify ownership, enabling passwordless authentication using Bitcoin wallets.
What is PayNym?
PayNym is a social layer built on BIP47 payment codes. It provides human-readable
identifiers (like +littlevoice) and a social graph of followers/following,
making it easier to discover and pay other Bitcoin users.
Quick Start: New to BIP47? Start with the BIP47 LAB for an interactive walkthrough of how payment codes work.
> BIP47 Protocol
BIP47 enables reusable payment codes that generate unique addresses for each transaction, preserving privacy while maintaining the convenience of a single identifier.
Payment Codes
A BIP47 payment code is a Base58Check-encoded string that starts with "PM8T". It contains a version byte, features byte, sign byte, x-coordinate of the public key, and chain code.
PM8TJYp8zHvhimVNRjUcEuULfmvmUML6YTbTSnU69MYy93AzsXELFLaVjpxc5mxDex7R8ttgtL1tGAt2TshZAoFeB5zn4c9nRo4oZpmuyuo4FTpUrd
Notification Address
Each payment code has a notification address derived from the public key at index 0. This address is used to signal the creation of a payment channel between two parties.
Creating a Payment Channel
- Alice obtains Bob's payment code
- Alice creates a notification transaction containing her encrypted payment code
- Bob monitors his notification address and detects Alice's transaction
- Both parties can now derive unique payment addresses for each other
Address Derivation
Payment addresses are derived using ECDH (Elliptic Curve Diffie-Hellman) to create a shared secret, which is then used to modify the public key derivation:
// Alice derives payment address for Bob
S = a × B // Shared secret (Alice's private key × Bob's public key)
s = SHA256(S_x) // x-coordinate of shared secret
K = B + s×G // Payment address public key
// Bob derives private key to spend
k = b + s // Bob's private key + shared secret scalar
Key Features
- Reusable: Share one code, receive unlimited payments
- Private: Each payment uses a unique address
- Non-interactive: Sender doesn't need receiver's cooperation
- Deterministic: Same addresses derived by both parties
Important: The notification transaction requires a small amount of Bitcoin (typically 546 sats) to be sent to the notification address. This is a one-time cost per payment channel.
> Auth47 Specification
Auth47 provides a challenge-response authentication protocol using BIP47 payment codes. It enables passwordless login by proving ownership of a payment code's notification address.
Protocol Overview
Auth47 uses the notification address of a BIP47 payment code as the identity. Authentication is performed by signing a challenge with the private key corresponding to the notification address.
Authentication Flow
- Challenge Generation: Server generates a unique nonce and creates an Auth47 URI
- QR Display: User scans the QR code with a compatible wallet
- Signature: Wallet signs the challenge using the notification address private key
- Verification: Server verifies the signature against the claimed payment code
- Authentication: Upon successful verification, user is authenticated
Auth47 URI Format
auth47://?c=[&r=][&e=]
Parameters
| Parameter | Description |
|---|---|
nonce |
Unique challenge identifier (16 bytes hex, in the URI hostname position) |
c |
Callback URL where the authentication response is POSTed |
r |
Resource URL (optional) - if omitted, callback URL is used as resource |
e |
Unix timestamp when challenge expires |
Challenge String Format: The challenge that gets signed always uses the r=
parameter format, even when the QR code only contains c=. If no explicit r=
parameter is present, the callback URL is used as the resource value. This ensures compatibility
with all wallet implementations (Samourai, Ashigaru, Sparrow, BlueWallet).
Verification Request
The wallet POSTs the following JSON to the callback URL:
{
"auth47_response": "1.0",
"challenge": "auth47://?r=&e=",
"nym": "PM8T...",
"signature": ""
}
Note: The challenge field always contains the r= format,
where the value is either the explicit resource URL from the QR code, or the callback URL if no
resource was specified. The c= parameter is never included in the signed challenge.
Signature Verification
The server verifies the signature using the notification address derived from the claimed payment code. The signature must be a valid Bitcoin message signature of the challenge URI.
Security Considerations
- Nonces expire after 5 minutes to prevent replay attacks
- Each nonce can only be used once
- Signatures must use the Bitcoin Message Signing format
- Servers should validate the expiry timestamp
Try it: Test Auth47 authentication on the Auth47 Login page.
> PayNym API
The PayNym API provides endpoints for creating and managing PayNym identities, following other PayNyms, and retrieving payment code information.
Base URL
https://paynym.rs/api/v1/
Public Endpoints
These endpoints do not require authentication and can be used to look up PayNym information.
Create PayNym
Create a new PayNym entry in the database.
| Parameter | Type | Description |
|---|---|---|
code |
string | A valid BIP47 payment code |
Get Token
Update the verification token for authenticated requests. Tokens are valid for 24 hours.
| Parameter | Type | Description |
|---|---|---|
code |
string | A valid BIP47 payment code |
Lookup Nym
Retrieve all known information about a PayNym account.
| Parameter | Type | Description |
|---|---|---|
nym |
string | Payment code, nymID, or nymName |
{
"codes": [
{
"claimed": true,
"segwit": true,
"code": "PM8T..."
}
],
"followers": [{ "nymId": "5iEpU..." }],
"following": [],
"nymID": "wXGgdC...",
"nymName": "littlevoice"
}
Authenticated Endpoints
These endpoints require authentication via the notification address signature.
Authentication Headers
| Header | Description |
|---|---|
auth-token |
The token obtained from /token endpoint |
Claim Payment Code
Claim ownership of a payment code by signing the token with the notification address.
| Parameter | Type | Description |
|---|---|---|
signature |
string | Token signed by BIP47 notification address |
Follow/Unfollow
Follow another PayNym account.
| Parameter | Type | Description |
|---|---|---|
target |
string | The nymID to follow |
signature |
string | Token signed by notification address |
Unfollow a PayNym account. Same parameters as /follow.
Add Payment Code
Add a new payment code to an existing Nym.
| Parameter | Type | Description |
|---|---|---|
nym |
string | Existing nymID, code, or nymName |
code |
string | New payment code to add |
signature |
string | Token signed by primary payment code |
Tip: Use the PayNym Explorer to look up PayNym details and see the API in action.
> Code Examples
Ready-to-use code snippets for common BIP47 and Auth47 operations.
Generate Payment Code
import ecc from '@bitcoinerlab/secp256k1';
import { BIP32Factory } from 'bip32';
import { BIP47Factory } from '@samouraiwallet/bip47';
const bip32 = BIP32Factory(ecc);
const bip47 = BIP47Factory(ecc);
// Generate from mnemonic
const seed = bip32.mnemonicToSeedSync(mnemonic);
const root = bip32.fromSeed(seed);
const account = root.derivePath("m/47'/0'/0'");
const paymentCode = bip47.fromBip32Node(account);
console.log(paymentCode.toBase58());
// PM8TJYp8zHvhimVNRjUcEuULfmvmUML6YTbTSnU69MYy93AzsXELFLaVjpxc5mxDex7R8ttgtL1tGAt2TshZAoFeB5zn4c9nRo4oZpmuyuo4FTpUrd
Derive Payment Address
// Alice derives address to pay Bob
const alice = bip47.fromBip32Node(aliceAccount);
const bob = bip47.fromBase58(bobPaymentCode);
// Get payment address at index 0
const paymentAddress = alice.getPaymentAddress(bob, 0, 'p2wpkh');
console.log(paymentAddress);
// tb1q8gpft5rpju8lcshfa6at44pev5y0q7kzfwqpg
Verify Auth47 Signature
import { Auth47Verifier } from '@samouraiwallet/auth47';
// IMPORTANT: Constructor expects (callbackUrl, ecc) - URL first, then ECC library
const verifier = new Auth47Verifier(callbackUrl, ecc);
const proof = {
auth47_response: challengeUri,
challenge: challengeUri,
nym: paymentCode,
signature: base64Signature
};
const result = verifier.verifyProof(proof, 'bitcoin');
if (result.result === 'ok') {
console.log('Authentication successful!');
} else {
console.error('Authentication failed:', result.error);
}
Lookup PayNym
// Lookup by nymID, nymName, or payment code
const response = await fetch('https://paynym.rs/api/v1/nym/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nym: '+littlevoice' })
});
const data = await response.json();
console.log(data.nymName); // "littlevoice"
console.log(data.nymID); // "wXGgdC..."
console.log(data.codes[0].code); // Payment code
Get PayNym Avatar
// Avatar URL format
https://paynym.rs/{payment_code}/avatar
// Example
https://paynym.rs/PM8TJYp8zHvhimVNRjUcEuULfmvmUML6YTbTSnU69MYy93AzsXELFLaVjpxc5mxDex7R8ttgtL1tGAt2TshZAoFeB5zn4c9nRo4oZpmuyuo4FTpUrd/avatar
> Resources
Official specifications, libraries, and community resources for BIP47 and PayNym.
Official Specifications
- BIP47 Specification - Official Bitcoin Improvement Proposal
- BIP47 Github Repository - Authentication protocol specification
- Auth47 Github Repository - Authentication protocol specification
Libraries
- @samouraiwallet/bip47 - BIP47 implementation for JavaScript/TypeScript
- @samouraiwallet/auth47 - Auth47 verification library
- @bitcoinerlab/secp256k1 - secp256k1 cryptography library
Wallets Supporting BIP47
- Samourai Wallet - Android wallet with full BIP47/PayNym support
- Sparrow Wallet - Desktop wallet with full BIP47/PayNym support
- BlueWallet - Android/iOS wallet with Non-Segwit BIP47 support
- Stack Wallet - Android/iOS/Desktop wallet with BIP47/PayNym integration
- Ashigaru - Android wallet with full BIP47/PayNym support
Community
- PayNym.rs - PayNym directory and API
- Support Bill & Keonne - Sign the petition, donate and get the word out
- TSB Signal Chat - A group chat for BIP47/PayNyms enjoyers. Contact Jordan to join.
Contribute: Found an error or want to improve this documentation? Submit a pull request to the GitHub repository .