You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs-src/webhooks/events.mdx.vel
+36-1Lines changed: 36 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -178,9 +178,44 @@ type Content =
178
178
| `application/*` | Document or file | `application/pdf`, `application/zip` |
179
179
180
180
<Warning>
181
-
**Byte-bearing arms ship metadata, not bytes.** `attachment`, `voice`, and `contact.photo` all carry `mimeType` / `size` / filename — never the raw bytes themselves and never a download URL. To process the actual content you need an additional retrieval step. Hold a [`spectrum-ts`](/spectrum-ts/getting-started) instance in a long-lived process and call its byte accessors, or contact support if you need attachment retrieval — the `message.id` from the webhook is the canonical handle any future retrieval API will accept. A first-class HTTP download endpoint is on the roadmap.
181
+
**Byte-bearing arms ship metadata, not bytes.** `attachment`, `voice`, and `contact.photo` carry `mimeType` / `size` / filename — never raw bytes and never a download URL. See [Retrieving attachment bytes](#retrieving-attachment-bytes) below.
182
182
</Warning>
183
183
184
+
##### Retrieving attachment bytes
185
+
186
+
The webhook payload tells you an attachment exists and hands you its metadata. To process the actual file bytes, you need a separate retrieval step. Two options today:
187
+
188
+
**Option 1 — `spectrum-ts` SDK in a long-lived process**
189
+
190
+
```ts
191
+
import { Spectrum } from 'spectrum-ts';
192
+
import { imessage } from 'spectrum-ts/providers/imessage';
193
+
194
+
// One Spectrum instance per process, reused across requests
195
+
const app = await Spectrum({
196
+
projectId: process.env.PROJECT_ID!,
197
+
projectSecret: process.env.PROJECT_SECRET!,
198
+
providers: [imessage.config()],
199
+
});
200
+
201
+
async function fetchAttachment(payload: WebhookEventPayload): Promise<Buffer> {
202
+
const space = await app.spaces.get(payload.space.id);
This works today. **Don't construct a new `Spectrum()` per request** — construction hits a rate-limited cloud API and will 429 under any real volume. Hoist to module scope and share across requests.
212
+
213
+
**Option 2 — HTTP download endpoint (on the roadmap)**
214
+
215
+
A first-class `GET /v1/messages/{messageId}/attachment` endpoint that returns bytes directly is planned. Until it ships, contact support for attachment retrieval in production environments where Option 1 isn't viable (serverless or edge runtimes, etc.).
216
+
217
+
The `message.id` from the webhook is the canonical handle any future retrieval API will accept.
218
+
184
219
##### Per-arm wire reference
185
220
186
221
Every arm of the `Content` union, post-projection. Hand-written rather than vellum-driven because the wire shapes deliberately diverge from the SDK shapes (function thunks dropped, server-internal fields suppressed, recursive targets reduced to slim refs).
0 commit comments