Skip to content

Commit d903082

Browse files
docs: add comprehensive API documentation
Created complete API reference documentation: API Core: - authentication.md: Wallet-based auth flow with ed25519 signatures - rate-limits.md: Per-endpoint rate limits and best practices - errors.md: Complete error handling guide with Stellar error mapping API Endpoints: - payments.md: Payment flow (pay-intent, submit, confirm, status, verify-tx) - links.md: Payment links API (create, get, status, account activation) - clients.md: Client management (list, save, update favorite) - prices.md: XLM price feed with caching and rate limiting API Resources: - invoice.md: Complete Invoice object schema and field reference All documentation includes: - Full request/response examples - Field descriptions and validation rules - Error handling strategies - Integration patterns and best practices - Mermaid diagrams for complex flows - TypeScript interfaces
1 parent 942e8b2 commit d903082

8 files changed

Lines changed: 3762 additions & 0 deletions

File tree

docs/api/authentication.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Authentication
2+
3+
Link2Pay uses **passwordless wallet-based authentication** powered by ed25519 cryptographic signatures. No passwords, API keys, or OAuth flows are required.
4+
5+
## Authentication Flow
6+
7+
The authentication system uses a challenge-response mechanism:
8+
9+
```mermaid
10+
sequenceDiagram
11+
participant Client
12+
participant API
13+
participant Freighter as Freighter Wallet
14+
15+
Client->>API: POST /api/auth/nonce
16+
Note over Client,API: { walletAddress: "GABC..." }
17+
API->>API: Generate nonce
18+
API-->>Client: { nonce, message, expiresIn: 300 }
19+
20+
Client->>Freighter: Sign message
21+
Note over Client,Freighter: User approves in wallet
22+
Freighter-->>Client: signature
23+
24+
Client->>API: POST /api/auth/session
25+
Note over Client,API: { walletAddress, nonce, signature }
26+
API->>API: Verify ed25519 signature
27+
API-->>Client: { token, expiresAt }
28+
```
29+
30+
## Step 1: Request a Nonce
31+
32+
Request a one-time nonce for your wallet address:
33+
34+
**Endpoint:** `POST /api/auth/nonce`
35+
36+
**Request Body:**
37+
```json
38+
{
39+
"walletAddress": "GAIXVVI3IHXPCFVD4NF6NFMYNHF7ZO5J5KN3AEVD67X3ZGXNCRQQ2AIC"
40+
}
41+
```
42+
43+
**Response:**
44+
```json
45+
{
46+
"nonce": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
47+
"message": "Link2Pay Authentication\nWallet: GAIXVVI3IHXPCFVD4NF6NFMYNHF7ZO5J5KN3AEVD67X3ZGXNCRQQ2AIC\nNonce: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6\nTimestamp: 2024-03-07T12:00:00.000Z",
48+
"expiresIn": 300
49+
}
50+
```
51+
52+
**Validation:**
53+
- `walletAddress` must be a valid Stellar address (56 characters, starting with `G`)
54+
- Nonce expires in 5 minutes (300 seconds)
55+
56+
## Step 2: Sign the Message
57+
58+
Use Freighter wallet or your Stellar keypair to sign the message returned in step 1:
59+
60+
```typescript
61+
import { signAuthEntry } from '@stellar/freighter-api';
62+
63+
const signature = await signAuthEntry(
64+
message,
65+
{ accountToSign: walletAddress }
66+
);
67+
```
68+
69+
## Step 3: Exchange for Session Token
70+
71+
Submit the signature to receive a session token:
72+
73+
**Endpoint:** `POST /api/auth/session`
74+
75+
**Request Body:**
76+
```json
77+
{
78+
"walletAddress": "GAIXVVI3IHXPCFVD4NF6NFMYNHF7ZO5J5KN3AEVD67X3ZGXNCRQQ2AIC",
79+
"nonce": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
80+
"signature": "3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d..."
81+
}
82+
```
83+
84+
**Success Response (200):**
85+
```json
86+
{
87+
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
88+
"expiresAt": "2024-03-07T13:00:00.000Z",
89+
"walletAddress": "GAIXVVI3IHXPCFVD4NF6NFMYNHF7ZO5J5KN3AEVD67X3ZGXNCRQQ2AIC"
90+
}
91+
```
92+
93+
**Error Response (401):**
94+
```json
95+
{
96+
"error": "Invalid or expired signature. Request a new nonce from POST /api/auth/nonce"
97+
}
98+
```
99+
100+
## Using the Session Token
101+
102+
Include the session token in the `Authorization` header for all authenticated requests:
103+
104+
```bash
105+
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
106+
https://api.link2pay.dev/api/invoices
107+
```
108+
109+
**Token Lifetime:**
110+
- Session tokens are valid for 1 hour
111+
- After expiration, repeat the authentication flow to get a new token
112+
113+
## Protected Endpoints
114+
115+
The following endpoints require authentication:
116+
117+
| Endpoint | Method | Description |
118+
|----------|--------|-------------|
119+
| `/api/invoices` | POST | Create invoice |
120+
| `/api/invoices` | GET | List your invoices |
121+
| `/api/invoices/:id/owner` | GET | Get invoice details (owner) |
122+
| `/api/invoices/:id` | PATCH | Update invoice |
123+
| `/api/invoices/:id/send` | POST | Send invoice |
124+
| `/api/invoices/:id` | DELETE | Delete invoice |
125+
| `/api/clients` | GET | List saved clients |
126+
| `/api/clients` | POST | Save client |
127+
| `/api/clients/:id/favorite` | PATCH | Update favorite status |
128+
| `/api/links` | POST | Create payment link |
129+
130+
## Security Considerations
131+
132+
### Why Wallet-Based Auth?
133+
134+
1. **No Password Storage**: Users don't need to remember passwords or manage API keys
135+
2. **Cryptographic Security**: Uses ed25519 signatures (same as Stellar network)
136+
3. **Non-Custodial**: Your private keys never leave your wallet
137+
4. **Phishing Resistant**: Users approve each signature in their wallet
138+
139+
### Implementation Details
140+
141+
- Nonces are single-use and expire in 5 minutes
142+
- Session tokens use JWT with HS256 signing
143+
- Signatures are verified using `@stellar/stellar-sdk`'s `Keypair.verify()` method
144+
- Failed authentication attempts are rate-limited (see [Rate Limits](/api/rate-limits))
145+
146+
## Example: Complete Authentication Flow
147+
148+
```typescript
149+
import { signAuthEntry } from '@stellar/freighter-api';
150+
151+
async function authenticate(walletAddress: string) {
152+
// Step 1: Request nonce
153+
const nonceRes = await fetch('https://api.link2pay.dev/api/auth/nonce', {
154+
method: 'POST',
155+
headers: { 'Content-Type': 'application/json' },
156+
body: JSON.stringify({ walletAddress })
157+
});
158+
const { nonce, message } = await nonceRes.json();
159+
160+
// Step 2: Sign with Freighter
161+
const signature = await signAuthEntry(message, {
162+
accountToSign: walletAddress
163+
});
164+
165+
// Step 3: Get session token
166+
const sessionRes = await fetch('https://api.link2pay.dev/api/auth/session', {
167+
method: 'POST',
168+
headers: { 'Content-Type': 'application/json' },
169+
body: JSON.stringify({ walletAddress, nonce, signature })
170+
});
171+
const { token, expiresAt } = await sessionRes.json();
172+
173+
return { token, expiresAt };
174+
}
175+
176+
// Use the token
177+
const { token } = await authenticate(myWalletAddress);
178+
179+
const invoices = await fetch('https://api.link2pay.dev/api/invoices', {
180+
headers: { 'Authorization': `Bearer ${token}` }
181+
});
182+
```
183+
184+
## Error Codes
185+
186+
| Status | Error | Description |
187+
|--------|-------|-------------|
188+
| 400 | Invalid Stellar address | Wallet address format is invalid |
189+
| 401 | Invalid or expired signature | Signature verification failed or nonce expired |
190+
| 401 | Authentication required | No Authorization header provided |
191+
| 401 | Invalid token | Token is malformed or expired |
192+
| 429 | Too many requests | Rate limit exceeded (see [Rate Limits](/api/rate-limits)) |
193+
194+
## Next Steps
195+
196+
- Learn about [Rate Limits](/api/rate-limits)
197+
- Explore [Invoice Endpoints](/api/endpoints/invoices)
198+
- Check [Integration Guide](/guide/integration/authentication)

0 commit comments

Comments
 (0)