@alvera-ai/platform-sdk 0.16.2 → 0.17.0
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/.agent/AGENTS.md +7 -0
- package/.agent/messages.md +45 -6
- package/.agent/mock-services.md +192 -0
- package/.agent/tools.md +45 -5
- package/dist/index.d.mts +2 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/.agent/AGENTS.md
CHANGED
|
@@ -576,6 +576,13 @@ of restating:
|
|
|
576
576
|
| Async + readiness | `async.md` |
|
|
577
577
|
| Debugging (HTTP interceptor + safe redaction) | `debugging.md` |
|
|
578
578
|
| Type naming + server-derived fields | `type_naming.md` |
|
|
579
|
+
| Local mock surfaces (WireMock / LocalStack) | `mock-services.md` |
|
|
580
|
+
|
|
581
|
+
`mock-services.md` answers the local-development questions the other
|
|
582
|
+
pages assume away: how the platform reaches mocked third-party APIs on
|
|
583
|
+
a laptop, the `endpoint_url` override on the sender tools, and why End
|
|
584
|
+
User Messaging points at WireMock rather than LocalStack. It is fetched
|
|
585
|
+
from the platform-metadata channel, not authored here.
|
|
579
586
|
|
|
580
587
|
## Just getting started?
|
|
581
588
|
|
package/.agent/messages.md
CHANGED
|
@@ -36,19 +36,28 @@ alias: `rm`.
|
|
|
36
36
|
## 1. The status lifecycle — and who writes each hop
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
pending → queued → sent → delivered
|
|
40
|
-
|
|
39
|
+
pending → accepted → queued → sending → sent → delivered
|
|
40
|
+
└──→ failed (+ failure_reason)
|
|
41
41
|
|
|
42
|
-
also:
|
|
42
|
+
also: duplicate (provider id already held by another send —
|
|
43
|
+
the send HAPPENED; terminal, never retried)
|
|
44
|
+
invalidated (idempotency key collision — the fire was
|
|
45
|
+
rejected, nothing went out)
|
|
43
46
|
received (inbound message, direction: 'inbound')
|
|
44
47
|
clicked (link in the message was clicked)
|
|
45
48
|
```
|
|
46
49
|
|
|
50
|
+
`accepted` (the provider took the send request) and `sending`
|
|
51
|
+
(dispatching to the carrier) are intermediate hops between `pending`
|
|
52
|
+
and `sent`; the order above is the order the contract declares them.
|
|
53
|
+
Treat any of them as "in flight, outcome unknown" — see **Status is
|
|
54
|
+
eventually honest** below.
|
|
55
|
+
|
|
47
56
|
Three different writers touch a message row. Know which is which:
|
|
48
57
|
|
|
49
58
|
| Writer | Writes | When |
|
|
50
59
|
|---|---|---|
|
|
51
|
-
| the action executor | the row itself; `pending`→`sent`, `external_id`, `sent_at` | at execution (writes the row at `pending`; advances to `sent` + sets `external_id` only on a live tool call — a dry-run stops at `pending`) |
|
|
60
|
+
| the action executor | the row itself; `pending`→`sent`, `external_id`, `sent_at`; also `duplicate` | at execution (writes the row at `pending`; advances to `sent` + sets `external_id` only on a live tool call — a dry-run stops at `pending`). Lands `duplicate` when the provider id it got back is already held by another send through the same tool |
|
|
52
61
|
| the action status updater | `delivered` / `failed`, `delivered_at`, `failure_reason` | later, when its poll runs (see `action_status_updaters.md` §7) |
|
|
53
62
|
| `connectedApps.updateMessageTracking` | `opened_at`, `form_submitted_at` — **never `status`** | when the recipient opens/submits the magic-link page |
|
|
54
63
|
|
|
@@ -63,6 +72,34 @@ Two consequences:
|
|
|
63
72
|
delivered nor failed yet. A UI should show that in-between state,
|
|
64
73
|
not guess.
|
|
65
74
|
|
|
75
|
+
### `failed` vs `duplicate` — never retry the second
|
|
76
|
+
|
|
77
|
+
These are **not** interchangeable, and the difference decides whether
|
|
78
|
+
a row is safe to re-send:
|
|
79
|
+
|
|
80
|
+
| | `failed` | `duplicate` |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| provider id | none was ever returned | one came back, but another send through the same tool already holds it |
|
|
83
|
+
| did anything go out? | no | **yes — the send happened** |
|
|
84
|
+
| retryable? | yes | **no** — never retried, never re-sent |
|
|
85
|
+
|
|
86
|
+
So a "retry everything that didn't reach `delivered`" sweep is wrong:
|
|
87
|
+
it must select on `failed`, never on "not delivered". Re-sending a
|
|
88
|
+
`duplicate` sends a second real message to a recipient who already
|
|
89
|
+
got one.
|
|
90
|
+
|
|
91
|
+
One consequence worth internalising: **the send path never records a
|
|
92
|
+
message that has an `external_id` as `failed`.** Once a provider id
|
|
93
|
+
comes back, the row stays `pending` until the delivery poller
|
|
94
|
+
resolves it. `failed` therefore means "nothing left the building",
|
|
95
|
+
not "we don't know yet".
|
|
96
|
+
|
|
97
|
+
`invalidated` is a third, separate thing — an idempotency-key
|
|
98
|
+
collision rejected the fire before it went out (see `idempotency_key`
|
|
99
|
+
in §2). Do not read the word "duplicate" in that context as the
|
|
100
|
+
`duplicate` status: `invalidated` means nothing was sent,
|
|
101
|
+
`duplicate` means something was.
|
|
102
|
+
|
|
66
103
|
## 2. Fields
|
|
67
104
|
|
|
68
105
|
Identity + routing:
|
|
@@ -98,8 +135,10 @@ Provenance (which workflow produced this):
|
|
|
98
135
|
```
|
|
99
136
|
workflow_id, action_id, decision_key, context_key,
|
|
100
137
|
idempotency_key — unique per (mdm_subject_id,
|
|
101
|
-
idempotency_key); a
|
|
102
|
-
lands as status 'invalidated'
|
|
138
|
+
idempotency_key); a repeat fire on the
|
|
139
|
+
same key lands as status 'invalidated'
|
|
140
|
+
(nothing sent) — NOT status 'duplicate',
|
|
141
|
+
which means a send did go out
|
|
103
142
|
sender_tool_id
|
|
104
143
|
```
|
|
105
144
|
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Mock Services
|
|
2
|
+
|
|
3
|
+
<!-- MDOC !-->
|
|
4
|
+
|
|
5
|
+
How the platform reaches mocked third-party APIs, on a laptop and from deployed
|
|
6
|
+
environments. Two mock surfaces exist and they answer different questions:
|
|
7
|
+
**WireMock** stands in for third-party SaaS APIs, **LocalStack** stands in for AWS.
|
|
8
|
+
|
|
9
|
+
## The two surfaces
|
|
10
|
+
|
|
11
|
+
**WireMock** (`wiremock/wiremock:3.10.0`) serves the stub corpus in
|
|
12
|
+
`wm_mappings/`, with response bodies in `wm_response_files/`. It covers the
|
|
13
|
+
third-party APIs the platform integrates with — Athenahealth, Twilio, Mailgun,
|
|
14
|
+
Stripe, SendGrid, HubSpot, QuickBooks, Airtable, Atomic FI, the LLM providers,
|
|
15
|
+
and a small set of AWS endpoints LocalStack cannot serve.
|
|
16
|
+
|
|
17
|
+
**LocalStack** serves AWS itself: `s3,lambda,sns,ssm,sqs,sts,logs,secretsmanager,cloudformation`
|
|
18
|
+
(`local-dependencies.yml`). See [Datalakes](datalakes.md) for how datalake
|
|
19
|
+
provisioning uses it.
|
|
20
|
+
|
|
21
|
+
The division is not arbitrary. LocalStack Community **cannot** serve
|
|
22
|
+
`pinpoint-sms-voice-v2` (501 — Ultimate tier only), so End User Messaging points
|
|
23
|
+
at WireMock for its send, its S3 media staging, and its STS credential probe. A
|
|
24
|
+
tool has one `endpoint_url`, so all three land on the same host.
|
|
25
|
+
|
|
26
|
+
## The corpus
|
|
27
|
+
|
|
28
|
+
Counted on `release/0.23.0` — 16 files, 98 stubs. The feature mix is what makes
|
|
29
|
+
WireMock itself load-bearing rather than incidental:
|
|
30
|
+
|
|
31
|
+
| Feature | Uses | What it does |
|
|
32
|
+
|---|---:|---|
|
|
33
|
+
| `urlPathPattern` | 80 | Regex path matching |
|
|
34
|
+
| `jsonBody` / `body` / `base64Body` | 85 | Inline response bodies |
|
|
35
|
+
| `bodyFileName` | 21 | Bodies served from `wm_response_files/` |
|
|
36
|
+
| `bodyPatterns` | 11 | Request-body matching |
|
|
37
|
+
| `queryParameters` | 9 | Query matching |
|
|
38
|
+
| `scenarioName` + `newScenarioState` | 7 | **Stateful scenarios — a state machine across requests** |
|
|
39
|
+
| `--global-response-templating` | on | Handlebars templating in responses |
|
|
40
|
+
|
|
41
|
+
The last two rows are why the corpus is served by the real WireMock image
|
|
42
|
+
everywhere rather than by a bespoke matcher. Reimplementing stateful scenarios
|
|
43
|
+
and a templating engine means re-earning fidelity, and a gap in a mock surfaces
|
|
44
|
+
as a test passing against a fiction rather than as a failure.
|
|
45
|
+
|
|
46
|
+
### Two gotchas that cost real time
|
|
47
|
+
|
|
48
|
+
**WireMock rejects unknown keys on a stub mapping.** A stray `_comment` field
|
|
49
|
+
makes it refuse to load the *whole file* and 404 everything in it, while
|
|
50
|
+
`json.load` and any JSON linter pass it happily. Put prose in the free-form
|
|
51
|
+
`metadata` object instead.
|
|
52
|
+
|
|
53
|
+
**WireMock loads mappings at boot.** After editing `wm_mappings/`, reload the
|
|
54
|
+
local container without restarting it:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
curl -X POST http://localhost:8080/__admin/mappings/reset
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That is the first thing to try when a stub 404s locally. It is not available on
|
|
61
|
+
the hosted instance — see below.
|
|
62
|
+
|
|
63
|
+
## Running locally
|
|
64
|
+
|
|
65
|
+
`make run-backing-services` starts both. WireMock listens on `:8080`, LocalStack
|
|
66
|
+
on `:4566`. Tool bodies reach them by setting `endpoint_url` — blank means real
|
|
67
|
+
AWS, any value replaces host, port and scheme.
|
|
68
|
+
|
|
69
|
+
LocalStack's S3 state does **not** survive a container restart. Recreate a bucket
|
|
70
|
+
after one:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 \
|
|
74
|
+
aws s3 mb s3://healthcare-lake-regulated --endpoint-url http://localhost:4566
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## The hosted mock — `wiremock.alvera.ai`
|
|
78
|
+
|
|
79
|
+
Deployed environments used to need their own always-on WireMock, which is the
|
|
80
|
+
wrong billing shape for a service that is idle almost all of the time. The corpus
|
|
81
|
+
now runs on Cloudflare Containers behind one hostname, billed only while awake.
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
flowchart TD
|
|
85
|
+
C["Consumers<br/>platform dev · UAT · integration-tests · CI"]
|
|
86
|
+
C -->|"https://wiremock.alvera.ai"| W
|
|
87
|
+
|
|
88
|
+
subgraph CF["Cloudflare"]
|
|
89
|
+
F["WAF custom rule<br/>/__admin → Block"]
|
|
90
|
+
W["Worker + Durable Object<br/>container binding"]
|
|
91
|
+
K["Container — basic<br/>wiremock/wiremock:3.10.0<br/>/mappings ◀ wm_mappings/<br/>/__files ◀ wm_response_files/"]
|
|
92
|
+
F -.->|"blocks before the Worker runs"| W
|
|
93
|
+
W -->|fetch| K
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**It lives in this repo**, at `mock-edge/`. Deploy from a normal checkout:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cd mock-edge && wrangler deploy
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The single line that makes this work without a vendored copy of the corpus:
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
"image_build_context": ".."
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
That sets the Docker build context to the repo root, so the Dockerfile copies
|
|
110
|
+
`wm_mappings/` and `wm_response_files/` from where they already live. Without it
|
|
111
|
+
the context is `mock-edge/` and the corpus would have to be duplicated there —
|
|
112
|
+
two directories that look identical until they quietly aren't.
|
|
113
|
+
|
|
114
|
+
### There is no authentication
|
|
115
|
+
|
|
116
|
+
The hostname is public and deliberately so. The corpus is synthetic fixture data,
|
|
117
|
+
the mock authenticates nobody, and a gate in front of it caused more problems
|
|
118
|
+
than it solved:
|
|
119
|
+
|
|
120
|
+
- Nineteen of the 98 stubs match on the `Authorization` header, because they
|
|
121
|
+
assert the *tool* authenticated to the API being mocked. Cloudflare Access
|
|
122
|
+
consumes `Authorization` for its own credential, so gating on that header made
|
|
123
|
+
those nineteen stubs stop matching.
|
|
124
|
+
- Any gate means a credential per consumer, which means minting, distributing,
|
|
125
|
+
rotating and revoking — for a service whose contents are fixtures.
|
|
126
|
+
|
|
127
|
+
The accepted risk is bot traffic waking the container. Workers include 10 million
|
|
128
|
+
requests a month before any charge, so the exposure is container time, not
|
|
129
|
+
request volume — and it is small enough to deal with if it ever shows up.
|
|
130
|
+
|
|
131
|
+
### The admin API is blocked
|
|
132
|
+
|
|
133
|
+
WireMock's admin API has no authentication of its own: anything that can reach
|
|
134
|
+
`/__admin` can read the request journal, reset scenarios, or reprogram stubs.
|
|
135
|
+
Publicly hosted, that surfaces as CI failing for no visible reason. A WAF custom
|
|
136
|
+
rule on the zone refuses it:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
(http.host eq "wiremock.alvera.ai" and http.request.uri.path contains "/__admin") → Block
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Scoped by `http.host` so it cannot affect the other services on `alvera.ai`.
|
|
143
|
+
Cloudflare normalises the URL before evaluating rules, so `/%5f%5fadmin` and
|
|
144
|
+
`//__admin` are blocked too — verified, not assumed.
|
|
145
|
+
|
|
146
|
+
> #### The block is safe *because* the corpus is baked {: .warning}
|
|
147
|
+
>
|
|
148
|
+
> Stubs live in the image. Nothing registers them at runtime, so nothing needs
|
|
149
|
+
> the admin API in production. **If that ever changes — if an app wants to
|
|
150
|
+
> register stubs at runtime — this rule must be reconsidered, not worked
|
|
151
|
+
> around.** It would also need `max_instances: 1` and a fixed container name,
|
|
152
|
+
> because registrations do not survive an instance sleeping or a request landing
|
|
153
|
+
> on a different instance.
|
|
154
|
+
|
|
155
|
+
### Adding or changing a stub
|
|
156
|
+
|
|
157
|
+
Edit `wm_mappings/` (or `wm_response_files/`), then redeploy. There is no hot
|
|
158
|
+
reload on the hosted instance — the image is the state, which makes the hosted
|
|
159
|
+
mock immutable per deploy and reproducible for CI.
|
|
160
|
+
|
|
161
|
+
### Verifying the hosted mock matches local
|
|
162
|
+
|
|
163
|
+
The failure worth catching is the two environments quietly disagreeing. Compare
|
|
164
|
+
them by hashing responses rather than asserting content, so the check does not
|
|
165
|
+
break when someone edits a stub — only when local and edge diverge:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
for base in http://localhost:8080 https://wiremock.alvera.ai; do
|
|
169
|
+
curl -s -X POST -H 'content-type: application/json' -d '{"contents":[]}' \
|
|
170
|
+
"$base/gemini/v1beta/models/gemini-2.0-flash:generateContent" | shasum -a 256
|
|
171
|
+
done
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The gemini stubs are the sharpest test: they use a seven-state scenario, so three
|
|
175
|
+
identical POSTs return three *different* bodies in a fixed order. Matching hashes
|
|
176
|
+
across three successive calls proves both environments walked the same state
|
|
177
|
+
machine — something no stateless matcher could fake.
|
|
178
|
+
|
|
179
|
+
## LocalStack at the edge
|
|
180
|
+
|
|
181
|
+
Not done, and deliberately scoped apart. LocalStack is also just an image and
|
|
182
|
+
rides the same mechanism, but Containers **sleep by design** and LocalStack's S3
|
|
183
|
+
state already does not survive a restart. What is an occasional annoyance locally
|
|
184
|
+
becomes routine when instances sleep between runs. Anything depending on objects
|
|
185
|
+
persisting must move to R2, which speaks S3 natively — migration work, not a flag
|
|
186
|
+
flip.
|
|
187
|
+
|
|
188
|
+
## Related
|
|
189
|
+
|
|
190
|
+
- [Tools](tools.md) — tool bodies, `endpoint_url`, and REST API auth methods
|
|
191
|
+
- [Datalakes](datalakes.md) — how datalake provisioning uses LocalStack
|
|
192
|
+
- [Connected Apps](connected_apps.md) — the third-party integrations the corpus stands in for
|
package/.agent/tools.md
CHANGED
|
@@ -257,11 +257,12 @@ Each branch has its own required-list. Common patterns:
|
|
|
257
257
|
OR (iam_role)
|
|
258
258
|
OR (assume_role_arn +
|
|
259
259
|
assume_role_external_id);
|
|
260
|
-
optional endpoint_url (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
260
|
+
optional endpoint_url (ONE override,
|
|
261
|
+
covering everything the tool reaches:
|
|
262
|
+
the SendMediaMessage send, S3 media
|
|
263
|
+
staging, and the save-time credential
|
|
264
|
+
probe; blank ⇒ each service resolves to
|
|
265
|
+
its own regional AWS host)
|
|
265
266
|
|
|
266
267
|
sql_database body db_type, db_host, db_port, db_name,
|
|
267
268
|
auth_method, db_username,
|
|
@@ -283,6 +284,45 @@ The full per-branch shape lives in
|
|
|
283
284
|
`packages/sdk/src/generated/types.gen.ts` under the matching
|
|
284
285
|
`Tool<Type>BodyWritable` types.
|
|
285
286
|
|
|
287
|
+
### Authoring an End User Messaging tool locally — every auth method works
|
|
288
|
+
|
|
289
|
+
`endpoint_url` is one override for the whole tool. Point it at a local
|
|
290
|
+
AWS-compatible stub and the send, the media staging, and the
|
|
291
|
+
save-time credential probe all follow it; leave it blank and each
|
|
292
|
+
service resolves to its own regional AWS host. There is no second
|
|
293
|
+
endpoint field — `media_bucket` names a bucket, not a host.
|
|
294
|
+
|
|
295
|
+
All three auth methods can be authored locally **and** against real
|
|
296
|
+
AWS. They do not all reach the same host, and are not meant to:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
auth_method endpoint_url set (local) endpoint_url blank
|
|
300
|
+
───────────────────────────────────────────────────────────────────
|
|
301
|
+
access_key everything → your stub everything → AWS
|
|
302
|
+
iam_role everything → your stub, but everything → AWS
|
|
303
|
+
the credential itself still
|
|
304
|
+
comes from the platform's
|
|
305
|
+
ambient chain
|
|
306
|
+
assume_role send + staging → your stub; everything → AWS
|
|
307
|
+
the STS AssumeRole leg is
|
|
308
|
+
NOT tool-steered (below)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Why `assume_role` deliberately splits.** That STS request is signed
|
|
312
|
+
with the **platform's own** ambient credentials — your role trusts a
|
|
313
|
+
platform identity, and the tool contributes only `assume_role_arn`
|
|
314
|
+
(the role in YOUR account) and `assume_role_external_id`. Letting a
|
|
315
|
+
tool field steer it would send a live SigV4 signature made with the
|
|
316
|
+
platform task role to a host the tool's author picked. So the STS
|
|
317
|
+
endpoint is a per-deployment constant, resolved by the platform, and
|
|
318
|
+
`assume_role` is the one auth method where the tool does not choose
|
|
319
|
+
it. This is by design — not a gap, and not a reason to prefer another
|
|
320
|
+
auth method when authoring locally.
|
|
321
|
+
|
|
322
|
+
If a local `assume_role` save is reaching real STS when you expected a
|
|
323
|
+
stub, that is the platform deployment's own STS configuration, not the
|
|
324
|
+
tool body. Nothing you can put in `endpoint_url` changes it.
|
|
325
|
+
|
|
286
326
|
### `assume_role` needs the platform's ARN — read it from `GET /api/ping`
|
|
287
327
|
|
|
288
328
|
The `assume_role` auth method (on `sns` and `end_user_messaging`
|
package/dist/index.d.mts
CHANGED
|
@@ -991,7 +991,7 @@ type ResolvePageResponse = {
|
|
|
991
991
|
/**
|
|
992
992
|
* Delivery status
|
|
993
993
|
*/
|
|
994
|
-
status: 'pending' | 'queued' | 'sent' | 'delivered' | 'read' | 'opened' | 'clicked' | 'form_submitted' | 'failed' | 'invalidated' | 'customer_rejected' | 'dry_run' | 'received';
|
|
994
|
+
status: 'pending' | 'accepted' | 'queued' | 'sending' | 'sent' | 'delivered' | 'read' | 'opened' | 'clicked' | 'form_submitted' | 'failed' | 'invalidated' | 'duplicate' | 'customer_rejected' | 'dry_run' | 'received';
|
|
995
995
|
/**
|
|
996
996
|
* Human-readable detail behind the current status, rendered from the delivery provider's event (e.g. the mailgun event name, or a bounce reason on failure)
|
|
997
997
|
*/
|
|
@@ -1943,7 +1943,7 @@ type UpdatePageResponse = {
|
|
|
1943
1943
|
/**
|
|
1944
1944
|
* Message status after applying the update through the monotonic guard
|
|
1945
1945
|
*/
|
|
1946
|
-
status?: 'pending' | 'queued' | 'sent' | 'delivered' | 'read' | 'opened' | 'clicked' | 'form_submitted' | 'failed' | 'invalidated' | 'customer_rejected' | 'dry_run' | 'received';
|
|
1946
|
+
status?: 'pending' | 'accepted' | 'queued' | 'sending' | 'sent' | 'delivered' | 'read' | 'opened' | 'clicked' | 'form_submitted' | 'failed' | 'invalidated' | 'duplicate' | 'customer_rejected' | 'dry_run' | 'received';
|
|
1947
1947
|
};
|
|
1948
1948
|
};
|
|
1949
1949
|
/**
|
|
@@ -2322,10 +2322,6 @@ type EndUserMessagingResponse = {
|
|
|
2322
2322
|
* S3 bucket (same region as the sending number) where author media is re-staged for SendMediaMessage
|
|
2323
2323
|
*/
|
|
2324
2324
|
media_bucket: string;
|
|
2325
|
-
/**
|
|
2326
|
-
* Custom S3 endpoint URL for media staging (e.g. http://localhost:4566 for LocalStack); leave blank for AWS S3 in the tool's region
|
|
2327
|
-
*/
|
|
2328
|
-
media_endpoint_url?: string | null;
|
|
2329
2325
|
/**
|
|
2330
2326
|
* Origination phone number or identity in E.164 format (e.g., +15551234567); must be MMS-capable
|
|
2331
2327
|
*/
|
|
@@ -4845,10 +4841,6 @@ type EndUserMessagingRequestWritable = {
|
|
|
4845
4841
|
* S3 bucket (same region as the sending number) where author media is re-staged for SendMediaMessage
|
|
4846
4842
|
*/
|
|
4847
4843
|
media_bucket: string;
|
|
4848
|
-
/**
|
|
4849
|
-
* Custom S3 endpoint URL for media staging (e.g. http://localhost:4566 for LocalStack); leave blank for AWS S3 in the tool's region
|
|
4850
|
-
*/
|
|
4851
|
-
media_endpoint_url?: string | null;
|
|
4852
4844
|
/**
|
|
4853
4845
|
* Origination phone number or identity in E.164 format (e.g., +15551234567); must be MMS-capable
|
|
4854
4846
|
*/
|