vybekiit 0.7.18 → 0.7.19
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/dist/global-skills/expo-skill-eval/scripts/check-static.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/clean-fixture.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/latest-sdk.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/make-fixture.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/make-workspace.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-android.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-ios.sh +0 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-web.sh +0 -0
- package/dist/global-skills/resend/SKILL.md +1 -1
- package/dist/global-skills/resend/references/api-keys.md +21 -2
- package/dist/global-skills/resend/references/broadcasts.md +32 -0
- package/dist/global-skills/resend/references/sending/email-management.md +105 -1
- package/dist/global-skills/use-railway/scripts/analyze-mongo.py +0 -0
- package/dist/global-skills/use-railway/scripts/analyze-mysql.py +0 -0
- package/dist/global-skills/use-railway/scripts/analyze-postgres.py +0 -0
- package/dist/global-skills/use-railway/scripts/analyze-redis.py +0 -0
- package/dist/global-skills/use-railway/scripts/enable-pg-stats.py +0 -0
- package/dist/global-skills/use-railway/scripts/pg-extensions.py +0 -0
- package/dist/global-skills/use-railway/scripts/railway-api.sh +0 -0
- package/package.json +22 -21
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -156,7 +156,7 @@ export async function POST(req: Request) {
|
|
|
156
156
|
| **Send batch emails** | [sending/overview.md](references/sending/overview.md) → [sending/batch-email-examples.md](references/sending/batch-email-examples.md) |
|
|
157
157
|
| **Full SDK examples** (Node.js, Python, Go, cURL) | [sending/single-email-examples.md](references/sending/single-email-examples.md) |
|
|
158
158
|
| **Idempotency, retries, error handling** | [sending/best-practices.md](references/sending/best-practices.md) |
|
|
159
|
-
| **Get, list, reschedule, cancel emails** | [sending/email-management.md](references/sending/email-management.md) |
|
|
159
|
+
| **Get, list, reschedule, cancel emails, retrieve metrics** | [sending/email-management.md](references/sending/email-management.md) |
|
|
160
160
|
| **Receive inbound emails** | [receiving.md](references/receiving.md) — domain setup, webhooks, attachments |
|
|
161
161
|
| **Manage templates** (CRUD, variables) | [templates.md](references/templates.md) — lifecycle, aliases, pagination |
|
|
162
162
|
| **Set up webhooks** (events, verification) | [webhooks.md](references/webhooks.md) — verification, CRUD, retry schedule, IP allowlist |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# API Keys
|
|
2
2
|
|
|
3
|
-
Create, list, and delete API keys programmatically. No get
|
|
3
|
+
Create, list, update, and delete API keys programmatically. No get endpoint exists.
|
|
4
4
|
|
|
5
5
|
## SDK Methods
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ Create, list, and delete API keys programmatically. No get or update endpoints e
|
|
|
8
8
|
|-----------|---------|--------|
|
|
9
9
|
| Create | `resend.apiKeys.create(params)` | `resend.ApiKeys.create(params)` |
|
|
10
10
|
| List | `resend.apiKeys.list(params?)` | `resend.ApiKeys.list()` |
|
|
11
|
+
| Update | `resend.apiKeys.update(id, params)` | `resend.ApiKeys.update(params)` |
|
|
11
12
|
| Delete | `resend.apiKeys.remove(id)` | `resend.ApiKeys.remove(id)` |
|
|
12
13
|
|
|
13
14
|
## Create Parameters
|
|
@@ -20,6 +21,12 @@ Create, list, and delete API keys programmatically. No get or update endpoints e
|
|
|
20
21
|
- `domainId`: only applies when `permission` is `"sending_access"` — scopes the key to a single domain
|
|
21
22
|
- `name`: max 50 characters
|
|
22
23
|
|
|
24
|
+
## Update Parameters
|
|
25
|
+
|
|
26
|
+
**Required:** `name`
|
|
27
|
+
|
|
28
|
+
Only `name` can be changed. `permission` and `domainId` are fixed at creation — recreate the key to change either.
|
|
29
|
+
|
|
23
30
|
## Examples
|
|
24
31
|
|
|
25
32
|
### Node.js
|
|
@@ -47,6 +54,11 @@ console.log('Key ID:', data.id);
|
|
|
47
54
|
// List all keys (tokens are NOT included in list response)
|
|
48
55
|
const { data: keys, error: listError } = await resend.apiKeys.list();
|
|
49
56
|
|
|
57
|
+
// Rename a key (only `name` is patchable)
|
|
58
|
+
const { data: updated, error: updateError } = await resend.apiKeys.update('api_key_id', {
|
|
59
|
+
name: 'Production Sending Key v2',
|
|
60
|
+
});
|
|
61
|
+
|
|
50
62
|
// Delete a key
|
|
51
63
|
const { data: deleted, error: deleteError } = await resend.apiKeys.remove('api_key_id');
|
|
52
64
|
```
|
|
@@ -71,6 +83,12 @@ print(f"API Key: {key['token']}")
|
|
|
71
83
|
# List all keys
|
|
72
84
|
keys = resend.ApiKeys.list()
|
|
73
85
|
|
|
86
|
+
# Rename a key (only "name" is patchable)
|
|
87
|
+
resend.ApiKeys.update({
|
|
88
|
+
"api_key_id": "api_key_id",
|
|
89
|
+
"name": "Production Sending Key v2",
|
|
90
|
+
})
|
|
91
|
+
|
|
74
92
|
# Delete a key
|
|
75
93
|
resend.ApiKeys.remove("api_key_id")
|
|
76
94
|
```
|
|
@@ -80,7 +98,8 @@ resend.ApiKeys.remove("api_key_id")
|
|
|
80
98
|
| Mistake | Fix |
|
|
81
99
|
|---------|-----|
|
|
82
100
|
| Not storing the token on create | The token is returned **once** — store it immediately |
|
|
83
|
-
| Expecting a get
|
|
101
|
+
| Expecting a get endpoint | Doesn't exist — list returns metadata only (no tokens) |
|
|
102
|
+
| Trying to update `permission` or `domainId` | Only `name` can be patched — recreate the key to change scope |
|
|
84
103
|
| Setting `domainId` with `full_access` | `domainId` only applies to `sending_access` keys |
|
|
85
104
|
| Calling `.delete()` instead of `.remove()` | Node.js SDK uses `.remove()` for all delete operations |
|
|
86
105
|
| Ignoring `error` return | Node.js SDK returns `{ data, error }` — always check `error` |
|
|
@@ -13,6 +13,8 @@ Send emails to audience segments. Broadcasts follow a two-step lifecycle: **crea
|
|
|
13
13
|
| Cancel | `resend.broadcasts.cancel(id)` | `resend.Broadcasts.cancel(id)` |
|
|
14
14
|
| Update | `resend.broadcasts.update(id, params)` | `resend.Broadcasts.update(params)` |
|
|
15
15
|
| Delete | `resend.broadcasts.remove(id)` | `resend.Broadcasts.remove(id)` |
|
|
16
|
+
| Clicked Links | `resend.broadcasts.clickedLinks(id, params?)` | `resend.Broadcasts.clicked_links(id, params?)` |
|
|
17
|
+
| Recipients | `resend.broadcasts.recipients(id, params)` | `resend.Broadcasts.recipients(id, params)` |
|
|
16
18
|
|
|
17
19
|
## Create Parameters
|
|
18
20
|
|
|
@@ -88,8 +90,36 @@ const { data, error } = await resend.broadcasts.cancel('bc_abc123');
|
|
|
88
90
|
// Delete — draft or scheduled only (deleting a scheduled broadcast also
|
|
89
91
|
// cancels its delivery). Sent broadcasts cannot be deleted.
|
|
90
92
|
const { data, error } = await resend.broadcasts.remove('bc_abc123');
|
|
93
|
+
|
|
94
|
+
// Clicked links — ranked by total clicks, paginated with cursors
|
|
95
|
+
const { data, error } = await resend.broadcasts.clickedLinks('bc_abc123', { limit: 10 });
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Recipients
|
|
99
|
+
|
|
100
|
+
List who a broadcast was sent to, filtered by a single event `type`. Results are
|
|
101
|
+
paginated with cursors (`after` / `before`).
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Who opened it
|
|
105
|
+
const { data, error } = await resend.broadcasts.recipients('bc_abc123', {
|
|
106
|
+
type: 'opened',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Who bounced, filtered to permanent bounces only
|
|
110
|
+
const { data, error } = await resend.broadcasts.recipients('bc_abc123', {
|
|
111
|
+
type: 'bounced',
|
|
112
|
+
bounceType: 'permanent',
|
|
113
|
+
});
|
|
91
114
|
```
|
|
92
115
|
|
|
116
|
+
`type` is required: `sent`, `delivered`, `opened`, `clicked`, `bounced`,
|
|
117
|
+
`complained`, `unsubscribed`, or `suppressed`. Each recipient row always has
|
|
118
|
+
`id` (an opaque pagination cursor, not a real entity id), `contact_id`
|
|
119
|
+
(nullable), and `email`. Depending on `type`, rows also include `count`
|
|
120
|
+
(opened/clicked), `bounce_type` (bounced), or `clicked_links` (clicked).
|
|
121
|
+
`bounce_type` is only meaningful when `type` is `bounced`.
|
|
122
|
+
|
|
93
123
|
## Python Example
|
|
94
124
|
|
|
95
125
|
```python
|
|
@@ -131,3 +161,5 @@ Use triple-mustache with a pipe for fallbacks: `{{{PROPERTY_KEY|fallback}}}`
|
|
|
131
161
|
| `{{VAR}}` instead of `{{{VAR}}}` | Triple braces required for variable interpolation |
|
|
132
162
|
| Ignoring `error` return | Node.js SDK returns `{ data, error }` — always check `error` |
|
|
133
163
|
| `scheduledAt` format confusion | Accepts both ISO 8601 (`2025-03-15T10:00:00Z`) and natural language (`in 1 hour`) |
|
|
164
|
+
| Treating clicked links' `id` as an entity ID | It's an opaque pagination cursor for that row — use it with `after`/`before`, not to look up the link elsewhere |
|
|
165
|
+
| Passing `bounceType` with a non-`bounced` type | Rejected with a 422 — only meaningful when `type: 'bounced'` |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
After sending, emails can be retrieved, listed, rescheduled, or
|
|
5
|
+
After sending, emails can be retrieved, listed, rescheduled, cancelled, or shared. Updates are limited to `scheduled_at` only — content cannot be changed after creation.
|
|
6
6
|
|
|
7
7
|
## SDK Methods
|
|
8
8
|
|
|
@@ -14,6 +14,7 @@ After sending, emails can be retrieved, listed, rescheduled, or cancelled. Updat
|
|
|
14
14
|
| List | `resend.emails.list({ limit, offset })` | Paginated list of sent emails |
|
|
15
15
|
| Update | `resend.emails.update({ id, scheduledAt })` | Reschedule only — no content changes |
|
|
16
16
|
| Cancel | `resend.emails.cancel(id)` | Cancel a scheduled email before it sends |
|
|
17
|
+
| Share | `resend.emails.share(id, { expiresIn })` | Create a public link for a sent or received email; `expiresIn` defaults to and caps at 48h |
|
|
17
18
|
|
|
18
19
|
### Python
|
|
19
20
|
|
|
@@ -23,6 +24,7 @@ After sending, emails can be retrieved, listed, rescheduled, or cancelled. Updat
|
|
|
23
24
|
| List | `resend.Emails.list(params)` |
|
|
24
25
|
| Update | `resend.Emails.update(params)` — params: `{ "id": ..., "scheduled_at": ... }` |
|
|
25
26
|
| Cancel | `resend.Emails.cancel(id)` |
|
|
27
|
+
| Share | `resend.Emails.share(email_id, params)` — params: `{ "expires_in": ... }` |
|
|
26
28
|
|
|
27
29
|
## Examples
|
|
28
30
|
|
|
@@ -72,6 +74,26 @@ if (error) console.error(error);
|
|
|
72
74
|
resend.Emails.cancel("email_abc123")
|
|
73
75
|
```
|
|
74
76
|
|
|
77
|
+
### Share a Sent or Received Email
|
|
78
|
+
|
|
79
|
+
Creates a public, unauthenticated link — anyone with the URL can view the email. Works for both sent and received emails; the API detects which type the ID belongs to.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const { data, error } = await resend.emails.share('email_abc123', {
|
|
83
|
+
expiresIn: '2 hours', // optional — human-readable duration, defaults to and caps at 48h
|
|
84
|
+
});
|
|
85
|
+
if (error) {
|
|
86
|
+
console.error(error);
|
|
87
|
+
} else {
|
|
88
|
+
console.log(data.url);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
shared = resend.Emails.share("email_abc123", {"expires_in": "2 hours"})
|
|
94
|
+
print(shared["url"])
|
|
95
|
+
```
|
|
96
|
+
|
|
75
97
|
## Retrieving Attachments
|
|
76
98
|
|
|
77
99
|
List and download attachments for sent emails. Returns metadata and a signed download URL.
|
|
@@ -124,6 +146,84 @@ const buffer = await response.arrayBuffer();
|
|
|
124
146
|
| `expires_at` | string | When the download URL expires |
|
|
125
147
|
| `size` | number | Size in bytes |
|
|
126
148
|
|
|
149
|
+
## Retrieving Metrics
|
|
150
|
+
|
|
151
|
+
Account-level email delivery and engagement metrics (sent, delivered, bounced, opened, clicked, etc.) for a date range. With no options, returns totals only. Optionally broken down by one or more dimensions: `period`, `domain`, `email`, `broadcast`.
|
|
152
|
+
|
|
153
|
+
`email` and `broadcast` are mutually exclusive — as dimensions, and as filters (`emailId`/`broadcastId`). Requesting both, in either form, is rejected.
|
|
154
|
+
|
|
155
|
+
### SDK Methods
|
|
156
|
+
|
|
157
|
+
| Operation | Node.js | Python |
|
|
158
|
+
|-----------|---------|--------|
|
|
159
|
+
| Get metrics | `resend.emails.metrics(options)` | `resend.Emails.metrics(params)` |
|
|
160
|
+
|
|
161
|
+
`options`/`params` (all optional):
|
|
162
|
+
|
|
163
|
+
| Field (Node.js / Python) | Type | Notes |
|
|
164
|
+
|-------|------|-------|
|
|
165
|
+
| `startDate` / `start_date` | string | ISO 8601 date or datetime. Defaults to 6 days before `endDate` |
|
|
166
|
+
| `endDate` / `end_date` | string | ISO 8601 date or datetime. Defaults to now |
|
|
167
|
+
| `timezone` | string | IANA timezone, e.g. `America/New_York`. Defaults to UTC |
|
|
168
|
+
| `granularity` | string | `hourly`, `daily`, `weekly`, or `monthly` — bucket size when `period` is a dimension. Defaults to `daily` |
|
|
169
|
+
| `metrics` | string[] | Which metrics to include. Defaults to all |
|
|
170
|
+
| `dimensions` | string[] | `period`, `domain`, `email`, `broadcast` — combinable except `email`+`broadcast` |
|
|
171
|
+
| `domainId` / `domain_id` | string[] | Restrict to these sending domain IDs (max 100) |
|
|
172
|
+
| `emailId` / `email_id` | string[] | Restrict to these email IDs (max 100). Cannot combine with `broadcast` dimension/`broadcastId` |
|
|
173
|
+
| `broadcastId` / `broadcast_id` | string[] | Restrict to these broadcast IDs (max 100). Cannot combine with `email` dimension/`emailId` |
|
|
174
|
+
|
|
175
|
+
### Examples
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Totals only, default 6-day window
|
|
179
|
+
const { data, error } = await resend.emails.metrics();
|
|
180
|
+
if (error) {
|
|
181
|
+
console.error(error);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log(data.totals.sent, data.totals.delivered);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Totals only, default 6-day window
|
|
189
|
+
metrics = resend.Emails.metrics({})
|
|
190
|
+
print(metrics["totals"]["sent"], metrics["totals"]["delivered"])
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Broken down by period and broadcast, filtered to one broadcast
|
|
195
|
+
const { data, error } = await resend.emails.metrics({
|
|
196
|
+
startDate: '2026-07-01',
|
|
197
|
+
endDate: '2026-07-08',
|
|
198
|
+
dimensions: ['period', 'broadcast'],
|
|
199
|
+
broadcastId: ['bc_abc123'],
|
|
200
|
+
});
|
|
201
|
+
if (error) console.error(error);
|
|
202
|
+
|
|
203
|
+
for (const row of data.data ?? []) {
|
|
204
|
+
console.log(row.period, row.broadcast_name, row.delivered);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
metrics = resend.Emails.metrics({
|
|
210
|
+
"start_date": "2026-07-01",
|
|
211
|
+
"end_date": "2026-07-08",
|
|
212
|
+
"dimensions": ["period", "broadcast"],
|
|
213
|
+
"broadcast_id": ["bc_abc123"],
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
for row in metrics.get("data", []):
|
|
217
|
+
print(row["period"], row["broadcast_name"], row["delivered"])
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Metrics Response Fields
|
|
221
|
+
|
|
222
|
+
| Field | Type | Description |
|
|
223
|
+
|-------|------|--------------|
|
|
224
|
+
| `totals` | object | Metric totals for the whole date range, keyed by metric name |
|
|
225
|
+
| `data` | array \| absent | Per-dimension breakdown rows. Absent when no `dimensions` were requested |
|
|
226
|
+
|
|
127
227
|
## Common Mistakes
|
|
128
228
|
|
|
129
229
|
| Mistake | Fix |
|
|
@@ -133,3 +233,7 @@ const buffer = await response.arrayBuffer();
|
|
|
133
233
|
| Cancelling too late | Cancel before the `scheduled_at` time — there's a brief processing window before send |
|
|
134
234
|
| Not checking `error` in Node.js | SDK returns `{ data, error }`, does not throw — always destructure and check |
|
|
135
235
|
| Using `.list()` without pagination | Pass `limit` and `offset` to paginate through results |
|
|
236
|
+
| Combining `email` and `broadcast` in metrics | These are mutually exclusive as dimensions and as filters — the request is rejected |
|
|
237
|
+
| Expecting `unique_opened`/`open_rate`-style metrics without tracking enabled | Open/click tracking must be enabled on the sending domain for these to be meaningful |
|
|
238
|
+
| Assuming a longer `expiresIn` is possible | 48 hours is the maximum — requesting more returns a validation error |
|
|
239
|
+
| Treating share links as revocable | There's no revoke endpoint — the link is valid until it expires, no early invalidation |
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vybekiit",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.19",
|
|
4
4
|
"description": "Choose your services, sign in, create a VybeKiit app, and open its verified local welcome page.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"packageManager": "pnpm@10.33.2",
|
|
6
7
|
"publishConfig": {
|
|
7
8
|
"access": "public"
|
|
8
9
|
},
|
|
@@ -13,36 +14,36 @@
|
|
|
13
14
|
"files": [
|
|
14
15
|
"dist"
|
|
15
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup && node scripts/bundleGlobalSkills.mjs",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"test": "vitest run"
|
|
21
|
+
},
|
|
16
22
|
"dependencies": {
|
|
17
23
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
18
24
|
"@aws-sdk/client-dynamodb": "^3.1075.0",
|
|
19
25
|
"@aws-sdk/client-s3": "^3.1075.0",
|
|
20
26
|
"@aws-sdk/lib-dynamodb": "^3.1075.0",
|
|
21
|
-
"@clack/prompts": "
|
|
27
|
+
"@clack/prompts": "catalog:",
|
|
22
28
|
"@neondatabase/serverless": "^0.10.4",
|
|
23
29
|
"@supabase/supabase-js": "^2.47.10",
|
|
24
|
-
"effect": "
|
|
30
|
+
"effect": "catalog:",
|
|
25
31
|
"firebase-admin": "^13.0.2",
|
|
26
32
|
"mongodb": "^7.4.0",
|
|
27
|
-
"open": "
|
|
33
|
+
"open": "catalog:",
|
|
28
34
|
"playwright": "^1.61.1"
|
|
29
35
|
},
|
|
30
36
|
"devDependencies": {
|
|
31
|
-
"@types/node": "
|
|
32
|
-
"tsup": "
|
|
33
|
-
"typescript": "
|
|
34
|
-
"vitest": "
|
|
35
|
-
"@vybekiit/
|
|
36
|
-
"@vybekiit/agent-
|
|
37
|
-
"@vybekiit/
|
|
38
|
-
"@vybekiit/
|
|
39
|
-
"@vybekiit/
|
|
40
|
-
"@vybekiit/payments": "
|
|
41
|
-
"@vybekiit/report-mode": "
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build": "tsup && node scripts/bundleGlobalSkills.mjs",
|
|
45
|
-
"typecheck": "tsc --noEmit",
|
|
46
|
-
"test": "vitest run"
|
|
37
|
+
"@types/node": "catalog:",
|
|
38
|
+
"tsup": "catalog:",
|
|
39
|
+
"typescript": "catalog:",
|
|
40
|
+
"vitest": "catalog:",
|
|
41
|
+
"@vybekiit/agent-kit": "workspace:*",
|
|
42
|
+
"@vybekiit/agent-mcp": "workspace:*",
|
|
43
|
+
"@vybekiit/core": "workspace:*",
|
|
44
|
+
"@vybekiit/db": "workspace:*",
|
|
45
|
+
"@vybekiit/deploy": "workspace:*",
|
|
46
|
+
"@vybekiit/payments": "workspace:*",
|
|
47
|
+
"@vybekiit/report-mode": "workspace:*"
|
|
47
48
|
}
|
|
48
|
-
}
|
|
49
|
+
}
|