@wspc/cli 0.0.9 → 0.0.11
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/cli.js +183 -69
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +17 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/spec/openapi.json +2055 -415
package/spec/openapi.json
CHANGED
|
@@ -323,10 +323,8 @@
|
|
|
323
323
|
"description": "Opaque pagination cursor. Pass the `next_cursor` returned by the previous page to fetch the next slice. Omit on the first call."
|
|
324
324
|
},
|
|
325
325
|
"limit": {
|
|
326
|
-
"type": "
|
|
327
|
-
"
|
|
328
|
-
"maximum": 100,
|
|
329
|
-
"description": "Maximum number of members to return in this page (1–100). Defaults to 50. Larger values trade fewer round-trips for more bytes per response."
|
|
326
|
+
"type": "string",
|
|
327
|
+
"description": "Maximum members to return. Clamped to [1, 100]. Defaults to 50."
|
|
330
328
|
}
|
|
331
329
|
}
|
|
332
330
|
},
|
|
@@ -1245,7 +1243,7 @@
|
|
|
1245
1243
|
"email": {
|
|
1246
1244
|
"type": "string",
|
|
1247
1245
|
"format": "email",
|
|
1248
|
-
"description": "Full alias address under
|
|
1246
|
+
"description": "Full alias address under the platform email domain or a fully verified organization custom domain, for example alice-shop@wspc.app or alice-shop@example.com."
|
|
1249
1247
|
}
|
|
1250
1248
|
},
|
|
1251
1249
|
"required": [
|
|
@@ -1284,6 +1282,151 @@
|
|
|
1284
1282
|
"created_at"
|
|
1285
1283
|
]
|
|
1286
1284
|
},
|
|
1285
|
+
"CreateDomainBody": {
|
|
1286
|
+
"type": "object",
|
|
1287
|
+
"properties": {
|
|
1288
|
+
"domain": {
|
|
1289
|
+
"type": "string",
|
|
1290
|
+
"description": "Custom domain hostname to register with the provider, for example `mail.example.com`."
|
|
1291
|
+
}
|
|
1292
|
+
},
|
|
1293
|
+
"required": [
|
|
1294
|
+
"domain"
|
|
1295
|
+
]
|
|
1296
|
+
},
|
|
1297
|
+
"EmailDomainObjectResponse": {
|
|
1298
|
+
"type": "object",
|
|
1299
|
+
"properties": {
|
|
1300
|
+
"domain": {
|
|
1301
|
+
"type": "object",
|
|
1302
|
+
"properties": {
|
|
1303
|
+
"domain": {
|
|
1304
|
+
"type": "string",
|
|
1305
|
+
"description": "Normalized lowercase ASCII hostname for the registered custom domain."
|
|
1306
|
+
},
|
|
1307
|
+
"status": {
|
|
1308
|
+
"type": "string",
|
|
1309
|
+
"enum": [
|
|
1310
|
+
"pending",
|
|
1311
|
+
"verified",
|
|
1312
|
+
"failed",
|
|
1313
|
+
"temporary_failure"
|
|
1314
|
+
],
|
|
1315
|
+
"description": "Overall upstream provider status for DNS ownership verification."
|
|
1316
|
+
},
|
|
1317
|
+
"sending_status": {
|
|
1318
|
+
"type": "string",
|
|
1319
|
+
"enum": [
|
|
1320
|
+
"pending",
|
|
1321
|
+
"verified",
|
|
1322
|
+
"failed",
|
|
1323
|
+
"disabled"
|
|
1324
|
+
],
|
|
1325
|
+
"description": "Provider-side sending readiness signal for this domain registration. Custom-domain aliases can send only when this value is `verified`."
|
|
1326
|
+
},
|
|
1327
|
+
"receiving_status": {
|
|
1328
|
+
"type": "string",
|
|
1329
|
+
"enum": [
|
|
1330
|
+
"pending",
|
|
1331
|
+
"verified",
|
|
1332
|
+
"failed",
|
|
1333
|
+
"disabled"
|
|
1334
|
+
],
|
|
1335
|
+
"description": "Provider-side receiving readiness signal for this domain registration. Custom-domain aliases can be created only when this value is `verified`."
|
|
1336
|
+
},
|
|
1337
|
+
"records": {
|
|
1338
|
+
"type": "array",
|
|
1339
|
+
"items": {
|
|
1340
|
+
"type": "object",
|
|
1341
|
+
"properties": {
|
|
1342
|
+
"type": {
|
|
1343
|
+
"type": "string",
|
|
1344
|
+
"enum": [
|
|
1345
|
+
"TXT",
|
|
1346
|
+
"CNAME",
|
|
1347
|
+
"MX"
|
|
1348
|
+
],
|
|
1349
|
+
"description": "DNS record type required by the upstream domain provider."
|
|
1350
|
+
},
|
|
1351
|
+
"name": {
|
|
1352
|
+
"type": "string",
|
|
1353
|
+
"description": "DNS hostname to create or update."
|
|
1354
|
+
},
|
|
1355
|
+
"value": {
|
|
1356
|
+
"type": "string",
|
|
1357
|
+
"description": "Expected DNS record value."
|
|
1358
|
+
},
|
|
1359
|
+
"status": {
|
|
1360
|
+
"type": "string",
|
|
1361
|
+
"enum": [
|
|
1362
|
+
"pending",
|
|
1363
|
+
"verified",
|
|
1364
|
+
"failed"
|
|
1365
|
+
],
|
|
1366
|
+
"description": "Latest provider verification status for this individual DNS record."
|
|
1367
|
+
},
|
|
1368
|
+
"purpose": {
|
|
1369
|
+
"type": "string",
|
|
1370
|
+
"enum": [
|
|
1371
|
+
"identity_verification",
|
|
1372
|
+
"dkim",
|
|
1373
|
+
"mail_from",
|
|
1374
|
+
"receiving_mx"
|
|
1375
|
+
],
|
|
1376
|
+
"description": "Why this DNS record is required, when the provider returns a purpose hint."
|
|
1377
|
+
},
|
|
1378
|
+
"ttl": {
|
|
1379
|
+
"type": "integer",
|
|
1380
|
+
"exclusiveMinimum": 0,
|
|
1381
|
+
"description": "Requested TTL in seconds, if the provider specifies one."
|
|
1382
|
+
},
|
|
1383
|
+
"priority": {
|
|
1384
|
+
"type": "integer",
|
|
1385
|
+
"minimum": 0,
|
|
1386
|
+
"description": "MX priority, when applicable."
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
"required": [
|
|
1390
|
+
"type",
|
|
1391
|
+
"name",
|
|
1392
|
+
"value",
|
|
1393
|
+
"status"
|
|
1394
|
+
]
|
|
1395
|
+
},
|
|
1396
|
+
"description": "DNS records currently cached from the provider for ownership verification."
|
|
1397
|
+
},
|
|
1398
|
+
"region": {
|
|
1399
|
+
"type": "string",
|
|
1400
|
+
"description": "Provider region hint, when returned by the upstream provider."
|
|
1401
|
+
},
|
|
1402
|
+
"created_at": {
|
|
1403
|
+
"type": "number",
|
|
1404
|
+
"description": "Unix epoch milliseconds when the local cache row was created."
|
|
1405
|
+
},
|
|
1406
|
+
"updated_at": {
|
|
1407
|
+
"type": "number",
|
|
1408
|
+
"description": "Unix epoch milliseconds when the local cache row was last refreshed."
|
|
1409
|
+
},
|
|
1410
|
+
"verified_at": {
|
|
1411
|
+
"type": "number",
|
|
1412
|
+
"description": "Unix epoch milliseconds when the domain last reached overall `verified` status. Omitted until the first successful verification."
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
"required": [
|
|
1416
|
+
"domain",
|
|
1417
|
+
"status",
|
|
1418
|
+
"sending_status",
|
|
1419
|
+
"receiving_status",
|
|
1420
|
+
"records",
|
|
1421
|
+
"created_at",
|
|
1422
|
+
"updated_at"
|
|
1423
|
+
]
|
|
1424
|
+
}
|
|
1425
|
+
},
|
|
1426
|
+
"required": [
|
|
1427
|
+
"domain"
|
|
1428
|
+
]
|
|
1429
|
+
},
|
|
1287
1430
|
"BatchIdsBody": {
|
|
1288
1431
|
"type": "object",
|
|
1289
1432
|
"properties": {
|
|
@@ -1330,6 +1473,18 @@
|
|
|
1330
1473
|
}
|
|
1331
1474
|
}
|
|
1332
1475
|
},
|
|
1476
|
+
"EmailDomainParam": {
|
|
1477
|
+
"type": "object",
|
|
1478
|
+
"properties": {
|
|
1479
|
+
"domain": {
|
|
1480
|
+
"type": "string",
|
|
1481
|
+
"description": "Custom domain hostname path parameter. URL-encode if your client requires it."
|
|
1482
|
+
}
|
|
1483
|
+
},
|
|
1484
|
+
"required": [
|
|
1485
|
+
"domain"
|
|
1486
|
+
]
|
|
1487
|
+
},
|
|
1333
1488
|
"GetEmailQuery": {
|
|
1334
1489
|
"type": "object",
|
|
1335
1490
|
"properties": {
|
|
@@ -1352,6 +1507,142 @@
|
|
|
1352
1507
|
}
|
|
1353
1508
|
}
|
|
1354
1509
|
},
|
|
1510
|
+
"EmailDomainListResponse": {
|
|
1511
|
+
"type": "object",
|
|
1512
|
+
"properties": {
|
|
1513
|
+
"domains": {
|
|
1514
|
+
"type": "array",
|
|
1515
|
+
"items": {
|
|
1516
|
+
"type": "object",
|
|
1517
|
+
"properties": {
|
|
1518
|
+
"domain": {
|
|
1519
|
+
"type": "string",
|
|
1520
|
+
"description": "Normalized lowercase ASCII hostname for the registered custom domain."
|
|
1521
|
+
},
|
|
1522
|
+
"status": {
|
|
1523
|
+
"type": "string",
|
|
1524
|
+
"enum": [
|
|
1525
|
+
"pending",
|
|
1526
|
+
"verified",
|
|
1527
|
+
"failed",
|
|
1528
|
+
"temporary_failure"
|
|
1529
|
+
],
|
|
1530
|
+
"description": "Overall upstream provider status for DNS ownership verification."
|
|
1531
|
+
},
|
|
1532
|
+
"sending_status": {
|
|
1533
|
+
"type": "string",
|
|
1534
|
+
"enum": [
|
|
1535
|
+
"pending",
|
|
1536
|
+
"verified",
|
|
1537
|
+
"failed",
|
|
1538
|
+
"disabled"
|
|
1539
|
+
],
|
|
1540
|
+
"description": "Provider-side sending readiness signal for this domain registration. Custom-domain aliases can send only when this value is `verified`."
|
|
1541
|
+
},
|
|
1542
|
+
"receiving_status": {
|
|
1543
|
+
"type": "string",
|
|
1544
|
+
"enum": [
|
|
1545
|
+
"pending",
|
|
1546
|
+
"verified",
|
|
1547
|
+
"failed",
|
|
1548
|
+
"disabled"
|
|
1549
|
+
],
|
|
1550
|
+
"description": "Provider-side receiving readiness signal for this domain registration. Custom-domain aliases can be created only when this value is `verified`."
|
|
1551
|
+
},
|
|
1552
|
+
"records": {
|
|
1553
|
+
"type": "array",
|
|
1554
|
+
"items": {
|
|
1555
|
+
"type": "object",
|
|
1556
|
+
"properties": {
|
|
1557
|
+
"type": {
|
|
1558
|
+
"type": "string",
|
|
1559
|
+
"enum": [
|
|
1560
|
+
"TXT",
|
|
1561
|
+
"CNAME",
|
|
1562
|
+
"MX"
|
|
1563
|
+
],
|
|
1564
|
+
"description": "DNS record type required by the upstream domain provider."
|
|
1565
|
+
},
|
|
1566
|
+
"name": {
|
|
1567
|
+
"type": "string",
|
|
1568
|
+
"description": "DNS hostname to create or update."
|
|
1569
|
+
},
|
|
1570
|
+
"value": {
|
|
1571
|
+
"type": "string",
|
|
1572
|
+
"description": "Expected DNS record value."
|
|
1573
|
+
},
|
|
1574
|
+
"status": {
|
|
1575
|
+
"type": "string",
|
|
1576
|
+
"enum": [
|
|
1577
|
+
"pending",
|
|
1578
|
+
"verified",
|
|
1579
|
+
"failed"
|
|
1580
|
+
],
|
|
1581
|
+
"description": "Latest provider verification status for this individual DNS record."
|
|
1582
|
+
},
|
|
1583
|
+
"purpose": {
|
|
1584
|
+
"type": "string",
|
|
1585
|
+
"enum": [
|
|
1586
|
+
"identity_verification",
|
|
1587
|
+
"dkim",
|
|
1588
|
+
"mail_from",
|
|
1589
|
+
"receiving_mx"
|
|
1590
|
+
],
|
|
1591
|
+
"description": "Why this DNS record is required, when the provider returns a purpose hint."
|
|
1592
|
+
},
|
|
1593
|
+
"ttl": {
|
|
1594
|
+
"type": "integer",
|
|
1595
|
+
"exclusiveMinimum": 0,
|
|
1596
|
+
"description": "Requested TTL in seconds, if the provider specifies one."
|
|
1597
|
+
},
|
|
1598
|
+
"priority": {
|
|
1599
|
+
"type": "integer",
|
|
1600
|
+
"minimum": 0,
|
|
1601
|
+
"description": "MX priority, when applicable."
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1604
|
+
"required": [
|
|
1605
|
+
"type",
|
|
1606
|
+
"name",
|
|
1607
|
+
"value",
|
|
1608
|
+
"status"
|
|
1609
|
+
]
|
|
1610
|
+
},
|
|
1611
|
+
"description": "DNS records currently cached from the provider for ownership verification."
|
|
1612
|
+
},
|
|
1613
|
+
"region": {
|
|
1614
|
+
"type": "string",
|
|
1615
|
+
"description": "Provider region hint, when returned by the upstream provider."
|
|
1616
|
+
},
|
|
1617
|
+
"created_at": {
|
|
1618
|
+
"type": "number",
|
|
1619
|
+
"description": "Unix epoch milliseconds when the local cache row was created."
|
|
1620
|
+
},
|
|
1621
|
+
"updated_at": {
|
|
1622
|
+
"type": "number",
|
|
1623
|
+
"description": "Unix epoch milliseconds when the local cache row was last refreshed."
|
|
1624
|
+
},
|
|
1625
|
+
"verified_at": {
|
|
1626
|
+
"type": "number",
|
|
1627
|
+
"description": "Unix epoch milliseconds when the domain last reached overall `verified` status. Omitted until the first successful verification."
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
"required": [
|
|
1631
|
+
"domain",
|
|
1632
|
+
"status",
|
|
1633
|
+
"sending_status",
|
|
1634
|
+
"receiving_status",
|
|
1635
|
+
"records",
|
|
1636
|
+
"created_at",
|
|
1637
|
+
"updated_at"
|
|
1638
|
+
]
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
"required": [
|
|
1643
|
+
"domains"
|
|
1644
|
+
]
|
|
1645
|
+
},
|
|
1355
1646
|
"ListEmailsQuery": {
|
|
1356
1647
|
"type": "object",
|
|
1357
1648
|
"properties": {
|
|
@@ -2688,6 +2979,12 @@
|
|
|
2688
2979
|
"items": {
|
|
2689
2980
|
"$ref": "#/components/schemas/Comment"
|
|
2690
2981
|
}
|
|
2982
|
+
},
|
|
2983
|
+
"children_next_cursor": {
|
|
2984
|
+
"type": "string"
|
|
2985
|
+
},
|
|
2986
|
+
"comments_next_cursor": {
|
|
2987
|
+
"type": "string"
|
|
2691
2988
|
}
|
|
2692
2989
|
},
|
|
2693
2990
|
"required": [
|
|
@@ -2742,6 +3039,10 @@
|
|
|
2742
3039
|
"items": {
|
|
2743
3040
|
"$ref": "#/components/schemas/Todo"
|
|
2744
3041
|
}
|
|
3042
|
+
},
|
|
3043
|
+
"next_cursor": {
|
|
3044
|
+
"type": "string",
|
|
3045
|
+
"description": "Opaque cursor for the next page. Absent on the last page."
|
|
2745
3046
|
}
|
|
2746
3047
|
},
|
|
2747
3048
|
"required": [
|
|
@@ -7153,13 +7454,11 @@
|
|
|
7153
7454
|
},
|
|
7154
7455
|
{
|
|
7155
7456
|
"schema": {
|
|
7156
|
-
"type": "
|
|
7157
|
-
"
|
|
7158
|
-
"maximum": 100,
|
|
7159
|
-
"description": "Maximum number of members to return in this page (1–100). Defaults to 50. Larger values trade fewer round-trips for more bytes per response."
|
|
7457
|
+
"type": "string",
|
|
7458
|
+
"description": "Maximum members to return. Clamped to [1, 100]. Defaults to 50."
|
|
7160
7459
|
},
|
|
7161
7460
|
"required": false,
|
|
7162
|
-
"description": "Maximum
|
|
7461
|
+
"description": "Maximum members to return. Clamped to [1, 100]. Defaults to 50.",
|
|
7163
7462
|
"name": "limit",
|
|
7164
7463
|
"in": "query"
|
|
7165
7464
|
}
|
|
@@ -14737,7 +15036,7 @@
|
|
|
14737
15036
|
"EmailAliases"
|
|
14738
15037
|
],
|
|
14739
15038
|
"summary": "Create a receiving alias",
|
|
14740
|
-
"description": "### Overview\nReserves and provisions a new passwordless/disposable receiving email alias address under the configured WSPC domain. All inbound emails received on this alias will be forwarded into the caller's inbox.\n\n### When to Use\n- Use this endpoint to spin up a fresh, dedicated email address (e.g., `alice-shop@wspc.app`) for specific websites, newsletters, or contexts to prevent spam or categorize incoming mail.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Alias Formatting**: The local part must be between 5 and 32 characters, start with an alphanumeric character, and only contain letters, numbers, dots, underscores, and hyphens.\n- **Limit Check**: Each user is allowed a maximum of 10 active email aliases. Soft-deleted aliases do not count against this quota limit.\n\n### Troubleshooting\n- **401 Unauthorized**: Bearer token is missing, invalid, or expired.\n- **400 Bad Request / INVALID_CHARSET / RESERVED**: The alias local part contains invalid characters, is too short/long, or matches a reserved keyword.\n- **409 Conflict / ALIAS_CONFLICT**: An alias with the exact requested email address already exists globally (whether active or soft-deleted by any user).\n- **429 Too Many Requests / ALIAS_LIMIT_EXCEEDED**: The user has reached the active alias cap limit of 10. A previously deleted alias must be cleaned up or wait for quota availability.",
|
|
15039
|
+
"description": "### Overview\nReserves and provisions a new passwordless/disposable receiving email alias address under the configured WSPC domain or a fully verified organization custom domain. All inbound emails received on this alias will be forwarded into the caller's inbox.\n\n### When to Use\n- Use this endpoint to spin up a fresh, dedicated email address (e.g., `alice-shop@wspc.app`) for specific websites, newsletters, or contexts to prevent spam or categorize incoming mail.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Alias Formatting**: The local part must be between 5 and 32 characters, start with an alphanumeric character, and only contain letters, numbers, dots, underscores, and hyphens.\n- **Custom Domains**: If the address uses a non-platform host, that domain must be registered to the caller's organization and have `status = verified`, `sending_status = verified`, and `receiving_status = verified`.\n- **Limit Check**: Each user is allowed a maximum of 10 active email aliases. Soft-deleted aliases do not count against this quota limit.\n\n### Troubleshooting\n- **401 Unauthorized**: Bearer token is missing, invalid, or expired.\n- **400 Bad Request / INVALID_CHARSET / RESERVED**: The alias local part contains invalid characters, is too short/long, or matches a reserved keyword.\n- **400 Bad Request / DOMAIN_NOT_FOUND**: The custom domain is not registered to the caller's organization.\n- **400 Bad Request / UNVERIFIED_DOMAIN**: The custom domain exists but is not verified yet.\n- **400 Bad Request / CUSTOM_DOMAIN_NOT_READY**: The custom domain exists but has not completed sending or receiving verification.\n- **409 Conflict / ALIAS_CONFLICT**: An alias with the exact requested email address already exists globally (whether active or soft-deleted by any user).\n- **429 Too Many Requests / ALIAS_LIMIT_EXCEEDED**: The user has reached the active alias cap limit of 10. A previously deleted alias must be cleaned up or wait for quota availability.",
|
|
14741
15040
|
"security": [
|
|
14742
15041
|
{
|
|
14743
15042
|
"bearerAuth": []
|
|
@@ -14789,6 +15088,12 @@
|
|
|
14789
15088
|
"value": {
|
|
14790
15089
|
"email": "alice-bills@wspc.app"
|
|
14791
15090
|
}
|
|
15091
|
+
},
|
|
15092
|
+
"customDomain": {
|
|
15093
|
+
"summary": "Fully verified custom domain alias",
|
|
15094
|
+
"value": {
|
|
15095
|
+
"email": "alice-shop@example.com"
|
|
15096
|
+
}
|
|
14792
15097
|
}
|
|
14793
15098
|
}
|
|
14794
15099
|
}
|
|
@@ -14817,7 +15122,7 @@
|
|
|
14817
15122
|
}
|
|
14818
15123
|
},
|
|
14819
15124
|
"400": {
|
|
14820
|
-
"description": "Invalid alias email address, local part,
|
|
15125
|
+
"description": "Invalid alias email address, local part, reserved local part, missing custom domain, unverified custom domain, or custom domain that is not ready for both sending and receiving.",
|
|
14821
15126
|
"content": {
|
|
14822
15127
|
"application/json": {
|
|
14823
15128
|
"schema": {
|
|
@@ -15275,61 +15580,141 @@
|
|
|
15275
15580
|
}
|
|
15276
15581
|
}
|
|
15277
15582
|
},
|
|
15278
|
-
"/email/
|
|
15279
|
-
"
|
|
15280
|
-
"operationId": "
|
|
15583
|
+
"/email/domains": {
|
|
15584
|
+
"post": {
|
|
15585
|
+
"operationId": "email_domain_create",
|
|
15281
15586
|
"tags": [
|
|
15282
|
-
"
|
|
15587
|
+
"EmailDomains"
|
|
15283
15588
|
],
|
|
15284
|
-
"summary": "
|
|
15285
|
-
"description": "### Overview\
|
|
15589
|
+
"summary": "Register a custom email domain",
|
|
15590
|
+
"description": "### Overview\nRegisters a new organization-owned custom email domain with the upstream provider and caches the returned DNS verification records in D1.\n\n### When to Use\n- Use this endpoint when onboarding a new custom email domain such as `mail.example.com`.\n- The response contains the DNS records the organization must publish before the domain can be verified.\n- This route registers the domain and returns DNS records. Custom-domain aliases require `status`, `sending_status`, and `receiving_status` to all be `verified`.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- Domain ownership is globally unique across the platform. Once any organization has reserved a domain, another org cannot register it.\n- This route requires custom domain provider credentials in production because it performs a live provider registration call.\n\n### Troubleshooting\n- **400 Bad Request / DOMAIN_INVALID / DOMAIN_RESERVED**: The hostname is malformed or belongs to the platform (`wspc.app`, `wspc.ai`, or their subdomains).\n- **409 Conflict / DOMAIN_CONFLICT**: The domain is already registered by some organization.\n- **502 Bad Gateway / DOMAIN_PROVIDER_ERROR**: The upstream provider request failed, timed out, or returned an unexpected shape.",
|
|
15286
15591
|
"security": [
|
|
15287
15592
|
{
|
|
15288
15593
|
"bearerAuth": []
|
|
15289
15594
|
}
|
|
15290
15595
|
],
|
|
15291
15596
|
"x-cli": {
|
|
15292
|
-
"command": "
|
|
15597
|
+
"command": "domain add",
|
|
15293
15598
|
"positional": [
|
|
15294
|
-
"
|
|
15599
|
+
"domain"
|
|
15295
15600
|
],
|
|
15296
15601
|
"display": {
|
|
15297
15602
|
"shape": "object",
|
|
15298
15603
|
"format": {
|
|
15299
|
-
"id": "id-short",
|
|
15300
|
-
"user_id": "id-short",
|
|
15301
15604
|
"created_at": "relative-time",
|
|
15302
|
-
"
|
|
15303
|
-
|
|
15605
|
+
"updated_at": "relative-time",
|
|
15606
|
+
"verified_at": "relative-time"
|
|
15607
|
+
},
|
|
15608
|
+
"dataPath": "domain"
|
|
15304
15609
|
}
|
|
15305
15610
|
},
|
|
15306
15611
|
"x-codeSamples": [
|
|
15307
15612
|
{
|
|
15308
15613
|
"lang": "shell",
|
|
15309
15614
|
"label": "curl",
|
|
15310
|
-
"source": "curl -X
|
|
15615
|
+
"source": "curl -X POST https://api.wspc.ai/email/domains \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"domain\":\"mail.example.com\"}'"
|
|
15311
15616
|
},
|
|
15312
15617
|
{
|
|
15313
15618
|
"lang": "bash",
|
|
15314
15619
|
"label": "wspc CLI",
|
|
15315
|
-
"source": "wspc email
|
|
15620
|
+
"source": "wspc email domain add mail.example.com"
|
|
15316
15621
|
}
|
|
15317
15622
|
],
|
|
15318
|
-
"
|
|
15319
|
-
|
|
15320
|
-
|
|
15321
|
-
|
|
15322
|
-
"
|
|
15323
|
-
|
|
15324
|
-
|
|
15325
|
-
|
|
15326
|
-
|
|
15327
|
-
|
|
15623
|
+
"requestBody": {
|
|
15624
|
+
"required": true,
|
|
15625
|
+
"content": {
|
|
15626
|
+
"application/json": {
|
|
15627
|
+
"schema": {
|
|
15628
|
+
"$ref": "#/components/schemas/CreateDomainBody"
|
|
15629
|
+
},
|
|
15630
|
+
"examples": {
|
|
15631
|
+
"minimal": {
|
|
15632
|
+
"summary": "Register one custom domain",
|
|
15633
|
+
"value": {
|
|
15634
|
+
"domain": "mail.example.com"
|
|
15635
|
+
}
|
|
15636
|
+
}
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15328
15639
|
}
|
|
15329
|
-
|
|
15640
|
+
},
|
|
15330
15641
|
"responses": {
|
|
15331
|
-
"
|
|
15332
|
-
"description": "
|
|
15642
|
+
"201": {
|
|
15643
|
+
"description": "Custom domain registered and DNS verification records returned. Custom-domain aliases require full domain readiness before use.",
|
|
15644
|
+
"content": {
|
|
15645
|
+
"application/json": {
|
|
15646
|
+
"schema": {
|
|
15647
|
+
"$ref": "#/components/schemas/EmailDomainObjectResponse"
|
|
15648
|
+
},
|
|
15649
|
+
"examples": {
|
|
15650
|
+
"happyPath": {
|
|
15651
|
+
"summary": "Pending verification with DNS instructions",
|
|
15652
|
+
"value": {
|
|
15653
|
+
"domain": {
|
|
15654
|
+
"domain": "mail.example.com",
|
|
15655
|
+
"status": "pending",
|
|
15656
|
+
"sending_status": "pending",
|
|
15657
|
+
"receiving_status": "pending",
|
|
15658
|
+
"records": [
|
|
15659
|
+
{
|
|
15660
|
+
"type": "TXT",
|
|
15661
|
+
"name": "mail.example.com",
|
|
15662
|
+
"value": "pm-domain-verification=abc123",
|
|
15663
|
+
"status": "pending",
|
|
15664
|
+
"ttl": 3600,
|
|
15665
|
+
"purpose": "identity_verification"
|
|
15666
|
+
},
|
|
15667
|
+
{
|
|
15668
|
+
"type": "CNAME",
|
|
15669
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
15670
|
+
"value": "selector1.domainkey.example.net",
|
|
15671
|
+
"status": "pending",
|
|
15672
|
+
"purpose": "dkim"
|
|
15673
|
+
}
|
|
15674
|
+
],
|
|
15675
|
+
"region": "us-east-1",
|
|
15676
|
+
"created_at": 1780166400000,
|
|
15677
|
+
"updated_at": 1780166400000
|
|
15678
|
+
}
|
|
15679
|
+
}
|
|
15680
|
+
}
|
|
15681
|
+
}
|
|
15682
|
+
}
|
|
15683
|
+
}
|
|
15684
|
+
},
|
|
15685
|
+
"400": {
|
|
15686
|
+
"description": "Malformed or platform-reserved domain hostname.",
|
|
15687
|
+
"content": {
|
|
15688
|
+
"application/json": {
|
|
15689
|
+
"schema": {
|
|
15690
|
+
"type": "object",
|
|
15691
|
+
"properties": {
|
|
15692
|
+
"error": {
|
|
15693
|
+
"type": "object",
|
|
15694
|
+
"properties": {
|
|
15695
|
+
"code": {
|
|
15696
|
+
"type": "string"
|
|
15697
|
+
},
|
|
15698
|
+
"message": {
|
|
15699
|
+
"type": "string"
|
|
15700
|
+
},
|
|
15701
|
+
"extra": {
|
|
15702
|
+
"type": "object",
|
|
15703
|
+
"additionalProperties": {}
|
|
15704
|
+
}
|
|
15705
|
+
},
|
|
15706
|
+
"required": [
|
|
15707
|
+
"code",
|
|
15708
|
+
"message"
|
|
15709
|
+
]
|
|
15710
|
+
}
|
|
15711
|
+
},
|
|
15712
|
+
"required": [
|
|
15713
|
+
"error"
|
|
15714
|
+
]
|
|
15715
|
+
}
|
|
15716
|
+
}
|
|
15717
|
+
}
|
|
15333
15718
|
},
|
|
15334
15719
|
"401": {
|
|
15335
15720
|
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
@@ -15376,8 +15761,8 @@
|
|
|
15376
15761
|
}
|
|
15377
15762
|
}
|
|
15378
15763
|
},
|
|
15379
|
-
"
|
|
15380
|
-
"description": "
|
|
15764
|
+
"409": {
|
|
15765
|
+
"description": "This domain is already registered by an organization.",
|
|
15381
15766
|
"content": {
|
|
15382
15767
|
"application/json": {
|
|
15383
15768
|
"schema": {
|
|
@@ -15503,149 +15888,159 @@
|
|
|
15503
15888
|
}
|
|
15504
15889
|
}
|
|
15505
15890
|
}
|
|
15506
|
-
}
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
|
|
15511
|
-
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15891
|
+
},
|
|
15892
|
+
"502": {
|
|
15893
|
+
"description": "The upstream provider call failed or provider credentials are missing.",
|
|
15894
|
+
"content": {
|
|
15895
|
+
"application/json": {
|
|
15896
|
+
"schema": {
|
|
15897
|
+
"type": "object",
|
|
15898
|
+
"properties": {
|
|
15899
|
+
"error": {
|
|
15900
|
+
"type": "object",
|
|
15901
|
+
"properties": {
|
|
15902
|
+
"code": {
|
|
15903
|
+
"type": "string"
|
|
15904
|
+
},
|
|
15905
|
+
"message": {
|
|
15906
|
+
"type": "string"
|
|
15907
|
+
},
|
|
15908
|
+
"extra": {
|
|
15909
|
+
"type": "object",
|
|
15910
|
+
"additionalProperties": {}
|
|
15911
|
+
}
|
|
15912
|
+
},
|
|
15913
|
+
"required": [
|
|
15914
|
+
"code",
|
|
15915
|
+
"message"
|
|
15916
|
+
]
|
|
15917
|
+
}
|
|
15918
|
+
},
|
|
15919
|
+
"required": [
|
|
15920
|
+
"error"
|
|
15921
|
+
]
|
|
15922
|
+
}
|
|
15923
|
+
}
|
|
15924
|
+
}
|
|
15925
|
+
}
|
|
15926
|
+
}
|
|
15927
|
+
},
|
|
15928
|
+
"get": {
|
|
15929
|
+
"operationId": "email_domain_list",
|
|
15930
|
+
"tags": [
|
|
15931
|
+
"EmailDomains"
|
|
15515
15932
|
],
|
|
15516
|
-
"summary": "
|
|
15517
|
-
"description": "### Overview\
|
|
15933
|
+
"summary": "List cached custom domains",
|
|
15934
|
+
"description": "### Overview\nReturns the caller organization's cached custom email domains from D1. This route does not call the upstream provider.\n\n### When to Use\n- Use this to render an admin view of all registered domains and their latest known verification state.\n- Use it to inspect DNS records that were previously fetched during create or verify operations.\n- The cached state includes DNS ownership, sending readiness, and receiving readiness used by custom-domain alias creation.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- Results are scoped to the caller organization and sorted newest-first by creation time.",
|
|
15518
15935
|
"security": [
|
|
15519
15936
|
{
|
|
15520
15937
|
"bearerAuth": []
|
|
15521
15938
|
}
|
|
15522
15939
|
],
|
|
15523
15940
|
"x-cli": {
|
|
15524
|
-
"command": "
|
|
15525
|
-
"positional": [
|
|
15526
|
-
"id"
|
|
15527
|
-
],
|
|
15528
|
-
"options": {
|
|
15529
|
-
"id": {
|
|
15530
|
-
"array": true,
|
|
15531
|
-
"mapsTo": "ids"
|
|
15532
|
-
}
|
|
15533
|
-
},
|
|
15941
|
+
"command": "domain ls",
|
|
15534
15942
|
"display": {
|
|
15535
|
-
"shape": "
|
|
15536
|
-
"
|
|
15943
|
+
"shape": "list",
|
|
15944
|
+
"columns": [
|
|
15945
|
+
"domain",
|
|
15946
|
+
"status",
|
|
15947
|
+
"sending_status",
|
|
15948
|
+
"receiving_status",
|
|
15949
|
+
"updated_at"
|
|
15950
|
+
],
|
|
15951
|
+
"format": {
|
|
15952
|
+
"updated_at": "relative-time",
|
|
15953
|
+
"verified_at": "relative-time"
|
|
15954
|
+
},
|
|
15955
|
+
"emptyMessage": "no domains",
|
|
15956
|
+
"dataPath": "domains"
|
|
15537
15957
|
}
|
|
15538
15958
|
},
|
|
15539
15959
|
"x-codeSamples": [
|
|
15540
15960
|
{
|
|
15541
15961
|
"lang": "shell",
|
|
15542
15962
|
"label": "curl",
|
|
15543
|
-
"source": "curl
|
|
15963
|
+
"source": "curl https://api.wspc.ai/email/domains \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
|
|
15544
15964
|
},
|
|
15545
15965
|
{
|
|
15546
15966
|
"lang": "bash",
|
|
15547
15967
|
"label": "wspc CLI",
|
|
15548
|
-
"source": "wspc email
|
|
15968
|
+
"source": "wspc email domain ls"
|
|
15549
15969
|
}
|
|
15550
15970
|
],
|
|
15551
|
-
"requestBody": {
|
|
15552
|
-
"required": true,
|
|
15553
|
-
"content": {
|
|
15554
|
-
"application/json": {
|
|
15555
|
-
"schema": {
|
|
15556
|
-
"$ref": "#/components/schemas/BatchIdsBody"
|
|
15557
|
-
},
|
|
15558
|
-
"examples": {
|
|
15559
|
-
"minimal": {
|
|
15560
|
-
"summary": "Single id",
|
|
15561
|
-
"value": {
|
|
15562
|
-
"ids": [
|
|
15563
|
-
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
|
|
15564
|
-
]
|
|
15565
|
-
}
|
|
15566
|
-
},
|
|
15567
|
-
"full": {
|
|
15568
|
-
"summary": "Multiple ids (up to 100 per call)",
|
|
15569
|
-
"value": {
|
|
15570
|
-
"ids": [
|
|
15571
|
-
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
15572
|
-
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G",
|
|
15573
|
-
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3H"
|
|
15574
|
-
]
|
|
15575
|
-
}
|
|
15576
|
-
}
|
|
15577
|
-
}
|
|
15578
|
-
}
|
|
15579
|
-
}
|
|
15580
|
-
},
|
|
15581
15971
|
"responses": {
|
|
15582
15972
|
"200": {
|
|
15583
|
-
"description": "
|
|
15973
|
+
"description": "Custom domains cached for the caller organization, including ownership, sending readiness, and receiving readiness state.",
|
|
15584
15974
|
"content": {
|
|
15585
15975
|
"application/json": {
|
|
15586
15976
|
"schema": {
|
|
15587
|
-
"$ref": "#/components/schemas/
|
|
15977
|
+
"$ref": "#/components/schemas/EmailDomainListResponse"
|
|
15588
15978
|
},
|
|
15589
15979
|
"examples": {
|
|
15590
15980
|
"happyPath": {
|
|
15591
|
-
"summary": "
|
|
15981
|
+
"summary": "Two cached domains",
|
|
15592
15982
|
"value": {
|
|
15593
|
-
"
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
"properties": {
|
|
15620
|
-
"code": {
|
|
15621
|
-
"type": "string"
|
|
15622
|
-
},
|
|
15623
|
-
"message": {
|
|
15624
|
-
"type": "string"
|
|
15983
|
+
"domains": [
|
|
15984
|
+
{
|
|
15985
|
+
"domain": "mail.example.com",
|
|
15986
|
+
"status": "pending",
|
|
15987
|
+
"sending_status": "pending",
|
|
15988
|
+
"receiving_status": "pending",
|
|
15989
|
+
"records": [
|
|
15990
|
+
{
|
|
15991
|
+
"type": "TXT",
|
|
15992
|
+
"name": "mail.example.com",
|
|
15993
|
+
"value": "pm-domain-verification=abc123",
|
|
15994
|
+
"status": "pending",
|
|
15995
|
+
"ttl": 3600,
|
|
15996
|
+
"purpose": "identity_verification"
|
|
15997
|
+
},
|
|
15998
|
+
{
|
|
15999
|
+
"type": "CNAME",
|
|
16000
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
16001
|
+
"value": "selector1.domainkey.example.net",
|
|
16002
|
+
"status": "pending",
|
|
16003
|
+
"purpose": "dkim"
|
|
16004
|
+
}
|
|
16005
|
+
],
|
|
16006
|
+
"region": "us-east-1",
|
|
16007
|
+
"created_at": 1780166400000,
|
|
16008
|
+
"updated_at": 1780166400000
|
|
15625
16009
|
},
|
|
15626
|
-
|
|
15627
|
-
"
|
|
15628
|
-
"
|
|
16010
|
+
{
|
|
16011
|
+
"domain": "reply.example.com",
|
|
16012
|
+
"status": "verified",
|
|
16013
|
+
"sending_status": "verified",
|
|
16014
|
+
"receiving_status": "disabled",
|
|
16015
|
+
"records": [
|
|
16016
|
+
{
|
|
16017
|
+
"type": "TXT",
|
|
16018
|
+
"name": "mail.example.com",
|
|
16019
|
+
"value": "pm-domain-verification=abc123",
|
|
16020
|
+
"status": "verified",
|
|
16021
|
+
"ttl": 3600,
|
|
16022
|
+
"purpose": "identity_verification"
|
|
16023
|
+
},
|
|
16024
|
+
{
|
|
16025
|
+
"type": "CNAME",
|
|
16026
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
16027
|
+
"value": "selector1.domainkey.example.net",
|
|
16028
|
+
"status": "verified",
|
|
16029
|
+
"purpose": "dkim"
|
|
16030
|
+
}
|
|
16031
|
+
],
|
|
16032
|
+
"region": "us-east-1",
|
|
16033
|
+
"created_at": 1780166400000,
|
|
16034
|
+
"updated_at": 1780167000000,
|
|
16035
|
+
"verified_at": 1780167000000
|
|
15629
16036
|
}
|
|
15630
|
-
},
|
|
15631
|
-
"required": [
|
|
15632
|
-
"code",
|
|
15633
|
-
"message"
|
|
15634
16037
|
]
|
|
15635
16038
|
}
|
|
15636
16039
|
},
|
|
15637
|
-
"
|
|
15638
|
-
"
|
|
15639
|
-
]
|
|
15640
|
-
},
|
|
15641
|
-
"examples": {
|
|
15642
|
-
"validationError": {
|
|
15643
|
-
"summary": "Body failed schema validation",
|
|
16040
|
+
"empty": {
|
|
16041
|
+
"summary": "No custom domains yet",
|
|
15644
16042
|
"value": {
|
|
15645
|
-
"
|
|
15646
|
-
"code": "VALIDATION_ERROR",
|
|
15647
|
-
"message": "title must not be empty"
|
|
15648
|
-
}
|
|
16043
|
+
"domains": []
|
|
15649
16044
|
}
|
|
15650
16045
|
}
|
|
15651
16046
|
}
|
|
@@ -15794,73 +16189,61 @@
|
|
|
15794
16189
|
}
|
|
15795
16190
|
}
|
|
15796
16191
|
},
|
|
15797
|
-
"/email/
|
|
15798
|
-
"
|
|
15799
|
-
"operationId": "
|
|
16192
|
+
"/email/aliases/{email}": {
|
|
16193
|
+
"delete": {
|
|
16194
|
+
"operationId": "email_alias_delete",
|
|
15800
16195
|
"tags": [
|
|
15801
|
-
"
|
|
16196
|
+
"EmailAliases"
|
|
15802
16197
|
],
|
|
15803
|
-
"summary": "
|
|
15804
|
-
"description": "### Overview\
|
|
16198
|
+
"summary": "Soft-delete an alias",
|
|
16199
|
+
"description": "### Overview\nSoft-deletes a specific active email receiving alias owned by the caller. Once soft-deleted, the alias stops accepting and forwarding any new inbound emails.\n\n### When to Use\n- Use this endpoint when decommissioning a disposable alias address that is no longer needed or is receiving excessive spam.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Data Retention**: Soft-deletion is immediate. Inbound mail forwarding stops, but historical emails previously received on this alias remain fully readable in the inbox.\n- **Restoration**: The alias remains globally reserved and cannot be created fresh by anyone; use `POST /email/aliases/{email}/restore` to reactivate.\n- **Path Parameter**: The `@` character in the `{email}` path parameter must be URL-encoded as `%40`.\n\n### Troubleshooting\n- **401 Unauthorized**: Missing or invalid token.\n- **404 Not Found**: No active alias with this exact address was found for the authenticated user, or the alias is already deleted.",
|
|
15805
16200
|
"security": [
|
|
15806
16201
|
{
|
|
15807
16202
|
"bearerAuth": []
|
|
15808
16203
|
}
|
|
15809
16204
|
],
|
|
15810
16205
|
"x-cli": {
|
|
15811
|
-
"command": "
|
|
15812
|
-
"
|
|
16206
|
+
"command": "alias rm",
|
|
16207
|
+
"positional": [
|
|
16208
|
+
"email"
|
|
16209
|
+
],
|
|
16210
|
+
"display": {
|
|
16211
|
+
"shape": "object",
|
|
16212
|
+
"format": {
|
|
16213
|
+
"id": "id-short",
|
|
16214
|
+
"user_id": "id-short",
|
|
16215
|
+
"created_at": "relative-time",
|
|
16216
|
+
"deleted_at": "relative-time"
|
|
16217
|
+
}
|
|
16218
|
+
}
|
|
15813
16219
|
},
|
|
15814
16220
|
"x-codeSamples": [
|
|
15815
16221
|
{
|
|
15816
16222
|
"lang": "shell",
|
|
15817
16223
|
"label": "curl",
|
|
15818
|
-
"source": "curl https://api.wspc.ai/email/
|
|
16224
|
+
"source": "curl -X DELETE https://api.wspc.ai/email/aliases/alice-shop%40wspc.app \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
|
|
15819
16225
|
},
|
|
15820
16226
|
{
|
|
15821
16227
|
"lang": "bash",
|
|
15822
16228
|
"label": "wspc CLI",
|
|
15823
|
-
"source": "wspc email
|
|
16229
|
+
"source": "wspc email alias rm alice-shop@wspc.app"
|
|
15824
16230
|
}
|
|
15825
16231
|
],
|
|
15826
16232
|
"parameters": [
|
|
15827
16233
|
{
|
|
15828
16234
|
"schema": {
|
|
15829
|
-
"type": "string"
|
|
15830
|
-
|
|
15831
|
-
"required": true,
|
|
15832
|
-
"name": "id",
|
|
15833
|
-
"in": "path"
|
|
15834
|
-
},
|
|
15835
|
-
{
|
|
15836
|
-
"schema": {
|
|
15837
|
-
"type": "string"
|
|
16235
|
+
"type": "string",
|
|
16236
|
+
"description": "Full alias email address. URL-encode @ as %40 in paths."
|
|
15838
16237
|
},
|
|
15839
16238
|
"required": true,
|
|
15840
|
-
"
|
|
16239
|
+
"description": "Full alias email address. URL-encode @ as %40 in paths.",
|
|
16240
|
+
"name": "email",
|
|
15841
16241
|
"in": "path"
|
|
15842
|
-
},
|
|
15843
|
-
{
|
|
15844
|
-
"schema": {
|
|
15845
|
-
"type": "string",
|
|
15846
|
-
"description": "When `true`, allow downloading an attachment whose parent email is soft-deleted. Defaults to `false`."
|
|
15847
|
-
},
|
|
15848
|
-
"required": false,
|
|
15849
|
-
"description": "When `true`, allow downloading an attachment whose parent email is soft-deleted. Defaults to `false`.",
|
|
15850
|
-
"name": "include_deleted",
|
|
15851
|
-
"in": "query"
|
|
15852
16242
|
}
|
|
15853
16243
|
],
|
|
15854
16244
|
"responses": {
|
|
15855
|
-
"
|
|
15856
|
-
"description": "
|
|
15857
|
-
"content": {
|
|
15858
|
-
"application/octet-stream": {
|
|
15859
|
-
"schema": {
|
|
15860
|
-
"type": "string"
|
|
15861
|
-
}
|
|
15862
|
-
}
|
|
15863
|
-
}
|
|
16245
|
+
"204": {
|
|
16246
|
+
"description": "Alias soft-deleted. Forwarding stops immediately. No response body."
|
|
15864
16247
|
},
|
|
15865
16248
|
"401": {
|
|
15866
16249
|
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
@@ -15908,7 +16291,7 @@
|
|
|
15908
16291
|
}
|
|
15909
16292
|
},
|
|
15910
16293
|
"404": {
|
|
15911
|
-
"description": "
|
|
16294
|
+
"description": "No active alias with this email address is owned by the caller.",
|
|
15912
16295
|
"content": {
|
|
15913
16296
|
"application/json": {
|
|
15914
16297
|
"schema": {
|
|
@@ -16038,44 +16421,881 @@
|
|
|
16038
16421
|
}
|
|
16039
16422
|
}
|
|
16040
16423
|
},
|
|
16041
|
-
"/email/messages/
|
|
16042
|
-
"
|
|
16043
|
-
"operationId": "
|
|
16424
|
+
"/email/messages/delete": {
|
|
16425
|
+
"post": {
|
|
16426
|
+
"operationId": "email_delete",
|
|
16044
16427
|
"tags": [
|
|
16045
16428
|
"Emails"
|
|
16046
16429
|
],
|
|
16047
|
-
"summary": "
|
|
16048
|
-
"description": "### Overview\
|
|
16430
|
+
"summary": "Soft-delete inbound emails",
|
|
16431
|
+
"description": "### Overview\nSoft-deletes a batch of inbound emails, moving them to the trash. Soft-deleted emails are immediately excluded from default inbox lists.\n\n### When to Use\n- Use this endpoint to trash one or more email messages from a user's inbox view.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- Accepts 1 to 100 email IDs per call.\n- Deletion is fully reversible: soft-deleted rows persist in the database and can be undeleted using the restore endpoint.\n- **Data Cleanup**: Out-of-band background processes eventually purge associated raw MIME source payloads and attachment bytes from R2; deletion does not immediately free storage.\n\n### Troubleshooting\n- **401 Unauthorized**: Invalid Bearer token.\n- **400 Bad Request**: The request body is malformed or exceeds the maximum limit of 100 IDs.",
|
|
16049
16432
|
"security": [
|
|
16050
16433
|
{
|
|
16051
16434
|
"bearerAuth": []
|
|
16052
16435
|
}
|
|
16053
16436
|
],
|
|
16054
16437
|
"x-cli": {
|
|
16055
|
-
"command": "email
|
|
16438
|
+
"command": "email rm",
|
|
16056
16439
|
"positional": [
|
|
16057
16440
|
"id"
|
|
16058
16441
|
],
|
|
16442
|
+
"options": {
|
|
16443
|
+
"id": {
|
|
16444
|
+
"array": true,
|
|
16445
|
+
"mapsTo": "ids"
|
|
16446
|
+
}
|
|
16447
|
+
},
|
|
16059
16448
|
"display": {
|
|
16060
16449
|
"shape": "object",
|
|
16061
|
-
"format": {
|
|
16062
|
-
"id": "id-short",
|
|
16063
|
-
"org_id": "id-short",
|
|
16064
|
-
"user_id": "id-short",
|
|
16065
|
-
"received_at": "relative-time",
|
|
16066
|
-
"created_at": "relative-time",
|
|
16067
|
-
"read_at": "relative-time",
|
|
16068
|
-
"deleted_at": "relative-time",
|
|
16069
|
-
"is_read": "bool-badge"
|
|
16070
|
-
},
|
|
16071
|
-
"dataPath": "email"
|
|
16450
|
+
"format": {}
|
|
16072
16451
|
}
|
|
16073
16452
|
},
|
|
16074
16453
|
"x-codeSamples": [
|
|
16075
16454
|
{
|
|
16076
16455
|
"lang": "shell",
|
|
16077
16456
|
"label": "curl",
|
|
16078
|
-
"source": "curl https://api.wspc.ai/email/messages/
|
|
16457
|
+
"source": "curl -X POST https://api.wspc.ai/email/messages/delete \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"ids\":[\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\",\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G\"]}'"
|
|
16458
|
+
},
|
|
16459
|
+
{
|
|
16460
|
+
"lang": "bash",
|
|
16461
|
+
"label": "wspc CLI",
|
|
16462
|
+
"source": "wspc email rm eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G"
|
|
16463
|
+
}
|
|
16464
|
+
],
|
|
16465
|
+
"requestBody": {
|
|
16466
|
+
"required": true,
|
|
16467
|
+
"content": {
|
|
16468
|
+
"application/json": {
|
|
16469
|
+
"schema": {
|
|
16470
|
+
"$ref": "#/components/schemas/BatchIdsBody"
|
|
16471
|
+
},
|
|
16472
|
+
"examples": {
|
|
16473
|
+
"minimal": {
|
|
16474
|
+
"summary": "Single id",
|
|
16475
|
+
"value": {
|
|
16476
|
+
"ids": [
|
|
16477
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
|
|
16478
|
+
]
|
|
16479
|
+
}
|
|
16480
|
+
},
|
|
16481
|
+
"full": {
|
|
16482
|
+
"summary": "Multiple ids (up to 100 per call)",
|
|
16483
|
+
"value": {
|
|
16484
|
+
"ids": [
|
|
16485
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
16486
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G",
|
|
16487
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3H"
|
|
16488
|
+
]
|
|
16489
|
+
}
|
|
16490
|
+
}
|
|
16491
|
+
}
|
|
16492
|
+
}
|
|
16493
|
+
}
|
|
16494
|
+
},
|
|
16495
|
+
"responses": {
|
|
16496
|
+
"200": {
|
|
16497
|
+
"description": "Bulk soft-delete result. `deleted` counts state changes only.",
|
|
16498
|
+
"content": {
|
|
16499
|
+
"application/json": {
|
|
16500
|
+
"schema": {
|
|
16501
|
+
"$ref": "#/components/schemas/DeleteBatchResponse"
|
|
16502
|
+
},
|
|
16503
|
+
"examples": {
|
|
16504
|
+
"happyPath": {
|
|
16505
|
+
"summary": "All ids matched and changed state",
|
|
16506
|
+
"value": {
|
|
16507
|
+
"deleted": 2,
|
|
16508
|
+
"not_found": []
|
|
16509
|
+
}
|
|
16510
|
+
},
|
|
16511
|
+
"partial": {
|
|
16512
|
+
"summary": "Some ids unknown to this user",
|
|
16513
|
+
"value": {
|
|
16514
|
+
"deleted": 1,
|
|
16515
|
+
"not_found": [
|
|
16516
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3X"
|
|
16517
|
+
]
|
|
16518
|
+
}
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
}
|
|
16522
|
+
}
|
|
16523
|
+
},
|
|
16524
|
+
"400": {
|
|
16525
|
+
"description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
|
|
16526
|
+
"content": {
|
|
16527
|
+
"application/json": {
|
|
16528
|
+
"schema": {
|
|
16529
|
+
"type": "object",
|
|
16530
|
+
"properties": {
|
|
16531
|
+
"error": {
|
|
16532
|
+
"type": "object",
|
|
16533
|
+
"properties": {
|
|
16534
|
+
"code": {
|
|
16535
|
+
"type": "string"
|
|
16536
|
+
},
|
|
16537
|
+
"message": {
|
|
16538
|
+
"type": "string"
|
|
16539
|
+
},
|
|
16540
|
+
"extra": {
|
|
16541
|
+
"type": "object",
|
|
16542
|
+
"additionalProperties": {}
|
|
16543
|
+
}
|
|
16544
|
+
},
|
|
16545
|
+
"required": [
|
|
16546
|
+
"code",
|
|
16547
|
+
"message"
|
|
16548
|
+
]
|
|
16549
|
+
}
|
|
16550
|
+
},
|
|
16551
|
+
"required": [
|
|
16552
|
+
"error"
|
|
16553
|
+
]
|
|
16554
|
+
},
|
|
16555
|
+
"examples": {
|
|
16556
|
+
"validationError": {
|
|
16557
|
+
"summary": "Body failed schema validation",
|
|
16558
|
+
"value": {
|
|
16559
|
+
"error": {
|
|
16560
|
+
"code": "VALIDATION_ERROR",
|
|
16561
|
+
"message": "title must not be empty"
|
|
16562
|
+
}
|
|
16563
|
+
}
|
|
16564
|
+
}
|
|
16565
|
+
}
|
|
16566
|
+
}
|
|
16567
|
+
}
|
|
16568
|
+
},
|
|
16569
|
+
"401": {
|
|
16570
|
+
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
16571
|
+
"content": {
|
|
16572
|
+
"application/json": {
|
|
16573
|
+
"schema": {
|
|
16574
|
+
"type": "object",
|
|
16575
|
+
"properties": {
|
|
16576
|
+
"error": {
|
|
16577
|
+
"type": "object",
|
|
16578
|
+
"properties": {
|
|
16579
|
+
"code": {
|
|
16580
|
+
"type": "string"
|
|
16581
|
+
},
|
|
16582
|
+
"message": {
|
|
16583
|
+
"type": "string"
|
|
16584
|
+
},
|
|
16585
|
+
"extra": {
|
|
16586
|
+
"type": "object",
|
|
16587
|
+
"additionalProperties": {}
|
|
16588
|
+
}
|
|
16589
|
+
},
|
|
16590
|
+
"required": [
|
|
16591
|
+
"code",
|
|
16592
|
+
"message"
|
|
16593
|
+
]
|
|
16594
|
+
}
|
|
16595
|
+
},
|
|
16596
|
+
"required": [
|
|
16597
|
+
"error"
|
|
16598
|
+
]
|
|
16599
|
+
},
|
|
16600
|
+
"examples": {
|
|
16601
|
+
"authRequired": {
|
|
16602
|
+
"summary": "Missing Authorization header",
|
|
16603
|
+
"value": {
|
|
16604
|
+
"error": {
|
|
16605
|
+
"code": "AUTH_REQUIRED",
|
|
16606
|
+
"message": "missing bearer token"
|
|
16607
|
+
}
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16610
|
+
}
|
|
16611
|
+
}
|
|
16612
|
+
}
|
|
16613
|
+
},
|
|
16614
|
+
"429": {
|
|
16615
|
+
"description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
|
|
16616
|
+
"content": {
|
|
16617
|
+
"application/json": {
|
|
16618
|
+
"schema": {
|
|
16619
|
+
"type": "object",
|
|
16620
|
+
"properties": {
|
|
16621
|
+
"error": {
|
|
16622
|
+
"type": "object",
|
|
16623
|
+
"properties": {
|
|
16624
|
+
"code": {
|
|
16625
|
+
"type": "string"
|
|
16626
|
+
},
|
|
16627
|
+
"message": {
|
|
16628
|
+
"type": "string"
|
|
16629
|
+
},
|
|
16630
|
+
"extra": {
|
|
16631
|
+
"type": "object",
|
|
16632
|
+
"additionalProperties": {}
|
|
16633
|
+
}
|
|
16634
|
+
},
|
|
16635
|
+
"required": [
|
|
16636
|
+
"code",
|
|
16637
|
+
"message"
|
|
16638
|
+
]
|
|
16639
|
+
}
|
|
16640
|
+
},
|
|
16641
|
+
"required": [
|
|
16642
|
+
"error"
|
|
16643
|
+
]
|
|
16644
|
+
},
|
|
16645
|
+
"examples": {
|
|
16646
|
+
"rateLimited": {
|
|
16647
|
+
"summary": "Per-key rate limit hit",
|
|
16648
|
+
"value": {
|
|
16649
|
+
"error": {
|
|
16650
|
+
"code": "RATE_LIMITED",
|
|
16651
|
+
"message": "rate limit exceeded",
|
|
16652
|
+
"extra": {
|
|
16653
|
+
"retry_after_seconds": 60,
|
|
16654
|
+
"limit_kind": "authenticated_per_key"
|
|
16655
|
+
}
|
|
16656
|
+
}
|
|
16657
|
+
}
|
|
16658
|
+
}
|
|
16659
|
+
}
|
|
16660
|
+
}
|
|
16661
|
+
}
|
|
16662
|
+
},
|
|
16663
|
+
"500": {
|
|
16664
|
+
"description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
|
|
16665
|
+
"content": {
|
|
16666
|
+
"application/json": {
|
|
16667
|
+
"schema": {
|
|
16668
|
+
"type": "object",
|
|
16669
|
+
"properties": {
|
|
16670
|
+
"error": {
|
|
16671
|
+
"type": "object",
|
|
16672
|
+
"properties": {
|
|
16673
|
+
"code": {
|
|
16674
|
+
"type": "string"
|
|
16675
|
+
},
|
|
16676
|
+
"message": {
|
|
16677
|
+
"type": "string"
|
|
16678
|
+
},
|
|
16679
|
+
"extra": {
|
|
16680
|
+
"type": "object",
|
|
16681
|
+
"additionalProperties": {}
|
|
16682
|
+
}
|
|
16683
|
+
},
|
|
16684
|
+
"required": [
|
|
16685
|
+
"code",
|
|
16686
|
+
"message"
|
|
16687
|
+
]
|
|
16688
|
+
}
|
|
16689
|
+
},
|
|
16690
|
+
"required": [
|
|
16691
|
+
"error"
|
|
16692
|
+
]
|
|
16693
|
+
},
|
|
16694
|
+
"examples": {
|
|
16695
|
+
"internalError": {
|
|
16696
|
+
"summary": "Unhandled exception",
|
|
16697
|
+
"value": {
|
|
16698
|
+
"error": {
|
|
16699
|
+
"code": "INTERNAL_ERROR",
|
|
16700
|
+
"message": "internal error"
|
|
16701
|
+
}
|
|
16702
|
+
}
|
|
16703
|
+
}
|
|
16704
|
+
}
|
|
16705
|
+
}
|
|
16706
|
+
}
|
|
16707
|
+
}
|
|
16708
|
+
}
|
|
16709
|
+
}
|
|
16710
|
+
},
|
|
16711
|
+
"/email/messages/{id}/attachments/{idx}": {
|
|
16712
|
+
"get": {
|
|
16713
|
+
"operationId": "email_attachment_get",
|
|
16714
|
+
"tags": [
|
|
16715
|
+
"Emails"
|
|
16716
|
+
],
|
|
16717
|
+
"summary": "Download an attachment by index",
|
|
16718
|
+
"description": "### Overview\nStreams the raw decoded bytes of a parsed attachment belonging to an inbound email. The response body is binary data instead of JSON.\n\n### When to Use\n- Use this endpoint when a user clicks to download a file attachment (such as an invoice PDF or image) or when an automated agent needs to process a file payload.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Response Headers**: The server sets the HTTP `Content-Type` matching the attachment's parsed MIME format and provides a `Content-Disposition: attachment; filename=\"<filename>\"` header.\n- **Soft-Deleted Parents**: Downloading files from soft-deleted emails is blocked with a 404 error, unless the query parameter `include_deleted=true` is provided.\n- **Path Parameter**: The `{idx}` must be a valid 0-based integer index pointing to the attachment list metadata.\n\n### Troubleshooting\n- **401 Unauthorized**: Invalid Bearer token.\n- **404 Not Found / EMAIL_NOT_FOUND**: The specified email ID does not exist or belongs to another user.\n- **404 Not Found / ATTACHMENT_NOT_FOUND**: The index `{idx}` is out of range for the email's attachment array.",
|
|
16719
|
+
"security": [
|
|
16720
|
+
{
|
|
16721
|
+
"bearerAuth": []
|
|
16722
|
+
}
|
|
16723
|
+
],
|
|
16724
|
+
"x-cli": {
|
|
16725
|
+
"command": "_handwritten",
|
|
16726
|
+
"hidden": true
|
|
16727
|
+
},
|
|
16728
|
+
"x-codeSamples": [
|
|
16729
|
+
{
|
|
16730
|
+
"lang": "shell",
|
|
16731
|
+
"label": "curl",
|
|
16732
|
+
"source": "curl https://api.wspc.ai/email/messages/eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F/attachments/0 \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -o invoice.pdf"
|
|
16733
|
+
},
|
|
16734
|
+
{
|
|
16735
|
+
"lang": "bash",
|
|
16736
|
+
"label": "wspc CLI",
|
|
16737
|
+
"source": "wspc email attachment eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F 0 --output invoice.pdf"
|
|
16738
|
+
}
|
|
16739
|
+
],
|
|
16740
|
+
"parameters": [
|
|
16741
|
+
{
|
|
16742
|
+
"schema": {
|
|
16743
|
+
"type": "string"
|
|
16744
|
+
},
|
|
16745
|
+
"required": true,
|
|
16746
|
+
"name": "id",
|
|
16747
|
+
"in": "path"
|
|
16748
|
+
},
|
|
16749
|
+
{
|
|
16750
|
+
"schema": {
|
|
16751
|
+
"type": "string"
|
|
16752
|
+
},
|
|
16753
|
+
"required": true,
|
|
16754
|
+
"name": "idx",
|
|
16755
|
+
"in": "path"
|
|
16756
|
+
},
|
|
16757
|
+
{
|
|
16758
|
+
"schema": {
|
|
16759
|
+
"type": "string",
|
|
16760
|
+
"description": "When `true`, allow downloading an attachment whose parent email is soft-deleted. Defaults to `false`."
|
|
16761
|
+
},
|
|
16762
|
+
"required": false,
|
|
16763
|
+
"description": "When `true`, allow downloading an attachment whose parent email is soft-deleted. Defaults to `false`.",
|
|
16764
|
+
"name": "include_deleted",
|
|
16765
|
+
"in": "query"
|
|
16766
|
+
}
|
|
16767
|
+
],
|
|
16768
|
+
"responses": {
|
|
16769
|
+
"200": {
|
|
16770
|
+
"description": "Raw attachment bytes. `Content-Type` matches the attachment's parsed MIME (often `application/pdf`, `image/jpeg`, `text/calendar`, or `application/octet-stream` when unknown). `Content-Disposition: attachment; filename=\"<filename>\"`.",
|
|
16771
|
+
"content": {
|
|
16772
|
+
"application/octet-stream": {
|
|
16773
|
+
"schema": {
|
|
16774
|
+
"type": "string"
|
|
16775
|
+
}
|
|
16776
|
+
}
|
|
16777
|
+
}
|
|
16778
|
+
},
|
|
16779
|
+
"401": {
|
|
16780
|
+
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
16781
|
+
"content": {
|
|
16782
|
+
"application/json": {
|
|
16783
|
+
"schema": {
|
|
16784
|
+
"type": "object",
|
|
16785
|
+
"properties": {
|
|
16786
|
+
"error": {
|
|
16787
|
+
"type": "object",
|
|
16788
|
+
"properties": {
|
|
16789
|
+
"code": {
|
|
16790
|
+
"type": "string"
|
|
16791
|
+
},
|
|
16792
|
+
"message": {
|
|
16793
|
+
"type": "string"
|
|
16794
|
+
},
|
|
16795
|
+
"extra": {
|
|
16796
|
+
"type": "object",
|
|
16797
|
+
"additionalProperties": {}
|
|
16798
|
+
}
|
|
16799
|
+
},
|
|
16800
|
+
"required": [
|
|
16801
|
+
"code",
|
|
16802
|
+
"message"
|
|
16803
|
+
]
|
|
16804
|
+
}
|
|
16805
|
+
},
|
|
16806
|
+
"required": [
|
|
16807
|
+
"error"
|
|
16808
|
+
]
|
|
16809
|
+
},
|
|
16810
|
+
"examples": {
|
|
16811
|
+
"authRequired": {
|
|
16812
|
+
"summary": "Missing Authorization header",
|
|
16813
|
+
"value": {
|
|
16814
|
+
"error": {
|
|
16815
|
+
"code": "AUTH_REQUIRED",
|
|
16816
|
+
"message": "missing bearer token"
|
|
16817
|
+
}
|
|
16818
|
+
}
|
|
16819
|
+
}
|
|
16820
|
+
}
|
|
16821
|
+
}
|
|
16822
|
+
}
|
|
16823
|
+
},
|
|
16824
|
+
"404": {
|
|
16825
|
+
"description": "Either the parent email is unknown / soft-deleted (`EMAIL_NOT_FOUND`) or `idx` is out of range (`ATTACHMENT_NOT_FOUND`).",
|
|
16826
|
+
"content": {
|
|
16827
|
+
"application/json": {
|
|
16828
|
+
"schema": {
|
|
16829
|
+
"type": "object",
|
|
16830
|
+
"properties": {
|
|
16831
|
+
"error": {
|
|
16832
|
+
"type": "object",
|
|
16833
|
+
"properties": {
|
|
16834
|
+
"code": {
|
|
16835
|
+
"type": "string"
|
|
16836
|
+
},
|
|
16837
|
+
"message": {
|
|
16838
|
+
"type": "string"
|
|
16839
|
+
},
|
|
16840
|
+
"extra": {
|
|
16841
|
+
"type": "object",
|
|
16842
|
+
"additionalProperties": {}
|
|
16843
|
+
}
|
|
16844
|
+
},
|
|
16845
|
+
"required": [
|
|
16846
|
+
"code",
|
|
16847
|
+
"message"
|
|
16848
|
+
]
|
|
16849
|
+
}
|
|
16850
|
+
},
|
|
16851
|
+
"required": [
|
|
16852
|
+
"error"
|
|
16853
|
+
]
|
|
16854
|
+
}
|
|
16855
|
+
}
|
|
16856
|
+
}
|
|
16857
|
+
},
|
|
16858
|
+
"429": {
|
|
16859
|
+
"description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
|
|
16860
|
+
"content": {
|
|
16861
|
+
"application/json": {
|
|
16862
|
+
"schema": {
|
|
16863
|
+
"type": "object",
|
|
16864
|
+
"properties": {
|
|
16865
|
+
"error": {
|
|
16866
|
+
"type": "object",
|
|
16867
|
+
"properties": {
|
|
16868
|
+
"code": {
|
|
16869
|
+
"type": "string"
|
|
16870
|
+
},
|
|
16871
|
+
"message": {
|
|
16872
|
+
"type": "string"
|
|
16873
|
+
},
|
|
16874
|
+
"extra": {
|
|
16875
|
+
"type": "object",
|
|
16876
|
+
"additionalProperties": {}
|
|
16877
|
+
}
|
|
16878
|
+
},
|
|
16879
|
+
"required": [
|
|
16880
|
+
"code",
|
|
16881
|
+
"message"
|
|
16882
|
+
]
|
|
16883
|
+
}
|
|
16884
|
+
},
|
|
16885
|
+
"required": [
|
|
16886
|
+
"error"
|
|
16887
|
+
]
|
|
16888
|
+
},
|
|
16889
|
+
"examples": {
|
|
16890
|
+
"rateLimited": {
|
|
16891
|
+
"summary": "Per-key rate limit hit",
|
|
16892
|
+
"value": {
|
|
16893
|
+
"error": {
|
|
16894
|
+
"code": "RATE_LIMITED",
|
|
16895
|
+
"message": "rate limit exceeded",
|
|
16896
|
+
"extra": {
|
|
16897
|
+
"retry_after_seconds": 60,
|
|
16898
|
+
"limit_kind": "authenticated_per_key"
|
|
16899
|
+
}
|
|
16900
|
+
}
|
|
16901
|
+
}
|
|
16902
|
+
}
|
|
16903
|
+
}
|
|
16904
|
+
}
|
|
16905
|
+
}
|
|
16906
|
+
},
|
|
16907
|
+
"500": {
|
|
16908
|
+
"description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
|
|
16909
|
+
"content": {
|
|
16910
|
+
"application/json": {
|
|
16911
|
+
"schema": {
|
|
16912
|
+
"type": "object",
|
|
16913
|
+
"properties": {
|
|
16914
|
+
"error": {
|
|
16915
|
+
"type": "object",
|
|
16916
|
+
"properties": {
|
|
16917
|
+
"code": {
|
|
16918
|
+
"type": "string"
|
|
16919
|
+
},
|
|
16920
|
+
"message": {
|
|
16921
|
+
"type": "string"
|
|
16922
|
+
},
|
|
16923
|
+
"extra": {
|
|
16924
|
+
"type": "object",
|
|
16925
|
+
"additionalProperties": {}
|
|
16926
|
+
}
|
|
16927
|
+
},
|
|
16928
|
+
"required": [
|
|
16929
|
+
"code",
|
|
16930
|
+
"message"
|
|
16931
|
+
]
|
|
16932
|
+
}
|
|
16933
|
+
},
|
|
16934
|
+
"required": [
|
|
16935
|
+
"error"
|
|
16936
|
+
]
|
|
16937
|
+
},
|
|
16938
|
+
"examples": {
|
|
16939
|
+
"internalError": {
|
|
16940
|
+
"summary": "Unhandled exception",
|
|
16941
|
+
"value": {
|
|
16942
|
+
"error": {
|
|
16943
|
+
"code": "INTERNAL_ERROR",
|
|
16944
|
+
"message": "internal error"
|
|
16945
|
+
}
|
|
16946
|
+
}
|
|
16947
|
+
}
|
|
16948
|
+
}
|
|
16949
|
+
}
|
|
16950
|
+
}
|
|
16951
|
+
}
|
|
16952
|
+
}
|
|
16953
|
+
}
|
|
16954
|
+
},
|
|
16955
|
+
"/email/domains/{domain}": {
|
|
16956
|
+
"get": {
|
|
16957
|
+
"operationId": "email_domain_get",
|
|
16958
|
+
"tags": [
|
|
16959
|
+
"EmailDomains"
|
|
16960
|
+
],
|
|
16961
|
+
"summary": "Get one cached custom domain",
|
|
16962
|
+
"description": "### Overview\nReturns the caller organization's cached state for one custom email domain. This is a pure D1 read and never calls the upstream provider.\n\n### When to Use\n- Use this to inspect the latest cached DNS records or verification status for a single domain.\n- This cached view includes ownership, sending readiness, and receiving readiness state for custom-domain alias decisions.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- The `{domain}` path parameter is normalized and validated server-side before lookup.\n\n### Troubleshooting\n- **400 Bad Request / DOMAIN_INVALID / DOMAIN_RESERVED**: The path hostname is malformed or reserved.\n- **404 Not Found / DOMAIN_NOT_FOUND**: The domain does not exist or belongs to another organization.",
|
|
16963
|
+
"security": [
|
|
16964
|
+
{
|
|
16965
|
+
"bearerAuth": []
|
|
16966
|
+
}
|
|
16967
|
+
],
|
|
16968
|
+
"x-cli": {
|
|
16969
|
+
"command": "domain show",
|
|
16970
|
+
"positional": [
|
|
16971
|
+
"domain"
|
|
16972
|
+
],
|
|
16973
|
+
"display": {
|
|
16974
|
+
"shape": "object",
|
|
16975
|
+
"format": {
|
|
16976
|
+
"created_at": "relative-time",
|
|
16977
|
+
"updated_at": "relative-time",
|
|
16978
|
+
"verified_at": "relative-time"
|
|
16979
|
+
},
|
|
16980
|
+
"dataPath": "domain"
|
|
16981
|
+
}
|
|
16982
|
+
},
|
|
16983
|
+
"x-codeSamples": [
|
|
16984
|
+
{
|
|
16985
|
+
"lang": "shell",
|
|
16986
|
+
"label": "curl",
|
|
16987
|
+
"source": "curl https://api.wspc.ai/email/domains/mail.example.com \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
|
|
16988
|
+
},
|
|
16989
|
+
{
|
|
16990
|
+
"lang": "bash",
|
|
16991
|
+
"label": "wspc CLI",
|
|
16992
|
+
"source": "wspc email domain show mail.example.com"
|
|
16993
|
+
}
|
|
16994
|
+
],
|
|
16995
|
+
"parameters": [
|
|
16996
|
+
{
|
|
16997
|
+
"schema": {
|
|
16998
|
+
"type": "string",
|
|
16999
|
+
"description": "Custom domain hostname path parameter. URL-encode if your client requires it."
|
|
17000
|
+
},
|
|
17001
|
+
"required": true,
|
|
17002
|
+
"description": "Custom domain hostname path parameter. URL-encode if your client requires it.",
|
|
17003
|
+
"name": "domain",
|
|
17004
|
+
"in": "path"
|
|
17005
|
+
}
|
|
17006
|
+
],
|
|
17007
|
+
"responses": {
|
|
17008
|
+
"200": {
|
|
17009
|
+
"description": "One custom domain cached for the caller organization, including ownership, sending readiness, and receiving readiness state.",
|
|
17010
|
+
"content": {
|
|
17011
|
+
"application/json": {
|
|
17012
|
+
"schema": {
|
|
17013
|
+
"$ref": "#/components/schemas/EmailDomainObjectResponse"
|
|
17014
|
+
},
|
|
17015
|
+
"examples": {
|
|
17016
|
+
"happyPath": {
|
|
17017
|
+
"summary": "Pending domain cache row",
|
|
17018
|
+
"value": {
|
|
17019
|
+
"domain": {
|
|
17020
|
+
"domain": "mail.example.com",
|
|
17021
|
+
"status": "pending",
|
|
17022
|
+
"sending_status": "pending",
|
|
17023
|
+
"receiving_status": "pending",
|
|
17024
|
+
"records": [
|
|
17025
|
+
{
|
|
17026
|
+
"type": "TXT",
|
|
17027
|
+
"name": "mail.example.com",
|
|
17028
|
+
"value": "pm-domain-verification=abc123",
|
|
17029
|
+
"status": "pending",
|
|
17030
|
+
"ttl": 3600,
|
|
17031
|
+
"purpose": "identity_verification"
|
|
17032
|
+
},
|
|
17033
|
+
{
|
|
17034
|
+
"type": "CNAME",
|
|
17035
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
17036
|
+
"value": "selector1.domainkey.example.net",
|
|
17037
|
+
"status": "pending",
|
|
17038
|
+
"purpose": "dkim"
|
|
17039
|
+
}
|
|
17040
|
+
],
|
|
17041
|
+
"region": "us-east-1",
|
|
17042
|
+
"created_at": 1780166400000,
|
|
17043
|
+
"updated_at": 1780166400000
|
|
17044
|
+
}
|
|
17045
|
+
}
|
|
17046
|
+
}
|
|
17047
|
+
}
|
|
17048
|
+
}
|
|
17049
|
+
}
|
|
17050
|
+
},
|
|
17051
|
+
"400": {
|
|
17052
|
+
"description": "Malformed or platform-reserved domain hostname.",
|
|
17053
|
+
"content": {
|
|
17054
|
+
"application/json": {
|
|
17055
|
+
"schema": {
|
|
17056
|
+
"type": "object",
|
|
17057
|
+
"properties": {
|
|
17058
|
+
"error": {
|
|
17059
|
+
"type": "object",
|
|
17060
|
+
"properties": {
|
|
17061
|
+
"code": {
|
|
17062
|
+
"type": "string"
|
|
17063
|
+
},
|
|
17064
|
+
"message": {
|
|
17065
|
+
"type": "string"
|
|
17066
|
+
},
|
|
17067
|
+
"extra": {
|
|
17068
|
+
"type": "object",
|
|
17069
|
+
"additionalProperties": {}
|
|
17070
|
+
}
|
|
17071
|
+
},
|
|
17072
|
+
"required": [
|
|
17073
|
+
"code",
|
|
17074
|
+
"message"
|
|
17075
|
+
]
|
|
17076
|
+
}
|
|
17077
|
+
},
|
|
17078
|
+
"required": [
|
|
17079
|
+
"error"
|
|
17080
|
+
]
|
|
17081
|
+
}
|
|
17082
|
+
}
|
|
17083
|
+
}
|
|
17084
|
+
},
|
|
17085
|
+
"401": {
|
|
17086
|
+
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
17087
|
+
"content": {
|
|
17088
|
+
"application/json": {
|
|
17089
|
+
"schema": {
|
|
17090
|
+
"type": "object",
|
|
17091
|
+
"properties": {
|
|
17092
|
+
"error": {
|
|
17093
|
+
"type": "object",
|
|
17094
|
+
"properties": {
|
|
17095
|
+
"code": {
|
|
17096
|
+
"type": "string"
|
|
17097
|
+
},
|
|
17098
|
+
"message": {
|
|
17099
|
+
"type": "string"
|
|
17100
|
+
},
|
|
17101
|
+
"extra": {
|
|
17102
|
+
"type": "object",
|
|
17103
|
+
"additionalProperties": {}
|
|
17104
|
+
}
|
|
17105
|
+
},
|
|
17106
|
+
"required": [
|
|
17107
|
+
"code",
|
|
17108
|
+
"message"
|
|
17109
|
+
]
|
|
17110
|
+
}
|
|
17111
|
+
},
|
|
17112
|
+
"required": [
|
|
17113
|
+
"error"
|
|
17114
|
+
]
|
|
17115
|
+
},
|
|
17116
|
+
"examples": {
|
|
17117
|
+
"authRequired": {
|
|
17118
|
+
"summary": "Missing Authorization header",
|
|
17119
|
+
"value": {
|
|
17120
|
+
"error": {
|
|
17121
|
+
"code": "AUTH_REQUIRED",
|
|
17122
|
+
"message": "missing bearer token"
|
|
17123
|
+
}
|
|
17124
|
+
}
|
|
17125
|
+
}
|
|
17126
|
+
}
|
|
17127
|
+
}
|
|
17128
|
+
}
|
|
17129
|
+
},
|
|
17130
|
+
"404": {
|
|
17131
|
+
"description": "The domain was not found for the caller organization.",
|
|
17132
|
+
"content": {
|
|
17133
|
+
"application/json": {
|
|
17134
|
+
"schema": {
|
|
17135
|
+
"type": "object",
|
|
17136
|
+
"properties": {
|
|
17137
|
+
"error": {
|
|
17138
|
+
"type": "object",
|
|
17139
|
+
"properties": {
|
|
17140
|
+
"code": {
|
|
17141
|
+
"type": "string"
|
|
17142
|
+
},
|
|
17143
|
+
"message": {
|
|
17144
|
+
"type": "string"
|
|
17145
|
+
},
|
|
17146
|
+
"extra": {
|
|
17147
|
+
"type": "object",
|
|
17148
|
+
"additionalProperties": {}
|
|
17149
|
+
}
|
|
17150
|
+
},
|
|
17151
|
+
"required": [
|
|
17152
|
+
"code",
|
|
17153
|
+
"message"
|
|
17154
|
+
]
|
|
17155
|
+
}
|
|
17156
|
+
},
|
|
17157
|
+
"required": [
|
|
17158
|
+
"error"
|
|
17159
|
+
]
|
|
17160
|
+
}
|
|
17161
|
+
}
|
|
17162
|
+
}
|
|
17163
|
+
},
|
|
17164
|
+
"429": {
|
|
17165
|
+
"description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
|
|
17166
|
+
"content": {
|
|
17167
|
+
"application/json": {
|
|
17168
|
+
"schema": {
|
|
17169
|
+
"type": "object",
|
|
17170
|
+
"properties": {
|
|
17171
|
+
"error": {
|
|
17172
|
+
"type": "object",
|
|
17173
|
+
"properties": {
|
|
17174
|
+
"code": {
|
|
17175
|
+
"type": "string"
|
|
17176
|
+
},
|
|
17177
|
+
"message": {
|
|
17178
|
+
"type": "string"
|
|
17179
|
+
},
|
|
17180
|
+
"extra": {
|
|
17181
|
+
"type": "object",
|
|
17182
|
+
"additionalProperties": {}
|
|
17183
|
+
}
|
|
17184
|
+
},
|
|
17185
|
+
"required": [
|
|
17186
|
+
"code",
|
|
17187
|
+
"message"
|
|
17188
|
+
]
|
|
17189
|
+
}
|
|
17190
|
+
},
|
|
17191
|
+
"required": [
|
|
17192
|
+
"error"
|
|
17193
|
+
]
|
|
17194
|
+
},
|
|
17195
|
+
"examples": {
|
|
17196
|
+
"rateLimited": {
|
|
17197
|
+
"summary": "Per-key rate limit hit",
|
|
17198
|
+
"value": {
|
|
17199
|
+
"error": {
|
|
17200
|
+
"code": "RATE_LIMITED",
|
|
17201
|
+
"message": "rate limit exceeded",
|
|
17202
|
+
"extra": {
|
|
17203
|
+
"retry_after_seconds": 60,
|
|
17204
|
+
"limit_kind": "authenticated_per_key"
|
|
17205
|
+
}
|
|
17206
|
+
}
|
|
17207
|
+
}
|
|
17208
|
+
}
|
|
17209
|
+
}
|
|
17210
|
+
}
|
|
17211
|
+
}
|
|
17212
|
+
},
|
|
17213
|
+
"500": {
|
|
17214
|
+
"description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
|
|
17215
|
+
"content": {
|
|
17216
|
+
"application/json": {
|
|
17217
|
+
"schema": {
|
|
17218
|
+
"type": "object",
|
|
17219
|
+
"properties": {
|
|
17220
|
+
"error": {
|
|
17221
|
+
"type": "object",
|
|
17222
|
+
"properties": {
|
|
17223
|
+
"code": {
|
|
17224
|
+
"type": "string"
|
|
17225
|
+
},
|
|
17226
|
+
"message": {
|
|
17227
|
+
"type": "string"
|
|
17228
|
+
},
|
|
17229
|
+
"extra": {
|
|
17230
|
+
"type": "object",
|
|
17231
|
+
"additionalProperties": {}
|
|
17232
|
+
}
|
|
17233
|
+
},
|
|
17234
|
+
"required": [
|
|
17235
|
+
"code",
|
|
17236
|
+
"message"
|
|
17237
|
+
]
|
|
17238
|
+
}
|
|
17239
|
+
},
|
|
17240
|
+
"required": [
|
|
17241
|
+
"error"
|
|
17242
|
+
]
|
|
17243
|
+
},
|
|
17244
|
+
"examples": {
|
|
17245
|
+
"internalError": {
|
|
17246
|
+
"summary": "Unhandled exception",
|
|
17247
|
+
"value": {
|
|
17248
|
+
"error": {
|
|
17249
|
+
"code": "INTERNAL_ERROR",
|
|
17250
|
+
"message": "internal error"
|
|
17251
|
+
}
|
|
17252
|
+
}
|
|
17253
|
+
}
|
|
17254
|
+
}
|
|
17255
|
+
}
|
|
17256
|
+
}
|
|
17257
|
+
}
|
|
17258
|
+
}
|
|
17259
|
+
}
|
|
17260
|
+
},
|
|
17261
|
+
"/email/messages/{id}": {
|
|
17262
|
+
"get": {
|
|
17263
|
+
"operationId": "email_get",
|
|
17264
|
+
"tags": [
|
|
17265
|
+
"Emails"
|
|
17266
|
+
],
|
|
17267
|
+
"summary": "Get an inbound email by id",
|
|
17268
|
+
"description": "### Overview\nFetches the metadata and plain-text body of a single inbound email by its unique ID. It also returns metadata for all associated attachments and optionally resolves the rendered HTML content.\n\n### When to Use\n- Use this endpoint to display the complete detail view of an email message.\n- Use it to extract attachment files or read complex HTML layouts.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **R2 HTML Read**: The HTML body is stored in Object Storage (R2). To fetch it, explicitly pass `include_html=true` (this incurs an extra R2 read charge; leave unset if only plain text is needed).\n- Returns a 404 error if the email has been soft-deleted, unless `include_deleted=true` is set.\n\n### Troubleshooting\n- **401 Unauthorized**: Missing or expired token.\n- **404 Not Found**: The specified email ID does not exist, belongs to another user, or has been soft-deleted (without `include_deleted=true`).",
|
|
17269
|
+
"security": [
|
|
17270
|
+
{
|
|
17271
|
+
"bearerAuth": []
|
|
17272
|
+
}
|
|
17273
|
+
],
|
|
17274
|
+
"x-cli": {
|
|
17275
|
+
"command": "email show",
|
|
17276
|
+
"positional": [
|
|
17277
|
+
"id"
|
|
17278
|
+
],
|
|
17279
|
+
"display": {
|
|
17280
|
+
"shape": "object",
|
|
17281
|
+
"format": {
|
|
17282
|
+
"id": "id-short",
|
|
17283
|
+
"org_id": "id-short",
|
|
17284
|
+
"user_id": "id-short",
|
|
17285
|
+
"received_at": "relative-time",
|
|
17286
|
+
"created_at": "relative-time",
|
|
17287
|
+
"read_at": "relative-time",
|
|
17288
|
+
"deleted_at": "relative-time",
|
|
17289
|
+
"is_read": "bool-badge"
|
|
17290
|
+
},
|
|
17291
|
+
"dataPath": "email"
|
|
17292
|
+
}
|
|
17293
|
+
},
|
|
17294
|
+
"x-codeSamples": [
|
|
17295
|
+
{
|
|
17296
|
+
"lang": "shell",
|
|
17297
|
+
"label": "curl",
|
|
17298
|
+
"source": "curl https://api.wspc.ai/email/messages/eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
|
|
16079
17299
|
},
|
|
16080
17300
|
{
|
|
16081
17301
|
"lang": "bash",
|
|
@@ -17631,12 +18851,256 @@
|
|
|
17631
18851
|
]
|
|
17632
18852
|
},
|
|
17633
18853
|
"examples": {
|
|
17634
|
-
"authRequired": {
|
|
17635
|
-
"summary": "Missing Authorization header",
|
|
18854
|
+
"authRequired": {
|
|
18855
|
+
"summary": "Missing Authorization header",
|
|
18856
|
+
"value": {
|
|
18857
|
+
"error": {
|
|
18858
|
+
"code": "AUTH_REQUIRED",
|
|
18859
|
+
"message": "missing bearer token"
|
|
18860
|
+
}
|
|
18861
|
+
}
|
|
18862
|
+
}
|
|
18863
|
+
}
|
|
18864
|
+
}
|
|
18865
|
+
}
|
|
18866
|
+
},
|
|
18867
|
+
"404": {
|
|
18868
|
+
"description": "No alias with this email address is owned by the caller.",
|
|
18869
|
+
"content": {
|
|
18870
|
+
"application/json": {
|
|
18871
|
+
"schema": {
|
|
18872
|
+
"type": "object",
|
|
18873
|
+
"properties": {
|
|
18874
|
+
"error": {
|
|
18875
|
+
"type": "object",
|
|
18876
|
+
"properties": {
|
|
18877
|
+
"code": {
|
|
18878
|
+
"type": "string"
|
|
18879
|
+
},
|
|
18880
|
+
"message": {
|
|
18881
|
+
"type": "string"
|
|
18882
|
+
},
|
|
18883
|
+
"extra": {
|
|
18884
|
+
"type": "object",
|
|
18885
|
+
"additionalProperties": {}
|
|
18886
|
+
}
|
|
18887
|
+
},
|
|
18888
|
+
"required": [
|
|
18889
|
+
"code",
|
|
18890
|
+
"message"
|
|
18891
|
+
]
|
|
18892
|
+
}
|
|
18893
|
+
},
|
|
18894
|
+
"required": [
|
|
18895
|
+
"error"
|
|
18896
|
+
]
|
|
18897
|
+
}
|
|
18898
|
+
}
|
|
18899
|
+
}
|
|
18900
|
+
},
|
|
18901
|
+
"429": {
|
|
18902
|
+
"description": "Either restoring would exceed the per-user active-alias limit (`ALIAS_LIMIT_EXCEEDED`) or the write rate limit was hit (`RATE_LIMITED`).",
|
|
18903
|
+
"content": {
|
|
18904
|
+
"application/json": {
|
|
18905
|
+
"schema": {
|
|
18906
|
+
"type": "object",
|
|
18907
|
+
"properties": {
|
|
18908
|
+
"error": {
|
|
18909
|
+
"type": "object",
|
|
18910
|
+
"properties": {
|
|
18911
|
+
"code": {
|
|
18912
|
+
"type": "string"
|
|
18913
|
+
},
|
|
18914
|
+
"message": {
|
|
18915
|
+
"type": "string"
|
|
18916
|
+
},
|
|
18917
|
+
"extra": {
|
|
18918
|
+
"type": "object",
|
|
18919
|
+
"additionalProperties": {}
|
|
18920
|
+
}
|
|
18921
|
+
},
|
|
18922
|
+
"required": [
|
|
18923
|
+
"code",
|
|
18924
|
+
"message"
|
|
18925
|
+
]
|
|
18926
|
+
}
|
|
18927
|
+
},
|
|
18928
|
+
"required": [
|
|
18929
|
+
"error"
|
|
18930
|
+
]
|
|
18931
|
+
}
|
|
18932
|
+
}
|
|
18933
|
+
}
|
|
18934
|
+
},
|
|
18935
|
+
"500": {
|
|
18936
|
+
"description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
|
|
18937
|
+
"content": {
|
|
18938
|
+
"application/json": {
|
|
18939
|
+
"schema": {
|
|
18940
|
+
"type": "object",
|
|
18941
|
+
"properties": {
|
|
18942
|
+
"error": {
|
|
18943
|
+
"type": "object",
|
|
18944
|
+
"properties": {
|
|
18945
|
+
"code": {
|
|
18946
|
+
"type": "string"
|
|
18947
|
+
},
|
|
18948
|
+
"message": {
|
|
18949
|
+
"type": "string"
|
|
18950
|
+
},
|
|
18951
|
+
"extra": {
|
|
18952
|
+
"type": "object",
|
|
18953
|
+
"additionalProperties": {}
|
|
18954
|
+
}
|
|
18955
|
+
},
|
|
18956
|
+
"required": [
|
|
18957
|
+
"code",
|
|
18958
|
+
"message"
|
|
18959
|
+
]
|
|
18960
|
+
}
|
|
18961
|
+
},
|
|
18962
|
+
"required": [
|
|
18963
|
+
"error"
|
|
18964
|
+
]
|
|
18965
|
+
},
|
|
18966
|
+
"examples": {
|
|
18967
|
+
"internalError": {
|
|
18968
|
+
"summary": "Unhandled exception",
|
|
18969
|
+
"value": {
|
|
18970
|
+
"error": {
|
|
18971
|
+
"code": "INTERNAL_ERROR",
|
|
18972
|
+
"message": "internal error"
|
|
18973
|
+
}
|
|
18974
|
+
}
|
|
18975
|
+
}
|
|
18976
|
+
}
|
|
18977
|
+
}
|
|
18978
|
+
}
|
|
18979
|
+
}
|
|
18980
|
+
}
|
|
18981
|
+
}
|
|
18982
|
+
},
|
|
18983
|
+
"/email/messages/restore": {
|
|
18984
|
+
"post": {
|
|
18985
|
+
"operationId": "email_restore",
|
|
18986
|
+
"tags": [
|
|
18987
|
+
"Emails"
|
|
18988
|
+
],
|
|
18989
|
+
"summary": "Restore soft-deleted inbound emails",
|
|
18990
|
+
"description": "### Overview\nRestores a batch of soft-deleted inbound emails from the trash, making them reappear in standard inbox lists.\n\n### When to Use\n- Use this endpoint to recover email messages that were trashed by mistake.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- Accepts 1 to 100 email IDs. Already-active IDs are silently ignored.\n\n### Troubleshooting\n- **401 Unauthorized**: Invalid token.\n- **400 Bad Request**: Malformed request or batch limit exceeded.",
|
|
18991
|
+
"security": [
|
|
18992
|
+
{
|
|
18993
|
+
"bearerAuth": []
|
|
18994
|
+
}
|
|
18995
|
+
],
|
|
18996
|
+
"x-cli": {
|
|
18997
|
+
"command": "_internal",
|
|
18998
|
+
"hidden": true
|
|
18999
|
+
},
|
|
19000
|
+
"x-codeSamples": [
|
|
19001
|
+
{
|
|
19002
|
+
"lang": "shell",
|
|
19003
|
+
"label": "curl",
|
|
19004
|
+
"source": "curl -X POST https://api.wspc.ai/email/messages/restore \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"ids\":[\"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F\"]}'"
|
|
19005
|
+
}
|
|
19006
|
+
],
|
|
19007
|
+
"requestBody": {
|
|
19008
|
+
"required": true,
|
|
19009
|
+
"content": {
|
|
19010
|
+
"application/json": {
|
|
19011
|
+
"schema": {
|
|
19012
|
+
"$ref": "#/components/schemas/BatchIdsBody"
|
|
19013
|
+
},
|
|
19014
|
+
"examples": {
|
|
19015
|
+
"minimal": {
|
|
19016
|
+
"summary": "Single id",
|
|
19017
|
+
"value": {
|
|
19018
|
+
"ids": [
|
|
19019
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F"
|
|
19020
|
+
]
|
|
19021
|
+
}
|
|
19022
|
+
},
|
|
19023
|
+
"full": {
|
|
19024
|
+
"summary": "Multiple ids (up to 100 per call)",
|
|
19025
|
+
"value": {
|
|
19026
|
+
"ids": [
|
|
19027
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19028
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3G",
|
|
19029
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3H"
|
|
19030
|
+
]
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19033
|
+
}
|
|
19034
|
+
}
|
|
19035
|
+
}
|
|
19036
|
+
},
|
|
19037
|
+
"responses": {
|
|
19038
|
+
"200": {
|
|
19039
|
+
"description": "Bulk restore result. `restored` counts state changes only.",
|
|
19040
|
+
"content": {
|
|
19041
|
+
"application/json": {
|
|
19042
|
+
"schema": {
|
|
19043
|
+
"$ref": "#/components/schemas/RestoreBatchResponse"
|
|
19044
|
+
},
|
|
19045
|
+
"examples": {
|
|
19046
|
+
"happyPath": {
|
|
19047
|
+
"summary": "All ids matched and changed state",
|
|
19048
|
+
"value": {
|
|
19049
|
+
"restored": 2,
|
|
19050
|
+
"not_found": []
|
|
19051
|
+
}
|
|
19052
|
+
},
|
|
19053
|
+
"partial": {
|
|
19054
|
+
"summary": "Some ids unknown to this user",
|
|
19055
|
+
"value": {
|
|
19056
|
+
"restored": 1,
|
|
19057
|
+
"not_found": [
|
|
19058
|
+
"eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3X"
|
|
19059
|
+
]
|
|
19060
|
+
}
|
|
19061
|
+
}
|
|
19062
|
+
}
|
|
19063
|
+
}
|
|
19064
|
+
}
|
|
19065
|
+
},
|
|
19066
|
+
"400": {
|
|
19067
|
+
"description": "Request validation failed. The body, query, or path parameters did not match the operation's schema.",
|
|
19068
|
+
"content": {
|
|
19069
|
+
"application/json": {
|
|
19070
|
+
"schema": {
|
|
19071
|
+
"type": "object",
|
|
19072
|
+
"properties": {
|
|
19073
|
+
"error": {
|
|
19074
|
+
"type": "object",
|
|
19075
|
+
"properties": {
|
|
19076
|
+
"code": {
|
|
19077
|
+
"type": "string"
|
|
19078
|
+
},
|
|
19079
|
+
"message": {
|
|
19080
|
+
"type": "string"
|
|
19081
|
+
},
|
|
19082
|
+
"extra": {
|
|
19083
|
+
"type": "object",
|
|
19084
|
+
"additionalProperties": {}
|
|
19085
|
+
}
|
|
19086
|
+
},
|
|
19087
|
+
"required": [
|
|
19088
|
+
"code",
|
|
19089
|
+
"message"
|
|
19090
|
+
]
|
|
19091
|
+
}
|
|
19092
|
+
},
|
|
19093
|
+
"required": [
|
|
19094
|
+
"error"
|
|
19095
|
+
]
|
|
19096
|
+
},
|
|
19097
|
+
"examples": {
|
|
19098
|
+
"validationError": {
|
|
19099
|
+
"summary": "Body failed schema validation",
|
|
17636
19100
|
"value": {
|
|
17637
19101
|
"error": {
|
|
17638
|
-
"code": "
|
|
17639
|
-
"message": "
|
|
19102
|
+
"code": "VALIDATION_ERROR",
|
|
19103
|
+
"message": "title must not be empty"
|
|
17640
19104
|
}
|
|
17641
19105
|
}
|
|
17642
19106
|
}
|
|
@@ -17644,8 +19108,8 @@
|
|
|
17644
19108
|
}
|
|
17645
19109
|
}
|
|
17646
19110
|
},
|
|
17647
|
-
"
|
|
17648
|
-
"description": "
|
|
19111
|
+
"401": {
|
|
19112
|
+
"description": "Authentication is required but missing or invalid. The Bearer token (API key or OAuth access token) was absent, malformed, or rejected.",
|
|
17649
19113
|
"content": {
|
|
17650
19114
|
"application/json": {
|
|
17651
19115
|
"schema": {
|
|
@@ -17674,12 +19138,23 @@
|
|
|
17674
19138
|
"required": [
|
|
17675
19139
|
"error"
|
|
17676
19140
|
]
|
|
19141
|
+
},
|
|
19142
|
+
"examples": {
|
|
19143
|
+
"authRequired": {
|
|
19144
|
+
"summary": "Missing Authorization header",
|
|
19145
|
+
"value": {
|
|
19146
|
+
"error": {
|
|
19147
|
+
"code": "AUTH_REQUIRED",
|
|
19148
|
+
"message": "missing bearer token"
|
|
19149
|
+
}
|
|
19150
|
+
}
|
|
19151
|
+
}
|
|
17677
19152
|
}
|
|
17678
19153
|
}
|
|
17679
19154
|
}
|
|
17680
19155
|
},
|
|
17681
19156
|
"429": {
|
|
17682
|
-
"description": "
|
|
19157
|
+
"description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
|
|
17683
19158
|
"content": {
|
|
17684
19159
|
"application/json": {
|
|
17685
19160
|
"schema": {
|
|
@@ -17708,6 +19183,21 @@
|
|
|
17708
19183
|
"required": [
|
|
17709
19184
|
"error"
|
|
17710
19185
|
]
|
|
19186
|
+
},
|
|
19187
|
+
"examples": {
|
|
19188
|
+
"rateLimited": {
|
|
19189
|
+
"summary": "Per-key rate limit hit",
|
|
19190
|
+
"value": {
|
|
19191
|
+
"error": {
|
|
19192
|
+
"code": "RATE_LIMITED",
|
|
19193
|
+
"message": "rate limit exceeded",
|
|
19194
|
+
"extra": {
|
|
19195
|
+
"retry_after_seconds": 60,
|
|
19196
|
+
"limit_kind": "authenticated_per_key"
|
|
19197
|
+
}
|
|
19198
|
+
}
|
|
19199
|
+
}
|
|
19200
|
+
}
|
|
17711
19201
|
}
|
|
17712
19202
|
}
|
|
17713
19203
|
}
|
|
@@ -17760,28 +19250,33 @@
|
|
|
17760
19250
|
}
|
|
17761
19251
|
}
|
|
17762
19252
|
},
|
|
17763
|
-
"/email/messages/
|
|
19253
|
+
"/email/messages/send": {
|
|
17764
19254
|
"post": {
|
|
17765
|
-
"operationId": "
|
|
19255
|
+
"operationId": "email_send",
|
|
17766
19256
|
"tags": [
|
|
17767
19257
|
"Emails"
|
|
17768
19258
|
],
|
|
17769
|
-
"summary": "
|
|
17770
|
-
"description": "### Overview\
|
|
19259
|
+
"summary": "Send an outbound email",
|
|
19260
|
+
"description": "### Overview\nSubmits a single outbound email for delivery from one of the caller's active aliases. All details, including attachments (inline base64 blobs or references to existing inbound attachments), are verified before sending. Platform-domain aliases use Cloudflare Email Service; verified custom-domain aliases use pete-mail.\n\n### When to Use\n- Use this endpoint to send new standalone emails or to reply to threaded inbound messages.\n- Use this in automated agent pipelines (like calendar invite generation or notifications) and CLI email send utilities.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- **Size Limits**: Individual attachments must not exceed 5 MiB, and the total size of all attachments per send must be 25 MiB or less.\n- **Security**: Up to 10 attachments are allowed. Outbound files with dangerous executable extensions (such as `.exe`, `.bat`, `.com`, `.scr`, `.cmd`, `.jar`, `.js`) are strictly blocked.\n- **Daily Quotas**: Sending is protected by per-user (100 sends/day) and per-alias (50 sends/day) daily quotas. Exceeding them triggers `RATE_LIMITED` or `QUOTA_EXCEEDED` errors.\n- **Custom Domains**: Platform-domain aliases use Cloudflare Email Service. Verified custom-domain aliases are routed through pete-mail. Custom domains must have `status = verified` and `sending_status = verified` or the send returns `CUSTOM_DOMAIN_NOT_READY`.\n- **Idempotency**: A stable `idempotency_key` (1-200 characters) must be supplied. Retrying a send with identical content and the same key returns `idempotent_replay: true` without sending duplicates. Reusing the key with changed content returns 409 `IDEMPOTENCY_KEY_REUSED`.\n\n### Troubleshooting\n- **401 Unauthorized**: Active Bearer token is invalid or has expired.\n- **404 Not Found**: The requested `from_alias_email` does not exist or has been soft-deleted, or the referenced `in_reply_to_email_id` is missing or belongs to a different user.\n- **409 Conflict / IDEMPOTENCY_KEY_REUSED**: An identical `idempotency_key` was reused with modified request payload. Use a fresh unique key.\n- **409 Conflict / CUSTOM_DOMAIN_NOT_READY**: The sender uses a custom domain that has not completed outbound sending verification.\n- **429 Too Many Requests / RATE_LIMITED**: The per-user rate limit or daily sending quota has been exceeded. Wait for quota reset.\n- **502 Bad Gateway**: The upstream outbound provider failed or rejected the message. The outbound row is persisted with `status: failed` along with provider-returned logs.",
|
|
17771
19261
|
"security": [
|
|
17772
19262
|
{
|
|
17773
19263
|
"bearerAuth": []
|
|
17774
19264
|
}
|
|
17775
19265
|
],
|
|
17776
19266
|
"x-cli": {
|
|
17777
|
-
"command": "
|
|
19267
|
+
"command": "_handwritten",
|
|
17778
19268
|
"hidden": true
|
|
17779
19269
|
},
|
|
17780
19270
|
"x-codeSamples": [
|
|
17781
19271
|
{
|
|
17782
19272
|
"lang": "shell",
|
|
17783
19273
|
"label": "curl",
|
|
17784
|
-
"source": "curl -X POST https://api.wspc.ai/email/messages/
|
|
19274
|
+
"source": "curl -X POST https://api.wspc.ai/email/messages/send \\\n -H \"Authorization: Bearer $WSPC_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"from_alias_email\":\"alice-shop@wspc.app\",\"to\":[\"alice@example.com\"],\"subject\":\"Welcome\",\"text\":\"Hi Alice\",\"idempotency_key\":\"retry-20260601-001\"}'"
|
|
19275
|
+
},
|
|
19276
|
+
{
|
|
19277
|
+
"lang": "bash",
|
|
19278
|
+
"label": "wspc CLI",
|
|
19279
|
+
"source": "wspc email send \\\n --from alice-shop@wspc.app \\\n --to alice@example.com \\\n --subject \"Welcome to WSPC\" \\\n --text \"Hi Alice — welcome aboard.\" \\\n --attach ./report.pdf \\\n --idempotency-key retry-20260601-001"
|
|
17785
19280
|
}
|
|
17786
19281
|
],
|
|
17787
19282
|
"requestBody": {
|
|
@@ -17789,25 +19284,41 @@
|
|
|
17789
19284
|
"content": {
|
|
17790
19285
|
"application/json": {
|
|
17791
19286
|
"schema": {
|
|
17792
|
-
"$ref": "#/components/schemas/
|
|
19287
|
+
"$ref": "#/components/schemas/SendEmailBody"
|
|
17793
19288
|
},
|
|
17794
19289
|
"examples": {
|
|
17795
19290
|
"minimal": {
|
|
17796
|
-
"summary": "
|
|
19291
|
+
"summary": "Fresh send — required fields only",
|
|
17797
19292
|
"value": {
|
|
17798
|
-
"
|
|
17799
|
-
|
|
17800
|
-
|
|
19293
|
+
"from_alias_email": "alice-shop@wspc.app",
|
|
19294
|
+
"to": [
|
|
19295
|
+
"alice@example.com"
|
|
19296
|
+
],
|
|
19297
|
+
"subject": "Welcome to WSPC",
|
|
19298
|
+
"text": "Hi Alice — welcome aboard.",
|
|
19299
|
+
"idempotency_key": "retry-20260601-001"
|
|
19300
|
+
}
|
|
19301
|
+
},
|
|
19302
|
+
"reply": {
|
|
19303
|
+
"summary": "Threaded reply — to/subject derived from the inbound message",
|
|
19304
|
+
"value": {
|
|
19305
|
+
"from_alias_email": "alice-shop@wspc.app",
|
|
19306
|
+
"in_reply_to_email_id": "eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19307
|
+
"text": "Thanks — replying inline.",
|
|
19308
|
+
"idempotency_key": "reply-20260601-001"
|
|
17801
19309
|
}
|
|
17802
19310
|
},
|
|
17803
19311
|
"full": {
|
|
17804
|
-
"summary": "
|
|
19312
|
+
"summary": "Multi-recipient with explicit subject",
|
|
17805
19313
|
"value": {
|
|
17806
|
-
"
|
|
17807
|
-
|
|
17808
|
-
"
|
|
17809
|
-
"
|
|
17810
|
-
]
|
|
19314
|
+
"from_alias_email": "alice-shop@wspc.app",
|
|
19315
|
+
"to": [
|
|
19316
|
+
"alice@example.com",
|
|
19317
|
+
"bob@example.com"
|
|
19318
|
+
],
|
|
19319
|
+
"subject": "Lunch with Alice",
|
|
19320
|
+
"text": "Confirming lunch — see you at the lobby at 12:30.",
|
|
19321
|
+
"idempotency_key": "lunch-confirm-20260601"
|
|
17811
19322
|
}
|
|
17812
19323
|
}
|
|
17813
19324
|
}
|
|
@@ -17816,27 +19327,63 @@
|
|
|
17816
19327
|
},
|
|
17817
19328
|
"responses": {
|
|
17818
19329
|
"200": {
|
|
17819
|
-
"description": "
|
|
19330
|
+
"description": "The send was accepted. Response `email.id` uses `out_<ULID>` for new outbound rows; legacy UUID ids remain accepted. Inspect `idempotent_replay`: `false` means the provider was invoked on this request, `true` means an earlier identical send was replayed.",
|
|
17820
19331
|
"content": {
|
|
17821
19332
|
"application/json": {
|
|
17822
19333
|
"schema": {
|
|
17823
|
-
"$ref": "#/components/schemas/
|
|
19334
|
+
"$ref": "#/components/schemas/SendEmailResponse"
|
|
17824
19335
|
},
|
|
17825
19336
|
"examples": {
|
|
17826
19337
|
"happyPath": {
|
|
17827
|
-
"summary": "
|
|
19338
|
+
"summary": "Fresh send succeeded",
|
|
17828
19339
|
"value": {
|
|
17829
|
-
"
|
|
17830
|
-
|
|
19340
|
+
"email": {
|
|
19341
|
+
"id": "out_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19342
|
+
"org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19343
|
+
"user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19344
|
+
"from_alias_email": "alice-shop@wspc.app",
|
|
19345
|
+
"from_addr": "alice-shop@wspc.app",
|
|
19346
|
+
"to": [
|
|
19347
|
+
"alice@example.com"
|
|
19348
|
+
],
|
|
19349
|
+
"subject": "Welcome to WSPC",
|
|
19350
|
+
"text_body": "Hi Alice — welcome aboard.",
|
|
19351
|
+
"message_id": "<01HW3K4N9V5G6Z8C2Q7B1Y0M3G@wspc.app>",
|
|
19352
|
+
"provider": "cloudflare-email-service",
|
|
19353
|
+
"request_hash": "sha256:abc...",
|
|
19354
|
+
"status": "sent",
|
|
19355
|
+
"idempotency_key": "retry-20260601-001",
|
|
19356
|
+
"submitted_at": 1748736000500,
|
|
19357
|
+
"created_at": 1748736000000,
|
|
19358
|
+
"updated_at": 1748736000500
|
|
19359
|
+
},
|
|
19360
|
+
"idempotent_replay": false
|
|
17831
19361
|
}
|
|
17832
19362
|
},
|
|
17833
|
-
"
|
|
17834
|
-
"summary": "
|
|
19363
|
+
"replay": {
|
|
19364
|
+
"summary": "Idempotent replay — provider not re-invoked",
|
|
17835
19365
|
"value": {
|
|
17836
|
-
"
|
|
17837
|
-
|
|
17838
|
-
"
|
|
17839
|
-
|
|
19366
|
+
"email": {
|
|
19367
|
+
"id": "out_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19368
|
+
"org_id": "org_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19369
|
+
"user_id": "usr_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
19370
|
+
"from_alias_email": "alice-shop@wspc.app",
|
|
19371
|
+
"from_addr": "alice-shop@wspc.app",
|
|
19372
|
+
"to": [
|
|
19373
|
+
"alice@example.com"
|
|
19374
|
+
],
|
|
19375
|
+
"subject": "Welcome to WSPC",
|
|
19376
|
+
"text_body": "Hi Alice — welcome aboard.",
|
|
19377
|
+
"message_id": "<01HW3K4N9V5G6Z8C2Q7B1Y0M3G@wspc.app>",
|
|
19378
|
+
"provider": "cloudflare-email-service",
|
|
19379
|
+
"request_hash": "sha256:abc...",
|
|
19380
|
+
"status": "sent",
|
|
19381
|
+
"idempotency_key": "retry-20260601-001",
|
|
19382
|
+
"submitted_at": 1748736000500,
|
|
19383
|
+
"created_at": 1748736000000,
|
|
19384
|
+
"updated_at": 1748736000500
|
|
19385
|
+
},
|
|
19386
|
+
"idempotent_replay": true
|
|
17840
19387
|
}
|
|
17841
19388
|
}
|
|
17842
19389
|
}
|
|
@@ -17933,8 +19480,110 @@
|
|
|
17933
19480
|
}
|
|
17934
19481
|
}
|
|
17935
19482
|
},
|
|
19483
|
+
"404": {
|
|
19484
|
+
"description": "`from_alias_email` is unknown / soft-deleted, or `in_reply_to_email_id` is not visible to the caller.",
|
|
19485
|
+
"content": {
|
|
19486
|
+
"application/json": {
|
|
19487
|
+
"schema": {
|
|
19488
|
+
"type": "object",
|
|
19489
|
+
"properties": {
|
|
19490
|
+
"error": {
|
|
19491
|
+
"type": "object",
|
|
19492
|
+
"properties": {
|
|
19493
|
+
"code": {
|
|
19494
|
+
"type": "string"
|
|
19495
|
+
},
|
|
19496
|
+
"message": {
|
|
19497
|
+
"type": "string"
|
|
19498
|
+
},
|
|
19499
|
+
"extra": {
|
|
19500
|
+
"type": "object",
|
|
19501
|
+
"additionalProperties": {}
|
|
19502
|
+
}
|
|
19503
|
+
},
|
|
19504
|
+
"required": [
|
|
19505
|
+
"code",
|
|
19506
|
+
"message"
|
|
19507
|
+
]
|
|
19508
|
+
}
|
|
19509
|
+
},
|
|
19510
|
+
"required": [
|
|
19511
|
+
"error"
|
|
19512
|
+
]
|
|
19513
|
+
}
|
|
19514
|
+
}
|
|
19515
|
+
}
|
|
19516
|
+
},
|
|
19517
|
+
"409": {
|
|
19518
|
+
"description": "Either an earlier send under this `idempotency_key` had different content, or the sender custom domain has not completed outbound sending verification.",
|
|
19519
|
+
"content": {
|
|
19520
|
+
"application/json": {
|
|
19521
|
+
"schema": {
|
|
19522
|
+
"type": "object",
|
|
19523
|
+
"properties": {
|
|
19524
|
+
"error": {
|
|
19525
|
+
"type": "object",
|
|
19526
|
+
"properties": {
|
|
19527
|
+
"code": {
|
|
19528
|
+
"type": "string"
|
|
19529
|
+
},
|
|
19530
|
+
"message": {
|
|
19531
|
+
"type": "string"
|
|
19532
|
+
},
|
|
19533
|
+
"extra": {
|
|
19534
|
+
"type": "object",
|
|
19535
|
+
"additionalProperties": {}
|
|
19536
|
+
}
|
|
19537
|
+
},
|
|
19538
|
+
"required": [
|
|
19539
|
+
"code",
|
|
19540
|
+
"message"
|
|
19541
|
+
]
|
|
19542
|
+
}
|
|
19543
|
+
},
|
|
19544
|
+
"required": [
|
|
19545
|
+
"error"
|
|
19546
|
+
]
|
|
19547
|
+
}
|
|
19548
|
+
}
|
|
19549
|
+
}
|
|
19550
|
+
},
|
|
17936
19551
|
"429": {
|
|
17937
|
-
"description": "
|
|
19552
|
+
"description": "Either the middleware send rate limit (`RATE_LIMITED`), the per-user daily cap of 100 sends (`RATE_LIMITED`), or the per-alias daily cap of 50 sends (`QUOTA_EXCEEDED`).",
|
|
19553
|
+
"content": {
|
|
19554
|
+
"application/json": {
|
|
19555
|
+
"schema": {
|
|
19556
|
+
"type": "object",
|
|
19557
|
+
"properties": {
|
|
19558
|
+
"error": {
|
|
19559
|
+
"type": "object",
|
|
19560
|
+
"properties": {
|
|
19561
|
+
"code": {
|
|
19562
|
+
"type": "string"
|
|
19563
|
+
},
|
|
19564
|
+
"message": {
|
|
19565
|
+
"type": "string"
|
|
19566
|
+
},
|
|
19567
|
+
"extra": {
|
|
19568
|
+
"type": "object",
|
|
19569
|
+
"additionalProperties": {}
|
|
19570
|
+
}
|
|
19571
|
+
},
|
|
19572
|
+
"required": [
|
|
19573
|
+
"code",
|
|
19574
|
+
"message"
|
|
19575
|
+
]
|
|
19576
|
+
}
|
|
19577
|
+
},
|
|
19578
|
+
"required": [
|
|
19579
|
+
"error"
|
|
19580
|
+
]
|
|
19581
|
+
}
|
|
19582
|
+
}
|
|
19583
|
+
}
|
|
19584
|
+
},
|
|
19585
|
+
"500": {
|
|
19586
|
+
"description": "Unhandled server error. The request was well-formed but the service failed unexpectedly. Safe to retry idempotent operations.",
|
|
17938
19587
|
"content": {
|
|
17939
19588
|
"application/json": {
|
|
17940
19589
|
"schema": {
|
|
@@ -17965,16 +19614,12 @@
|
|
|
17965
19614
|
]
|
|
17966
19615
|
},
|
|
17967
19616
|
"examples": {
|
|
17968
|
-
"
|
|
17969
|
-
"summary": "
|
|
19617
|
+
"internalError": {
|
|
19618
|
+
"summary": "Unhandled exception",
|
|
17970
19619
|
"value": {
|
|
17971
19620
|
"error": {
|
|
17972
|
-
"code": "
|
|
17973
|
-
"message": "
|
|
17974
|
-
"extra": {
|
|
17975
|
-
"retry_after_seconds": 60,
|
|
17976
|
-
"limit_kind": "authenticated_per_key"
|
|
17977
|
-
}
|
|
19621
|
+
"code": "INTERNAL_ERROR",
|
|
19622
|
+
"message": "internal error"
|
|
17978
19623
|
}
|
|
17979
19624
|
}
|
|
17980
19625
|
}
|
|
@@ -17982,8 +19627,8 @@
|
|
|
17982
19627
|
}
|
|
17983
19628
|
}
|
|
17984
19629
|
},
|
|
17985
|
-
"
|
|
17986
|
-
"description": "
|
|
19630
|
+
"502": {
|
|
19631
|
+
"description": "The upstream email provider rejected the message. The row is persisted with `status: failed` and `error_code` / `error_message` set.",
|
|
17987
19632
|
"content": {
|
|
17988
19633
|
"application/json": {
|
|
17989
19634
|
"schema": {
|
|
@@ -18012,17 +19657,6 @@
|
|
|
18012
19657
|
"required": [
|
|
18013
19658
|
"error"
|
|
18014
19659
|
]
|
|
18015
|
-
},
|
|
18016
|
-
"examples": {
|
|
18017
|
-
"internalError": {
|
|
18018
|
-
"summary": "Unhandled exception",
|
|
18019
|
-
"value": {
|
|
18020
|
-
"error": {
|
|
18021
|
-
"code": "INTERNAL_ERROR",
|
|
18022
|
-
"message": "internal error"
|
|
18023
|
-
}
|
|
18024
|
-
}
|
|
18025
|
-
}
|
|
18026
19660
|
}
|
|
18027
19661
|
}
|
|
18028
19662
|
}
|
|
@@ -18030,140 +19664,128 @@
|
|
|
18030
19664
|
}
|
|
18031
19665
|
}
|
|
18032
19666
|
},
|
|
18033
|
-
"/email/
|
|
19667
|
+
"/email/domains/{domain}/verify": {
|
|
18034
19668
|
"post": {
|
|
18035
|
-
"operationId": "
|
|
19669
|
+
"operationId": "email_domain_verify",
|
|
18036
19670
|
"tags": [
|
|
18037
|
-
"
|
|
19671
|
+
"EmailDomains"
|
|
18038
19672
|
],
|
|
18039
|
-
"summary": "
|
|
18040
|
-
"description": "### Overview\
|
|
19673
|
+
"summary": "Verify a custom domain with the provider",
|
|
19674
|
+
"description": "### Overview\nTriggers an upstream provider verification attempt for one custom email domain, refreshes the cached DNS records/status in D1, and returns the updated row.\nThis route refreshes DNS registration and verification state. Custom-domain aliases require `status`, `sending_status`, and `receiving_status` to all be `verified`.\n\n### When to Use\n- Use this after publishing the required DNS records, or whenever you want to refresh cached provider state explicitly.\n- If the provider verify call returns incomplete DNS records, the worker performs a follow-up provider read before responding.\n\n### Constraints\n- Requires a valid Bearer token in the `Authorization` header.\n- This route requires custom domain provider credentials in production because it performs live provider calls.\n- Verification is asynchronous provider work; a successful response may still report `status: pending`.\n- `status: verified` plus `sending_status: verified` enables custom-domain outbound send for active aliases; `receiving_status: verified` is also required before new custom-domain aliases can be created.\n\n### Troubleshooting\n- **400 Bad Request / DOMAIN_INVALID / DOMAIN_RESERVED**: The path hostname is malformed or reserved.\n- **404 Not Found / DOMAIN_NOT_FOUND**: The domain does not exist or belongs to another organization.\n- **502 Bad Gateway / DOMAIN_PROVIDER_ERROR**: Provider verification failed, timed out, or credentials are missing.",
|
|
18041
19675
|
"security": [
|
|
18042
19676
|
{
|
|
18043
19677
|
"bearerAuth": []
|
|
18044
19678
|
}
|
|
18045
19679
|
],
|
|
18046
19680
|
"x-cli": {
|
|
18047
|
-
"command": "
|
|
18048
|
-
"
|
|
19681
|
+
"command": "domain verify",
|
|
19682
|
+
"positional": [
|
|
19683
|
+
"domain"
|
|
19684
|
+
],
|
|
19685
|
+
"display": {
|
|
19686
|
+
"shape": "object",
|
|
19687
|
+
"format": {
|
|
19688
|
+
"created_at": "relative-time",
|
|
19689
|
+
"updated_at": "relative-time",
|
|
19690
|
+
"verified_at": "relative-time"
|
|
19691
|
+
},
|
|
19692
|
+
"dataPath": "domain"
|
|
19693
|
+
}
|
|
18049
19694
|
},
|
|
18050
19695
|
"x-codeSamples": [
|
|
18051
19696
|
{
|
|
18052
19697
|
"lang": "shell",
|
|
18053
19698
|
"label": "curl",
|
|
18054
|
-
"source": "curl -X POST https://api.wspc.ai/email/
|
|
19699
|
+
"source": "curl -X POST https://api.wspc.ai/email/domains/mail.example.com/verify \\\n -H \"Authorization: Bearer $WSPC_API_KEY\""
|
|
18055
19700
|
},
|
|
18056
19701
|
{
|
|
18057
19702
|
"lang": "bash",
|
|
18058
19703
|
"label": "wspc CLI",
|
|
18059
|
-
"source": "wspc email
|
|
19704
|
+
"source": "wspc email domain verify mail.example.com"
|
|
18060
19705
|
}
|
|
18061
19706
|
],
|
|
18062
|
-
"
|
|
18063
|
-
|
|
18064
|
-
|
|
18065
|
-
|
|
18066
|
-
"
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
"value": {
|
|
18073
|
-
"from_alias_email": "alice-shop@wspc.app",
|
|
18074
|
-
"to": [
|
|
18075
|
-
"alice@example.com"
|
|
18076
|
-
],
|
|
18077
|
-
"subject": "Welcome to WSPC",
|
|
18078
|
-
"text": "Hi Alice — welcome aboard.",
|
|
18079
|
-
"idempotency_key": "retry-20260601-001"
|
|
18080
|
-
}
|
|
18081
|
-
},
|
|
18082
|
-
"reply": {
|
|
18083
|
-
"summary": "Threaded reply — to/subject derived from the inbound message",
|
|
18084
|
-
"value": {
|
|
18085
|
-
"from_alias_email": "alice-shop@wspc.app",
|
|
18086
|
-
"in_reply_to_email_id": "eml_01HW3K4N9V5G6Z8C2Q7B1Y0M3F",
|
|
18087
|
-
"text": "Thanks — replying inline.",
|
|
18088
|
-
"idempotency_key": "reply-20260601-001"
|
|
18089
|
-
}
|
|
18090
|
-
},
|
|
18091
|
-
"full": {
|
|
18092
|
-
"summary": "Multi-recipient with explicit subject",
|
|
18093
|
-
"value": {
|
|
18094
|
-
"from_alias_email": "alice-shop@wspc.app",
|
|
18095
|
-
"to": [
|
|
18096
|
-
"alice@example.com",
|
|
18097
|
-
"bob@example.com"
|
|
18098
|
-
],
|
|
18099
|
-
"subject": "Lunch with Alice",
|
|
18100
|
-
"text": "Confirming lunch — see you at the lobby at 12:30.",
|
|
18101
|
-
"idempotency_key": "lunch-confirm-20260601"
|
|
18102
|
-
}
|
|
18103
|
-
}
|
|
18104
|
-
}
|
|
18105
|
-
}
|
|
19707
|
+
"parameters": [
|
|
19708
|
+
{
|
|
19709
|
+
"schema": {
|
|
19710
|
+
"type": "string",
|
|
19711
|
+
"description": "Custom domain hostname path parameter. URL-encode if your client requires it."
|
|
19712
|
+
},
|
|
19713
|
+
"required": true,
|
|
19714
|
+
"description": "Custom domain hostname path parameter. URL-encode if your client requires it.",
|
|
19715
|
+
"name": "domain",
|
|
19716
|
+
"in": "path"
|
|
18106
19717
|
}
|
|
18107
|
-
|
|
19718
|
+
],
|
|
18108
19719
|
"responses": {
|
|
18109
19720
|
"200": {
|
|
18110
|
-
"description": "
|
|
19721
|
+
"description": "Updated cached provider state after a verification attempt, including ownership, sending readiness, and receiving readiness.",
|
|
18111
19722
|
"content": {
|
|
18112
19723
|
"application/json": {
|
|
18113
19724
|
"schema": {
|
|
18114
|
-
"$ref": "#/components/schemas/
|
|
19725
|
+
"$ref": "#/components/schemas/EmailDomainObjectResponse"
|
|
18115
19726
|
},
|
|
18116
19727
|
"examples": {
|
|
18117
19728
|
"happyPath": {
|
|
18118
|
-
"summary": "
|
|
18119
|
-
"value": {
|
|
18120
|
-
"
|
|
18121
|
-
"
|
|
18122
|
-
"
|
|
18123
|
-
"
|
|
18124
|
-
"
|
|
18125
|
-
"
|
|
18126
|
-
|
|
18127
|
-
|
|
19729
|
+
"summary": "Domain ownership and sending verified; receiving is not ready yet",
|
|
19730
|
+
"value": {
|
|
19731
|
+
"domain": {
|
|
19732
|
+
"domain": "mail.example.com",
|
|
19733
|
+
"status": "verified",
|
|
19734
|
+
"sending_status": "verified",
|
|
19735
|
+
"receiving_status": "disabled",
|
|
19736
|
+
"records": [
|
|
19737
|
+
{
|
|
19738
|
+
"type": "TXT",
|
|
19739
|
+
"name": "mail.example.com",
|
|
19740
|
+
"value": "pm-domain-verification=abc123",
|
|
19741
|
+
"status": "verified",
|
|
19742
|
+
"ttl": 3600,
|
|
19743
|
+
"purpose": "identity_verification"
|
|
19744
|
+
},
|
|
19745
|
+
{
|
|
19746
|
+
"type": "CNAME",
|
|
19747
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
19748
|
+
"value": "selector1.domainkey.example.net",
|
|
19749
|
+
"status": "verified",
|
|
19750
|
+
"purpose": "dkim"
|
|
19751
|
+
}
|
|
18128
19752
|
],
|
|
18129
|
-
"
|
|
18130
|
-
"
|
|
18131
|
-
"
|
|
18132
|
-
"
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
|
|
18140
|
-
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
|
|
18144
|
-
|
|
18145
|
-
|
|
18146
|
-
|
|
18147
|
-
|
|
18148
|
-
|
|
18149
|
-
|
|
18150
|
-
|
|
18151
|
-
|
|
18152
|
-
|
|
18153
|
-
|
|
19753
|
+
"region": "us-east-1",
|
|
19754
|
+
"created_at": 1780166400000,
|
|
19755
|
+
"updated_at": 1780167000000,
|
|
19756
|
+
"verified_at": 1780167000000
|
|
19757
|
+
}
|
|
19758
|
+
}
|
|
19759
|
+
},
|
|
19760
|
+
"stillPending": {
|
|
19761
|
+
"summary": "Provider accepted verify request but DNS is not ready yet",
|
|
19762
|
+
"value": {
|
|
19763
|
+
"domain": {
|
|
19764
|
+
"domain": "mail.example.com",
|
|
19765
|
+
"status": "pending",
|
|
19766
|
+
"sending_status": "pending",
|
|
19767
|
+
"receiving_status": "pending",
|
|
19768
|
+
"records": [
|
|
19769
|
+
{
|
|
19770
|
+
"type": "TXT",
|
|
19771
|
+
"name": "mail.example.com",
|
|
19772
|
+
"value": "pm-domain-verification=abc123",
|
|
19773
|
+
"status": "pending",
|
|
19774
|
+
"ttl": 3600,
|
|
19775
|
+
"purpose": "identity_verification"
|
|
19776
|
+
},
|
|
19777
|
+
{
|
|
19778
|
+
"type": "CNAME",
|
|
19779
|
+
"name": "selector1._domainkey.mail.example.com",
|
|
19780
|
+
"value": "selector1.domainkey.example.net",
|
|
19781
|
+
"status": "pending",
|
|
19782
|
+
"purpose": "dkim"
|
|
19783
|
+
}
|
|
18154
19784
|
],
|
|
18155
|
-
"
|
|
18156
|
-
"
|
|
18157
|
-
"
|
|
18158
|
-
|
|
18159
|
-
"request_hash": "sha256:abc...",
|
|
18160
|
-
"status": "sent",
|
|
18161
|
-
"idempotency_key": "retry-20260601-001",
|
|
18162
|
-
"submitted_at": 1748736000500,
|
|
18163
|
-
"created_at": 1748736000000,
|
|
18164
|
-
"updated_at": 1748736000500
|
|
18165
|
-
},
|
|
18166
|
-
"idempotent_replay": true
|
|
19785
|
+
"region": "us-east-1",
|
|
19786
|
+
"created_at": 1780166400000,
|
|
19787
|
+
"updated_at": 1780166400000
|
|
19788
|
+
}
|
|
18167
19789
|
}
|
|
18168
19790
|
}
|
|
18169
19791
|
}
|
|
@@ -18171,7 +19793,7 @@
|
|
|
18171
19793
|
}
|
|
18172
19794
|
},
|
|
18173
19795
|
"400": {
|
|
18174
|
-
"description": "
|
|
19796
|
+
"description": "Malformed or platform-reserved domain hostname.",
|
|
18175
19797
|
"content": {
|
|
18176
19798
|
"application/json": {
|
|
18177
19799
|
"schema": {
|
|
@@ -18200,17 +19822,6 @@
|
|
|
18200
19822
|
"required": [
|
|
18201
19823
|
"error"
|
|
18202
19824
|
]
|
|
18203
|
-
},
|
|
18204
|
-
"examples": {
|
|
18205
|
-
"validationError": {
|
|
18206
|
-
"summary": "Body failed schema validation",
|
|
18207
|
-
"value": {
|
|
18208
|
-
"error": {
|
|
18209
|
-
"code": "VALIDATION_ERROR",
|
|
18210
|
-
"message": "title must not be empty"
|
|
18211
|
-
}
|
|
18212
|
-
}
|
|
18213
|
-
}
|
|
18214
19825
|
}
|
|
18215
19826
|
}
|
|
18216
19827
|
}
|
|
@@ -18261,7 +19872,7 @@
|
|
|
18261
19872
|
}
|
|
18262
19873
|
},
|
|
18263
19874
|
"404": {
|
|
18264
|
-
"description": "
|
|
19875
|
+
"description": "The domain was not found for the caller organization.",
|
|
18265
19876
|
"content": {
|
|
18266
19877
|
"application/json": {
|
|
18267
19878
|
"schema": {
|
|
@@ -18294,8 +19905,8 @@
|
|
|
18294
19905
|
}
|
|
18295
19906
|
}
|
|
18296
19907
|
},
|
|
18297
|
-
"
|
|
18298
|
-
"description": "
|
|
19908
|
+
"429": {
|
|
19909
|
+
"description": "Rate limit exceeded. Retry after the duration in `error.extra.retry_after_seconds`. `limit_kind` identifies which bucket was exhausted.",
|
|
18299
19910
|
"content": {
|
|
18300
19911
|
"application/json": {
|
|
18301
19912
|
"schema": {
|
|
@@ -18324,40 +19935,21 @@
|
|
|
18324
19935
|
"required": [
|
|
18325
19936
|
"error"
|
|
18326
19937
|
]
|
|
18327
|
-
}
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
"schema": {
|
|
18336
|
-
"type": "object",
|
|
18337
|
-
"properties": {
|
|
18338
|
-
"error": {
|
|
18339
|
-
"type": "object",
|
|
18340
|
-
"properties": {
|
|
18341
|
-
"code": {
|
|
18342
|
-
"type": "string"
|
|
18343
|
-
},
|
|
18344
|
-
"message": {
|
|
18345
|
-
"type": "string"
|
|
18346
|
-
},
|
|
19938
|
+
},
|
|
19939
|
+
"examples": {
|
|
19940
|
+
"rateLimited": {
|
|
19941
|
+
"summary": "Per-key rate limit hit",
|
|
19942
|
+
"value": {
|
|
19943
|
+
"error": {
|
|
19944
|
+
"code": "RATE_LIMITED",
|
|
19945
|
+
"message": "rate limit exceeded",
|
|
18347
19946
|
"extra": {
|
|
18348
|
-
"
|
|
18349
|
-
"
|
|
19947
|
+
"retry_after_seconds": 60,
|
|
19948
|
+
"limit_kind": "authenticated_per_key"
|
|
18350
19949
|
}
|
|
18351
|
-
}
|
|
18352
|
-
"required": [
|
|
18353
|
-
"code",
|
|
18354
|
-
"message"
|
|
18355
|
-
]
|
|
19950
|
+
}
|
|
18356
19951
|
}
|
|
18357
|
-
}
|
|
18358
|
-
"required": [
|
|
18359
|
-
"error"
|
|
18360
|
-
]
|
|
19952
|
+
}
|
|
18361
19953
|
}
|
|
18362
19954
|
}
|
|
18363
19955
|
}
|
|
@@ -18408,7 +20000,7 @@
|
|
|
18408
20000
|
}
|
|
18409
20001
|
},
|
|
18410
20002
|
"502": {
|
|
18411
|
-
"description": "The upstream
|
|
20003
|
+
"description": "The upstream provider call failed or provider credentials are missing.",
|
|
18412
20004
|
"content": {
|
|
18413
20005
|
"application/json": {
|
|
18414
20006
|
"schema": {
|
|
@@ -20079,7 +21671,7 @@
|
|
|
20079
21671
|
}
|
|
20080
21672
|
},
|
|
20081
21673
|
"summary": "List comments on a todo",
|
|
20082
|
-
"description": "### 🎯 Overview & Purpose\nList the comments attached to a todo, oldest-first by default.\n\n### 💡 Key Features & Constraints\n* **Ordering**: Defaults to chronological (`asc`). Pass `order=desc` for newest-first.\n* **Soft-deleted**: Hidden by default; pass `include_deleted=true` to include them.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the target todo does not exist or is soft-deleted.",
|
|
21674
|
+
"description": "### 🎯 Overview & Purpose\nList the comments attached to a todo, oldest-first by default.\n\n### 💡 Key Features & Constraints\n* **Ordering**: Defaults to chronological (`asc`). Pass `order=desc` for newest-first.\n* **Soft-deleted**: Hidden by default; pass `include_deleted=true` to include them.\n* **Pagination**: Use `limit` (max 200, default 50) and `cursor` (the `next_cursor` from a previous response) to page through results. When `next_cursor` is absent in the response, you are on the last page. Returns `{ comments, next_cursor? }`. Changing `order` invalidates a cursor.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the target todo does not exist or is soft-deleted.\n* **`VALIDATION_ERROR`**: Thrown if a cursor was produced with a different `order` than the current request.",
|
|
20083
21675
|
"security": [
|
|
20084
21676
|
{
|
|
20085
21677
|
"bearerAuth": []
|
|
@@ -20128,6 +21720,26 @@
|
|
|
20128
21720
|
"required": false,
|
|
20129
21721
|
"name": "include_deleted",
|
|
20130
21722
|
"in": "query"
|
|
21723
|
+
},
|
|
21724
|
+
{
|
|
21725
|
+
"schema": {
|
|
21726
|
+
"type": "string",
|
|
21727
|
+
"description": "Max comments to return. Clamped to [1, 200]. Default 50 server-side."
|
|
21728
|
+
},
|
|
21729
|
+
"required": false,
|
|
21730
|
+
"description": "Max comments to return. Clamped to [1, 200]. Default 50 server-side.",
|
|
21731
|
+
"name": "limit",
|
|
21732
|
+
"in": "query"
|
|
21733
|
+
},
|
|
21734
|
+
{
|
|
21735
|
+
"schema": {
|
|
21736
|
+
"type": "string",
|
|
21737
|
+
"description": "Opaque pagination cursor returned in `next_cursor` of a previous response."
|
|
21738
|
+
},
|
|
21739
|
+
"required": false,
|
|
21740
|
+
"description": "Opaque pagination cursor returned in `next_cursor` of a previous response.",
|
|
21741
|
+
"name": "cursor",
|
|
21742
|
+
"in": "query"
|
|
20131
21743
|
}
|
|
20132
21744
|
],
|
|
20133
21745
|
"responses": {
|
|
@@ -20143,6 +21755,10 @@
|
|
|
20143
21755
|
"items": {
|
|
20144
21756
|
"$ref": "#/components/schemas/Comment"
|
|
20145
21757
|
}
|
|
21758
|
+
},
|
|
21759
|
+
"next_cursor": {
|
|
21760
|
+
"type": "string",
|
|
21761
|
+
"description": "Opaque cursor for the next page. Absent on the last page."
|
|
20146
21762
|
}
|
|
20147
21763
|
},
|
|
20148
21764
|
"required": [
|
|
@@ -22843,6 +24459,26 @@
|
|
|
22843
24459
|
"required": false,
|
|
22844
24460
|
"name": "include_orphan_fields",
|
|
22845
24461
|
"in": "query"
|
|
24462
|
+
},
|
|
24463
|
+
{
|
|
24464
|
+
"schema": {
|
|
24465
|
+
"type": "string",
|
|
24466
|
+
"description": "Max todos to return. Clamped to [1, 200]. Default 50 server-side."
|
|
24467
|
+
},
|
|
24468
|
+
"required": false,
|
|
24469
|
+
"description": "Max todos to return. Clamped to [1, 200]. Default 50 server-side.",
|
|
24470
|
+
"name": "limit",
|
|
24471
|
+
"in": "query"
|
|
24472
|
+
},
|
|
24473
|
+
{
|
|
24474
|
+
"schema": {
|
|
24475
|
+
"type": "string",
|
|
24476
|
+
"description": "Opaque pagination cursor returned in `next_cursor` of a previous response."
|
|
24477
|
+
},
|
|
24478
|
+
"required": false,
|
|
24479
|
+
"description": "Opaque pagination cursor returned in `next_cursor` of a previous response.",
|
|
24480
|
+
"name": "cursor",
|
|
24481
|
+
"in": "query"
|
|
22846
24482
|
}
|
|
22847
24483
|
],
|
|
22848
24484
|
"responses": {
|
|
@@ -30975,6 +32611,10 @@
|
|
|
30975
32611
|
"name": "EmailAliases",
|
|
30976
32612
|
"description": "User-managed @wspc.app email aliases that route inbound mail to the user's inbox."
|
|
30977
32613
|
},
|
|
32614
|
+
{
|
|
32615
|
+
"name": "EmailDomains",
|
|
32616
|
+
"description": "EmailDomains endpoints."
|
|
32617
|
+
},
|
|
30978
32618
|
{
|
|
30979
32619
|
"name": "Emails",
|
|
30980
32620
|
"description": "Inbound and outbound email messages with attachment support."
|