{"openapi":"3.1.0","info":{"title":"DoggySign API","version":"1.0.0","description":"A REST API on the SAME meter and the same allowance as the user interface.\n\nBoth paths call one `Meter.recordSend`, so an API send and a UI send cost exactly\nthe same thing and are counted in one place. The API is not a separate service with\nits own quota.\n\n**Corrections, voids, resends, drafts, test sends and re-issues never cost anything.**\nOnly the first successful send of a packet is billable. Every other action still\nwrites a ledger row, so `GET /v1/usage` can show you that it was free rather than\nshowing you silence.\n\n**There is no sign endpoint.** A signature is only ever applied inside a\nparty-authenticated signing session. `POST /v1/packets/{id}/signing-sessions` mints\nthe URL for one; a `returnUrl` the browser lands on afterwards is a browser signal,\nnever proof of completion. The webhook and the audit log are the truth.\n\nRate limit: 5000 requests per hour per key, enforced with 429 and\na `Retry-After` header. Never a human review gate."},"servers":[{"url":"https://doggysign.com/v1"}],"tags":[{"name":"Packets","description":"Create, read, send and change packets."},{"name":"Templates","description":"Reusable packets. Same entity, discriminated by kind."},{"name":"Evidence","description":"The audit trail and the Signing Certificate."},{"name":"Signing","description":"Party-authenticated signing sessions (R8)."},{"name":"Webhooks","description":"Endpoints, the delivery log, and replay."},{"name":"Account","description":"Capabilities and the per-unit usage ledger."}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key, as `Authorization: Bearer pb_...`.\n\nScopes are granular and are checked per route. A scope says what the KEY may do;\nthe account the key acts as still has to be permitted the action. Both must pass,\nso issuing a key never escalates whoever holds it, and revoking a person’s\nmembership revokes their keys with it.\n\nScopes: `packets:read`, `packets:write`, `packets:send`, `templates:read`, `templates:write`, `webhooks:read`, `webhooks:write`, `usage:read`."}},"schemas":{"Error":{"type":"object","required":["code","message","requestId","docsUrl","retryable","details"],"description":"One error contract for every route. The cause is never misreported, and a partial failure is never returned as a 200 with failures buried in the body.","properties":{"code":{"type":"string","enum":["bad_request","validation_failed","unauthenticated","forbidden","not_found","conflict","locked","limit_exceeded","rate_limited","unsupported_media_type","payload_too_large","internal_error","service_unavailable"]},"message":{"type":"string"},"requestId":{"type":"string","description":"Echoed on every response, so a support conversation can name one request."},"docsUrl":{"type":"string"},"retryable":{"type":"boolean","description":"Whether the identical request may be retried unchanged."},"details":{"type":"array","items":{"type":"object","required":["path","code","message"],"properties":{"path":{"type":"string","description":"JSON pointer, e.g. /parties/0/email."},"code":{"type":"string"},"message":{"type":"string"}}},"description":"Every problem with the request, not the first one. A sender with three mistakes should see three."}}},"Packet":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["packet","template"]},"status":{"type":"string","enum":["draft","sent","viewed","completed","declined","voided","expired"]},"title":{"type":"string"},"emailSubject":{"type":"string"},"emailBody":{"type":"string"},"currentStage":{"type":"integer"},"expiresAt":{"type":["string","null"],"format":"date-time"},"externalId":{"type":["string","null"],"description":"Your own reference. Indexed."},"createdAt":{"type":"string","format":"date-time"},"sentAt":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"meterEventId":{"type":["string","null"],"description":"The single billable send, or null if this packet never sent."}}},"Party":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"localId":{"type":"string","description":"Chosen by you and unique only within the packet. Fields join on it, so a whole packet is one POST with no round-trip to learn server ids."},"role":{"type":"string","enum":["signer","approver","viewer","copy","delegator"]},"name":{"type":"string"},"email":{"type":"string","format":"email"},"stage":{"type":"integer","description":"Equal integers are notified together."},"status":{"type":"string","enum":["pending","sent","viewed","completed","declined","bounced","delegated"]},"externalUserId":{"type":["string","null"],"description":"The embedded-signing switch. Non-null means no email is sent."},"bounceReason":{"type":["string","null"],"description":"Reported for every role, copy parties included. You never have to change a party’s role to learn that their address failed."}}},"Document":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"localId":{"type":"string"},"name":{"type":"string"},"order":{"type":"integer"},"pageCount":{"type":"integer"},"sizeBytes":{"type":"integer"},"sha256":{"type":"string"}}},"Field":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string","description":"The field key: your export column, your CSV header, your conditional reference and your mirror key, all at once. You author it; we never generate one."},"type":{"type":"string","enum":["signature","initials","date_signed","full_name","email","text","number","date","checkbox","radio_group","dropdown","formula","attachment","company","title","approve","decline"]},"required":{"type":"boolean"},"value":{"type":["string","null"]}}},"AuditEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"seq":{"type":"integer","description":"Monotonic per packet and gapless."},"type":{"type":"string","enum":["packet.created","packet.sent","packet.resent","packet.viewed","packet.completed","packet.declined","packet.voided","packet.expired","packet.corrected","packet.deleted","packet.purge_queued","packet.purged","packet.reminder_sent","packet.locked","packet.unlocked","packet.ownership_transferred","party.email_sent","party.email_bounced","party.opened","party.viewed","party.consent_accepted","party.auth_passed","party.auth_failed","party.signature_adopted","party.field_completed","party.finished","party.declined","party.delegated","party.finish_later","party.downloaded","party.printed","document.added","document.replaced","document.removed","document.flattened","certificate.generated","webhook.delivered","webhook.failed"]},"occurredAt":{"type":"string","format":"date-time"},"payload":{"type":"object","additionalProperties":true},"prevHash":{"type":"string"},"hash":{"type":"string","description":"SHA-256 over a canonical form of this event."}}},"MeterEvent":{"type":"object","description":"One row per action, line by line. Never a monthly aggregate.","properties":{"id":{"type":"string","format":"uuid"},"packetId":{"type":"string","format":"uuid"},"occurredAt":{"type":"string","format":"date-time"},"source":{"type":"string","enum":["ui","api","import","public_link"]},"reason":{"type":"string"},"billable":{"type":"boolean","description":"True for exactly one reason: first_send."}}},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"description":{"type":"string"},"secret":{"type":"string","description":"Returned only when the endpoint is created or its secret rotated."},"events":{"type":"array","items":{"type":"string","enum":["packet.created","packet.sent","packet.resent","packet.viewed","packet.completed","packet.declined","packet.voided","packet.expired","packet.corrected","packet.deleted","packet.purge_queued","packet.purged","packet.reminder_sent","packet.locked","packet.unlocked","packet.ownership_transferred","party.email_sent","party.email_bounced","party.opened","party.viewed","party.consent_accepted","party.auth_passed","party.auth_failed","party.signature_adopted","party.field_completed","party.finished","party.declined","party.delegated","party.finish_later","party.downloaded","party.printed","document.added","document.replaced","document.removed","document.flattened","certificate.generated","webhook.delivered","webhook.failed"]},"description":"Empty means every event."},"status":{"type":"string","enum":["active","failing","disabled"]},"consecutiveFailures":{"type":"integer"}}},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string"},"eventType":{"type":"string"},"state":{"type":"string","enum":["pending","delivering","delivered","failed","dead_lettered"]},"attempt":{"type":"integer"},"statusCode":{"type":["integer","null"]},"responseBody":{"type":["string","null"]},"nextRetryAt":{"type":["string","null"],"format":"date-time"}}},"SigningSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"packetId":{"type":"string","format":"uuid"},"partyId":{"type":"string","format":"uuid"},"url":{"type":"string","description":"Single-use and short-lived. Returned once; we cannot show it again."},"expiresAt":{"type":"string","format":"date-time"}}},"PacketPage":{"type":"object","required":["items","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Packet"}},"nextCursor":{"type":["string","null"],"description":"Opaque. Pass back verbatim; never parse it in a client."},"hasMore":{"type":"boolean"}}},"AuditEventPage":{"type":"object","required":["items","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AuditEvent"}},"nextCursor":{"type":["string","null"],"description":"Opaque. Pass back verbatim; never parse it in a client."},"hasMore":{"type":"boolean"}}},"MeterEventPage":{"type":"object","required":["items","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/MeterEvent"}},"nextCursor":{"type":["string","null"],"description":"Opaque. Pass back verbatim; never parse it in a client."},"hasMore":{"type":"boolean"}}},"WebhookDeliveryPage":{"type":"object","required":["items","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"nextCursor":{"type":["string","null"],"description":"Opaque. Pass back verbatim; never parse it in a client."},"hasMore":{"type":"boolean"}}}}},"x-webhooks":{"signature":{"description":"Every delivery carries `X-Webhook-Signature: t=<unix>,v1=<hex>`, an HMAC-SHA256 over\n`<timestamp>.<raw body>` using the endpoint secret.\n\n**The timestamp is inside the signed material, not beside it.** A signature over the\nbody alone stays valid forever, so anyone who captures one request can replay it at\nany point in the future and it still verifies. Bind the timestamp in and a replay is\ndetectable: reject anything more than 300 seconds from your\nown clock, and compare digests in constant time.\n\nAlso sent: `X-Webhook-Timestamp`, `X-Webhook-Id` (stable per event — use it\nto deduplicate a redelivery), `X-Webhook-Event` and `X-Webhook-Attempt`.\n\nFailed deliveries retry with exponential backoff plus full jitter, an endpoint that\nkeeps failing is backed off and eventually disabled rather than retried forever, and\nanything that exhausts its attempts is dead-lettered and kept — so you can fix your\nreceiver and replay it yourself."}},"x-limits":{"partiesPerPacket":50,"documentsPerPacket":20,"pagesPerDocument":500,"pagesPerPacket":1000,"bytesPerDocument":26214400,"bytesPerPacket":52428800,"fieldsPerPacket":2000,"webhookEndpointsPerWorkspace":20},"paths":{"/packets":{"post":{"summary":"Create a packet","description":"Documents, parties, fields and routing in one call, using ids you choose yourself. Pass `send: true` to create and send in one request, which also requires `packets:send`. Validation problems come back as a list, because a sender with three mistakes should see three.\n\nRequires scope: `packets:write`.","tags":["Packets"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed. Every problem is listed in `details`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List packets","description":"Newest first, cursor paginated. Filter by `status` or your `externalId`.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"From a previous response’s nextCursor. Opaque."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","sent","viewed","completed","declined","voided","expired"]}},{"name":"externalId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of packets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacketPage"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}":{"get":{"summary":"Read a packet","description":"Status and metadata. Reads never change anything, including a lock.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The packet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such packet in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/send":{"post":{"summary":"Send a packet","description":"An explicit transition, never a status write. This is the one billable action in the whole API, and it is metered by the same function the user interface calls.\n\nRequires scope: `packets:send`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The packet cannot be sent from its current status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/void":{"post":{"summary":"Void a packet","description":"Terminal and irreversible. A reason is required. Never billable.\n\nRequires scope: `packets:send`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Voided.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A reason is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/resend":{"post":{"summary":"Resend to outstanding parties","description":"New links, and the reminder clock restarts. Never billable.\n\nRequires scope: `packets:send`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Resent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/correct":{"post":{"summary":"Correct a packet in flight","description":"Fix a name, an address, the message or the expiry while the packet is moving. Never billable — a typo in someone’s name does not cost you a send.\n\nRequires scope: `packets:write`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Corrected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"Somebody else holds the correction lock.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/documents":{"get":{"summary":"List documents","description":"With the SHA-256 the certificate prints and the verification page checks.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The documents.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/documents/{documentId}":{"get":{"summary":"Download a document","description":"The PDF bytes. `?combined` for the whole set, `?certificate` to append it.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"application/pdf"},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/parties":{"get":{"summary":"List parties","description":"Including `bounceReason` for every role. You never have to change a party’s role to find out that their address failed.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The parties.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/fields":{"get":{"summary":"Read field values","description":"Keyed by field key — the identifier you authored, not a uuid.\n\nRequires scope: `packets:read`.","tags":["Packets"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Values, keyed by field key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Field"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/audit-events":{"get":{"summary":"Read the audit trail","description":"Typed events with their hash chain, so you can verify it yourself rather than string-matching an untyped array of name/value pairs.\n\nRequires scope: `packets:read`.","tags":["Evidence"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"From a previous response’s nextCursor. Opaque."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"A page of events.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditEventPage"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/certificate":{"get":{"summary":"Read the Signing Certificate","description":"The machine-readable record plus the verification result, and the code anyone can type into the public verification page without an account.\n\nRequires scope: `packets:read`.","tags":["Evidence"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The certificate."},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No certificate has been issued for this packet yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/packets/{id}/signing-sessions":{"post":{"summary":"Mint a signing session","description":"For embedded signing: the party must carry an `externalUserId`, because your app authenticates them. Single-use and short-lived, and minting a new one revokes every previous session for that party, so \"we sent a new link\" is true in the only sense that matters.\n\nA `returnUrl` is where the browser lands afterwards. It proves the browser went there and nothing else — the webhook and the audit log are the truth.\n\nRequires scope: `packets:send`.","tags":["Signing"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"The session URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SigningSession"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"That party is not an embedded-signing party.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/templates":{"get":{"summary":"List templates","description":"The same entity as a packet, discriminated by kind.\n\nRequires scope: `templates:read`.","tags":["Templates"],"security":[{"apiKey":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"From a previous response’s nextCursor. Opaque."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"A page of templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacketPage"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a template","description":"Same payload as a packet, with `kind: template`.\n\nRequires scope: `templates:write`.","tags":["Templates"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/templates/{id}":{"get":{"summary":"Read a template","description":"Metadata for one template.\n\nRequires scope: `templates:read`.","tags":["Templates"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Packet"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a template","description":"Soft delete. Packets already created from it are untouched.\n\nRequires scope: `templates:write`.","tags":["Templates"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/capabilities":{"get":{"summary":"Read the capability object","description":"What this workspace and this key can actually do, and — when something is off — WHICH of the two turned it off. A plan limit and an administrator’s setting are different facts and you are told which one is in play.\n\nRequires scope: `packets:read`.","tags":["Account"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The capability object."},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/usage":{"get":{"summary":"Read the usage ledger","description":"One row per action, line by line, never a monthly aggregate. Corrections, voids, resends, drafts and test sends appear here marked free rather than not appearing at all — so you can reconstruct exactly what you were charged for.\n\nRequires scope: `usage:read`.","tags":["Account"],"security":[{"apiKey":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"From a previous response’s nextCursor. Opaque."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"The ledger.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeterEventPage"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"summary":"List webhook endpoints","description":"Secrets are never returned here.\n\nRequires scope: `webhooks:read`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"The endpoints.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a webhook endpoint","description":"https only, no credentials in the URL, no private or loopback host. The secret is returned once, here.\n\nRequires scope: `webhooks:write`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"responses":{"201":{"description":"Created, with the secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The URL or the event list was rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"put":{"summary":"Update a webhook endpoint","description":"Setting `status: active` also clears the failure counter.\n\nRequires scope: `webhooks:write`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a webhook endpoint","description":"Its delivery history goes with it.\n\nRequires scope: `webhooks:write`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/deliveries":{"get":{"summary":"Read the delivery log","description":"Every attempt, with its status code and the response body your endpoint returned. Failures are kept, not dropped — \"it never arrived\" is only answerable if the failure is still here to read.\n\nRequires scope: `webhooks:read`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"From a previous response’s nextCursor. Opaque."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"endpointId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"A page of deliveries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryPage"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/deliveries/{id}/replay":{"post":{"summary":"Replay a delivery","description":"Self-serve. Fix your endpoint and replay it yourself; you do not need to open a ticket. The payload is the original one, byte for byte.\n\nRequires scope: `webhooks:write`.","tags":["Webhooks"],"security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Queued for redelivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"401":{"description":"No API key, or a key that is revoked, expired or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks a required scope, or the account lacks the permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such delivery in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}