@attesso/sdk 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -241
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -1,305 +1,136 @@
|
|
|
1
1
|
# @attesso/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
API client for executing payments against FIDO2-signed mandates.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install @attesso/sdk
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
AI agents need to spend money. Attesso gives them a wallet with hardware-backed security and user-controlled spending limits.
|
|
12
|
-
|
|
13
|
-
This SDK lets agents:
|
|
14
|
-
- Execute payments within pre-authorized limits
|
|
15
|
-
- Prove their identity to merchants
|
|
16
|
-
- Check available spending power
|
|
17
|
-
|
|
18
|
-
**No mobile app required.** Users authorize spending with WebAuthn passkeys (FaceID/TouchID) directly in the browser.
|
|
19
|
-
|
|
20
|
-
## Quick Start
|
|
9
|
+
## AttessoClient
|
|
21
10
|
|
|
22
11
|
```typescript
|
|
23
12
|
import { AttessoClient } from '@attesso/sdk';
|
|
24
13
|
|
|
25
14
|
const client = new AttessoClient({
|
|
26
15
|
apiKey: process.env.ATTESSO_API_KEY,
|
|
16
|
+
baseUrl: process.env.ATTESSO_BASE_URL, // optional
|
|
27
17
|
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Methods
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
#### getMandate(mandateId)
|
|
23
|
+
```typescript
|
|
30
24
|
const mandate = await client.getMandate('mandate_xyz');
|
|
31
|
-
|
|
25
|
+
// { id, botId, maxAmount, currency, merchant?, status, expiresAt?, createdAt }
|
|
26
|
+
```
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
#### executePayment(options)
|
|
29
|
+
```typescript
|
|
34
30
|
const payment = await client.executePayment({
|
|
35
31
|
mandateId: 'mandate_xyz',
|
|
36
|
-
amount: 34700, //
|
|
37
|
-
merchant: '
|
|
32
|
+
amount: 34700, // cents
|
|
33
|
+
merchant: 'Acme Corp',
|
|
38
34
|
});
|
|
39
|
-
|
|
40
|
-
// Get identity token for merchant verification
|
|
41
|
-
const passport = await client.getPassport('mandate_xyz');
|
|
35
|
+
// { id, mandateId, amount, merchant, status, createdAt }
|
|
42
36
|
```
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Users create spending mandates in your web dashboard using WebAuthn passkeys:
|
|
47
|
-
|
|
38
|
+
#### getPayment(paymentId)
|
|
48
39
|
```typescript
|
|
49
|
-
|
|
50
|
-
import { startAuthentication } from '@simplewebauthn/browser';
|
|
51
|
-
|
|
52
|
-
// 1. Get authentication options from your backend
|
|
53
|
-
const authOptions = await fetch('/api/auth/webauthn/authenticate/options', {
|
|
54
|
-
method: 'POST',
|
|
55
|
-
}).then(r => r.json());
|
|
56
|
-
|
|
57
|
-
// 2. User authenticates with FaceID/TouchID (or QR code on desktop)
|
|
58
|
-
const assertion = await startAuthentication(authOptions);
|
|
59
|
-
|
|
60
|
-
// 3. Create mandate with the assertion
|
|
61
|
-
const mandate = await fetch('/api/mandates', {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
headers: { 'Content-Type': 'application/json' },
|
|
64
|
-
body: JSON.stringify({
|
|
65
|
-
botId: 'bot_travel_agent',
|
|
66
|
-
maxAmount: 50000, // $500.00
|
|
67
|
-
currency: 'usd',
|
|
68
|
-
merchant: 'United Airlines',
|
|
69
|
-
webAuthnAssertion: assertion,
|
|
70
|
-
}),
|
|
71
|
-
}).then(r => r.json());
|
|
72
|
-
|
|
73
|
-
// 4. Pass mandateId to your AI agent
|
|
40
|
+
const payment = await client.getPayment('payment_abc');
|
|
74
41
|
```
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
On desktops without biometrics (TouchID), WebAuthn automatically shows a QR code. Users scan it with their phone and authenticate using the phone's FaceID/TouchID. The signature still comes from hardware (phone's Secure Enclave).
|
|
79
|
-
|
|
80
|
-
## Vercel AI SDK Integration
|
|
81
|
-
|
|
82
|
-
One line gives your AI agent a wallet:
|
|
83
|
-
|
|
43
|
+
#### getPassport(mandateId)
|
|
84
44
|
```typescript
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const result = await generateText({
|
|
89
|
-
model: openai('gpt-4o'),
|
|
90
|
-
tools: attesso.tools(),
|
|
91
|
-
prompt: 'Book me a flight to NYC under $500',
|
|
92
|
-
});
|
|
45
|
+
const passport = await client.getPassport('mandate_xyz');
|
|
46
|
+
// { token, expiresAt }
|
|
93
47
|
```
|
|
94
48
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
| Tool | Description |
|
|
98
|
-
|------|-------------|
|
|
99
|
-
| `attesso_pay` | Execute payment against mandate |
|
|
100
|
-
| `attesso_get_mandate` | Check spending limits |
|
|
101
|
-
| `attesso_get_passport` | Get identity token |
|
|
102
|
-
| `attesso_capture` | Capture authorized payment |
|
|
103
|
-
| `attesso_cancel` | Cancel and release funds |
|
|
104
|
-
| `attesso_check_balance` | Quick balance check |
|
|
105
|
-
|
|
106
|
-
### Configuration
|
|
107
|
-
|
|
49
|
+
#### capture(paymentId, options)
|
|
108
50
|
```typescript
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
maxAmountPerTransaction: 50000, // $500 cap
|
|
51
|
+
const result = await client.capture('payment_abc', {
|
|
52
|
+
amount: 34700,
|
|
53
|
+
metadata: { orderId: '123' },
|
|
113
54
|
});
|
|
55
|
+
// { id, authorizedAmount, capturedAmount, status: 'completed' }
|
|
114
56
|
```
|
|
115
57
|
|
|
116
|
-
|
|
117
|
-
|
|
58
|
+
#### cancel(paymentId)
|
|
118
59
|
```typescript
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const client = new AttessoClient({ apiKey: '...' });
|
|
122
|
-
|
|
123
|
-
// Get mandate details
|
|
124
|
-
const mandate = await client.getMandate(mandateId);
|
|
125
|
-
|
|
126
|
-
// Execute payment
|
|
127
|
-
const payment = await client.executePayment({
|
|
128
|
-
mandateId,
|
|
129
|
-
amount: 10000,
|
|
130
|
-
merchant: 'Acme Corp',
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Check payment status
|
|
134
|
-
const status = await client.getPayment(payment.id);
|
|
135
|
-
|
|
136
|
-
// Auth/Capture flow
|
|
137
|
-
const auth = await client.executePayment({
|
|
138
|
-
mandateId,
|
|
139
|
-
amount: 50000,
|
|
140
|
-
merchant: 'Hotel',
|
|
141
|
-
});
|
|
142
|
-
await client.capture(auth.id, { amount: 45000 }); // Final price
|
|
143
|
-
|
|
144
|
-
// Cancel authorization
|
|
145
|
-
await client.cancel(auth.id);
|
|
146
|
-
|
|
147
|
-
// Get passport token
|
|
148
|
-
const passport = await client.getPassport(mandateId);
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## How It Works
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
User creates mandate → WebAuthn passkey signs authorization
|
|
155
|
-
↓ (FaceID/TouchID or phone QR)
|
|
156
|
-
Mandate stored → Hardware attestation verified
|
|
157
|
-
↓
|
|
158
|
-
AI Agent calls SDK → SDK checks mandate limits
|
|
159
|
-
↓
|
|
160
|
-
Payment executed → Funds transferred via Stripe
|
|
161
|
-
↓
|
|
162
|
-
Merchant verifies → Passport proves authorized spending
|
|
60
|
+
const result = await client.cancel('payment_abc');
|
|
61
|
+
// { id, authorizedAmount, status: 'cancelled' }
|
|
163
62
|
```
|
|
164
63
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- **WebAuthn Passkeys**: Mandates signed by device Secure Enclave
|
|
168
|
-
- **Cross-Device Support**: QR-based authentication for desktops
|
|
169
|
-
- **User Control**: Instant revocation, spending limits
|
|
170
|
-
- **Cryptographic Identity**: JWT passports verifiable offline
|
|
171
|
-
|
|
172
|
-
## Infrastructure Security
|
|
173
|
-
|
|
174
|
-
### Idempotency
|
|
175
|
-
- Idempotency keys required on all payment operations
|
|
176
|
-
- Concurrent duplicates return `409 Conflict`
|
|
177
|
-
- Request payloads hashed to detect tampering
|
|
178
|
-
|
|
179
|
-
### WebAuthn
|
|
180
|
-
- Origin-bound credentials (phishing-resistant)
|
|
181
|
-
- Single-use challenges with TTL
|
|
182
|
-
- Hardware counter validation
|
|
183
|
-
|
|
184
|
-
### Rate Limiting
|
|
185
|
-
| Endpoint | Limit |
|
|
186
|
-
|----------|-------|
|
|
187
|
-
| Auth | 5/min |
|
|
188
|
-
| Payments | 30/min |
|
|
189
|
-
| General | 100/min |
|
|
190
|
-
|
|
191
|
-
### Webhook Processing
|
|
192
|
-
- Stripe event deduplication via `WebhookEvent` table
|
|
193
|
-
- Row-level locking (`SELECT ... FOR UPDATE`)
|
|
194
|
-
- Serializable transaction isolation
|
|
195
|
-
|
|
196
|
-
### Hardware Security by Device
|
|
197
|
-
|
|
198
|
-
| Device | Security | Auth Method |
|
|
199
|
-
|--------|----------|-------------|
|
|
200
|
-
| iPhone/iPad | Secure Enclave | FaceID/TouchID |
|
|
201
|
-
| Mac (Touch ID) | Secure Enclave | TouchID |
|
|
202
|
-
| Mac (no Touch ID) | Phone via QR | Phone's Secure Enclave |
|
|
203
|
-
| Windows (Hello) | TPM 2.0 | Windows Hello |
|
|
204
|
-
| Windows (no Hello) | Phone via QR | Requires Bluetooth + manual selection |
|
|
205
|
-
| Android | TEE/StrongBox | Fingerprint/Face |
|
|
206
|
-
|
|
207
|
-
**Windows Note:** Without Windows Hello, users see a USB security key prompt first. They must click Cancel and select "iPhone/Android" for QR code. Bluetooth must be enabled.
|
|
208
|
-
|
|
209
|
-
## Application Fee Routing (Optional)
|
|
210
|
-
|
|
211
|
-
Configure application fees per transaction. The protocol uses an additive settlement model, calculating charges on top of the base amount. This ensures merchant principal preservation while automating fee routing to the connected Stripe account.
|
|
212
|
-
|
|
213
|
-
### Configuration
|
|
64
|
+
## Vercel AI SDK
|
|
214
65
|
|
|
215
66
|
```typescript
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
amount: 10000, // $100.00 principal amount
|
|
219
|
-
currency: 'usd',
|
|
220
|
-
merchant: 'Acme Corp',
|
|
221
|
-
mandateId: 'mandate_xyz',
|
|
222
|
-
paymentId: 'payment_abc',
|
|
223
|
-
userId: 'user_123',
|
|
224
|
-
applicationFee: {
|
|
225
|
-
destinationAccountId: 'acct_your_stripe_connect_id',
|
|
226
|
-
feePercent: 5, // percentage of principal
|
|
227
|
-
// OR
|
|
228
|
-
feeFixed: 100, // fixed amount (cents)
|
|
229
|
-
// OR both combined
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Fee Routing Options
|
|
235
|
-
|
|
236
|
-
| Parameter | Example | On $100 principal |
|
|
237
|
-
|-----------|---------|-------------------|
|
|
238
|
-
| `feePercent` | `5` | +$5.00 |
|
|
239
|
-
| `feeFixed` | `100` | +$1.00 |
|
|
240
|
-
| Hybrid | `{ percent: 2, fixed: 30 }` | +$2.30 |
|
|
241
|
-
|
|
242
|
-
### Settlement Model
|
|
243
|
-
|
|
244
|
-
$100 principal with 1% protocol fee + 5% application fee:
|
|
245
|
-
|
|
246
|
-
| Settlement | Amount |
|
|
247
|
-
|------------|--------|
|
|
248
|
-
| Net Settlement (Merchant) | $100.00 |
|
|
249
|
-
| Protocol Fee (Attesso) | $1.00 |
|
|
250
|
-
| Application Fee | $5.00 |
|
|
251
|
-
| **Total Authorization** | **$106.00** |
|
|
67
|
+
import { generateText } from 'ai';
|
|
68
|
+
import { attesso } from '@attesso/sdk/vercel';
|
|
252
69
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
70
|
+
const result = await generateText({
|
|
71
|
+
model: openai('gpt-4o'),
|
|
72
|
+
tools: attesso.tools({
|
|
73
|
+
mandateId: 'mandate_xyz', // optional: pre-select mandate
|
|
74
|
+
merchant: 'Acme Corp', // optional: lock to merchant
|
|
75
|
+
maxAmountPerTransaction: 50000, // optional: per-tx cap
|
|
76
|
+
}),
|
|
77
|
+
prompt: 'Book a flight under $500',
|
|
78
|
+
});
|
|
256
79
|
```
|
|
257
80
|
|
|
258
|
-
###
|
|
259
|
-
|
|
260
|
-
- Stripe Connect account (`acct_...` ID)
|
|
261
|
-
- Application fee routing is optional—omit to disable
|
|
81
|
+
### Tools
|
|
262
82
|
|
|
263
|
-
|
|
83
|
+
| Tool | Parameters | Returns |
|
|
84
|
+
|------|------------|---------|
|
|
85
|
+
| `attesso_pay` | `{ mandateId?, amount, merchant? }` | PaymentResponse |
|
|
86
|
+
| `attesso_get_mandate` | `{ mandateId? }` | MandateResponse |
|
|
87
|
+
| `attesso_get_payment` | `{ paymentId }` | PaymentResponse |
|
|
88
|
+
| `attesso_get_passport` | `{ mandateId? }` | PassportToken |
|
|
89
|
+
| `attesso_capture` | `{ paymentId, amount, metadata? }` | CaptureResponse |
|
|
90
|
+
| `attesso_cancel` | `{ paymentId }` | CancelResponse |
|
|
91
|
+
| `attesso_check_balance` | `{ mandateId? }` | `{ available, currency, status }` |
|
|
264
92
|
|
|
265
|
-
|
|
93
|
+
## Origin Restrictions
|
|
266
94
|
|
|
267
95
|
```typescript
|
|
268
96
|
const client = new AttessoClient({
|
|
269
|
-
apiKey: '
|
|
270
|
-
allowedOrigins: [
|
|
271
|
-
'https://myapp.com',
|
|
272
|
-
'https://*.trusted-partner.com', // Wildcard subdomains
|
|
273
|
-
],
|
|
97
|
+
apiKey: '...',
|
|
98
|
+
allowedOrigins: ['https://myapp.com', 'https://*.trusted.com'],
|
|
274
99
|
});
|
|
275
100
|
```
|
|
276
101
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
## Environment Variables
|
|
280
|
-
|
|
281
|
-
```bash
|
|
282
|
-
ATTESSO_API_KEY=your_api_key
|
|
283
|
-
ATTESSO_BASE_URL=https://api.attesso.dev # optional
|
|
284
|
-
```
|
|
102
|
+
Throws `OriginNotAllowedError` if called from unlisted origin.
|
|
285
103
|
|
|
286
|
-
##
|
|
287
|
-
|
|
288
|
-
Full type safety included:
|
|
104
|
+
## Types
|
|
289
105
|
|
|
290
106
|
```typescript
|
|
291
107
|
import type {
|
|
292
108
|
MandateResponse,
|
|
293
109
|
PaymentResponse,
|
|
294
110
|
PassportToken,
|
|
295
|
-
|
|
111
|
+
CapturePaymentResponse,
|
|
112
|
+
CancelAuthorizationResponse,
|
|
296
113
|
} from '@attesso/sdk';
|
|
297
114
|
```
|
|
298
115
|
|
|
116
|
+
## Errors
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { AttessoError, OriginNotAllowedError } from '@attesso/sdk';
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
await client.executePayment({ ... });
|
|
123
|
+
} catch (e) {
|
|
124
|
+
if (e instanceof AttessoError) {
|
|
125
|
+
console.log(e.code); // MANDATE_NOT_FOUND, AMOUNT_EXCEEDS_LIMIT, etc.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
299
130
|
## Requirements
|
|
300
131
|
|
|
301
132
|
- Node.js 18+
|
|
302
|
-
- For Vercel AI SDK
|
|
133
|
+
- For Vercel AI SDK: `ai` >= 3.0, `zod` >= 3.0
|
|
303
134
|
|
|
304
135
|
## License
|
|
305
136
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@attesso/sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "API client for executing payments against FIDO2-signed mandates. Includes Vercel AI SDK tools.",
|
|
5
5
|
"author": "Attesso",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -41,11 +41,9 @@
|
|
|
41
41
|
"keywords": [
|
|
42
42
|
"attesso",
|
|
43
43
|
"payments",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"vercel-ai-sdk",
|
|
48
|
-
"ai-tools"
|
|
44
|
+
"mandates",
|
|
45
|
+
"fido2",
|
|
46
|
+
"vercel-ai-sdk"
|
|
49
47
|
],
|
|
50
48
|
"dependencies": {
|
|
51
49
|
"@attesso/gatekeeper": "workspace:*",
|