@primitivedotdev/sdk 1.30.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -112,6 +112,10 @@ const openapiDocument = {
112
112
  {
113
113
  "name": "Registries",
114
114
  "description": "The Agent Registry: ownable directories of agents, addressable by a\nregistry-scoped handle. A registry's publish policy (owner_only, request,\nor open) decides whether a publish lists immediately or pends owner\napproval. An agent is defined once with a globally unique,\nreachability-verified address, then published into any registry under a\nhandle. Discovery reads (list, resolve, get) are public for public\nregistries; managing a registry and moderating requests use the owner's\nAPI key.\n"
115
+ },
116
+ {
117
+ "name": "Contacts",
118
+ "description": "Organization contacts and per-address agent preferences."
115
119
  }
116
120
  ],
117
121
  "paths": {
@@ -4259,62 +4263,25 @@ const openapiDocument = {
4259
4263
  "404": { "$ref": "#/components/responses/NotFound" }
4260
4264
  }
4261
4265
  }
4262
- }
4263
- },
4264
- "components": {
4265
- "securitySchemes": {
4266
- "BearerAuth": {
4267
- "type": "http",
4268
- "scheme": "bearer",
4269
- "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
4270
- },
4271
- "DownloadToken": {
4272
- "type": "apiKey",
4273
- "in": "query",
4274
- "name": "token",
4275
- "description": "Signed download token provided in webhook payloads"
4276
- }
4277
4266
  },
4278
- "parameters": {
4279
- "AttachmentPartIndex": {
4280
- "name": "part_index",
4281
- "in": "path",
4282
- "required": true,
4283
- "description": "The attachment metadata `part_index`, not its offset in the attachments array",
4284
- "schema": {
4285
- "type": "integer",
4286
- "format": "int32",
4287
- "minimum": 0,
4288
- "maximum": 2147483647
4289
- }
4290
- },
4291
- "ResourceId": {
4292
- "name": "id",
4293
- "in": "path",
4294
- "required": true,
4267
+ "/contacts": { "get": {
4268
+ "operationId": "listContacts",
4269
+ "summary": "list Contacts",
4270
+ "tags": ["Contacts"],
4271
+ "security": [{ "BearerAuth": [] }],
4272
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
4273
+ "parameters": [{
4274
+ "name": "cursor",
4275
+ "in": "query",
4295
4276
  "schema": {
4296
4277
  "type": "string",
4297
- "format": "uuid"
4278
+ "format": "email",
4279
+ "maxLength": 254,
4280
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4298
4281
  },
4299
- "description": "Resource UUID"
4300
- },
4301
- "IdempotencyKey": {
4302
- "name": "idempotency-key",
4303
- "in": "header",
4304
4282
  "required": false,
4305
- "schema": {
4306
- "type": "string",
4307
- "maxLength": 255
4308
- },
4309
- "description": "Optional idempotency key. Retrying a request with the same key returns\nthe original result instead of repeating the side effect (for\n`createEmailChallenge`, re-sending the email).\n"
4310
- },
4311
- "Cursor": {
4312
- "name": "cursor",
4313
- "in": "query",
4314
- "schema": { "type": "string" },
4315
- "description": "Pagination cursor from a previous response's `meta.cursor` field.\nFormat: `{ISO-datetime}|{id}`\n"
4316
- },
4317
- "Limit": {
4283
+ "description": "cursor for contacts."
4284
+ }, {
4318
4285
  "name": "limit",
4319
4286
  "in": "query",
4320
4287
  "schema": {
@@ -4323,127 +4290,1835 @@ const openapiDocument = {
4323
4290
  "maximum": 100,
4324
4291
  "default": 50
4325
4292
  },
4326
- "description": "Number of results per page"
4327
- },
4328
- "MemoryKeyQuery": {
4329
- "name": "key",
4330
- "in": "query",
4331
- "required": true,
4332
- "description": "Memory key. Must be at most 512 UTF-8 bytes.",
4333
- "schema": {
4334
- "type": "string",
4335
- "minLength": 1,
4336
- "maxLength": 512
4337
- }
4338
- },
4339
- "MemoryScopeQueryType": {
4340
- "name": "scope_type",
4341
- "in": "query",
4342
- "required": false,
4343
- "description": "Explicit scope type. Omit to use automatic scope resolution. Pass\n`function` with `scope_id=<function-id>`, or `org` with no `scope_id`.\n",
4344
- "schema": {
4345
- "type": "string",
4346
- "enum": ["org", "function"]
4347
- }
4348
- },
4349
- "MemoryScopeId": {
4350
- "name": "scope_id",
4351
- "in": "query",
4352
4293
  "required": false,
4353
- "description": "Function id UUID when `scope_type=function`. Not valid with\n`scope_type=org`.\n",
4354
- "schema": {
4355
- "type": "string",
4356
- "format": "uuid"
4357
- }
4358
- }
4359
- },
4360
- "responses": {
4361
- "AttachmentPart": {
4362
- "description": "Original attachment bytes; never a JSON envelope or a base64 string",
4363
- "content": { "application/octet-stream": { "schema": {
4364
- "type": "string",
4365
- "format": "binary"
4366
- } } },
4367
- "headers": {
4368
- "X-Content-SHA256": {
4369
- "description": "SHA-256 hex digest of the original bytes",
4370
- "schema": {
4371
- "type": "string",
4372
- "pattern": "^[a-fA-F0-9]{64}$"
4294
+ "description": "limit for contacts."
4295
+ }],
4296
+ "responses": {
4297
+ "200": {
4298
+ "description": "Success",
4299
+ "content": { "application/json": { "schema": { "allOf": [{
4300
+ "type": "object",
4301
+ "properties": { "success": {
4302
+ "type": "boolean",
4303
+ "const": true
4304
+ } },
4305
+ "required": [
4306
+ "success",
4307
+ "data",
4308
+ "meta"
4309
+ ]
4310
+ }, {
4311
+ "type": "object",
4312
+ "properties": {
4313
+ "data": {
4314
+ "type": "array",
4315
+ "items": {
4316
+ "type": "object",
4317
+ "additionalProperties": false,
4318
+ "properties": {
4319
+ "address": {
4320
+ "type": "string",
4321
+ "format": "email",
4322
+ "maxLength": 254,
4323
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4324
+ },
4325
+ "display_name": {
4326
+ "type": ["string", "null"],
4327
+ "maxLength": 200
4328
+ },
4329
+ "version": {
4330
+ "type": "string",
4331
+ "format": "uuid",
4332
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
4333
+ },
4334
+ "created_at": {
4335
+ "type": "string",
4336
+ "format": "date-time"
4337
+ },
4338
+ "updated_at": {
4339
+ "type": "string",
4340
+ "format": "date-time"
4341
+ }
4342
+ },
4343
+ "required": [
4344
+ "address",
4345
+ "display_name",
4346
+ "version",
4347
+ "created_at",
4348
+ "updated_at"
4349
+ ]
4350
+ }
4351
+ },
4352
+ "meta": {
4353
+ "type": "object",
4354
+ "required": ["cursor"],
4355
+ "properties": {
4356
+ "limit": { "type": "integer" },
4357
+ "cursor": { "type": ["string", "null"] }
4358
+ }
4359
+ }
4373
4360
  }
4374
- },
4375
- "Content-Disposition": {
4376
- "description": "Safe attachment disposition with a sanitized filename",
4377
- "schema": { "type": "string" }
4378
- },
4379
- "Cache-Control": {
4380
- "description": "Attachment responses are private and must not be stored by caches",
4381
- "schema": {
4382
- "type": "string",
4383
- "example": "private, no-store"
4361
+ }] } } },
4362
+ "headers": {
4363
+ "ratelimit-limit": {
4364
+ "description": "Maximum number of requests allowed in the current window.",
4365
+ "schema": {
4366
+ "type": "integer",
4367
+ "minimum": 1,
4368
+ "example": 120
4369
+ }
4370
+ },
4371
+ "ratelimit-remaining": {
4372
+ "description": "Remaining requests in the current window.",
4373
+ "schema": {
4374
+ "type": "integer",
4375
+ "minimum": 0,
4376
+ "example": 118
4377
+ }
4378
+ },
4379
+ "ratelimit-reset": {
4380
+ "description": "Unix timestamp (seconds) when the current window resets.",
4381
+ "schema": {
4382
+ "type": "integer",
4383
+ "example": 1700000060
4384
+ }
4385
+ },
4386
+ "ratelimit-policy": {
4387
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
4388
+ "schema": {
4389
+ "type": "string",
4390
+ "example": "120;w=60"
4391
+ }
4392
+ },
4393
+ "Cache-Control": {
4394
+ "schema": {
4395
+ "type": "string",
4396
+ "const": "no-store"
4397
+ },
4398
+ "description": "Always fresh policy metadata."
4384
4399
  }
4385
4400
  }
4386
- }
4387
- },
4388
- "PullContentGone": {
4389
- "description": "Queued content is no longer available",
4390
- "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4391
- },
4392
- "RequestCanceled": {
4393
- "description": "Request was canceled",
4394
- "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4395
- },
4396
- "PullUnavailable": {
4397
- "description": "Local receiving is unavailable",
4398
- "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4399
- },
4400
- "Unauthorized": {
4401
- "description": "Invalid or missing API key",
4402
- "content": { "application/json": {
4403
- "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4404
- "example": {
4405
- "success": false,
4406
- "error": {
4407
- "code": "unauthorized",
4408
- "message": "Invalid or missing API key"
4401
+ },
4402
+ "400": {
4403
+ "description": "Invalid request parameters",
4404
+ "content": { "application/json": {
4405
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4406
+ "example": {
4407
+ "success": false,
4408
+ "error": {
4409
+ "code": "validation_error",
4410
+ "message": "Invalid domain format"
4411
+ }
4409
4412
  }
4410
- }
4411
- } }
4412
- },
4413
- "Forbidden": {
4414
- "description": "Authenticated caller lacks permission for the operation",
4415
- "content": { "application/json": {
4416
- "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4417
- "example": {
4418
- "success": false,
4419
- "error": {
4420
- "code": "forbidden",
4421
- "message": "Insufficient permissions"
4413
+ } }
4414
+ },
4415
+ "401": {
4416
+ "description": "Invalid or missing API key",
4417
+ "content": { "application/json": {
4418
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4419
+ "example": {
4420
+ "success": false,
4421
+ "error": {
4422
+ "code": "unauthorized",
4423
+ "message": "Invalid or missing API key"
4424
+ }
4422
4425
  }
4423
- }
4424
- } }
4425
- },
4426
- "NotFound": {
4427
- "description": "Resource not found",
4428
- "content": { "application/json": {
4429
- "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4430
- "example": {
4431
- "success": false,
4432
- "error": {
4433
- "code": "not_found",
4434
- "message": "Resource not found"
4426
+ } }
4427
+ },
4428
+ "403": {
4429
+ "description": "Authenticated caller lacks permission for the operation",
4430
+ "content": { "application/json": {
4431
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4432
+ "example": {
4433
+ "success": false,
4434
+ "error": {
4435
+ "code": "forbidden",
4436
+ "message": "Insufficient permissions"
4437
+ }
4435
4438
  }
4436
- }
4437
- } }
4438
- },
4439
- "ValidationError": {
4440
- "description": "Invalid request parameters",
4441
- "content": { "application/json": {
4442
- "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4443
- "example": {
4444
- "success": false,
4445
- "error": {
4446
- "code": "validation_error",
4439
+ } }
4440
+ },
4441
+ "404": {
4442
+ "description": "Resource not found",
4443
+ "content": { "application/json": {
4444
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4445
+ "example": {
4446
+ "success": false,
4447
+ "error": {
4448
+ "code": "not_found",
4449
+ "message": "Resource not found"
4450
+ }
4451
+ }
4452
+ } }
4453
+ },
4454
+ "409": {
4455
+ "description": "contact_conflict: write precondition did not match.",
4456
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4457
+ },
4458
+ "429": {
4459
+ "description": "Rate limit exceeded",
4460
+ "headers": { "Retry-After": {
4461
+ "schema": { "type": "integer" },
4462
+ "description": "Seconds to wait before retrying"
4463
+ } },
4464
+ "content": { "application/json": {
4465
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4466
+ "example": {
4467
+ "success": false,
4468
+ "error": {
4469
+ "code": "rate_limit_exceeded",
4470
+ "message": "Rate limit exceeded"
4471
+ }
4472
+ }
4473
+ } }
4474
+ }
4475
+ }
4476
+ } },
4477
+ "/contacts/{address}": {
4478
+ "get": {
4479
+ "operationId": "getContact",
4480
+ "summary": "get Contact",
4481
+ "tags": ["Contacts"],
4482
+ "security": [{ "BearerAuth": [] }],
4483
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
4484
+ "parameters": [{
4485
+ "name": "address",
4486
+ "in": "path",
4487
+ "schema": {
4488
+ "type": "string",
4489
+ "format": "email",
4490
+ "maxLength": 254,
4491
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4492
+ },
4493
+ "required": true,
4494
+ "description": "address for contacts."
4495
+ }],
4496
+ "responses": {
4497
+ "200": {
4498
+ "description": "Success",
4499
+ "content": { "application/json": { "schema": { "allOf": [{
4500
+ "type": "object",
4501
+ "properties": { "success": {
4502
+ "type": "boolean",
4503
+ "const": true
4504
+ } },
4505
+ "required": ["success", "data"]
4506
+ }, {
4507
+ "type": "object",
4508
+ "properties": { "data": {
4509
+ "type": "object",
4510
+ "additionalProperties": false,
4511
+ "properties": {
4512
+ "address": {
4513
+ "type": "string",
4514
+ "format": "email",
4515
+ "maxLength": 254,
4516
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4517
+ },
4518
+ "display_name": {
4519
+ "type": ["string", "null"],
4520
+ "maxLength": 200
4521
+ },
4522
+ "version": {
4523
+ "type": "string",
4524
+ "format": "uuid",
4525
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
4526
+ },
4527
+ "created_at": {
4528
+ "type": "string",
4529
+ "format": "date-time"
4530
+ },
4531
+ "updated_at": {
4532
+ "type": "string",
4533
+ "format": "date-time"
4534
+ }
4535
+ },
4536
+ "required": [
4537
+ "address",
4538
+ "display_name",
4539
+ "version",
4540
+ "created_at",
4541
+ "updated_at"
4542
+ ]
4543
+ } }
4544
+ }] } } },
4545
+ "headers": {
4546
+ "ratelimit-limit": {
4547
+ "description": "Maximum number of requests allowed in the current window.",
4548
+ "schema": {
4549
+ "type": "integer",
4550
+ "minimum": 1,
4551
+ "example": 120
4552
+ }
4553
+ },
4554
+ "ratelimit-remaining": {
4555
+ "description": "Remaining requests in the current window.",
4556
+ "schema": {
4557
+ "type": "integer",
4558
+ "minimum": 0,
4559
+ "example": 118
4560
+ }
4561
+ },
4562
+ "ratelimit-reset": {
4563
+ "description": "Unix timestamp (seconds) when the current window resets.",
4564
+ "schema": {
4565
+ "type": "integer",
4566
+ "example": 1700000060
4567
+ }
4568
+ },
4569
+ "ratelimit-policy": {
4570
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
4571
+ "schema": {
4572
+ "type": "string",
4573
+ "example": "120;w=60"
4574
+ }
4575
+ },
4576
+ "Cache-Control": {
4577
+ "schema": {
4578
+ "type": "string",
4579
+ "const": "no-store"
4580
+ },
4581
+ "description": "Always fresh policy metadata."
4582
+ }
4583
+ }
4584
+ },
4585
+ "400": {
4586
+ "description": "Invalid request parameters",
4587
+ "content": { "application/json": {
4588
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4589
+ "example": {
4590
+ "success": false,
4591
+ "error": {
4592
+ "code": "validation_error",
4593
+ "message": "Invalid domain format"
4594
+ }
4595
+ }
4596
+ } }
4597
+ },
4598
+ "401": {
4599
+ "description": "Invalid or missing API key",
4600
+ "content": { "application/json": {
4601
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4602
+ "example": {
4603
+ "success": false,
4604
+ "error": {
4605
+ "code": "unauthorized",
4606
+ "message": "Invalid or missing API key"
4607
+ }
4608
+ }
4609
+ } }
4610
+ },
4611
+ "403": {
4612
+ "description": "Authenticated caller lacks permission for the operation",
4613
+ "content": { "application/json": {
4614
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4615
+ "example": {
4616
+ "success": false,
4617
+ "error": {
4618
+ "code": "forbidden",
4619
+ "message": "Insufficient permissions"
4620
+ }
4621
+ }
4622
+ } }
4623
+ },
4624
+ "404": {
4625
+ "description": "Resource not found",
4626
+ "content": { "application/json": {
4627
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4628
+ "example": {
4629
+ "success": false,
4630
+ "error": {
4631
+ "code": "not_found",
4632
+ "message": "Resource not found"
4633
+ }
4634
+ }
4635
+ } }
4636
+ },
4637
+ "409": {
4638
+ "description": "contact_conflict: write precondition did not match.",
4639
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4640
+ },
4641
+ "429": {
4642
+ "description": "Rate limit exceeded",
4643
+ "headers": { "Retry-After": {
4644
+ "schema": { "type": "integer" },
4645
+ "description": "Seconds to wait before retrying"
4646
+ } },
4647
+ "content": { "application/json": {
4648
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4649
+ "example": {
4650
+ "success": false,
4651
+ "error": {
4652
+ "code": "rate_limit_exceeded",
4653
+ "message": "Rate limit exceeded"
4654
+ }
4655
+ }
4656
+ } }
4657
+ }
4658
+ }
4659
+ },
4660
+ "put": {
4661
+ "operationId": "putContact",
4662
+ "summary": "put Contact",
4663
+ "tags": ["Contacts"],
4664
+ "security": [{ "BearerAuth": [] }],
4665
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
4666
+ "parameters": [{
4667
+ "name": "address",
4668
+ "in": "path",
4669
+ "schema": {
4670
+ "type": "string",
4671
+ "format": "email",
4672
+ "maxLength": 254,
4673
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4674
+ },
4675
+ "required": true,
4676
+ "description": "address for contacts."
4677
+ }],
4678
+ "requestBody": {
4679
+ "required": true,
4680
+ "content": { "application/json": { "schema": { "oneOf": [{
4681
+ "type": "object",
4682
+ "additionalProperties": false,
4683
+ "properties": {
4684
+ "display_name": {
4685
+ "type": ["string", "null"],
4686
+ "maxLength": 200
4687
+ },
4688
+ "if_absent": {
4689
+ "type": "boolean",
4690
+ "const": true
4691
+ }
4692
+ },
4693
+ "required": ["if_absent"]
4694
+ }, {
4695
+ "type": "object",
4696
+ "additionalProperties": false,
4697
+ "properties": {
4698
+ "display_name": {
4699
+ "type": ["string", "null"],
4700
+ "maxLength": 200
4701
+ },
4702
+ "if_version": {
4703
+ "type": "string",
4704
+ "format": "uuid",
4705
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
4706
+ }
4707
+ },
4708
+ "required": ["if_version"]
4709
+ }] } } }
4710
+ },
4711
+ "responses": {
4712
+ "200": {
4713
+ "description": "Success",
4714
+ "content": { "application/json": { "schema": { "allOf": [{
4715
+ "type": "object",
4716
+ "properties": { "success": {
4717
+ "type": "boolean",
4718
+ "const": true
4719
+ } },
4720
+ "required": ["success", "data"]
4721
+ }, {
4722
+ "type": "object",
4723
+ "properties": { "data": {
4724
+ "type": "object",
4725
+ "additionalProperties": false,
4726
+ "properties": {
4727
+ "address": {
4728
+ "type": "string",
4729
+ "format": "email",
4730
+ "maxLength": 254,
4731
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4732
+ },
4733
+ "display_name": {
4734
+ "type": ["string", "null"],
4735
+ "maxLength": 200
4736
+ },
4737
+ "version": {
4738
+ "type": "string",
4739
+ "format": "uuid",
4740
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
4741
+ },
4742
+ "created_at": {
4743
+ "type": "string",
4744
+ "format": "date-time"
4745
+ },
4746
+ "updated_at": {
4747
+ "type": "string",
4748
+ "format": "date-time"
4749
+ }
4750
+ },
4751
+ "required": [
4752
+ "address",
4753
+ "display_name",
4754
+ "version",
4755
+ "created_at",
4756
+ "updated_at"
4757
+ ]
4758
+ } }
4759
+ }] } } },
4760
+ "headers": {
4761
+ "ratelimit-limit": {
4762
+ "description": "Maximum number of requests allowed in the current window.",
4763
+ "schema": {
4764
+ "type": "integer",
4765
+ "minimum": 1,
4766
+ "example": 120
4767
+ }
4768
+ },
4769
+ "ratelimit-remaining": {
4770
+ "description": "Remaining requests in the current window.",
4771
+ "schema": {
4772
+ "type": "integer",
4773
+ "minimum": 0,
4774
+ "example": 118
4775
+ }
4776
+ },
4777
+ "ratelimit-reset": {
4778
+ "description": "Unix timestamp (seconds) when the current window resets.",
4779
+ "schema": {
4780
+ "type": "integer",
4781
+ "example": 1700000060
4782
+ }
4783
+ },
4784
+ "ratelimit-policy": {
4785
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
4786
+ "schema": {
4787
+ "type": "string",
4788
+ "example": "120;w=60"
4789
+ }
4790
+ },
4791
+ "Cache-Control": {
4792
+ "schema": {
4793
+ "type": "string",
4794
+ "const": "no-store"
4795
+ },
4796
+ "description": "Always fresh policy metadata."
4797
+ }
4798
+ }
4799
+ },
4800
+ "400": {
4801
+ "description": "Invalid request parameters",
4802
+ "content": { "application/json": {
4803
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4804
+ "example": {
4805
+ "success": false,
4806
+ "error": {
4807
+ "code": "validation_error",
4808
+ "message": "Invalid domain format"
4809
+ }
4810
+ }
4811
+ } }
4812
+ },
4813
+ "401": {
4814
+ "description": "Invalid or missing API key",
4815
+ "content": { "application/json": {
4816
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4817
+ "example": {
4818
+ "success": false,
4819
+ "error": {
4820
+ "code": "unauthorized",
4821
+ "message": "Invalid or missing API key"
4822
+ }
4823
+ }
4824
+ } }
4825
+ },
4826
+ "403": {
4827
+ "description": "Authenticated caller lacks permission for the operation",
4828
+ "content": { "application/json": {
4829
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4830
+ "example": {
4831
+ "success": false,
4832
+ "error": {
4833
+ "code": "forbidden",
4834
+ "message": "Insufficient permissions"
4835
+ }
4836
+ }
4837
+ } }
4838
+ },
4839
+ "404": {
4840
+ "description": "Resource not found",
4841
+ "content": { "application/json": {
4842
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4843
+ "example": {
4844
+ "success": false,
4845
+ "error": {
4846
+ "code": "not_found",
4847
+ "message": "Resource not found"
4848
+ }
4849
+ }
4850
+ } }
4851
+ },
4852
+ "409": {
4853
+ "description": "contact_conflict: write precondition did not match.",
4854
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
4855
+ },
4856
+ "429": {
4857
+ "description": "Rate limit exceeded",
4858
+ "headers": { "Retry-After": {
4859
+ "schema": { "type": "integer" },
4860
+ "description": "Seconds to wait before retrying"
4861
+ } },
4862
+ "content": { "application/json": {
4863
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4864
+ "example": {
4865
+ "success": false,
4866
+ "error": {
4867
+ "code": "rate_limit_exceeded",
4868
+ "message": "Rate limit exceeded"
4869
+ }
4870
+ }
4871
+ } }
4872
+ }
4873
+ }
4874
+ },
4875
+ "delete": {
4876
+ "operationId": "deleteContact",
4877
+ "summary": "delete Contact",
4878
+ "tags": ["Contacts"],
4879
+ "security": [{ "BearerAuth": [] }],
4880
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
4881
+ "parameters": [{
4882
+ "name": "address",
4883
+ "in": "path",
4884
+ "schema": {
4885
+ "type": "string",
4886
+ "format": "email",
4887
+ "maxLength": 254,
4888
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
4889
+ },
4890
+ "required": true,
4891
+ "description": "address for contacts."
4892
+ }, {
4893
+ "name": "if_version",
4894
+ "in": "query",
4895
+ "schema": {
4896
+ "type": "string",
4897
+ "format": "uuid",
4898
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
4899
+ },
4900
+ "required": true,
4901
+ "description": "if_version for contacts."
4902
+ }],
4903
+ "responses": {
4904
+ "200": {
4905
+ "description": "Success",
4906
+ "content": { "application/json": { "schema": { "allOf": [{
4907
+ "type": "object",
4908
+ "properties": { "success": {
4909
+ "type": "boolean",
4910
+ "const": true
4911
+ } },
4912
+ "required": ["success", "data"]
4913
+ }, {
4914
+ "type": "object",
4915
+ "properties": { "data": {
4916
+ "type": "object",
4917
+ "additionalProperties": false,
4918
+ "properties": { "deleted": { "type": "boolean" } },
4919
+ "required": ["deleted"]
4920
+ } }
4921
+ }] } } },
4922
+ "headers": {
4923
+ "ratelimit-limit": {
4924
+ "description": "Maximum number of requests allowed in the current window.",
4925
+ "schema": {
4926
+ "type": "integer",
4927
+ "minimum": 1,
4928
+ "example": 120
4929
+ }
4930
+ },
4931
+ "ratelimit-remaining": {
4932
+ "description": "Remaining requests in the current window.",
4933
+ "schema": {
4934
+ "type": "integer",
4935
+ "minimum": 0,
4936
+ "example": 118
4937
+ }
4938
+ },
4939
+ "ratelimit-reset": {
4940
+ "description": "Unix timestamp (seconds) when the current window resets.",
4941
+ "schema": {
4942
+ "type": "integer",
4943
+ "example": 1700000060
4944
+ }
4945
+ },
4946
+ "ratelimit-policy": {
4947
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
4948
+ "schema": {
4949
+ "type": "string",
4950
+ "example": "120;w=60"
4951
+ }
4952
+ },
4953
+ "Cache-Control": {
4954
+ "schema": {
4955
+ "type": "string",
4956
+ "const": "no-store"
4957
+ },
4958
+ "description": "Always fresh policy metadata."
4959
+ }
4960
+ }
4961
+ },
4962
+ "400": {
4963
+ "description": "Invalid request parameters",
4964
+ "content": { "application/json": {
4965
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4966
+ "example": {
4967
+ "success": false,
4968
+ "error": {
4969
+ "code": "validation_error",
4970
+ "message": "Invalid domain format"
4971
+ }
4972
+ }
4973
+ } }
4974
+ },
4975
+ "401": {
4976
+ "description": "Invalid or missing API key",
4977
+ "content": { "application/json": {
4978
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4979
+ "example": {
4980
+ "success": false,
4981
+ "error": {
4982
+ "code": "unauthorized",
4983
+ "message": "Invalid or missing API key"
4984
+ }
4985
+ }
4986
+ } }
4987
+ },
4988
+ "403": {
4989
+ "description": "Authenticated caller lacks permission for the operation",
4990
+ "content": { "application/json": {
4991
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4992
+ "example": {
4993
+ "success": false,
4994
+ "error": {
4995
+ "code": "forbidden",
4996
+ "message": "Insufficient permissions"
4997
+ }
4998
+ }
4999
+ } }
5000
+ },
5001
+ "404": {
5002
+ "description": "Resource not found",
5003
+ "content": { "application/json": {
5004
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5005
+ "example": {
5006
+ "success": false,
5007
+ "error": {
5008
+ "code": "not_found",
5009
+ "message": "Resource not found"
5010
+ }
5011
+ }
5012
+ } }
5013
+ },
5014
+ "409": {
5015
+ "description": "contact_conflict: write precondition did not match.",
5016
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
5017
+ },
5018
+ "429": {
5019
+ "description": "Rate limit exceeded",
5020
+ "headers": { "Retry-After": {
5021
+ "schema": { "type": "integer" },
5022
+ "description": "Seconds to wait before retrying"
5023
+ } },
5024
+ "content": { "application/json": {
5025
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5026
+ "example": {
5027
+ "success": false,
5028
+ "error": {
5029
+ "code": "rate_limit_exceeded",
5030
+ "message": "Rate limit exceeded"
5031
+ }
5032
+ }
5033
+ } }
5034
+ }
5035
+ }
5036
+ }
5037
+ },
5038
+ "/agent-contacts/{agent_address}": { "get": {
5039
+ "operationId": "listAgentContacts",
5040
+ "summary": "list Agent Contacts",
5041
+ "tags": ["Contacts"],
5042
+ "security": [{ "BearerAuth": [] }],
5043
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
5044
+ "parameters": [
5045
+ {
5046
+ "name": "agent_address",
5047
+ "in": "path",
5048
+ "schema": {
5049
+ "type": "string",
5050
+ "format": "email",
5051
+ "maxLength": 254,
5052
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5053
+ },
5054
+ "required": true,
5055
+ "description": "agent_address for contacts."
5056
+ },
5057
+ {
5058
+ "name": "cursor",
5059
+ "in": "query",
5060
+ "schema": {
5061
+ "type": "string",
5062
+ "format": "email",
5063
+ "maxLength": 254,
5064
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5065
+ },
5066
+ "required": false,
5067
+ "description": "cursor for contacts."
5068
+ },
5069
+ {
5070
+ "name": "limit",
5071
+ "in": "query",
5072
+ "schema": {
5073
+ "type": "integer",
5074
+ "minimum": 1,
5075
+ "maximum": 100,
5076
+ "default": 50
5077
+ },
5078
+ "required": false,
5079
+ "description": "limit for contacts."
5080
+ }
5081
+ ],
5082
+ "responses": {
5083
+ "200": {
5084
+ "description": "Success",
5085
+ "content": { "application/json": { "schema": { "allOf": [{
5086
+ "type": "object",
5087
+ "properties": { "success": {
5088
+ "type": "boolean",
5089
+ "const": true
5090
+ } },
5091
+ "required": [
5092
+ "success",
5093
+ "data",
5094
+ "meta"
5095
+ ]
5096
+ }, {
5097
+ "type": "object",
5098
+ "properties": {
5099
+ "data": {
5100
+ "type": "array",
5101
+ "items": {
5102
+ "type": "object",
5103
+ "additionalProperties": false,
5104
+ "properties": {
5105
+ "agent_address": {
5106
+ "type": "string",
5107
+ "format": "email",
5108
+ "maxLength": 254,
5109
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5110
+ },
5111
+ "contact_address": {
5112
+ "type": "string",
5113
+ "format": "email",
5114
+ "maxLength": 254,
5115
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5116
+ },
5117
+ "purpose": {
5118
+ "type": ["string", "null"],
5119
+ "maxLength": 2e3
5120
+ },
5121
+ "notify": { "type": "boolean" },
5122
+ "notify_since": {
5123
+ "type": ["string", "null"],
5124
+ "format": "date-time"
5125
+ },
5126
+ "notification_generation": {
5127
+ "type": ["string", "null"],
5128
+ "format": "uuid"
5129
+ },
5130
+ "version": {
5131
+ "type": "string",
5132
+ "format": "uuid",
5133
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
5134
+ },
5135
+ "created_at": {
5136
+ "type": "string",
5137
+ "format": "date-time"
5138
+ },
5139
+ "updated_at": {
5140
+ "type": "string",
5141
+ "format": "date-time"
5142
+ }
5143
+ },
5144
+ "required": [
5145
+ "agent_address",
5146
+ "contact_address",
5147
+ "purpose",
5148
+ "notify",
5149
+ "notify_since",
5150
+ "notification_generation",
5151
+ "version",
5152
+ "created_at",
5153
+ "updated_at"
5154
+ ]
5155
+ }
5156
+ },
5157
+ "meta": {
5158
+ "type": "object",
5159
+ "required": ["cursor"],
5160
+ "properties": {
5161
+ "limit": { "type": "integer" },
5162
+ "cursor": { "type": ["string", "null"] }
5163
+ }
5164
+ }
5165
+ }
5166
+ }] } } },
5167
+ "headers": {
5168
+ "ratelimit-limit": {
5169
+ "description": "Maximum number of requests allowed in the current window.",
5170
+ "schema": {
5171
+ "type": "integer",
5172
+ "minimum": 1,
5173
+ "example": 120
5174
+ }
5175
+ },
5176
+ "ratelimit-remaining": {
5177
+ "description": "Remaining requests in the current window.",
5178
+ "schema": {
5179
+ "type": "integer",
5180
+ "minimum": 0,
5181
+ "example": 118
5182
+ }
5183
+ },
5184
+ "ratelimit-reset": {
5185
+ "description": "Unix timestamp (seconds) when the current window resets.",
5186
+ "schema": {
5187
+ "type": "integer",
5188
+ "example": 1700000060
5189
+ }
5190
+ },
5191
+ "ratelimit-policy": {
5192
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
5193
+ "schema": {
5194
+ "type": "string",
5195
+ "example": "120;w=60"
5196
+ }
5197
+ },
5198
+ "Cache-Control": {
5199
+ "schema": {
5200
+ "type": "string",
5201
+ "const": "no-store"
5202
+ },
5203
+ "description": "Always fresh policy metadata."
5204
+ }
5205
+ }
5206
+ },
5207
+ "400": {
5208
+ "description": "Invalid request parameters",
5209
+ "content": { "application/json": {
5210
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5211
+ "example": {
5212
+ "success": false,
5213
+ "error": {
5214
+ "code": "validation_error",
5215
+ "message": "Invalid domain format"
5216
+ }
5217
+ }
5218
+ } }
5219
+ },
5220
+ "401": {
5221
+ "description": "Invalid or missing API key",
5222
+ "content": { "application/json": {
5223
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5224
+ "example": {
5225
+ "success": false,
5226
+ "error": {
5227
+ "code": "unauthorized",
5228
+ "message": "Invalid or missing API key"
5229
+ }
5230
+ }
5231
+ } }
5232
+ },
5233
+ "403": {
5234
+ "description": "Authenticated caller lacks permission for the operation",
5235
+ "content": { "application/json": {
5236
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5237
+ "example": {
5238
+ "success": false,
5239
+ "error": {
5240
+ "code": "forbidden",
5241
+ "message": "Insufficient permissions"
5242
+ }
5243
+ }
5244
+ } }
5245
+ },
5246
+ "404": {
5247
+ "description": "Resource not found",
5248
+ "content": { "application/json": {
5249
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5250
+ "example": {
5251
+ "success": false,
5252
+ "error": {
5253
+ "code": "not_found",
5254
+ "message": "Resource not found"
5255
+ }
5256
+ }
5257
+ } }
5258
+ },
5259
+ "409": {
5260
+ "description": "contact_conflict: write precondition did not match.",
5261
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
5262
+ },
5263
+ "429": {
5264
+ "description": "Rate limit exceeded",
5265
+ "headers": { "Retry-After": {
5266
+ "schema": { "type": "integer" },
5267
+ "description": "Seconds to wait before retrying"
5268
+ } },
5269
+ "content": { "application/json": {
5270
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5271
+ "example": {
5272
+ "success": false,
5273
+ "error": {
5274
+ "code": "rate_limit_exceeded",
5275
+ "message": "Rate limit exceeded"
5276
+ }
5277
+ }
5278
+ } }
5279
+ }
5280
+ }
5281
+ } },
5282
+ "/agent-contacts/{agent_address}/{contact_address}": {
5283
+ "put": {
5284
+ "operationId": "putAgentContact",
5285
+ "summary": "put Agent Contact",
5286
+ "tags": ["Contacts"],
5287
+ "security": [{ "BearerAuth": [] }],
5288
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
5289
+ "parameters": [{
5290
+ "name": "agent_address",
5291
+ "in": "path",
5292
+ "schema": {
5293
+ "type": "string",
5294
+ "format": "email",
5295
+ "maxLength": 254,
5296
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5297
+ },
5298
+ "required": true,
5299
+ "description": "agent_address for contacts."
5300
+ }, {
5301
+ "name": "contact_address",
5302
+ "in": "path",
5303
+ "schema": {
5304
+ "type": "string",
5305
+ "format": "email",
5306
+ "maxLength": 254,
5307
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5308
+ },
5309
+ "required": true,
5310
+ "description": "contact_address for contacts."
5311
+ }],
5312
+ "requestBody": {
5313
+ "required": true,
5314
+ "content": { "application/json": { "schema": { "oneOf": [{
5315
+ "type": "object",
5316
+ "additionalProperties": false,
5317
+ "properties": {
5318
+ "purpose": {
5319
+ "type": ["string", "null"],
5320
+ "maxLength": 2e3
5321
+ },
5322
+ "notify": { "type": "boolean" },
5323
+ "if_absent": {
5324
+ "type": "boolean",
5325
+ "const": true
5326
+ }
5327
+ },
5328
+ "required": ["if_absent"]
5329
+ }, {
5330
+ "type": "object",
5331
+ "additionalProperties": false,
5332
+ "properties": {
5333
+ "purpose": {
5334
+ "type": ["string", "null"],
5335
+ "maxLength": 2e3
5336
+ },
5337
+ "notify": { "type": "boolean" },
5338
+ "if_version": {
5339
+ "type": "string",
5340
+ "format": "uuid",
5341
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
5342
+ }
5343
+ },
5344
+ "required": ["if_version"]
5345
+ }] } } }
5346
+ },
5347
+ "responses": {
5348
+ "200": {
5349
+ "description": "Success",
5350
+ "content": { "application/json": { "schema": { "allOf": [{
5351
+ "type": "object",
5352
+ "properties": { "success": {
5353
+ "type": "boolean",
5354
+ "const": true
5355
+ } },
5356
+ "required": ["success", "data"]
5357
+ }, {
5358
+ "type": "object",
5359
+ "properties": { "data": {
5360
+ "type": "object",
5361
+ "additionalProperties": false,
5362
+ "properties": {
5363
+ "agent_address": {
5364
+ "type": "string",
5365
+ "format": "email",
5366
+ "maxLength": 254,
5367
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5368
+ },
5369
+ "contact_address": {
5370
+ "type": "string",
5371
+ "format": "email",
5372
+ "maxLength": 254,
5373
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5374
+ },
5375
+ "purpose": {
5376
+ "type": ["string", "null"],
5377
+ "maxLength": 2e3
5378
+ },
5379
+ "notify": { "type": "boolean" },
5380
+ "notify_since": {
5381
+ "type": ["string", "null"],
5382
+ "format": "date-time"
5383
+ },
5384
+ "notification_generation": {
5385
+ "type": ["string", "null"],
5386
+ "format": "uuid"
5387
+ },
5388
+ "version": {
5389
+ "type": "string",
5390
+ "format": "uuid",
5391
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
5392
+ },
5393
+ "created_at": {
5394
+ "type": "string",
5395
+ "format": "date-time"
5396
+ },
5397
+ "updated_at": {
5398
+ "type": "string",
5399
+ "format": "date-time"
5400
+ }
5401
+ },
5402
+ "required": [
5403
+ "agent_address",
5404
+ "contact_address",
5405
+ "purpose",
5406
+ "notify",
5407
+ "notify_since",
5408
+ "notification_generation",
5409
+ "version",
5410
+ "created_at",
5411
+ "updated_at"
5412
+ ]
5413
+ } }
5414
+ }] } } },
5415
+ "headers": {
5416
+ "ratelimit-limit": {
5417
+ "description": "Maximum number of requests allowed in the current window.",
5418
+ "schema": {
5419
+ "type": "integer",
5420
+ "minimum": 1,
5421
+ "example": 120
5422
+ }
5423
+ },
5424
+ "ratelimit-remaining": {
5425
+ "description": "Remaining requests in the current window.",
5426
+ "schema": {
5427
+ "type": "integer",
5428
+ "minimum": 0,
5429
+ "example": 118
5430
+ }
5431
+ },
5432
+ "ratelimit-reset": {
5433
+ "description": "Unix timestamp (seconds) when the current window resets.",
5434
+ "schema": {
5435
+ "type": "integer",
5436
+ "example": 1700000060
5437
+ }
5438
+ },
5439
+ "ratelimit-policy": {
5440
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
5441
+ "schema": {
5442
+ "type": "string",
5443
+ "example": "120;w=60"
5444
+ }
5445
+ },
5446
+ "Cache-Control": {
5447
+ "schema": {
5448
+ "type": "string",
5449
+ "const": "no-store"
5450
+ },
5451
+ "description": "Always fresh policy metadata."
5452
+ }
5453
+ }
5454
+ },
5455
+ "400": {
5456
+ "description": "Invalid request parameters",
5457
+ "content": { "application/json": {
5458
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5459
+ "example": {
5460
+ "success": false,
5461
+ "error": {
5462
+ "code": "validation_error",
5463
+ "message": "Invalid domain format"
5464
+ }
5465
+ }
5466
+ } }
5467
+ },
5468
+ "401": {
5469
+ "description": "Invalid or missing API key",
5470
+ "content": { "application/json": {
5471
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5472
+ "example": {
5473
+ "success": false,
5474
+ "error": {
5475
+ "code": "unauthorized",
5476
+ "message": "Invalid or missing API key"
5477
+ }
5478
+ }
5479
+ } }
5480
+ },
5481
+ "403": {
5482
+ "description": "Authenticated caller lacks permission for the operation",
5483
+ "content": { "application/json": {
5484
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5485
+ "example": {
5486
+ "success": false,
5487
+ "error": {
5488
+ "code": "forbidden",
5489
+ "message": "Insufficient permissions"
5490
+ }
5491
+ }
5492
+ } }
5493
+ },
5494
+ "404": {
5495
+ "description": "Resource not found",
5496
+ "content": { "application/json": {
5497
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5498
+ "example": {
5499
+ "success": false,
5500
+ "error": {
5501
+ "code": "not_found",
5502
+ "message": "Resource not found"
5503
+ }
5504
+ }
5505
+ } }
5506
+ },
5507
+ "409": {
5508
+ "description": "contact_conflict: write precondition did not match.",
5509
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
5510
+ },
5511
+ "429": {
5512
+ "description": "Rate limit exceeded",
5513
+ "headers": { "Retry-After": {
5514
+ "schema": { "type": "integer" },
5515
+ "description": "Seconds to wait before retrying"
5516
+ } },
5517
+ "content": { "application/json": {
5518
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5519
+ "example": {
5520
+ "success": false,
5521
+ "error": {
5522
+ "code": "rate_limit_exceeded",
5523
+ "message": "Rate limit exceeded"
5524
+ }
5525
+ }
5526
+ } }
5527
+ }
5528
+ }
5529
+ },
5530
+ "delete": {
5531
+ "operationId": "deleteAgentContact",
5532
+ "summary": "delete Agent Contact",
5533
+ "tags": ["Contacts"],
5534
+ "security": [{ "BearerAuth": [] }],
5535
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
5536
+ "parameters": [
5537
+ {
5538
+ "name": "agent_address",
5539
+ "in": "path",
5540
+ "schema": {
5541
+ "type": "string",
5542
+ "format": "email",
5543
+ "maxLength": 254,
5544
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5545
+ },
5546
+ "required": true,
5547
+ "description": "agent_address for contacts."
5548
+ },
5549
+ {
5550
+ "name": "contact_address",
5551
+ "in": "path",
5552
+ "schema": {
5553
+ "type": "string",
5554
+ "format": "email",
5555
+ "maxLength": 254,
5556
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
5557
+ },
5558
+ "required": true,
5559
+ "description": "contact_address for contacts."
5560
+ },
5561
+ {
5562
+ "name": "if_version",
5563
+ "in": "query",
5564
+ "schema": {
5565
+ "type": "string",
5566
+ "format": "uuid",
5567
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
5568
+ },
5569
+ "required": true,
5570
+ "description": "if_version for contacts."
5571
+ }
5572
+ ],
5573
+ "responses": {
5574
+ "200": {
5575
+ "description": "Success",
5576
+ "content": { "application/json": { "schema": { "allOf": [{
5577
+ "type": "object",
5578
+ "properties": { "success": {
5579
+ "type": "boolean",
5580
+ "const": true
5581
+ } },
5582
+ "required": ["success", "data"]
5583
+ }, {
5584
+ "type": "object",
5585
+ "properties": { "data": {
5586
+ "type": "object",
5587
+ "additionalProperties": false,
5588
+ "properties": { "deleted": { "type": "boolean" } },
5589
+ "required": ["deleted"]
5590
+ } }
5591
+ }] } } },
5592
+ "headers": {
5593
+ "ratelimit-limit": {
5594
+ "description": "Maximum number of requests allowed in the current window.",
5595
+ "schema": {
5596
+ "type": "integer",
5597
+ "minimum": 1,
5598
+ "example": 120
5599
+ }
5600
+ },
5601
+ "ratelimit-remaining": {
5602
+ "description": "Remaining requests in the current window.",
5603
+ "schema": {
5604
+ "type": "integer",
5605
+ "minimum": 0,
5606
+ "example": 118
5607
+ }
5608
+ },
5609
+ "ratelimit-reset": {
5610
+ "description": "Unix timestamp (seconds) when the current window resets.",
5611
+ "schema": {
5612
+ "type": "integer",
5613
+ "example": 1700000060
5614
+ }
5615
+ },
5616
+ "ratelimit-policy": {
5617
+ "description": "Rate-limit policy in `limit;w=seconds` format, e.g. `120;w=60`.",
5618
+ "schema": {
5619
+ "type": "string",
5620
+ "example": "120;w=60"
5621
+ }
5622
+ },
5623
+ "Cache-Control": {
5624
+ "schema": {
5625
+ "type": "string",
5626
+ "const": "no-store"
5627
+ },
5628
+ "description": "Always fresh policy metadata."
5629
+ }
5630
+ }
5631
+ },
5632
+ "400": {
5633
+ "description": "Invalid request parameters",
5634
+ "content": { "application/json": {
5635
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5636
+ "example": {
5637
+ "success": false,
5638
+ "error": {
5639
+ "code": "validation_error",
5640
+ "message": "Invalid domain format"
5641
+ }
5642
+ }
5643
+ } }
5644
+ },
5645
+ "401": {
5646
+ "description": "Invalid or missing API key",
5647
+ "content": { "application/json": {
5648
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5649
+ "example": {
5650
+ "success": false,
5651
+ "error": {
5652
+ "code": "unauthorized",
5653
+ "message": "Invalid or missing API key"
5654
+ }
5655
+ }
5656
+ } }
5657
+ },
5658
+ "403": {
5659
+ "description": "Authenticated caller lacks permission for the operation",
5660
+ "content": { "application/json": {
5661
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5662
+ "example": {
5663
+ "success": false,
5664
+ "error": {
5665
+ "code": "forbidden",
5666
+ "message": "Insufficient permissions"
5667
+ }
5668
+ }
5669
+ } }
5670
+ },
5671
+ "404": {
5672
+ "description": "Resource not found",
5673
+ "content": { "application/json": {
5674
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5675
+ "example": {
5676
+ "success": false,
5677
+ "error": {
5678
+ "code": "not_found",
5679
+ "message": "Resource not found"
5680
+ }
5681
+ }
5682
+ } }
5683
+ },
5684
+ "409": {
5685
+ "description": "contact_conflict: write precondition did not match.",
5686
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
5687
+ },
5688
+ "429": {
5689
+ "description": "Rate limit exceeded",
5690
+ "headers": { "Retry-After": {
5691
+ "schema": { "type": "integer" },
5692
+ "description": "Seconds to wait before retrying"
5693
+ } },
5694
+ "content": { "application/json": {
5695
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5696
+ "example": {
5697
+ "success": false,
5698
+ "error": {
5699
+ "code": "rate_limit_exceeded",
5700
+ "message": "Rate limit exceeded"
5701
+ }
5702
+ }
5703
+ } }
5704
+ }
5705
+ }
5706
+ }
5707
+ },
5708
+ "/agent-connections/claim": { "post": {
5709
+ "operationId": "claimAgentConnection",
5710
+ "tags": ["Agent Connections"],
5711
+ "summary": "claim Agent Connection",
5712
+ "description": "Address-bound external runtime pairing. Management operations require an organization owner or admin session or OAuth token; members and organization API keys cannot manage connections. Claim is authorized only by its one-use invitation. Connected means a real challenge was received and a reply sent by the current bound credential was received back. Invitations expire after 15 minutes. Reconnection preserves the address and revokes previous credentials. Status responses contain no credentials. Runtime credentials allow only address-scoped mail operations, organization note reads and own-address note writes. The credential is returned once. If the claim response is lost or the outcome is unknown, request a fresh owner invitation instead of retrying the consumed invitation.",
5713
+ "security": [],
5714
+ "parameters": [{
5715
+ "name": "Idempotency-Key",
5716
+ "in": "header",
5717
+ "required": false,
5718
+ "description": "This header does not enable credential replay for this one-use claim. If the response is lost or the outcome is unknown, request a fresh owner invitation. Do not assume that retrying the same key or payload can recover the returned credential.",
5719
+ "schema": {
5720
+ "type": "string",
5721
+ "minLength": 1,
5722
+ "maxLength": 255
5723
+ }
5724
+ }],
5725
+ "responses": {
5726
+ "200": {
5727
+ "description": "Success",
5728
+ "headers": { "Cache-Control": {
5729
+ "description": "Credentials and status must not be cached.",
5730
+ "schema": {
5731
+ "type": "string",
5732
+ "const": "no-store"
5733
+ }
5734
+ } },
5735
+ "content": { "application/json": { "schema": {
5736
+ "type": "object",
5737
+ "required": ["success", "data"],
5738
+ "properties": {
5739
+ "success": {
5740
+ "const": true,
5741
+ "type": "boolean"
5742
+ },
5743
+ "data": {
5744
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
5745
+ "type": "object",
5746
+ "properties": {
5747
+ "connection": {
5748
+ "type": "object",
5749
+ "properties": {
5750
+ "address": {
5751
+ "type": "string",
5752
+ "format": "email",
5753
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
5754
+ },
5755
+ "name": {
5756
+ "type": "string",
5757
+ "minLength": 1,
5758
+ "maxLength": 80
5759
+ },
5760
+ "owner_address": {
5761
+ "type": "string",
5762
+ "format": "email",
5763
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
5764
+ },
5765
+ "status": {
5766
+ "type": "string",
5767
+ "enum": [
5768
+ "pending",
5769
+ "claimed",
5770
+ "connected",
5771
+ "revoked"
5772
+ ]
5773
+ },
5774
+ "created_at": {
5775
+ "type": "string",
5776
+ "format": "date-time",
5777
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
5778
+ },
5779
+ "updated_at": {
5780
+ "type": "string",
5781
+ "format": "date-time",
5782
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
5783
+ },
5784
+ "claimed_at": { "anyOf": [{
5785
+ "type": "string",
5786
+ "format": "date-time",
5787
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
5788
+ }, { "type": "null" }] },
5789
+ "verified_at": { "anyOf": [{
5790
+ "type": "string",
5791
+ "format": "date-time",
5792
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
5793
+ }, { "type": "null" }] },
5794
+ "last_seen_at": { "anyOf": [{
5795
+ "type": "string",
5796
+ "format": "date-time",
5797
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
5798
+ }, { "type": "null" }] }
5799
+ },
5800
+ "required": [
5801
+ "address",
5802
+ "name",
5803
+ "owner_address",
5804
+ "status",
5805
+ "created_at",
5806
+ "updated_at",
5807
+ "claimed_at",
5808
+ "verified_at",
5809
+ "last_seen_at"
5810
+ ],
5811
+ "additionalProperties": false
5812
+ },
5813
+ "org_id": {
5814
+ "type": "string",
5815
+ "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
5816
+ },
5817
+ "owner_address": {
5818
+ "type": "string",
5819
+ "format": "email",
5820
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
5821
+ },
5822
+ "api_key": { "type": "string" },
5823
+ "api_base_url": {
5824
+ "type": "string",
5825
+ "format": "uri"
5826
+ }
5827
+ },
5828
+ "required": [
5829
+ "connection",
5830
+ "org_id",
5831
+ "owner_address",
5832
+ "api_key",
5833
+ "api_base_url"
5834
+ ],
5835
+ "additionalProperties": false
5836
+ }
5837
+ }
5838
+ } } }
5839
+ },
5840
+ "400": {
5841
+ "description": "Invalid request parameters",
5842
+ "content": { "application/json": {
5843
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5844
+ "example": {
5845
+ "success": false,
5846
+ "error": {
5847
+ "code": "validation_error",
5848
+ "message": "Invalid domain format"
5849
+ }
5850
+ }
5851
+ } }
5852
+ },
5853
+ "401": {
5854
+ "description": "Invalid or missing API key",
5855
+ "content": { "application/json": {
5856
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5857
+ "example": {
5858
+ "success": false,
5859
+ "error": {
5860
+ "code": "unauthorized",
5861
+ "message": "Invalid or missing API key"
5862
+ }
5863
+ }
5864
+ } }
5865
+ },
5866
+ "403": {
5867
+ "description": "Authenticated caller lacks permission for the operation",
5868
+ "content": { "application/json": {
5869
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5870
+ "example": {
5871
+ "success": false,
5872
+ "error": {
5873
+ "code": "forbidden",
5874
+ "message": "Insufficient permissions"
5875
+ }
5876
+ }
5877
+ } }
5878
+ },
5879
+ "404": {
5880
+ "description": "Resource not found",
5881
+ "content": { "application/json": {
5882
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5883
+ "example": {
5884
+ "success": false,
5885
+ "error": {
5886
+ "code": "not_found",
5887
+ "message": "Resource not found"
5888
+ }
5889
+ }
5890
+ } }
5891
+ },
5892
+ "409": {
5893
+ "description": "The request conflicts with the current state of the resource",
5894
+ "content": { "application/json": {
5895
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5896
+ "example": {
5897
+ "success": false,
5898
+ "error": {
5899
+ "code": "conflict",
5900
+ "message": "settlement already in progress"
5901
+ }
5902
+ }
5903
+ } }
5904
+ },
5905
+ "429": {
5906
+ "description": "Rate limit exceeded",
5907
+ "headers": { "Retry-After": {
5908
+ "schema": { "type": "integer" },
5909
+ "description": "Seconds to wait before retrying"
5910
+ } },
5911
+ "content": { "application/json": {
5912
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
5913
+ "example": {
5914
+ "success": false,
5915
+ "error": {
5916
+ "code": "rate_limit_exceeded",
5917
+ "message": "Rate limit exceeded"
5918
+ }
5919
+ }
5920
+ } }
5921
+ }
5922
+ },
5923
+ "requestBody": {
5924
+ "required": true,
5925
+ "content": { "application/json": { "schema": {
5926
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
5927
+ "type": "object",
5928
+ "properties": { "token": {
5929
+ "type": "string",
5930
+ "minLength": 32,
5931
+ "maxLength": 256
5932
+ } },
5933
+ "required": ["token"],
5934
+ "additionalProperties": false
5935
+ } } }
5936
+ }
5937
+ } }
5938
+ },
5939
+ "components": {
5940
+ "securitySchemes": {
5941
+ "BearerAuth": {
5942
+ "type": "http",
5943
+ "scheme": "bearer",
5944
+ "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
5945
+ },
5946
+ "DownloadToken": {
5947
+ "type": "apiKey",
5948
+ "in": "query",
5949
+ "name": "token",
5950
+ "description": "Signed download token provided in webhook payloads"
5951
+ }
5952
+ },
5953
+ "parameters": {
5954
+ "AttachmentPartIndex": {
5955
+ "name": "part_index",
5956
+ "in": "path",
5957
+ "required": true,
5958
+ "description": "The attachment metadata `part_index`, not its offset in the attachments array",
5959
+ "schema": {
5960
+ "type": "integer",
5961
+ "format": "int32",
5962
+ "minimum": 0,
5963
+ "maximum": 2147483647
5964
+ }
5965
+ },
5966
+ "ResourceId": {
5967
+ "name": "id",
5968
+ "in": "path",
5969
+ "required": true,
5970
+ "schema": {
5971
+ "type": "string",
5972
+ "format": "uuid"
5973
+ },
5974
+ "description": "Resource UUID"
5975
+ },
5976
+ "IdempotencyKey": {
5977
+ "name": "idempotency-key",
5978
+ "in": "header",
5979
+ "required": false,
5980
+ "schema": {
5981
+ "type": "string",
5982
+ "maxLength": 255
5983
+ },
5984
+ "description": "Optional idempotency key. Retrying a request with the same key returns\nthe original result instead of repeating the side effect (for\n`createEmailChallenge`, re-sending the email).\n"
5985
+ },
5986
+ "Cursor": {
5987
+ "name": "cursor",
5988
+ "in": "query",
5989
+ "schema": { "type": "string" },
5990
+ "description": "Pagination cursor from a previous response's `meta.cursor` field.\nFormat: `{ISO-datetime}|{id}`\n"
5991
+ },
5992
+ "Limit": {
5993
+ "name": "limit",
5994
+ "in": "query",
5995
+ "schema": {
5996
+ "type": "integer",
5997
+ "minimum": 1,
5998
+ "maximum": 100,
5999
+ "default": 50
6000
+ },
6001
+ "description": "Number of results per page"
6002
+ },
6003
+ "MemoryKeyQuery": {
6004
+ "name": "key",
6005
+ "in": "query",
6006
+ "required": true,
6007
+ "description": "Memory key. Must be at most 512 UTF-8 bytes.",
6008
+ "schema": {
6009
+ "type": "string",
6010
+ "minLength": 1,
6011
+ "maxLength": 512
6012
+ }
6013
+ },
6014
+ "MemoryScopeQueryType": {
6015
+ "name": "scope_type",
6016
+ "in": "query",
6017
+ "required": false,
6018
+ "description": "Explicit scope type. Omit to use automatic scope resolution. Pass\n`function` with `scope_id=<function-id>`, or `org` with no `scope_id`.\n",
6019
+ "schema": {
6020
+ "type": "string",
6021
+ "enum": ["org", "function"]
6022
+ }
6023
+ },
6024
+ "MemoryScopeId": {
6025
+ "name": "scope_id",
6026
+ "in": "query",
6027
+ "required": false,
6028
+ "description": "Function id UUID when `scope_type=function`. Not valid with\n`scope_type=org`.\n",
6029
+ "schema": {
6030
+ "type": "string",
6031
+ "format": "uuid"
6032
+ }
6033
+ }
6034
+ },
6035
+ "responses": {
6036
+ "AttachmentPart": {
6037
+ "description": "Original attachment bytes; never a JSON envelope or a base64 string",
6038
+ "content": { "application/octet-stream": { "schema": {
6039
+ "type": "string",
6040
+ "format": "binary"
6041
+ } } },
6042
+ "headers": {
6043
+ "X-Content-SHA256": {
6044
+ "description": "SHA-256 hex digest of the original bytes",
6045
+ "schema": {
6046
+ "type": "string",
6047
+ "pattern": "^[a-fA-F0-9]{64}$"
6048
+ }
6049
+ },
6050
+ "Content-Disposition": {
6051
+ "description": "Safe attachment disposition with a sanitized filename",
6052
+ "schema": { "type": "string" }
6053
+ },
6054
+ "Cache-Control": {
6055
+ "description": "Attachment responses are private and must not be stored by caches",
6056
+ "schema": {
6057
+ "type": "string",
6058
+ "example": "private, no-store"
6059
+ }
6060
+ }
6061
+ }
6062
+ },
6063
+ "PullContentGone": {
6064
+ "description": "Queued content is no longer available",
6065
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
6066
+ },
6067
+ "RequestCanceled": {
6068
+ "description": "Request was canceled",
6069
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
6070
+ },
6071
+ "PullUnavailable": {
6072
+ "description": "Local receiving is unavailable",
6073
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
6074
+ },
6075
+ "Unauthorized": {
6076
+ "description": "Invalid or missing API key",
6077
+ "content": { "application/json": {
6078
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
6079
+ "example": {
6080
+ "success": false,
6081
+ "error": {
6082
+ "code": "unauthorized",
6083
+ "message": "Invalid or missing API key"
6084
+ }
6085
+ }
6086
+ } }
6087
+ },
6088
+ "Forbidden": {
6089
+ "description": "Authenticated caller lacks permission for the operation",
6090
+ "content": { "application/json": {
6091
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
6092
+ "example": {
6093
+ "success": false,
6094
+ "error": {
6095
+ "code": "forbidden",
6096
+ "message": "Insufficient permissions"
6097
+ }
6098
+ }
6099
+ } }
6100
+ },
6101
+ "NotFound": {
6102
+ "description": "Resource not found",
6103
+ "content": { "application/json": {
6104
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
6105
+ "example": {
6106
+ "success": false,
6107
+ "error": {
6108
+ "code": "not_found",
6109
+ "message": "Resource not found"
6110
+ }
6111
+ }
6112
+ } }
6113
+ },
6114
+ "ValidationError": {
6115
+ "description": "Invalid request parameters",
6116
+ "content": { "application/json": {
6117
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
6118
+ "example": {
6119
+ "success": false,
6120
+ "error": {
6121
+ "code": "validation_error",
4447
6122
  "message": "Invalid domain format"
4448
6123
  }
4449
6124
  }
@@ -5473,7 +7148,15 @@ const openapiDocument = {
5473
7148
  "credit_code_not_eligible",
5474
7149
  "credit_code_balance_cap",
5475
7150
  "rate_limited",
5476
- "service_unavailable"
7151
+ "service_unavailable",
7152
+ "connection_domain_unavailable",
7153
+ "connection_address_unavailable",
7154
+ "connection_owner_address_invalid",
7155
+ "connection_invitation_unavailable",
7156
+ "agent_connection_scope_forbidden",
7157
+ "address_note_conflict",
7158
+ "address_not_controlled",
7159
+ "contact_conflict"
5477
7160
  ]
5478
7161
  },
5479
7162
  "message": { "type": "string" },
@@ -11791,15 +13474,228 @@ const operationManifest = [
11791
13474
  {
11792
13475
  "binaryResponse": false,
11793
13476
  "bodyRequired": false,
11794
- "command": "get-account",
11795
- "description": null,
13477
+ "command": "get-account",
13478
+ "description": null,
13479
+ "hasJsonBody": false,
13480
+ "method": "GET",
13481
+ "operationId": "getAccount",
13482
+ "path": "/account",
13483
+ "pathParams": [],
13484
+ "queryParams": [],
13485
+ "requestSchema": null,
13486
+ "responseSchema": {
13487
+ "type": "object",
13488
+ "properties": {
13489
+ "id": {
13490
+ "type": "string",
13491
+ "format": "uuid"
13492
+ },
13493
+ "email": { "type": "string" },
13494
+ "plan": { "type": "string" },
13495
+ "limits": {
13496
+ "type": "object",
13497
+ "description": "Plan-derived quota limits for an account.",
13498
+ "properties": {
13499
+ "storage_mb": { "type": "number" },
13500
+ "send_per_hour": { "type": "number" },
13501
+ "send_per_day": { "type": "number" },
13502
+ "api_per_minute": { "type": "number" },
13503
+ "webhooks_max_global": { "type": ["number", "null"] },
13504
+ "webhooks_per_domain": { "type": "boolean" },
13505
+ "filters_per_domain": { "type": "boolean" },
13506
+ "spam_thresholds_per_domain": { "type": "boolean" }
13507
+ },
13508
+ "required": [
13509
+ "storage_mb",
13510
+ "send_per_hour",
13511
+ "send_per_day",
13512
+ "api_per_minute",
13513
+ "webhooks_max_global",
13514
+ "webhooks_per_domain",
13515
+ "filters_per_domain",
13516
+ "spam_thresholds_per_domain"
13517
+ ]
13518
+ },
13519
+ "entitlements": {
13520
+ "type": "array",
13521
+ "items": { "type": "string" },
13522
+ "description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
13523
+ },
13524
+ "managed_inbox_address": {
13525
+ "type": ["string", "null"],
13526
+ "description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
13527
+ },
13528
+ "created_at": {
13529
+ "type": "string",
13530
+ "format": "date-time"
13531
+ },
13532
+ "onboarding_completed": { "type": "boolean" },
13533
+ "onboarding_step": { "type": ["string", "null"] },
13534
+ "stripe_subscription_status": { "type": ["string", "null"] },
13535
+ "subscription_current_period_end": {
13536
+ "type": ["string", "null"],
13537
+ "format": "date-time"
13538
+ },
13539
+ "subscription_cancel_at_period_end": { "type": ["boolean", "null"] },
13540
+ "spam_threshold": {
13541
+ "type": ["number", "null"],
13542
+ "minimum": 0,
13543
+ "maximum": 15
13544
+ },
13545
+ "discard_content_on_webhook_confirmed": { "type": "boolean" },
13546
+ "webhook_secret_rotated_at": {
13547
+ "type": ["string", "null"],
13548
+ "format": "date-time"
13549
+ }
13550
+ },
13551
+ "required": [
13552
+ "id",
13553
+ "email",
13554
+ "plan",
13555
+ "limits",
13556
+ "entitlements",
13557
+ "managed_inbox_address",
13558
+ "created_at",
13559
+ "discard_content_on_webhook_confirmed"
13560
+ ]
13561
+ },
13562
+ "sdkName": "getAccount",
13563
+ "summary": "Get account info",
13564
+ "tag": "Account",
13565
+ "tagCommand": "account"
13566
+ },
13567
+ {
13568
+ "binaryResponse": false,
13569
+ "bodyRequired": false,
13570
+ "command": "get-storage-stats",
13571
+ "description": null,
13572
+ "hasJsonBody": false,
13573
+ "method": "GET",
13574
+ "operationId": "getStorageStats",
13575
+ "path": "/account/storage",
13576
+ "pathParams": [],
13577
+ "queryParams": [],
13578
+ "requestSchema": null,
13579
+ "responseSchema": {
13580
+ "type": "object",
13581
+ "properties": {
13582
+ "used_bytes": {
13583
+ "type": "integer",
13584
+ "description": "Total storage used in bytes"
13585
+ },
13586
+ "used_kb": {
13587
+ "type": "number",
13588
+ "description": "Total storage used in kilobytes (1 decimal)"
13589
+ },
13590
+ "used_mb": {
13591
+ "type": "number",
13592
+ "description": "Total storage used in megabytes (2 decimals)"
13593
+ },
13594
+ "quota_mb": {
13595
+ "type": "number",
13596
+ "description": "Storage quota in megabytes (based on plan)"
13597
+ },
13598
+ "percentage": {
13599
+ "type": "number",
13600
+ "description": "Percentage of quota used (1 decimal)"
13601
+ },
13602
+ "emails_count": {
13603
+ "type": "integer",
13604
+ "description": "Number of stored emails"
13605
+ }
13606
+ },
13607
+ "required": [
13608
+ "used_bytes",
13609
+ "used_kb",
13610
+ "used_mb",
13611
+ "quota_mb",
13612
+ "percentage",
13613
+ "emails_count"
13614
+ ]
13615
+ },
13616
+ "sdkName": "getStorageStats",
13617
+ "summary": "Get storage usage",
13618
+ "tag": "Account",
13619
+ "tagCommand": "account"
13620
+ },
13621
+ {
13622
+ "binaryResponse": false,
13623
+ "bodyRequired": false,
13624
+ "command": "get-webhook-secret",
13625
+ "description": "Returns the webhook signing secret for your account. If no\nsecret exists yet, one is generated automatically on first\naccess.\n\nSigning is account-scoped, not per-endpoint. Every webhook\ndelivery from any of your registered endpoints is signed\nwith this single secret. Rotate via\n`POST /account/webhook-secret/rotate`.\n\n**Secret format**: the returned string looks base64-shaped\n(e.g. `XNHBBW8VqoBjRfNs1tkZj11jTk...`) but is NOT base64.\nUse it AS-IS as a UTF-8 string when computing HMAC over a\ndelivery body. Base64-decoding before HMAC will silently\nproduce mismatched signatures.\n\nSee the API-level \"Webhook signing\" section for the full\nwire format (header name, signed string shape, hash algo,\ntolerance) including a language-agnostic verification\nrecipe.\n",
11796
13626
  "hasJsonBody": false,
11797
13627
  "method": "GET",
11798
- "operationId": "getAccount",
11799
- "path": "/account",
13628
+ "operationId": "getWebhookSecret",
13629
+ "path": "/account/webhook-secret",
13630
+ "pathParams": [],
13631
+ "queryParams": [],
13632
+ "requestSchema": null,
13633
+ "responseSchema": {
13634
+ "type": "object",
13635
+ "properties": { "secret": {
13636
+ "type": "string",
13637
+ "description": "The webhook signing secret value"
13638
+ } },
13639
+ "required": ["secret"]
13640
+ },
13641
+ "sdkName": "getWebhookSecret",
13642
+ "summary": "Get webhook signing secret",
13643
+ "tag": "Account",
13644
+ "tagCommand": "account"
13645
+ },
13646
+ {
13647
+ "binaryResponse": false,
13648
+ "bodyRequired": false,
13649
+ "command": "rotate-webhook-secret",
13650
+ "description": "Generates a new webhook signing secret, replacing the current one.\nRate limited to once per 60 minutes.\n",
13651
+ "hasJsonBody": false,
13652
+ "method": "POST",
13653
+ "operationId": "rotateWebhookSecret",
13654
+ "path": "/account/webhook-secret/rotate",
11800
13655
  "pathParams": [],
11801
13656
  "queryParams": [],
11802
13657
  "requestSchema": null,
13658
+ "responseSchema": {
13659
+ "type": "object",
13660
+ "properties": { "secret": {
13661
+ "type": "string",
13662
+ "description": "The webhook signing secret value"
13663
+ } },
13664
+ "required": ["secret"]
13665
+ },
13666
+ "sdkName": "rotateWebhookSecret",
13667
+ "summary": "Rotate webhook signing secret",
13668
+ "tag": "Account",
13669
+ "tagCommand": "account"
13670
+ },
13671
+ {
13672
+ "binaryResponse": false,
13673
+ "bodyRequired": true,
13674
+ "command": "update-account",
13675
+ "description": null,
13676
+ "hasJsonBody": true,
13677
+ "method": "PATCH",
13678
+ "operationId": "updateAccount",
13679
+ "path": "/account",
13680
+ "pathParams": [],
13681
+ "queryParams": [],
13682
+ "requestSchema": {
13683
+ "type": "object",
13684
+ "additionalProperties": false,
13685
+ "properties": {
13686
+ "spam_threshold": {
13687
+ "type": ["number", "null"],
13688
+ "minimum": 0,
13689
+ "maximum": 15,
13690
+ "description": "Global spam score threshold (0-15). Emails scoring above this are rejected. Set to null to disable."
13691
+ },
13692
+ "discard_content_on_webhook_confirmed": {
13693
+ "type": "boolean",
13694
+ "description": "Whether to discard email content after the webhook endpoint confirms receipt."
13695
+ }
13696
+ },
13697
+ "minProperties": 1
13698
+ },
11803
13699
  "responseSchema": {
11804
13700
  "type": "object",
11805
13701
  "properties": {
@@ -11809,6 +13705,73 @@ const operationManifest = [
11809
13705
  },
11810
13706
  "email": { "type": "string" },
11811
13707
  "plan": { "type": "string" },
13708
+ "spam_threshold": {
13709
+ "type": ["number", "null"],
13710
+ "minimum": 0,
13711
+ "maximum": 15
13712
+ },
13713
+ "discard_content_on_webhook_confirmed": { "type": "boolean" }
13714
+ },
13715
+ "required": [
13716
+ "id",
13717
+ "email",
13718
+ "plan",
13719
+ "discard_content_on_webhook_confirmed"
13720
+ ]
13721
+ },
13722
+ "sdkName": "updateAccount",
13723
+ "summary": "Update account settings",
13724
+ "tag": "Account",
13725
+ "tagCommand": "account"
13726
+ },
13727
+ {
13728
+ "binaryResponse": false,
13729
+ "bodyRequired": true,
13730
+ "command": "create-agent-account",
13731
+ "description": "Creates an emailless agent account without authentication and returns a\none-time API key (prefixed `prim_`) plus a provisioned managed inbox.\nThe account is on the `agent` plan: reply-only (it can send only to\naddresses that have already sent it authenticated mail) with tight send\nlimits. Use the returned `api_key` as a Bearer token on later calls. The\naccount can be upgraded to a full developer account by confirming an\nemail through the claim flow. This endpoint does not require an API key.\n",
13732
+ "hasJsonBody": true,
13733
+ "method": "POST",
13734
+ "operationId": "createAgentAccount",
13735
+ "path": "/agent/accounts",
13736
+ "pathParams": [],
13737
+ "queryParams": [],
13738
+ "requestSchema": {
13739
+ "type": "object",
13740
+ "additionalProperties": false,
13741
+ "properties": {
13742
+ "terms_accepted": {
13743
+ "type": "boolean",
13744
+ "enum": [true],
13745
+ "description": "Must be true to accept the Terms of Service and Privacy Policy."
13746
+ },
13747
+ "device_name": {
13748
+ "type": "string",
13749
+ "minLength": 1,
13750
+ "maxLength": 80,
13751
+ "description": "Optional label for the device or agent creating the account."
13752
+ }
13753
+ },
13754
+ "required": ["terms_accepted"]
13755
+ },
13756
+ "responseSchema": {
13757
+ "type": "object",
13758
+ "properties": {
13759
+ "api_key": {
13760
+ "type": "string",
13761
+ "description": "One-time API key (prefixed `prim_`). Shown once; store it securely."
13762
+ },
13763
+ "org_id": {
13764
+ "type": "string",
13765
+ "format": "uuid"
13766
+ },
13767
+ "address": {
13768
+ "type": ["string", "null"],
13769
+ "description": "Provisioned managed inbox FQDN, or null if the inbox publish was deferred."
13770
+ },
13771
+ "plan": {
13772
+ "type": "string",
13773
+ "enum": ["agent"]
13774
+ },
11812
13775
  "limits": {
11813
13776
  "type": "object",
11814
13777
  "description": "Plan-derived quota limits for an account.",
@@ -11833,261 +13796,286 @@ const operationManifest = [
11833
13796
  "spam_thresholds_per_domain"
11834
13797
  ]
11835
13798
  },
11836
- "entitlements": {
11837
- "type": "array",
11838
- "items": { "type": "string" },
11839
- "description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
11840
- },
11841
- "managed_inbox_address": {
11842
- "type": ["string", "null"],
11843
- "description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
11844
- },
11845
- "created_at": {
11846
- "type": "string",
11847
- "format": "date-time"
11848
- },
11849
- "onboarding_completed": { "type": "boolean" },
11850
- "onboarding_step": { "type": ["string", "null"] },
11851
- "stripe_subscription_status": { "type": ["string", "null"] },
11852
- "subscription_current_period_end": {
11853
- "type": ["string", "null"],
11854
- "format": "date-time"
11855
- },
11856
- "subscription_cancel_at_period_end": { "type": ["boolean", "null"] },
11857
- "spam_threshold": {
11858
- "type": ["number", "null"],
11859
- "minimum": 0,
11860
- "maximum": 15
11861
- },
11862
- "discard_content_on_webhook_confirmed": { "type": "boolean" },
11863
- "webhook_secret_rotated_at": {
11864
- "type": ["string", "null"],
11865
- "format": "date-time"
13799
+ "upgrade": {
13800
+ "type": "object",
13801
+ "description": "In-band pointer to the upgrade path for an agent account.",
13802
+ "properties": {
13803
+ "plan": {
13804
+ "type": "string",
13805
+ "enum": ["developer"]
13806
+ },
13807
+ "description": { "type": "string" },
13808
+ "claim_path": { "type": "string" }
13809
+ },
13810
+ "required": [
13811
+ "plan",
13812
+ "description",
13813
+ "claim_path"
13814
+ ]
11866
13815
  }
11867
13816
  },
11868
13817
  "required": [
11869
- "id",
11870
- "email",
13818
+ "api_key",
13819
+ "org_id",
13820
+ "address",
11871
13821
  "plan",
11872
13822
  "limits",
11873
- "entitlements",
11874
- "managed_inbox_address",
11875
- "created_at",
11876
- "discard_content_on_webhook_confirmed"
13823
+ "upgrade"
11877
13824
  ]
11878
13825
  },
11879
- "sdkName": "getAccount",
11880
- "summary": "Get account info",
11881
- "tag": "Account",
11882
- "tagCommand": "account"
13826
+ "sdkName": "createAgentAccount",
13827
+ "summary": "Create an emailless agent account",
13828
+ "tag": "Agent",
13829
+ "tagCommand": "agent"
11883
13830
  },
11884
13831
  {
11885
13832
  "binaryResponse": false,
11886
13833
  "bodyRequired": false,
11887
- "command": "get-storage-stats",
11888
- "description": null,
11889
- "hasJsonBody": false,
11890
- "method": "GET",
11891
- "operationId": "getStorageStats",
11892
- "path": "/account/storage",
13834
+ "command": "create-agent-claim-link",
13835
+ "description": "Mints an opaque, single-use link an agent can hand to a human to\ncomplete the email-confirmation upgrade in a browser. Authenticated by\nthe agent's own API key. `claim_url` is null when the API host cannot\nresolve a web origin to build the link.\n",
13836
+ "hasJsonBody": true,
13837
+ "method": "POST",
13838
+ "operationId": "createAgentClaimLink",
13839
+ "path": "/agent/claim/link",
13840
+ "pathParams": [],
13841
+ "queryParams": [],
13842
+ "requestSchema": {
13843
+ "type": "object",
13844
+ "additionalProperties": false,
13845
+ "description": "No fields; an empty object is accepted.",
13846
+ "properties": {}
13847
+ },
13848
+ "responseSchema": {
13849
+ "type": "object",
13850
+ "properties": {
13851
+ "claim_token": { "type": "string" },
13852
+ "claim_url": {
13853
+ "type": ["string", "null"],
13854
+ "description": "Browser URL to hand to a human, or null if no web origin is configured."
13855
+ },
13856
+ "expires_in_seconds": { "type": "integer" }
13857
+ },
13858
+ "required": [
13859
+ "claim_token",
13860
+ "claim_url",
13861
+ "expires_in_seconds"
13862
+ ]
13863
+ },
13864
+ "sdkName": "createAgentClaimLink",
13865
+ "summary": "Create a browser claim link",
13866
+ "tag": "Agent",
13867
+ "tagCommand": "agent"
13868
+ },
13869
+ {
13870
+ "binaryResponse": false,
13871
+ "bodyRequired": true,
13872
+ "command": "resend-agent-signup-verification",
13873
+ "description": "Sends a new email verification code for a pending agent signup session.\nThis endpoint does not require an API key.\n",
13874
+ "hasJsonBody": true,
13875
+ "method": "POST",
13876
+ "operationId": "resendAgentSignupVerification",
13877
+ "path": "/agent/signup/resend",
11893
13878
  "pathParams": [],
11894
13879
  "queryParams": [],
11895
- "requestSchema": null,
13880
+ "requestSchema": {
13881
+ "type": "object",
13882
+ "additionalProperties": false,
13883
+ "properties": { "signup_token": {
13884
+ "type": "string",
13885
+ "minLength": 1
13886
+ } },
13887
+ "required": ["signup_token"]
13888
+ },
11896
13889
  "responseSchema": {
11897
13890
  "type": "object",
11898
13891
  "properties": {
11899
- "used_bytes": {
11900
- "type": "integer",
11901
- "description": "Total storage used in bytes"
11902
- },
11903
- "used_kb": {
11904
- "type": "number",
11905
- "description": "Total storage used in kilobytes (1 decimal)"
11906
- },
11907
- "used_mb": {
11908
- "type": "number",
11909
- "description": "Total storage used in megabytes (2 decimals)"
13892
+ "email": {
13893
+ "type": "string",
13894
+ "format": "email"
11910
13895
  },
11911
- "quota_mb": {
11912
- "type": "number",
11913
- "description": "Storage quota in megabytes (based on plan)"
13896
+ "expires_in": {
13897
+ "type": "integer",
13898
+ "description": "Seconds until the pending signup expires"
11914
13899
  },
11915
- "percentage": {
11916
- "type": "number",
11917
- "description": "Percentage of quota used (1 decimal)"
13900
+ "resend_after": {
13901
+ "type": "integer",
13902
+ "description": "Minimum seconds before requesting another verification email"
11918
13903
  },
11919
- "emails_count": {
13904
+ "verification_code_length": {
11920
13905
  "type": "integer",
11921
- "description": "Number of stored emails"
13906
+ "description": "Number of digits in the emailed verification code"
11922
13907
  }
11923
13908
  },
11924
13909
  "required": [
11925
- "used_bytes",
11926
- "used_kb",
11927
- "used_mb",
11928
- "quota_mb",
11929
- "percentage",
11930
- "emails_count"
13910
+ "email",
13911
+ "expires_in",
13912
+ "resend_after",
13913
+ "verification_code_length"
11931
13914
  ]
11932
13915
  },
11933
- "sdkName": "getStorageStats",
11934
- "summary": "Get storage usage",
11935
- "tag": "Account",
11936
- "tagCommand": "account"
13916
+ "sdkName": "resendAgentSignupVerification",
13917
+ "summary": "Resend agent signup verification code",
13918
+ "tag": "Agent",
13919
+ "tagCommand": "agent"
11937
13920
  },
11938
13921
  {
11939
13922
  "binaryResponse": false,
11940
- "bodyRequired": false,
11941
- "command": "get-webhook-secret",
11942
- "description": "Returns the webhook signing secret for your account. If no\nsecret exists yet, one is generated automatically on first\naccess.\n\nSigning is account-scoped, not per-endpoint. Every webhook\ndelivery from any of your registered endpoints is signed\nwith this single secret. Rotate via\n`POST /account/webhook-secret/rotate`.\n\n**Secret format**: the returned string looks base64-shaped\n(e.g. `XNHBBW8VqoBjRfNs1tkZj11jTk...`) but is NOT base64.\nUse it AS-IS as a UTF-8 string when computing HMAC over a\ndelivery body. Base64-decoding before HMAC will silently\nproduce mismatched signatures.\n\nSee the API-level \"Webhook signing\" section for the full\nwire format (header name, signed string shape, hash algo,\ntolerance) including a language-agnostic verification\nrecipe.\n",
11943
- "hasJsonBody": false,
11944
- "method": "GET",
11945
- "operationId": "getWebhookSecret",
11946
- "path": "/account/webhook-secret",
13923
+ "bodyRequired": true,
13924
+ "command": "start-agent-claim",
13925
+ "description": "Begins upgrading an emailless `agent` account into a full `developer`\naccount by confirming an email address. Authenticated by the agent's own\nAPI key (the org is taken from the credential). Sends a verification\ncode to the supplied email and returns the claim session id plus resend\ntiming. Submit the code to `/agent/claim/verify` to complete the\nupgrade. Confirming an email that already belongs to a Primitive account\nis rejected.\n",
13926
+ "hasJsonBody": true,
13927
+ "method": "POST",
13928
+ "operationId": "startAgentClaim",
13929
+ "path": "/agent/claim/start",
11947
13930
  "pathParams": [],
11948
13931
  "queryParams": [],
11949
- "requestSchema": null,
11950
- "responseSchema": {
13932
+ "requestSchema": {
11951
13933
  "type": "object",
11952
- "properties": { "secret": {
13934
+ "additionalProperties": false,
13935
+ "properties": { "email": {
11953
13936
  "type": "string",
11954
- "description": "The webhook signing secret value"
13937
+ "format": "email",
13938
+ "maxLength": 254,
13939
+ "description": "Email to confirm. Must not already belong to a Primitive account."
11955
13940
  } },
11956
- "required": ["secret"]
13941
+ "required": ["email"]
11957
13942
  },
11958
- "sdkName": "getWebhookSecret",
11959
- "summary": "Get webhook signing secret",
11960
- "tag": "Account",
11961
- "tagCommand": "account"
11962
- },
11963
- {
11964
- "binaryResponse": false,
11965
- "bodyRequired": false,
11966
- "command": "rotate-webhook-secret",
11967
- "description": "Generates a new webhook signing secret, replacing the current one.\nRate limited to once per 60 minutes.\n",
11968
- "hasJsonBody": false,
11969
- "method": "POST",
11970
- "operationId": "rotateWebhookSecret",
11971
- "path": "/account/webhook-secret/rotate",
11972
- "pathParams": [],
11973
- "queryParams": [],
11974
- "requestSchema": null,
11975
13943
  "responseSchema": {
11976
13944
  "type": "object",
11977
- "properties": { "secret": {
11978
- "type": "string",
11979
- "description": "The webhook signing secret value"
11980
- } },
11981
- "required": ["secret"]
13945
+ "properties": {
13946
+ "claim_session_id": { "type": "string" },
13947
+ "resend_after_seconds": { "type": "integer" },
13948
+ "expires_in_seconds": { "type": "integer" }
13949
+ },
13950
+ "required": [
13951
+ "claim_session_id",
13952
+ "resend_after_seconds",
13953
+ "expires_in_seconds"
13954
+ ]
11982
13955
  },
11983
- "sdkName": "rotateWebhookSecret",
11984
- "summary": "Rotate webhook signing secret",
11985
- "tag": "Account",
11986
- "tagCommand": "account"
13956
+ "sdkName": "startAgentClaim",
13957
+ "summary": "Start an agent account email claim",
13958
+ "tag": "Agent",
13959
+ "tagCommand": "agent"
11987
13960
  },
11988
13961
  {
11989
13962
  "binaryResponse": false,
11990
13963
  "bodyRequired": true,
11991
- "command": "update-account",
11992
- "description": null,
13964
+ "command": "start-agent-signup",
13965
+ "description": "Starts an agent-native signup session. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
11993
13966
  "hasJsonBody": true,
11994
- "method": "PATCH",
11995
- "operationId": "updateAccount",
11996
- "path": "/account",
13967
+ "method": "POST",
13968
+ "operationId": "startAgentSignup",
13969
+ "path": "/agent/signup/start",
11997
13970
  "pathParams": [],
11998
13971
  "queryParams": [],
11999
13972
  "requestSchema": {
12000
13973
  "type": "object",
12001
13974
  "additionalProperties": false,
12002
13975
  "properties": {
12003
- "spam_threshold": {
12004
- "type": ["number", "null"],
12005
- "minimum": 0,
12006
- "maximum": 15,
12007
- "description": "Global spam score threshold (0-15). Emails scoring above this are rejected. Set to null to disable."
13976
+ "email": {
13977
+ "type": "string",
13978
+ "format": "email",
13979
+ "maxLength": 254
12008
13980
  },
12009
- "discard_content_on_webhook_confirmed": {
13981
+ "signup_code": {
13982
+ "type": "string",
13983
+ "minLength": 1,
13984
+ "maxLength": 128,
13985
+ "description": "Optional signup code. Omit if you do not have one."
13986
+ },
13987
+ "terms_accepted": {
12010
13988
  "type": "boolean",
12011
- "description": "Whether to discard email content after the webhook endpoint confirms receipt."
13989
+ "const": true,
13990
+ "description": "Must be true to confirm acceptance of Primitive's Terms of Service and Privacy Policy"
13991
+ },
13992
+ "device_name": {
13993
+ "type": "string",
13994
+ "minLength": 1,
13995
+ "maxLength": 80,
13996
+ "description": "Human-readable device name used for the created agent OAuth session"
13997
+ },
13998
+ "metadata": {
13999
+ "type": "object",
14000
+ "additionalProperties": true,
14001
+ "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
12012
14002
  }
12013
14003
  },
12014
- "minProperties": 1
14004
+ "required": ["email", "terms_accepted"]
12015
14005
  },
12016
14006
  "responseSchema": {
12017
14007
  "type": "object",
12018
14008
  "properties": {
12019
- "id": {
14009
+ "signup_token": {
12020
14010
  "type": "string",
12021
- "format": "uuid"
14011
+ "description": "Opaque token used to verify or resend the pending agent signup"
12022
14012
  },
12023
- "email": { "type": "string" },
12024
- "plan": { "type": "string" },
12025
- "spam_threshold": {
12026
- "type": ["number", "null"],
12027
- "minimum": 0,
12028
- "maximum": 15
14013
+ "email": {
14014
+ "type": "string",
14015
+ "format": "email"
12029
14016
  },
12030
- "discard_content_on_webhook_confirmed": { "type": "boolean" }
14017
+ "expires_in": {
14018
+ "type": "integer",
14019
+ "description": "Seconds until the pending signup expires"
14020
+ },
14021
+ "resend_after": {
14022
+ "type": "integer",
14023
+ "description": "Minimum seconds before requesting another verification email"
14024
+ },
14025
+ "verification_code_length": {
14026
+ "type": "integer",
14027
+ "description": "Number of digits in the emailed verification code"
14028
+ }
12031
14029
  },
12032
14030
  "required": [
12033
- "id",
14031
+ "signup_token",
12034
14032
  "email",
12035
- "plan",
12036
- "discard_content_on_webhook_confirmed"
14033
+ "expires_in",
14034
+ "resend_after",
14035
+ "verification_code_length"
12037
14036
  ]
12038
14037
  },
12039
- "sdkName": "updateAccount",
12040
- "summary": "Update account settings",
12041
- "tag": "Account",
12042
- "tagCommand": "account"
14038
+ "sdkName": "startAgentSignup",
14039
+ "summary": "Start agent account signup",
14040
+ "tag": "Agent",
14041
+ "tagCommand": "agent"
12043
14042
  },
12044
14043
  {
12045
14044
  "binaryResponse": false,
12046
14045
  "bodyRequired": true,
12047
- "command": "create-agent-account",
12048
- "description": "Creates an emailless agent account without authentication and returns a\none-time API key (prefixed `prim_`) plus a provisioned managed inbox.\nThe account is on the `agent` plan: reply-only (it can send only to\naddresses that have already sent it authenticated mail) with tight send\nlimits. Use the returned `api_key` as a Bearer token on later calls. The\naccount can be upgraded to a full developer account by confirming an\nemail through the claim flow. This endpoint does not require an API key.\n",
14046
+ "command": "verify-agent-claim",
14047
+ "description": "Confirms the verification code emailed by `/agent/claim/start` and\nupgrades the account to the `developer` plan. The org id, API key, and\nmanaged inbox all carry over; the send cap lifts. Authenticated by the\nagent's own API key.\n",
12049
14048
  "hasJsonBody": true,
12050
14049
  "method": "POST",
12051
- "operationId": "createAgentAccount",
12052
- "path": "/agent/accounts",
14050
+ "operationId": "verifyAgentClaim",
14051
+ "path": "/agent/claim/verify",
12053
14052
  "pathParams": [],
12054
14053
  "queryParams": [],
12055
14054
  "requestSchema": {
12056
14055
  "type": "object",
12057
14056
  "additionalProperties": false,
12058
- "properties": {
12059
- "terms_accepted": {
12060
- "type": "boolean",
12061
- "enum": [true],
12062
- "description": "Must be true to accept the Terms of Service and Privacy Policy."
12063
- },
12064
- "device_name": {
12065
- "type": "string",
12066
- "minLength": 1,
12067
- "maxLength": 80,
12068
- "description": "Optional label for the device or agent creating the account."
12069
- }
12070
- },
12071
- "required": ["terms_accepted"]
14057
+ "properties": { "verification_code": {
14058
+ "type": "string",
14059
+ "minLength": 1,
14060
+ "maxLength": 32,
14061
+ "description": "The verification code emailed by the claim start step."
14062
+ } },
14063
+ "required": ["verification_code"]
12072
14064
  },
12073
14065
  "responseSchema": {
12074
14066
  "type": "object",
12075
14067
  "properties": {
12076
- "api_key": {
12077
- "type": "string",
12078
- "description": "One-time API key (prefixed `prim_`). Shown once; store it securely."
12079
- },
12080
14068
  "org_id": {
12081
14069
  "type": "string",
12082
- "format": "uuid"
12083
- },
12084
- "address": {
12085
- "type": ["string", "null"],
12086
- "description": "Provisioned managed inbox FQDN, or null if the inbox publish was deferred."
14070
+ "format": "uuid"
12087
14071
  },
12088
14072
  "plan": {
12089
14073
  "type": "string",
12090
- "enum": ["agent"]
14074
+ "enum": ["developer"]
14075
+ },
14076
+ "email": {
14077
+ "type": "string",
14078
+ "format": "email"
12091
14079
  },
12092
14080
  "limits": {
12093
14081
  "type": "object",
@@ -12112,545 +14100,675 @@ const operationManifest = [
12112
14100
  "filters_per_domain",
12113
14101
  "spam_thresholds_per_domain"
12114
14102
  ]
12115
- },
12116
- "upgrade": {
12117
- "type": "object",
12118
- "description": "In-band pointer to the upgrade path for an agent account.",
12119
- "properties": {
12120
- "plan": {
12121
- "type": "string",
12122
- "enum": ["developer"]
12123
- },
12124
- "description": { "type": "string" },
12125
- "claim_path": { "type": "string" }
12126
- },
12127
- "required": [
12128
- "plan",
12129
- "description",
12130
- "claim_path"
12131
- ]
12132
14103
  }
12133
14104
  },
12134
14105
  "required": [
12135
- "api_key",
12136
14106
  "org_id",
12137
- "address",
12138
14107
  "plan",
12139
- "limits",
12140
- "upgrade"
14108
+ "email",
14109
+ "limits"
12141
14110
  ]
12142
14111
  },
12143
- "sdkName": "createAgentAccount",
12144
- "summary": "Create an emailless agent account",
14112
+ "sdkName": "verifyAgentClaim",
14113
+ "summary": "Verify an agent account email claim",
12145
14114
  "tag": "Agent",
12146
14115
  "tagCommand": "agent"
12147
14116
  },
12148
14117
  {
12149
14118
  "binaryResponse": false,
12150
- "bodyRequired": false,
12151
- "command": "create-agent-claim-link",
12152
- "description": "Mints an opaque, single-use link an agent can hand to a human to\ncomplete the email-confirmation upgrade in a browser. Authenticated by\nthe agent's own API key. `claim_url` is null when the API host cannot\nresolve a web origin to build the link.\n",
14119
+ "bodyRequired": true,
14120
+ "command": "verify-agent-signup",
14121
+ "description": "Verifies the email code for an agent signup session and creates\nthe account when needed. When the session was started with a\n`signup_code`, the reserved code is redeemed; sessions started\nwithout a code skip the redemption step. An org-scoped OAuth\nsession for CLI authentication is minted and the raw tokens are\nreturned exactly once. For existing users, the optional `org_id`\nselects which accessible workspace should receive the new\nsession (no signup-code redemption is performed for existing\nusers regardless of how the session was started).\n",
12153
14122
  "hasJsonBody": true,
12154
14123
  "method": "POST",
12155
- "operationId": "createAgentClaimLink",
12156
- "path": "/agent/claim/link",
14124
+ "operationId": "verifyAgentSignup",
14125
+ "path": "/agent/signup/verify",
12157
14126
  "pathParams": [],
12158
14127
  "queryParams": [],
12159
14128
  "requestSchema": {
12160
14129
  "type": "object",
12161
14130
  "additionalProperties": false,
12162
- "description": "No fields; an empty object is accepted.",
12163
- "properties": {}
14131
+ "properties": {
14132
+ "signup_token": {
14133
+ "type": "string",
14134
+ "minLength": 1
14135
+ },
14136
+ "verification_code": {
14137
+ "type": "string",
14138
+ "minLength": 1,
14139
+ "maxLength": 32
14140
+ },
14141
+ "org_id": {
14142
+ "type": "string",
14143
+ "format": "uuid",
14144
+ "description": "Optional workspace id to target when the verified email already belongs to multiple workspaces"
14145
+ }
14146
+ },
14147
+ "required": ["signup_token", "verification_code"]
12164
14148
  },
12165
14149
  "responseSchema": {
12166
14150
  "type": "object",
12167
14151
  "properties": {
12168
- "claim_token": { "type": "string" },
12169
- "claim_url": {
12170
- "type": ["string", "null"],
12171
- "description": "Browser URL to hand to a human, or null if no web origin is configured."
14152
+ "api_key": {
14153
+ "type": "string",
14154
+ "description": "Legacy alias for access_token. New CLI builds should persist access_token and refresh_token."
12172
14155
  },
12173
- "expires_in_seconds": { "type": "integer" }
14156
+ "key_id": {
14157
+ "type": "string",
14158
+ "format": "uuid",
14159
+ "description": "Legacy alias for oauth_grant_id"
14160
+ },
14161
+ "key_prefix": {
14162
+ "type": "string",
14163
+ "description": "Legacy display prefix derived from access_token"
14164
+ },
14165
+ "access_token": {
14166
+ "type": "string",
14167
+ "description": "OAuth access token for CLI API authentication"
14168
+ },
14169
+ "refresh_token": {
14170
+ "type": "string",
14171
+ "description": "OAuth refresh token used by the CLI to renew access"
14172
+ },
14173
+ "token_type": {
14174
+ "type": "string",
14175
+ "enum": ["Bearer"]
14176
+ },
14177
+ "expires_in": {
14178
+ "type": "integer",
14179
+ "description": "Seconds until access_token expires"
14180
+ },
14181
+ "auth_method": {
14182
+ "type": "string",
14183
+ "enum": ["oauth"]
14184
+ },
14185
+ "oauth_grant_id": {
14186
+ "type": "string",
14187
+ "format": "uuid"
14188
+ },
14189
+ "oauth_client_id": { "type": "string" },
14190
+ "org_id": {
14191
+ "type": "string",
14192
+ "format": "uuid"
14193
+ },
14194
+ "org_name": { "type": ["string", "null"] },
14195
+ "orgs": {
14196
+ "type": "array",
14197
+ "items": {
14198
+ "type": "object",
14199
+ "properties": {
14200
+ "id": {
14201
+ "type": "string",
14202
+ "format": "uuid"
14203
+ },
14204
+ "name": { "type": ["string", "null"] }
14205
+ },
14206
+ "required": ["id", "name"]
14207
+ },
14208
+ "description": "Workspaces available to the verified email. The minted session targets `org_id`."
14209
+ }
12174
14210
  },
12175
14211
  "required": [
12176
- "claim_token",
12177
- "claim_url",
12178
- "expires_in_seconds"
14212
+ "api_key",
14213
+ "key_id",
14214
+ "key_prefix",
14215
+ "access_token",
14216
+ "refresh_token",
14217
+ "token_type",
14218
+ "expires_in",
14219
+ "auth_method",
14220
+ "oauth_grant_id",
14221
+ "oauth_client_id",
14222
+ "org_id",
14223
+ "org_name",
14224
+ "orgs"
12179
14225
  ]
12180
14226
  },
12181
- "sdkName": "createAgentClaimLink",
12182
- "summary": "Create a browser claim link",
14227
+ "sdkName": "verifyAgentSignup",
14228
+ "summary": "Verify agent signup and create OAuth tokens",
12183
14229
  "tag": "Agent",
12184
14230
  "tagCommand": "agent"
12185
14231
  },
12186
14232
  {
12187
14233
  "binaryResponse": false,
12188
14234
  "bodyRequired": true,
12189
- "command": "resend-agent-signup-verification",
12190
- "description": "Sends a new email verification code for a pending agent signup session.\nThis endpoint does not require an API key.\n",
14235
+ "command": "claim-agent-connection",
14236
+ "description": "Address-bound external runtime pairing. Management operations require an organization owner or admin session or OAuth token; members and organization API keys cannot manage connections. Claim is authorized only by its one-use invitation. Connected means a real challenge was received and a reply sent by the current bound credential was received back. Invitations expire after 15 minutes. Reconnection preserves the address and revokes previous credentials. Status responses contain no credentials. Runtime credentials allow only address-scoped mail operations, organization note reads and own-address note writes. The credential is returned once. If the claim response is lost or the outcome is unknown, request a fresh owner invitation instead of retrying the consumed invitation.",
12191
14237
  "hasJsonBody": true,
12192
14238
  "method": "POST",
12193
- "operationId": "resendAgentSignupVerification",
12194
- "path": "/agent/signup/resend",
14239
+ "operationId": "claimAgentConnection",
14240
+ "path": "/agent-connections/claim",
12195
14241
  "pathParams": [],
12196
14242
  "queryParams": [],
12197
14243
  "requestSchema": {
14244
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
12198
14245
  "type": "object",
12199
- "additionalProperties": false,
12200
- "properties": { "signup_token": {
14246
+ "properties": { "token": {
12201
14247
  "type": "string",
12202
- "minLength": 1
14248
+ "minLength": 32,
14249
+ "maxLength": 256
12203
14250
  } },
12204
- "required": ["signup_token"]
14251
+ "required": ["token"],
14252
+ "additionalProperties": false
12205
14253
  },
12206
14254
  "responseSchema": {
12207
14255
  "type": "object",
14256
+ "required": ["success", "data"],
12208
14257
  "properties": {
12209
- "email": {
12210
- "type": "string",
12211
- "format": "email"
12212
- },
12213
- "expires_in": {
12214
- "type": "integer",
12215
- "description": "Seconds until the pending signup expires"
14258
+ "success": {
14259
+ "const": true,
14260
+ "type": "boolean"
12216
14261
  },
12217
- "resend_after": {
12218
- "type": "integer",
12219
- "description": "Minimum seconds before requesting another verification email"
14262
+ "data": {
14263
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14264
+ "type": "object",
14265
+ "properties": {
14266
+ "connection": {
14267
+ "type": "object",
14268
+ "properties": {
14269
+ "address": {
14270
+ "type": "string",
14271
+ "format": "email",
14272
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
14273
+ },
14274
+ "name": {
14275
+ "type": "string",
14276
+ "minLength": 1,
14277
+ "maxLength": 80
14278
+ },
14279
+ "owner_address": {
14280
+ "type": "string",
14281
+ "format": "email",
14282
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
14283
+ },
14284
+ "status": {
14285
+ "type": "string",
14286
+ "enum": [
14287
+ "pending",
14288
+ "claimed",
14289
+ "connected",
14290
+ "revoked"
14291
+ ]
14292
+ },
14293
+ "created_at": {
14294
+ "type": "string",
14295
+ "format": "date-time",
14296
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
14297
+ },
14298
+ "updated_at": {
14299
+ "type": "string",
14300
+ "format": "date-time",
14301
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
14302
+ },
14303
+ "claimed_at": { "anyOf": [{
14304
+ "type": "string",
14305
+ "format": "date-time",
14306
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
14307
+ }, { "type": "null" }] },
14308
+ "verified_at": { "anyOf": [{
14309
+ "type": "string",
14310
+ "format": "date-time",
14311
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
14312
+ }, { "type": "null" }] },
14313
+ "last_seen_at": { "anyOf": [{
14314
+ "type": "string",
14315
+ "format": "date-time",
14316
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
14317
+ }, { "type": "null" }] }
14318
+ },
14319
+ "required": [
14320
+ "address",
14321
+ "name",
14322
+ "owner_address",
14323
+ "status",
14324
+ "created_at",
14325
+ "updated_at",
14326
+ "claimed_at",
14327
+ "verified_at",
14328
+ "last_seen_at"
14329
+ ],
14330
+ "additionalProperties": false
14331
+ },
14332
+ "org_id": {
14333
+ "type": "string",
14334
+ "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
14335
+ },
14336
+ "owner_address": {
14337
+ "type": "string",
14338
+ "format": "email",
14339
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
14340
+ },
14341
+ "api_key": { "type": "string" },
14342
+ "api_base_url": {
14343
+ "type": "string",
14344
+ "format": "uri"
14345
+ }
14346
+ },
14347
+ "required": [
14348
+ "connection",
14349
+ "org_id",
14350
+ "owner_address",
14351
+ "api_key",
14352
+ "api_base_url"
14353
+ ],
14354
+ "additionalProperties": false
14355
+ }
14356
+ }
14357
+ },
14358
+ "sdkName": "claimAgentConnection",
14359
+ "summary": "claim Agent Connection",
14360
+ "tag": "Agent Connections",
14361
+ "tagCommand": "agent-connections"
14362
+ },
14363
+ {
14364
+ "binaryResponse": false,
14365
+ "bodyRequired": false,
14366
+ "command": "remove-agent-connection",
14367
+ "description": "Permanently removes a revoked connection record. Requires an organization\nowner or admin session or OAuth token; organization API keys are denied.\nDisconnect first using DELETE /agent-connections/{address}. An active\nconnection returns 409 connection_not_revoked. Missing or already removed\nrecords return 404. Mail, address notes, domains and external runtimes are\npreserved. The same address can be paired again with a new invitation;\nold credentials and invitations remain invalid.\n",
14368
+ "hasJsonBody": false,
14369
+ "method": "POST",
14370
+ "operationId": "removeAgentConnection",
14371
+ "path": "/agent-connections/{address}/remove",
14372
+ "pathParams": [{
14373
+ "description": "The email address identifying the revoked connection.",
14374
+ "enum": null,
14375
+ "name": "address",
14376
+ "required": true,
14377
+ "type": "string"
14378
+ }],
14379
+ "queryParams": [],
14380
+ "requestSchema": null,
14381
+ "responseSchema": {
14382
+ "type": "object",
14383
+ "required": ["success", "data"],
14384
+ "properties": {
14385
+ "success": {
14386
+ "type": "boolean",
14387
+ "const": true
12220
14388
  },
12221
- "verification_code_length": {
12222
- "type": "integer",
12223
- "description": "Number of digits in the emailed verification code"
14389
+ "data": {
14390
+ "type": "object",
14391
+ "required": ["deleted"],
14392
+ "properties": { "deleted": {
14393
+ "type": "boolean",
14394
+ "const": true
14395
+ } }
12224
14396
  }
12225
- },
12226
- "required": [
12227
- "email",
12228
- "expires_in",
12229
- "resend_after",
12230
- "verification_code_length"
12231
- ]
14397
+ }
12232
14398
  },
12233
- "sdkName": "resendAgentSignupVerification",
12234
- "summary": "Resend agent signup verification code",
12235
- "tag": "Agent",
12236
- "tagCommand": "agent"
14399
+ "sdkName": "removeAgentConnection",
14400
+ "summary": "Remove a revoked agent connection",
14401
+ "tag": "Agent Connections",
14402
+ "tagCommand": "agent-connections"
12237
14403
  },
12238
14404
  {
12239
14405
  "binaryResponse": false,
12240
- "bodyRequired": true,
12241
- "command": "start-agent-claim",
12242
- "description": "Begins upgrading an emailless `agent` account into a full `developer`\naccount by confirming an email address. Authenticated by the agent's own\nAPI key (the org is taken from the credential). Sends a verification\ncode to the supplied email and returns the claim session id plus resend\ntiming. Submit the code to `/agent/claim/verify` to complete the\nupgrade. Confirming an email that already belongs to a Primitive account\nis rejected.\n",
14406
+ "bodyRequired": false,
14407
+ "command": "cli-logout",
14408
+ "description": "Revokes the OAuth grant used to authenticate the request. API-key\nauthenticated legacy logout requests succeed without deleting server API\nkeys so old local CLI state can be cleared safely.\n",
12243
14409
  "hasJsonBody": true,
12244
14410
  "method": "POST",
12245
- "operationId": "startAgentClaim",
12246
- "path": "/agent/claim/start",
14411
+ "operationId": "cliLogout",
14412
+ "path": "/cli/logout",
12247
14413
  "pathParams": [],
12248
14414
  "queryParams": [],
12249
14415
  "requestSchema": {
12250
14416
  "type": "object",
12251
14417
  "additionalProperties": false,
12252
- "properties": { "email": {
14418
+ "properties": { "key_id": {
12253
14419
  "type": "string",
12254
- "format": "email",
12255
- "maxLength": 254,
12256
- "description": "Email to confirm. Must not already belong to a Primitive account."
12257
- } },
12258
- "required": ["email"]
14420
+ "format": "uuid",
14421
+ "description": "Optional id guard; when provided it must match the authenticated OAuth grant id or API key id"
14422
+ } }
12259
14423
  },
12260
14424
  "responseSchema": {
12261
14425
  "type": "object",
12262
14426
  "properties": {
12263
- "claim_session_id": { "type": "string" },
12264
- "resend_after_seconds": { "type": "integer" },
12265
- "expires_in_seconds": { "type": "integer" }
14427
+ "revoked": {
14428
+ "type": "boolean",
14429
+ "description": "True when an OAuth grant was revoked. False for API-key-authenticated legacy logout, which only clears local CLI state."
14430
+ },
14431
+ "key_id": {
14432
+ "type": "string",
14433
+ "format": "uuid",
14434
+ "description": "API key id for API-key-authenticated legacy logout"
14435
+ },
14436
+ "oauth_grant_id": {
14437
+ "type": "string",
14438
+ "format": "uuid",
14439
+ "description": "OAuth grant id revoked by OAuth-authenticated logout"
14440
+ }
12266
14441
  },
12267
- "required": [
12268
- "claim_session_id",
12269
- "resend_after_seconds",
12270
- "expires_in_seconds"
12271
- ]
14442
+ "required": ["revoked"]
12272
14443
  },
12273
- "sdkName": "startAgentClaim",
12274
- "summary": "Start an agent account email claim",
12275
- "tag": "Agent",
12276
- "tagCommand": "agent"
14444
+ "sdkName": "cliLogout",
14445
+ "summary": "Revoke the current CLI OAuth session",
14446
+ "tag": "CLI",
14447
+ "tagCommand": "cli"
12277
14448
  },
12278
14449
  {
12279
14450
  "binaryResponse": false,
12280
14451
  "bodyRequired": true,
12281
- "command": "start-agent-signup",
12282
- "description": "Starts an agent-native signup session. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
14452
+ "command": "poll-cli-login",
14453
+ "description": "Polls a CLI login session until the browser approval either succeeds,\nis denied, expires, or is polled too quickly. The OAuth token set is\ncreated only after approval and is returned exactly once.\n",
12283
14454
  "hasJsonBody": true,
12284
14455
  "method": "POST",
12285
- "operationId": "startAgentSignup",
12286
- "path": "/agent/signup/start",
14456
+ "operationId": "pollCliLogin",
14457
+ "path": "/cli/login/poll",
12287
14458
  "pathParams": [],
12288
14459
  "queryParams": [],
12289
14460
  "requestSchema": {
12290
14461
  "type": "object",
12291
14462
  "additionalProperties": false,
14463
+ "properties": { "device_code": {
14464
+ "type": "string",
14465
+ "minLength": 1
14466
+ } },
14467
+ "required": ["device_code"]
14468
+ },
14469
+ "responseSchema": {
14470
+ "type": "object",
12292
14471
  "properties": {
12293
- "email": {
14472
+ "api_key": {
12294
14473
  "type": "string",
12295
- "format": "email",
12296
- "maxLength": 254
14474
+ "description": "Legacy alias for access_token. New CLI builds should persist access_token and refresh_token."
12297
14475
  },
12298
- "signup_code": {
14476
+ "key_id": {
12299
14477
  "type": "string",
12300
- "minLength": 1,
12301
- "maxLength": 128,
12302
- "description": "Optional signup code. Omit if you do not have one."
14478
+ "format": "uuid",
14479
+ "description": "Legacy alias for oauth_grant_id"
12303
14480
  },
12304
- "terms_accepted": {
12305
- "type": "boolean",
12306
- "const": true,
12307
- "description": "Must be true to confirm acceptance of Primitive's Terms of Service and Privacy Policy"
14481
+ "key_prefix": {
14482
+ "type": "string",
14483
+ "description": "Legacy display prefix derived from access_token"
12308
14484
  },
12309
- "device_name": {
14485
+ "access_token": {
12310
14486
  "type": "string",
12311
- "minLength": 1,
12312
- "maxLength": 80,
12313
- "description": "Human-readable device name used for the created agent OAuth session"
14487
+ "description": "OAuth access token for CLI API authentication"
12314
14488
  },
12315
- "metadata": {
12316
- "type": "object",
12317
- "additionalProperties": true,
12318
- "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
12319
- }
12320
- },
12321
- "required": ["email", "terms_accepted"]
12322
- },
12323
- "responseSchema": {
12324
- "type": "object",
12325
- "properties": {
12326
- "signup_token": {
14489
+ "refresh_token": {
12327
14490
  "type": "string",
12328
- "description": "Opaque token used to verify or resend the pending agent signup"
14491
+ "description": "OAuth refresh token used by the CLI to renew access"
12329
14492
  },
12330
- "email": {
14493
+ "token_type": {
12331
14494
  "type": "string",
12332
- "format": "email"
14495
+ "enum": ["Bearer"]
12333
14496
  },
12334
14497
  "expires_in": {
12335
14498
  "type": "integer",
12336
- "description": "Seconds until the pending signup expires"
14499
+ "description": "Seconds until access_token expires"
12337
14500
  },
12338
- "resend_after": {
12339
- "type": "integer",
12340
- "description": "Minimum seconds before requesting another verification email"
14501
+ "auth_method": {
14502
+ "type": "string",
14503
+ "enum": ["oauth"]
12341
14504
  },
12342
- "verification_code_length": {
12343
- "type": "integer",
12344
- "description": "Number of digits in the emailed verification code"
12345
- }
14505
+ "oauth_grant_id": {
14506
+ "type": "string",
14507
+ "format": "uuid"
14508
+ },
14509
+ "oauth_client_id": { "type": "string" },
14510
+ "org_id": {
14511
+ "type": "string",
14512
+ "format": "uuid"
14513
+ },
14514
+ "org_name": { "type": ["string", "null"] }
12346
14515
  },
12347
14516
  "required": [
12348
- "signup_token",
12349
- "email",
14517
+ "api_key",
14518
+ "key_id",
14519
+ "key_prefix",
14520
+ "access_token",
14521
+ "refresh_token",
14522
+ "token_type",
12350
14523
  "expires_in",
12351
- "resend_after",
12352
- "verification_code_length"
14524
+ "auth_method",
14525
+ "oauth_grant_id",
14526
+ "oauth_client_id",
14527
+ "org_id",
14528
+ "org_name"
12353
14529
  ]
12354
14530
  },
12355
- "sdkName": "startAgentSignup",
12356
- "summary": "Start agent account signup",
12357
- "tag": "Agent",
12358
- "tagCommand": "agent"
14531
+ "sdkName": "pollCliLogin",
14532
+ "summary": "Poll CLI browser login",
14533
+ "tag": "CLI",
14534
+ "tagCommand": "cli"
12359
14535
  },
12360
14536
  {
12361
14537
  "binaryResponse": false,
12362
14538
  "bodyRequired": true,
12363
- "command": "verify-agent-claim",
12364
- "description": "Confirms the verification code emailed by `/agent/claim/start` and\nupgrades the account to the `developer` plan. The org id, API key, and\nmanaged inbox all carry over; the send cap lifts. Authenticated by the\nagent's own API key.\n",
14539
+ "command": "resend-cli-signup-verification",
14540
+ "description": "Sends a new email verification code for a pending CLI signup session.\nThis endpoint does not require an API key.\n",
12365
14541
  "hasJsonBody": true,
12366
14542
  "method": "POST",
12367
- "operationId": "verifyAgentClaim",
12368
- "path": "/agent/claim/verify",
14543
+ "operationId": "resendCliSignupVerification",
14544
+ "path": "/cli/signup/resend",
12369
14545
  "pathParams": [],
12370
14546
  "queryParams": [],
12371
14547
  "requestSchema": {
12372
14548
  "type": "object",
12373
14549
  "additionalProperties": false,
12374
- "properties": { "verification_code": {
14550
+ "properties": { "signup_token": {
12375
14551
  "type": "string",
12376
- "minLength": 1,
12377
- "maxLength": 32,
12378
- "description": "The verification code emailed by the claim start step."
14552
+ "minLength": 1
12379
14553
  } },
12380
- "required": ["verification_code"]
14554
+ "required": ["signup_token"]
12381
14555
  },
12382
14556
  "responseSchema": {
12383
14557
  "type": "object",
12384
14558
  "properties": {
12385
- "org_id": {
12386
- "type": "string",
12387
- "format": "uuid"
12388
- },
12389
- "plan": {
12390
- "type": "string",
12391
- "enum": ["developer"]
12392
- },
12393
14559
  "email": {
12394
14560
  "type": "string",
12395
14561
  "format": "email"
12396
14562
  },
12397
- "limits": {
12398
- "type": "object",
12399
- "description": "Plan-derived quota limits for an account.",
12400
- "properties": {
12401
- "storage_mb": { "type": "number" },
12402
- "send_per_hour": { "type": "number" },
12403
- "send_per_day": { "type": "number" },
12404
- "api_per_minute": { "type": "number" },
12405
- "webhooks_max_global": { "type": ["number", "null"] },
12406
- "webhooks_per_domain": { "type": "boolean" },
12407
- "filters_per_domain": { "type": "boolean" },
12408
- "spam_thresholds_per_domain": { "type": "boolean" }
12409
- },
12410
- "required": [
12411
- "storage_mb",
12412
- "send_per_hour",
12413
- "send_per_day",
12414
- "api_per_minute",
12415
- "webhooks_max_global",
12416
- "webhooks_per_domain",
12417
- "filters_per_domain",
12418
- "spam_thresholds_per_domain"
12419
- ]
14563
+ "expires_in": {
14564
+ "type": "integer",
14565
+ "description": "Seconds until the pending signup expires"
14566
+ },
14567
+ "resend_after": {
14568
+ "type": "integer",
14569
+ "description": "Minimum seconds before requesting another verification email"
14570
+ },
14571
+ "verification_code_length": {
14572
+ "type": "integer",
14573
+ "description": "Number of digits in the emailed verification code"
12420
14574
  }
12421
14575
  },
12422
14576
  "required": [
12423
- "org_id",
12424
- "plan",
12425
14577
  "email",
12426
- "limits"
14578
+ "expires_in",
14579
+ "resend_after",
14580
+ "verification_code_length"
12427
14581
  ]
12428
14582
  },
12429
- "sdkName": "verifyAgentClaim",
12430
- "summary": "Verify an agent account email claim",
12431
- "tag": "Agent",
12432
- "tagCommand": "agent"
14583
+ "sdkName": "resendCliSignupVerification",
14584
+ "summary": "Resend CLI signup verification code",
14585
+ "tag": "CLI",
14586
+ "tagCommand": "cli"
12433
14587
  },
12434
14588
  {
12435
14589
  "binaryResponse": false,
12436
- "bodyRequired": true,
12437
- "command": "verify-agent-signup",
12438
- "description": "Verifies the email code for an agent signup session and creates\nthe account when needed. When the session was started with a\n`signup_code`, the reserved code is redeemed; sessions started\nwithout a code skip the redemption step. An org-scoped OAuth\nsession for CLI authentication is minted and the raw tokens are\nreturned exactly once. For existing users, the optional `org_id`\nselects which accessible workspace should receive the new\nsession (no signup-code redemption is performed for existing\nusers regardless of how the session was started).\n",
14590
+ "bodyRequired": false,
14591
+ "command": "start-cli-login",
14592
+ "description": "Starts a browser-assisted CLI login session. The response includes a\ndevice code for polling and a user code that the user approves in the\nbrowser. This endpoint does not require an API key.\n",
12439
14593
  "hasJsonBody": true,
12440
- "method": "POST",
12441
- "operationId": "verifyAgentSignup",
12442
- "path": "/agent/signup/verify",
14594
+ "method": "POST",
14595
+ "operationId": "startCliLogin",
14596
+ "path": "/cli/login/start",
12443
14597
  "pathParams": [],
12444
14598
  "queryParams": [],
12445
14599
  "requestSchema": {
12446
14600
  "type": "object",
12447
14601
  "additionalProperties": false,
12448
14602
  "properties": {
12449
- "signup_token": {
12450
- "type": "string",
12451
- "minLength": 1
12452
- },
12453
- "verification_code": {
14603
+ "device_name": {
12454
14604
  "type": "string",
12455
14605
  "minLength": 1,
12456
- "maxLength": 32
14606
+ "maxLength": 80,
14607
+ "description": "Human-readable device name shown during browser approval"
12457
14608
  },
12458
- "org_id": {
12459
- "type": "string",
12460
- "format": "uuid",
12461
- "description": "Optional workspace id to target when the verified email already belongs to multiple workspaces"
14609
+ "metadata": {
14610
+ "type": "object",
14611
+ "additionalProperties": true,
14612
+ "description": "Optional client metadata stored with the login session; serialized JSON must be 2048 bytes or fewer"
12462
14613
  }
12463
- },
12464
- "required": ["signup_token", "verification_code"]
14614
+ }
12465
14615
  },
12466
14616
  "responseSchema": {
12467
14617
  "type": "object",
12468
14618
  "properties": {
12469
- "api_key": {
12470
- "type": "string",
12471
- "description": "Legacy alias for access_token. New CLI builds should persist access_token and refresh_token."
12472
- },
12473
- "key_id": {
12474
- "type": "string",
12475
- "format": "uuid",
12476
- "description": "Legacy alias for oauth_grant_id"
12477
- },
12478
- "key_prefix": {
14619
+ "device_code": {
12479
14620
  "type": "string",
12480
- "description": "Legacy display prefix derived from access_token"
14621
+ "description": "Opaque code used by the CLI to poll for approval"
12481
14622
  },
12482
- "access_token": {
14623
+ "user_code": {
12483
14624
  "type": "string",
12484
- "description": "OAuth access token for CLI API authentication"
14625
+ "pattern": "^[BCDFGHJKLMNPQRSTVWXZ]{4}-[BCDFGHJKLMNPQRSTVWXZ]{4}$",
14626
+ "description": "Short code the user confirms in the browser"
12485
14627
  },
12486
- "refresh_token": {
14628
+ "verification_uri": {
12487
14629
  "type": "string",
12488
- "description": "OAuth refresh token used by the CLI to renew access"
14630
+ "description": "Browser URL where the user approves the login"
12489
14631
  },
12490
- "token_type": {
14632
+ "verification_uri_complete": {
12491
14633
  "type": "string",
12492
- "enum": ["Bearer"]
14634
+ "description": "Browser URL with the user code prefilled"
12493
14635
  },
12494
14636
  "expires_in": {
12495
14637
  "type": "integer",
12496
- "description": "Seconds until access_token expires"
12497
- },
12498
- "auth_method": {
12499
- "type": "string",
12500
- "enum": ["oauth"]
12501
- },
12502
- "oauth_grant_id": {
12503
- "type": "string",
12504
- "format": "uuid"
12505
- },
12506
- "oauth_client_id": { "type": "string" },
12507
- "org_id": {
12508
- "type": "string",
12509
- "format": "uuid"
14638
+ "description": "Seconds until the login session expires"
12510
14639
  },
12511
- "org_name": { "type": ["string", "null"] },
12512
- "orgs": {
12513
- "type": "array",
12514
- "items": {
12515
- "type": "object",
12516
- "properties": {
12517
- "id": {
12518
- "type": "string",
12519
- "format": "uuid"
12520
- },
12521
- "name": { "type": ["string", "null"] }
12522
- },
12523
- "required": ["id", "name"]
12524
- },
12525
- "description": "Workspaces available to the verified email. The minted session targets `org_id`."
14640
+ "interval": {
14641
+ "type": "integer",
14642
+ "description": "Minimum seconds between poll requests"
12526
14643
  }
12527
14644
  },
12528
14645
  "required": [
12529
- "api_key",
12530
- "key_id",
12531
- "key_prefix",
12532
- "access_token",
12533
- "refresh_token",
12534
- "token_type",
14646
+ "device_code",
14647
+ "user_code",
14648
+ "verification_uri",
14649
+ "verification_uri_complete",
12535
14650
  "expires_in",
12536
- "auth_method",
12537
- "oauth_grant_id",
12538
- "oauth_client_id",
12539
- "org_id",
12540
- "org_name",
12541
- "orgs"
14651
+ "interval"
12542
14652
  ]
12543
14653
  },
12544
- "sdkName": "verifyAgentSignup",
12545
- "summary": "Verify agent signup and create OAuth tokens",
12546
- "tag": "Agent",
12547
- "tagCommand": "agent"
14654
+ "sdkName": "startCliLogin",
14655
+ "summary": "Start CLI browser login",
14656
+ "tag": "CLI",
14657
+ "tagCommand": "cli"
12548
14658
  },
12549
14659
  {
12550
14660
  "binaryResponse": false,
12551
- "bodyRequired": false,
12552
- "command": "remove-agent-connection",
12553
- "description": "Permanently removes a revoked connection record. Requires an organization\nowner or admin session or OAuth token; organization API keys are denied.\nDisconnect first using DELETE /agent-connections/{address}. An active\nconnection returns 409 connection_not_revoked. Missing or already removed\nrecords return 404. Mail, address notes, domains and external runtimes are\npreserved. The same address can be paired again with a new invitation;\nold credentials and invitations remain invalid.\n",
12554
- "hasJsonBody": false,
14661
+ "bodyRequired": true,
14662
+ "command": "start-cli-signup",
14663
+ "description": "Starts a terminal-native CLI signup. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
14664
+ "hasJsonBody": true,
12555
14665
  "method": "POST",
12556
- "operationId": "removeAgentConnection",
12557
- "path": "/agent-connections/{address}/remove",
12558
- "pathParams": [{
12559
- "description": "The email address identifying the revoked connection.",
12560
- "enum": null,
12561
- "name": "address",
12562
- "required": true,
12563
- "type": "string"
12564
- }],
14666
+ "operationId": "startCliSignup",
14667
+ "path": "/cli/signup/start",
14668
+ "pathParams": [],
12565
14669
  "queryParams": [],
12566
- "requestSchema": null,
12567
- "responseSchema": {
14670
+ "requestSchema": {
12568
14671
  "type": "object",
12569
- "required": ["success", "data"],
14672
+ "additionalProperties": false,
12570
14673
  "properties": {
12571
- "success": {
14674
+ "email": {
14675
+ "type": "string",
14676
+ "format": "email",
14677
+ "maxLength": 254
14678
+ },
14679
+ "signup_code": {
14680
+ "type": "string",
14681
+ "minLength": 1,
14682
+ "maxLength": 128,
14683
+ "description": "Optional signup code. Omit if you do not have one."
14684
+ },
14685
+ "terms_accepted": {
12572
14686
  "type": "boolean",
12573
- "const": true
14687
+ "const": true,
14688
+ "description": "Must be true to confirm acceptance of Primitive's Terms of Service and Privacy Policy"
12574
14689
  },
12575
- "data": {
14690
+ "device_name": {
14691
+ "type": "string",
14692
+ "minLength": 1,
14693
+ "maxLength": 80,
14694
+ "description": "Human-readable device name used for the created CLI OAuth grant"
14695
+ },
14696
+ "metadata": {
12576
14697
  "type": "object",
12577
- "required": ["deleted"],
12578
- "properties": { "deleted": {
12579
- "type": "boolean",
12580
- "const": true
12581
- } }
14698
+ "additionalProperties": true,
14699
+ "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
12582
14700
  }
12583
- }
12584
- },
12585
- "sdkName": "removeAgentConnection",
12586
- "summary": "Remove a revoked agent connection",
12587
- "tag": "Agent Connections",
12588
- "tagCommand": "agent-connections"
12589
- },
12590
- {
12591
- "binaryResponse": false,
12592
- "bodyRequired": false,
12593
- "command": "cli-logout",
12594
- "description": "Revokes the OAuth grant used to authenticate the request. API-key\nauthenticated legacy logout requests succeed without deleting server API\nkeys so old local CLI state can be cleared safely.\n",
12595
- "hasJsonBody": true,
12596
- "method": "POST",
12597
- "operationId": "cliLogout",
12598
- "path": "/cli/logout",
12599
- "pathParams": [],
12600
- "queryParams": [],
12601
- "requestSchema": {
12602
- "type": "object",
12603
- "additionalProperties": false,
12604
- "properties": { "key_id": {
12605
- "type": "string",
12606
- "format": "uuid",
12607
- "description": "Optional id guard; when provided it must match the authenticated OAuth grant id or API key id"
12608
- } }
14701
+ },
14702
+ "required": ["email", "terms_accepted"]
12609
14703
  },
12610
14704
  "responseSchema": {
12611
14705
  "type": "object",
12612
14706
  "properties": {
12613
- "revoked": {
12614
- "type": "boolean",
12615
- "description": "True when an OAuth grant was revoked. False for API-key-authenticated legacy logout, which only clears local CLI state."
12616
- },
12617
- "key_id": {
14707
+ "signup_token": {
12618
14708
  "type": "string",
12619
- "format": "uuid",
12620
- "description": "API key id for API-key-authenticated legacy logout"
14709
+ "description": "Opaque token used to verify or resend the pending CLI signup"
12621
14710
  },
12622
- "oauth_grant_id": {
14711
+ "email": {
12623
14712
  "type": "string",
12624
- "format": "uuid",
12625
- "description": "OAuth grant id revoked by OAuth-authenticated logout"
14713
+ "format": "email"
14714
+ },
14715
+ "expires_in": {
14716
+ "type": "integer",
14717
+ "description": "Seconds until the pending signup expires"
14718
+ },
14719
+ "resend_after": {
14720
+ "type": "integer",
14721
+ "description": "Minimum seconds before requesting another verification email"
14722
+ },
14723
+ "verification_code_length": {
14724
+ "type": "integer",
14725
+ "description": "Number of digits in the emailed verification code"
12626
14726
  }
12627
14727
  },
12628
- "required": ["revoked"]
14728
+ "required": [
14729
+ "signup_token",
14730
+ "email",
14731
+ "expires_in",
14732
+ "resend_after",
14733
+ "verification_code_length"
14734
+ ]
12629
14735
  },
12630
- "sdkName": "cliLogout",
12631
- "summary": "Revoke the current CLI OAuth session",
14736
+ "sdkName": "startCliSignup",
14737
+ "summary": "Start CLI account signup",
12632
14738
  "tag": "CLI",
12633
14739
  "tagCommand": "cli"
12634
14740
  },
12635
14741
  {
12636
14742
  "binaryResponse": false,
12637
14743
  "bodyRequired": true,
12638
- "command": "poll-cli-login",
12639
- "description": "Polls a CLI login session until the browser approval either succeeds,\nis denied, expires, or is polled too quickly. The OAuth token set is\ncreated only after approval and is returned exactly once.\n",
14744
+ "command": "verify-cli-signup",
14745
+ "description": "Verifies the email code for a CLI signup session and creates the\naccount. When the session was started with a `signup_code`, the\nreserved code is redeemed; sessions started without a code skip\nthe redemption step. Either way an org-scoped OAuth CLI session\nis created and the token set is returned exactly once. This\nendpoint does not require an API key.\n",
12640
14746
  "hasJsonBody": true,
12641
14747
  "method": "POST",
12642
- "operationId": "pollCliLogin",
12643
- "path": "/cli/login/poll",
14748
+ "operationId": "verifyCliSignup",
14749
+ "path": "/cli/signup/verify",
12644
14750
  "pathParams": [],
12645
14751
  "queryParams": [],
12646
14752
  "requestSchema": {
12647
14753
  "type": "object",
12648
14754
  "additionalProperties": false,
12649
- "properties": { "device_code": {
12650
- "type": "string",
12651
- "minLength": 1
12652
- } },
12653
- "required": ["device_code"]
14755
+ "properties": {
14756
+ "signup_token": {
14757
+ "type": "string",
14758
+ "minLength": 1
14759
+ },
14760
+ "verification_code": {
14761
+ "type": "string",
14762
+ "minLength": 1,
14763
+ "maxLength": 32
14764
+ },
14765
+ "password": {
14766
+ "type": "string",
14767
+ "minLength": 1,
14768
+ "maxLength": 1024
14769
+ }
14770
+ },
14771
+ "required": ["signup_token", "verification_code"]
12654
14772
  },
12655
14773
  "responseSchema": {
12656
14774
  "type": "object",
@@ -12714,314 +14832,515 @@ const operationManifest = [
12714
14832
  "org_name"
12715
14833
  ]
12716
14834
  },
12717
- "sdkName": "pollCliLogin",
12718
- "summary": "Poll CLI browser login",
14835
+ "sdkName": "verifyCliSignup",
14836
+ "summary": "Verify CLI signup and create OAuth session",
12719
14837
  "tag": "CLI",
12720
14838
  "tagCommand": "cli"
12721
14839
  },
12722
14840
  {
12723
14841
  "binaryResponse": false,
12724
- "bodyRequired": true,
12725
- "command": "resend-cli-signup-verification",
12726
- "description": "Sends a new email verification code for a pending CLI signup session.\nThis endpoint does not require an API key.\n",
12727
- "hasJsonBody": true,
12728
- "method": "POST",
12729
- "operationId": "resendCliSignupVerification",
12730
- "path": "/cli/signup/resend",
12731
- "pathParams": [],
12732
- "queryParams": [],
12733
- "requestSchema": {
14842
+ "bodyRequired": false,
14843
+ "command": "delete-agent-contact",
14844
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
14845
+ "hasJsonBody": false,
14846
+ "method": "DELETE",
14847
+ "operationId": "deleteAgentContact",
14848
+ "path": "/agent-contacts/{agent_address}/{contact_address}",
14849
+ "pathParams": [{
14850
+ "description": "agent_address for contacts.",
14851
+ "enum": null,
14852
+ "name": "agent_address",
14853
+ "required": true,
14854
+ "type": "string"
14855
+ }, {
14856
+ "description": "contact_address for contacts.",
14857
+ "enum": null,
14858
+ "name": "contact_address",
14859
+ "required": true,
14860
+ "type": "string"
14861
+ }],
14862
+ "queryParams": [{
14863
+ "description": "if_version for contacts.",
14864
+ "enum": null,
14865
+ "name": "if_version",
14866
+ "required": true,
14867
+ "type": "string"
14868
+ }],
14869
+ "requestSchema": null,
14870
+ "responseSchema": {
12734
14871
  "type": "object",
12735
14872
  "additionalProperties": false,
12736
- "properties": { "signup_token": {
12737
- "type": "string",
12738
- "minLength": 1
12739
- } },
12740
- "required": ["signup_token"]
14873
+ "properties": { "deleted": { "type": "boolean" } },
14874
+ "required": ["deleted"]
12741
14875
  },
14876
+ "sdkName": "deleteAgentContact",
14877
+ "summary": "delete Agent Contact",
14878
+ "tag": "Contacts",
14879
+ "tagCommand": "contacts"
14880
+ },
14881
+ {
14882
+ "binaryResponse": false,
14883
+ "bodyRequired": false,
14884
+ "command": "delete-contact",
14885
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
14886
+ "hasJsonBody": false,
14887
+ "method": "DELETE",
14888
+ "operationId": "deleteContact",
14889
+ "path": "/contacts/{address}",
14890
+ "pathParams": [{
14891
+ "description": "address for contacts.",
14892
+ "enum": null,
14893
+ "name": "address",
14894
+ "required": true,
14895
+ "type": "string"
14896
+ }],
14897
+ "queryParams": [{
14898
+ "description": "if_version for contacts.",
14899
+ "enum": null,
14900
+ "name": "if_version",
14901
+ "required": true,
14902
+ "type": "string"
14903
+ }],
14904
+ "requestSchema": null,
12742
14905
  "responseSchema": {
12743
14906
  "type": "object",
12744
- "properties": {
12745
- "email": {
12746
- "type": "string",
12747
- "format": "email"
12748
- },
12749
- "expires_in": {
12750
- "type": "integer",
12751
- "description": "Seconds until the pending signup expires"
12752
- },
12753
- "resend_after": {
12754
- "type": "integer",
12755
- "description": "Minimum seconds before requesting another verification email"
12756
- },
12757
- "verification_code_length": {
12758
- "type": "integer",
12759
- "description": "Number of digits in the emailed verification code"
12760
- }
12761
- },
12762
- "required": [
12763
- "email",
12764
- "expires_in",
12765
- "resend_after",
12766
- "verification_code_length"
12767
- ]
14907
+ "additionalProperties": false,
14908
+ "properties": { "deleted": { "type": "boolean" } },
14909
+ "required": ["deleted"]
12768
14910
  },
12769
- "sdkName": "resendCliSignupVerification",
12770
- "summary": "Resend CLI signup verification code",
12771
- "tag": "CLI",
12772
- "tagCommand": "cli"
14911
+ "sdkName": "deleteContact",
14912
+ "summary": "delete Contact",
14913
+ "tag": "Contacts",
14914
+ "tagCommand": "contacts"
12773
14915
  },
12774
14916
  {
12775
14917
  "binaryResponse": false,
12776
14918
  "bodyRequired": false,
12777
- "command": "start-cli-login",
12778
- "description": "Starts a browser-assisted CLI login session. The response includes a\ndevice code for polling and a user code that the user approves in the\nbrowser. This endpoint does not require an API key.\n",
12779
- "hasJsonBody": true,
12780
- "method": "POST",
12781
- "operationId": "startCliLogin",
12782
- "path": "/cli/login/start",
12783
- "pathParams": [],
14919
+ "command": "get-contact",
14920
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
14921
+ "hasJsonBody": false,
14922
+ "method": "GET",
14923
+ "operationId": "getContact",
14924
+ "path": "/contacts/{address}",
14925
+ "pathParams": [{
14926
+ "description": "address for contacts.",
14927
+ "enum": null,
14928
+ "name": "address",
14929
+ "required": true,
14930
+ "type": "string"
14931
+ }],
12784
14932
  "queryParams": [],
12785
- "requestSchema": {
14933
+ "requestSchema": null,
14934
+ "responseSchema": {
12786
14935
  "type": "object",
12787
14936
  "additionalProperties": false,
12788
14937
  "properties": {
12789
- "device_name": {
14938
+ "address": {
12790
14939
  "type": "string",
12791
- "minLength": 1,
12792
- "maxLength": 80,
12793
- "description": "Human-readable device name shown during browser approval"
14940
+ "format": "email",
14941
+ "maxLength": 254,
14942
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
12794
14943
  },
12795
- "metadata": {
12796
- "type": "object",
12797
- "additionalProperties": true,
12798
- "description": "Optional client metadata stored with the login session; serialized JSON must be 2048 bytes or fewer"
12799
- }
12800
- }
12801
- },
12802
- "responseSchema": {
12803
- "type": "object",
12804
- "properties": {
12805
- "device_code": {
12806
- "type": "string",
12807
- "description": "Opaque code used by the CLI to poll for approval"
14944
+ "display_name": {
14945
+ "type": ["string", "null"],
14946
+ "maxLength": 200
12808
14947
  },
12809
- "user_code": {
14948
+ "version": {
12810
14949
  "type": "string",
12811
- "pattern": "^[BCDFGHJKLMNPQRSTVWXZ]{4}-[BCDFGHJKLMNPQRSTVWXZ]{4}$",
12812
- "description": "Short code the user confirms in the browser"
14950
+ "format": "uuid",
14951
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
12813
14952
  },
12814
- "verification_uri": {
14953
+ "created_at": {
12815
14954
  "type": "string",
12816
- "description": "Browser URL where the user approves the login"
14955
+ "format": "date-time"
12817
14956
  },
12818
- "verification_uri_complete": {
14957
+ "updated_at": {
12819
14958
  "type": "string",
12820
- "description": "Browser URL with the user code prefilled"
14959
+ "format": "date-time"
14960
+ }
14961
+ },
14962
+ "required": [
14963
+ "address",
14964
+ "display_name",
14965
+ "version",
14966
+ "created_at",
14967
+ "updated_at"
14968
+ ]
14969
+ },
14970
+ "sdkName": "getContact",
14971
+ "summary": "get Contact",
14972
+ "tag": "Contacts",
14973
+ "tagCommand": "contacts"
14974
+ },
14975
+ {
14976
+ "binaryResponse": false,
14977
+ "bodyRequired": false,
14978
+ "command": "list-agent-contacts",
14979
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
14980
+ "hasJsonBody": false,
14981
+ "method": "GET",
14982
+ "operationId": "listAgentContacts",
14983
+ "path": "/agent-contacts/{agent_address}",
14984
+ "pathParams": [{
14985
+ "description": "agent_address for contacts.",
14986
+ "enum": null,
14987
+ "name": "agent_address",
14988
+ "required": true,
14989
+ "type": "string"
14990
+ }],
14991
+ "queryParams": [{
14992
+ "description": "cursor for contacts.",
14993
+ "enum": null,
14994
+ "name": "cursor",
14995
+ "required": false,
14996
+ "type": "string"
14997
+ }, {
14998
+ "default": 50,
14999
+ "description": "limit for contacts.",
15000
+ "enum": null,
15001
+ "maximum": 100,
15002
+ "minimum": 1,
15003
+ "name": "limit",
15004
+ "required": false,
15005
+ "type": "integer"
15006
+ }],
15007
+ "requestSchema": null,
15008
+ "responseSchema": {
15009
+ "type": "array",
15010
+ "items": {
15011
+ "type": "object",
15012
+ "additionalProperties": false,
15013
+ "properties": {
15014
+ "agent_address": {
15015
+ "type": "string",
15016
+ "format": "email",
15017
+ "maxLength": 254,
15018
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
15019
+ },
15020
+ "contact_address": {
15021
+ "type": "string",
15022
+ "format": "email",
15023
+ "maxLength": 254,
15024
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
15025
+ },
15026
+ "purpose": {
15027
+ "type": ["string", "null"],
15028
+ "maxLength": 2e3
15029
+ },
15030
+ "notify": { "type": "boolean" },
15031
+ "notify_since": {
15032
+ "type": ["string", "null"],
15033
+ "format": "date-time"
15034
+ },
15035
+ "notification_generation": {
15036
+ "type": ["string", "null"],
15037
+ "format": "uuid"
15038
+ },
15039
+ "version": {
15040
+ "type": "string",
15041
+ "format": "uuid",
15042
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
15043
+ },
15044
+ "created_at": {
15045
+ "type": "string",
15046
+ "format": "date-time"
15047
+ },
15048
+ "updated_at": {
15049
+ "type": "string",
15050
+ "format": "date-time"
15051
+ }
12821
15052
  },
12822
- "expires_in": {
12823
- "type": "integer",
12824
- "description": "Seconds until the login session expires"
15053
+ "required": [
15054
+ "agent_address",
15055
+ "contact_address",
15056
+ "purpose",
15057
+ "notify",
15058
+ "notify_since",
15059
+ "notification_generation",
15060
+ "version",
15061
+ "created_at",
15062
+ "updated_at"
15063
+ ]
15064
+ }
15065
+ },
15066
+ "sdkName": "listAgentContacts",
15067
+ "summary": "list Agent Contacts",
15068
+ "tag": "Contacts",
15069
+ "tagCommand": "contacts"
15070
+ },
15071
+ {
15072
+ "binaryResponse": false,
15073
+ "bodyRequired": false,
15074
+ "command": "list-contacts",
15075
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
15076
+ "hasJsonBody": false,
15077
+ "method": "GET",
15078
+ "operationId": "listContacts",
15079
+ "path": "/contacts",
15080
+ "pathParams": [],
15081
+ "queryParams": [{
15082
+ "description": "cursor for contacts.",
15083
+ "enum": null,
15084
+ "name": "cursor",
15085
+ "required": false,
15086
+ "type": "string"
15087
+ }, {
15088
+ "default": 50,
15089
+ "description": "limit for contacts.",
15090
+ "enum": null,
15091
+ "maximum": 100,
15092
+ "minimum": 1,
15093
+ "name": "limit",
15094
+ "required": false,
15095
+ "type": "integer"
15096
+ }],
15097
+ "requestSchema": null,
15098
+ "responseSchema": {
15099
+ "type": "array",
15100
+ "items": {
15101
+ "type": "object",
15102
+ "additionalProperties": false,
15103
+ "properties": {
15104
+ "address": {
15105
+ "type": "string",
15106
+ "format": "email",
15107
+ "maxLength": 254,
15108
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
15109
+ },
15110
+ "display_name": {
15111
+ "type": ["string", "null"],
15112
+ "maxLength": 200
15113
+ },
15114
+ "version": {
15115
+ "type": "string",
15116
+ "format": "uuid",
15117
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
15118
+ },
15119
+ "created_at": {
15120
+ "type": "string",
15121
+ "format": "date-time"
15122
+ },
15123
+ "updated_at": {
15124
+ "type": "string",
15125
+ "format": "date-time"
15126
+ }
12825
15127
  },
12826
- "interval": {
12827
- "type": "integer",
12828
- "description": "Minimum seconds between poll requests"
12829
- }
12830
- },
12831
- "required": [
12832
- "device_code",
12833
- "user_code",
12834
- "verification_uri",
12835
- "verification_uri_complete",
12836
- "expires_in",
12837
- "interval"
12838
- ]
15128
+ "required": [
15129
+ "address",
15130
+ "display_name",
15131
+ "version",
15132
+ "created_at",
15133
+ "updated_at"
15134
+ ]
15135
+ }
12839
15136
  },
12840
- "sdkName": "startCliLogin",
12841
- "summary": "Start CLI browser login",
12842
- "tag": "CLI",
12843
- "tagCommand": "cli"
15137
+ "sdkName": "listContacts",
15138
+ "summary": "list Contacts",
15139
+ "tag": "Contacts",
15140
+ "tagCommand": "contacts"
12844
15141
  },
12845
15142
  {
12846
15143
  "binaryResponse": false,
12847
15144
  "bodyRequired": true,
12848
- "command": "start-cli-signup",
12849
- "description": "Starts a terminal-native CLI signup. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
15145
+ "command": "put-agent-contact",
15146
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
12850
15147
  "hasJsonBody": true,
12851
- "method": "POST",
12852
- "operationId": "startCliSignup",
12853
- "path": "/cli/signup/start",
12854
- "pathParams": [],
15148
+ "method": "PUT",
15149
+ "operationId": "putAgentContact",
15150
+ "path": "/agent-contacts/{agent_address}/{contact_address}",
15151
+ "pathParams": [{
15152
+ "description": "agent_address for contacts.",
15153
+ "enum": null,
15154
+ "name": "agent_address",
15155
+ "required": true,
15156
+ "type": "string"
15157
+ }, {
15158
+ "description": "contact_address for contacts.",
15159
+ "enum": null,
15160
+ "name": "contact_address",
15161
+ "required": true,
15162
+ "type": "string"
15163
+ }],
12855
15164
  "queryParams": [],
12856
- "requestSchema": {
15165
+ "requestSchema": { "oneOf": [{
12857
15166
  "type": "object",
12858
15167
  "additionalProperties": false,
12859
15168
  "properties": {
12860
- "email": {
12861
- "type": "string",
12862
- "format": "email",
12863
- "maxLength": 254
12864
- },
12865
- "signup_code": {
12866
- "type": "string",
12867
- "minLength": 1,
12868
- "maxLength": 128,
12869
- "description": "Optional signup code. Omit if you do not have one."
15169
+ "purpose": {
15170
+ "type": ["string", "null"],
15171
+ "maxLength": 2e3
12870
15172
  },
12871
- "terms_accepted": {
15173
+ "notify": { "type": "boolean" },
15174
+ "if_absent": {
12872
15175
  "type": "boolean",
12873
- "const": true,
12874
- "description": "Must be true to confirm acceptance of Primitive's Terms of Service and Privacy Policy"
15176
+ "const": true
15177
+ }
15178
+ },
15179
+ "required": ["if_absent"]
15180
+ }, {
15181
+ "type": "object",
15182
+ "additionalProperties": false,
15183
+ "properties": {
15184
+ "purpose": {
15185
+ "type": ["string", "null"],
15186
+ "maxLength": 2e3
12875
15187
  },
12876
- "device_name": {
15188
+ "notify": { "type": "boolean" },
15189
+ "if_version": {
12877
15190
  "type": "string",
12878
- "minLength": 1,
12879
- "maxLength": 80,
12880
- "description": "Human-readable device name used for the created CLI OAuth grant"
12881
- },
12882
- "metadata": {
12883
- "type": "object",
12884
- "additionalProperties": true,
12885
- "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
15191
+ "format": "uuid",
15192
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
12886
15193
  }
12887
15194
  },
12888
- "required": ["email", "terms_accepted"]
12889
- },
15195
+ "required": ["if_version"]
15196
+ }] },
12890
15197
  "responseSchema": {
12891
15198
  "type": "object",
15199
+ "additionalProperties": false,
12892
15200
  "properties": {
12893
- "signup_token": {
15201
+ "agent_address": {
12894
15202
  "type": "string",
12895
- "description": "Opaque token used to verify or resend the pending CLI signup"
15203
+ "format": "email",
15204
+ "maxLength": 254,
15205
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
12896
15206
  },
12897
- "email": {
15207
+ "contact_address": {
12898
15208
  "type": "string",
12899
- "format": "email"
15209
+ "format": "email",
15210
+ "maxLength": 254,
15211
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
12900
15212
  },
12901
- "expires_in": {
12902
- "type": "integer",
12903
- "description": "Seconds until the pending signup expires"
15213
+ "purpose": {
15214
+ "type": ["string", "null"],
15215
+ "maxLength": 2e3
12904
15216
  },
12905
- "resend_after": {
12906
- "type": "integer",
12907
- "description": "Minimum seconds before requesting another verification email"
15217
+ "notify": { "type": "boolean" },
15218
+ "notify_since": {
15219
+ "type": ["string", "null"],
15220
+ "format": "date-time"
12908
15221
  },
12909
- "verification_code_length": {
12910
- "type": "integer",
12911
- "description": "Number of digits in the emailed verification code"
15222
+ "notification_generation": {
15223
+ "type": ["string", "null"],
15224
+ "format": "uuid"
15225
+ },
15226
+ "version": {
15227
+ "type": "string",
15228
+ "format": "uuid",
15229
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
15230
+ },
15231
+ "created_at": {
15232
+ "type": "string",
15233
+ "format": "date-time"
15234
+ },
15235
+ "updated_at": {
15236
+ "type": "string",
15237
+ "format": "date-time"
12912
15238
  }
12913
15239
  },
12914
15240
  "required": [
12915
- "signup_token",
12916
- "email",
12917
- "expires_in",
12918
- "resend_after",
12919
- "verification_code_length"
15241
+ "agent_address",
15242
+ "contact_address",
15243
+ "purpose",
15244
+ "notify",
15245
+ "notify_since",
15246
+ "notification_generation",
15247
+ "version",
15248
+ "created_at",
15249
+ "updated_at"
12920
15250
  ]
12921
15251
  },
12922
- "sdkName": "startCliSignup",
12923
- "summary": "Start CLI account signup",
12924
- "tag": "CLI",
12925
- "tagCommand": "cli"
15252
+ "sdkName": "putAgentContact",
15253
+ "summary": "put Agent Contact",
15254
+ "tag": "Contacts",
15255
+ "tagCommand": "contacts"
12926
15256
  },
12927
15257
  {
12928
15258
  "binaryResponse": false,
12929
15259
  "bodyRequired": true,
12930
- "command": "verify-cli-signup",
12931
- "description": "Verifies the email code for a CLI signup session and creates the\naccount. When the session was started with a `signup_code`, the\nreserved code is redeemed; sessions started without a code skip\nthe redemption step. Either way an org-scoped OAuth CLI session\nis created and the token set is returned exactly once. This\nendpoint does not require an API key.\n",
15260
+ "command": "put-contact",
15261
+ "description": "Organization directory and agent preferences; no profiles, message history or runtime presence. Existing organization credentials use tenant permissions. Connected keys may read the directory, create address-only missing contacts using if_absent:true, and access only their own agent memberships; they cannot edit shared labels or delete directory entries. Function credentials are not granted access. Memberships require an existing local agent connection (including revoked connections) and an existing contact. PUT requires exactly one precondition. if_absent returns an existing row unchanged when supplied fields agree; otherwise 409. notify defaults false. Off-to-on generates a new server timestamp and generation; on-to-on and purpose-only edits preserve them. Disable clears activation metadata. Deletion atomically removes membership eligibility. Receivers must recheck generation/preferences before dispatch and pause admission when their policy cache is older than 30 seconds; explicit reply waits are independent. DELETE requires if_version, returns deleted:false for an absent row, and rejects stale versions of recreated rows. Pages use ascending canonical address, with meta.cursor null on the last page. Lists are live pages, not snapshots.",
12932
15262
  "hasJsonBody": true,
12933
- "method": "POST",
12934
- "operationId": "verifyCliSignup",
12935
- "path": "/cli/signup/verify",
12936
- "pathParams": [],
15263
+ "method": "PUT",
15264
+ "operationId": "putContact",
15265
+ "path": "/contacts/{address}",
15266
+ "pathParams": [{
15267
+ "description": "address for contacts.",
15268
+ "enum": null,
15269
+ "name": "address",
15270
+ "required": true,
15271
+ "type": "string"
15272
+ }],
12937
15273
  "queryParams": [],
12938
- "requestSchema": {
15274
+ "requestSchema": { "oneOf": [{
12939
15275
  "type": "object",
12940
15276
  "additionalProperties": false,
12941
15277
  "properties": {
12942
- "signup_token": {
12943
- "type": "string",
12944
- "minLength": 1
12945
- },
12946
- "verification_code": {
12947
- "type": "string",
12948
- "minLength": 1,
12949
- "maxLength": 32
15278
+ "display_name": {
15279
+ "type": ["string", "null"],
15280
+ "maxLength": 200
12950
15281
  },
12951
- "password": {
12952
- "type": "string",
12953
- "minLength": 1,
12954
- "maxLength": 1024
15282
+ "if_absent": {
15283
+ "type": "boolean",
15284
+ "const": true
12955
15285
  }
12956
15286
  },
12957
- "required": ["signup_token", "verification_code"]
12958
- },
12959
- "responseSchema": {
15287
+ "required": ["if_absent"]
15288
+ }, {
12960
15289
  "type": "object",
15290
+ "additionalProperties": false,
12961
15291
  "properties": {
12962
- "api_key": {
12963
- "type": "string",
12964
- "description": "Legacy alias for access_token. New CLI builds should persist access_token and refresh_token."
15292
+ "display_name": {
15293
+ "type": ["string", "null"],
15294
+ "maxLength": 200
12965
15295
  },
12966
- "key_id": {
15296
+ "if_version": {
12967
15297
  "type": "string",
12968
15298
  "format": "uuid",
12969
- "description": "Legacy alias for oauth_grant_id"
12970
- },
12971
- "key_prefix": {
12972
- "type": "string",
12973
- "description": "Legacy display prefix derived from access_token"
12974
- },
12975
- "access_token": {
12976
- "type": "string",
12977
- "description": "OAuth access token for CLI API authentication"
12978
- },
12979
- "refresh_token": {
12980
- "type": "string",
12981
- "description": "OAuth refresh token used by the CLI to renew access"
12982
- },
12983
- "token_type": {
15299
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
15300
+ }
15301
+ },
15302
+ "required": ["if_version"]
15303
+ }] },
15304
+ "responseSchema": {
15305
+ "type": "object",
15306
+ "additionalProperties": false,
15307
+ "properties": {
15308
+ "address": {
12984
15309
  "type": "string",
12985
- "enum": ["Bearer"]
15310
+ "format": "email",
15311
+ "maxLength": 254,
15312
+ "description": "Bare email address; trim and lowercase, preserving dots and plus tags."
12986
15313
  },
12987
- "expires_in": {
12988
- "type": "integer",
12989
- "description": "Seconds until access_token expires"
15314
+ "display_name": {
15315
+ "type": ["string", "null"],
15316
+ "maxLength": 200
12990
15317
  },
12991
- "auth_method": {
15318
+ "version": {
12992
15319
  "type": "string",
12993
- "enum": ["oauth"]
15320
+ "format": "uuid",
15321
+ "description": "Opaque CAS token. Changes on mutations and cannot be reused after deletion/recreation."
12994
15322
  },
12995
- "oauth_grant_id": {
15323
+ "created_at": {
12996
15324
  "type": "string",
12997
- "format": "uuid"
15325
+ "format": "date-time"
12998
15326
  },
12999
- "oauth_client_id": { "type": "string" },
13000
- "org_id": {
15327
+ "updated_at": {
13001
15328
  "type": "string",
13002
- "format": "uuid"
13003
- },
13004
- "org_name": { "type": ["string", "null"] }
15329
+ "format": "date-time"
15330
+ }
13005
15331
  },
13006
15332
  "required": [
13007
- "api_key",
13008
- "key_id",
13009
- "key_prefix",
13010
- "access_token",
13011
- "refresh_token",
13012
- "token_type",
13013
- "expires_in",
13014
- "auth_method",
13015
- "oauth_grant_id",
13016
- "oauth_client_id",
13017
- "org_id",
13018
- "org_name"
15333
+ "address",
15334
+ "display_name",
15335
+ "version",
15336
+ "created_at",
15337
+ "updated_at"
13019
15338
  ]
13020
15339
  },
13021
- "sdkName": "verifyCliSignup",
13022
- "summary": "Verify CLI signup and create OAuth session",
13023
- "tag": "CLI",
13024
- "tagCommand": "cli"
15340
+ "sdkName": "putContact",
15341
+ "summary": "put Contact",
15342
+ "tag": "Contacts",
15343
+ "tagCommand": "contacts"
13025
15344
  },
13026
15345
  {
13027
15346
  "binaryResponse": false,