Skip to main content
Glama
document_groups.py17.2 kB
""" SignNow API Data Models - Document Groups and Template Groups Pydantic models for SignNow API responses and requests related to document groups and template groups. """ from typing import Any from typing_extensions import Self from pydantic import BaseModel, EmailStr, Field, HttpUrl class DocumentGroupTemplate(BaseModel): """Single item of the `document_group_templates` array.""" folder_id: str | None = Field(None, description="Folder ID, if the group is stored in a folder") last_updated: int = Field(..., description="Unix timestamp of the last update") template_group_id: str = Field(..., description="Document-group template ID") template_group_name: str = Field(..., description="Name of the template group") owner_email: EmailStr = Field(..., description="Owner of the template group") templates: list[dict[str, Any]] = Field(..., description="Templates in this group") is_prepared: bool = Field(..., description="Whether the group is ready for sending") class DocumentGroupTemplatesResponse(BaseModel): """Full JSON response from `/user/documentgroup/templates`.""" document_group_templates: list[DocumentGroupTemplate] document_group_template_total_count: int = Field(..., description="Total number of template groups in the response") class DocumentGroupDocument(BaseModel): """Document information within a document group.""" id: str = Field(..., description="Document ID") document_name: str | None = Field(None, description="Document name") thumbnail: dict[str, str] = Field(..., description="Document thumbnails") roles: list[str] = Field(..., description="Roles defined for this document") class DocumentGroup(BaseModel): """Single document group from the `/user/documentgroups` endpoint.""" last_updated: int = Field(..., description="Unix timestamp of the last update") group_id: str = Field(..., description="Document group ID") group_name: str = Field(..., description="Name of the document group") invite_id: str | None = Field(None, description="Invite ID for this group") invite_status: str | None = Field(None, description="Status of the invite (e.g., 'pending')") documents: list[DocumentGroupDocument] = Field(..., description="List of documents in this group") class DocumentGroupsResponse(BaseModel): """Full JSON response from `/user/documentgroups`.""" document_groups: list[DocumentGroup] document_group_total_count: int = Field(..., description="Total number of document groups") class CreateDocumentGroupRequest(BaseModel): """Request model for creating document group.""" document_ids: list[str] = Field(..., description="Array of document IDs to group together") group_name: str = Field(..., description="Name for the document group") class CreateDocumentGroupResponse(BaseModel): """Response model for creating document group.""" id: str = Field(..., description="ID of the created document group") class CreateDocumentGroupTemplateRequest(BaseModel): """Request model for creating document group template.""" name: str = Field(..., description="Document group template name") folder_id: str | None = Field(None, description="ID of the templates folder") class CreateDocumentGroupTemplateResponse(BaseModel): """Response model for creating document group template.""" data: dict[str, str] = Field(..., description="Document group template ID") class CreateDocumentGroupTemplateFromGroupRequest(BaseModel): """Request model for creating document group template from document group.""" name: str = Field(..., description="Name for the new document group template") folder_id: str | None = Field(None, description="Folder where to save the template (must be Templates folder or subfolder)") class AddTemplateToDocumentGroupTemplateRequest(BaseModel): """Request model for adding template to document group template.""" document_id: str | None = Field(None, description="ID of the document to add") template_id: str | None = Field(None, description="ID of the template to add") class AddTemplateToDocumentGroupTemplateResponse(BaseModel): """Response model for adding template to document group template.""" data: dict[str, str] = Field(..., description="ID of the added template") class CreateDocumentGroupFromTemplateRequest(BaseModel): """Request model for creating document group from template.""" group_name: str = Field(..., description="Name of the document group") client_timestamp: str | None = Field(None, description="Timestamp of client") folder_id: str | None = Field(None, description="ID of the folder") class DocumentGroupTemplateDocument(BaseModel): """Document in document group template.""" id: str = Field(..., description="Document ID") role: str = Field(..., description="Recipient's role name") action: str = Field(..., description="Allowed action: 'view', 'sign', 'approve'") class DocumentGroupTemplateRecipientReminder(BaseModel): """Reminder settings for document group template recipient.""" remind_after: int | None = Field(None, description="Send reminder after specified days") remind_before: int | None = Field(None, description="Send reminder before expiration") remind_repeat: int | None = Field(None, description="Send reminder every specified days") class DocumentGroupTemplateRecipientAuthentication(BaseModel): """Authentication settings for document group template recipient.""" type: str = Field(..., description="Authentication type: 'phone' or 'password'") value: str | None = Field(None, description="Password value for password authentication") phone: str | None = Field(None, description="Phone number for phone authentication") method: str | None = Field(None, description="Method for phone: 'sms' or 'phone_call'") sms_message: str | None = Field(None, description="Custom SMS message with {password} placeholder") class DocumentGroupTemplateRecipientAttributes(BaseModel): """Attributes for document group template recipient.""" message: str | None = Field(None, description="Invite email message") subject: str | None = Field(None, description="Invite email subject") expiration_days: int | None = Field(None, description="Days until invite expires (3-180)") reminder: DocumentGroupTemplateRecipientReminder | None = Field(None, description="Reminder email settings") allow_forwarding: bool | None = Field(None, description="Allow recipients to reassign invite") i_am_recipient: bool | None = Field(None, description="Document sender is also recipient") show_decline_button: bool | None = Field(None, description="Show decline button on signature fields") redirect_uri: str | None = Field(None, description="URL after recipient completes document") redirect_target: str | None = Field(None, description="Redirect target: 'blank' or 'self'") decline_redirect_uri: str | None = Field(None, description="URL after recipient declines document") close_redirect_uri: str | None = Field(None, description="URL after save progress or close") def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]: # noqa: ANN401 """Override model_dump to exclude redirect_target if redirect_uri is not provided.""" data = super().model_dump(**kwargs) if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data: del data["redirect_target"] return data class DocumentGroupTemplateRecipient(BaseModel): """Recipient in document group template.""" name: str = Field(..., description="Recipient's name") email: str | None = Field(None, description="Recipient's email address") order: int = Field(..., description="Recipient's order of signing") documents: list[DocumentGroupTemplateDocument] = Field(..., description="List of documents and roles") attributes: DocumentGroupTemplateRecipientAttributes | None = Field(None, description="Recipient attributes") class UnmappedDocument(BaseModel): """Unmapped document in document group template.""" id: str = Field(..., description="Document ID") role: str = Field(..., description="Recipient's role name") action: str = Field(..., description="Allowed action") class AllowedUnmappedSignDocument(BaseModel): """Allowed unmapped sign document.""" id: str = Field(..., description="Document ID") role: str = Field(..., description="Recipient's role name") recipient: str = Field(..., description="Recipient's name") class GetDocumentGroupTemplateRecipientsResponse(BaseModel): """Response model for getting document group template recipients.""" data: dict[str, Any] = Field(..., description="Recipients data including recipients, unmapped documents, and cc") class EditDocumentGroupTemplateRecipientsRequest(BaseModel): """Request model for editing document group template recipients.""" recipients: list[DocumentGroupTemplateRecipient] = Field(..., description="List of recipients") unmapped_documents: list[UnmappedDocument] | None = Field(None, description="List of unmapped documents") allowed_unmapped_sign_documents: list[AllowedUnmappedSignDocument] | None = Field(None, description="List of allowed unmapped sign documents") cc: list[str] | None = Field(None, description="List of cc recipient emails (max 100)") class CreateDocumentGroupFromTemplateResponse(BaseModel): """Response model for creating document group from template.""" data: dict[str, Any] = Field(..., description="Created document group data") # Embedded models for document groups class CreateDocumentGroupEmbeddedEditorRequest(BaseModel): """Request model for creating document group embedded editor link.""" redirect_uri: str | None = Field(None, description="Link that opens after editing the document group") link_expiration: int | None = Field(15, description="Link expiration in minutes (default: 15, max: 43200 for Admin users)") redirect_target: str | None = Field("self", description="Redirect target: 'blank' (new tab) or 'self' (same tab)") def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]: # noqa: ANN401 """Override model_dump to exclude redirect_target if redirect_uri is not provided.""" data = super().model_dump(**kwargs) if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data: del data["redirect_target"] return data class CreateDocumentGroupEmbeddedSendingRequest(BaseModel): """Request model for creating document group embedded sending link.""" redirect_uri: str | None = Field(None, description="Page that opens after embedded sending has been set up") redirect_target: str | None = Field("self", description="Redirect target: 'blank' (new tab) or 'self' (same tab)") link_expiration: int | None = Field(15, description="Link expiration in minutes (15-45, max: 43200 for Admin users)") type: str | None = Field("manage", description="Sending step: 'manage' (Add documents), 'edit' (editor), 'send-invite' (Send Invite page)") def model_dump(self: Self, **kwargs: Any) -> dict[str, Any]: # noqa: ANN401 """Override model_dump to exclude redirect_target if redirect_uri is not provided.""" data = super().model_dump(**kwargs) if (not self.redirect_uri or not self.redirect_uri.strip()) and "redirect_target" in data: del data["redirect_target"] return data class GetDocumentGroupResponse(BaseModel): """Response model for getting a single document group.""" id: str = Field(..., description="Document group ID") group_name: str = Field(..., description="Name of the document group") invite_id: str | None = Field(None, description="Invite ID for this group") documents: list[DocumentGroupDocument] = Field(..., description="List of documents in this group") originator_organization_settings: list[dict[str, Any]] = Field(..., description="Organization settings for the originator") # V2 Document Group models class DocumentGroupV2Owner(BaseModel): """Owner information in v2 document group response.""" id: str = Field(..., description="Owner ID") email: str = Field(..., description="Owner email") organization: dict[str, str] = Field(..., description="Organization info with ID") class DocumentGroupV2Thumbnail(BaseModel): """Thumbnail URLs for document in v2 response.""" small: str = Field(..., description="Small thumbnail URL") medium: str = Field(..., description="Medium thumbnail URL") large: str = Field(..., description="Large thumbnail URL") class DocumentGroupV2EmailStatus(BaseModel): """Email status for field invite in v2 response.""" status: str = Field(..., description="Email status (e.g., 'sent')") created_at: int = Field(..., description="Unix timestamp when status was created") last_reaction_at: int = Field(..., description="Unix timestamp of last reaction") class DocumentGroupV2EmailGroup(BaseModel): """Email group information in v2 response.""" id: str | None = Field(None, description="Email group ID") name: str | None = Field(None, description="Email group name") class DocumentGroupV2FieldInvite(BaseModel): """Field invite information in v2 response.""" id: str = Field(..., description="Field invite ID") created: int = Field(..., description="Unix timestamp when invite was created") updated: int = Field(..., description="Unix timestamp when invite was updated") status: str = Field(..., description="Invite status (e.g., 'pending')") expiration_time: int = Field(..., description="Unix timestamp when invite expires") expiration_days: int = Field(..., description="Number of days until expiration") signer_email: str = Field(..., description="Email of the signer") password_protected: str = Field(..., description="Whether invite is password protected ('1' or '0')") email_group: DocumentGroupV2EmailGroup | None = Field(None, description="Email group if used") email_statuses: list[DocumentGroupV2EmailStatus] = Field(..., description="List of email statuses") class DocumentGroupV2DocumentOwner(BaseModel): """Document owner information in v2 response.""" id: str = Field(..., description="Document owner ID") email: str = Field(..., description="Document owner email") class DocumentGroupV2Document(BaseModel): """Document information in v2 document group response.""" roles: list[str] = Field(..., description="List of roles for this document") document_name: str = Field(..., description="Name of the document") id: str = Field(..., description="Document ID") updated: int = Field(..., description="Unix timestamp when document was last updated") field_invites: list[DocumentGroupV2FieldInvite] = Field(..., description="List of field invites for this document") class DocumentGroupV2FreeformInvite(BaseModel): """Freeform invite information in v2 response.""" id: str | None = Field(None, description="Freeform invite ID") last_id: str | None = Field(None, description="Last freeform invite ID") class DocumentGroupV2Data(BaseModel): """Document group data in v2 response.""" id: str = Field(..., description="Document group ID") name: str = Field(..., description="Document group name") created: int = Field(..., description="Unix timestamp when group was created") invite_id: str | None = Field(None, description="Current invite ID") pending_step_id: str | None = Field(None, description="ID of the pending step") state: str = Field(..., description="Current state of the document group (e.g., 'pending')") last_invite_id: str | None = Field(None, description="ID of the last invite") documents: list[DocumentGroupV2Document] = Field(..., description="List of documents in the group") class GetDocumentGroupV2Response(BaseModel): """Response model for getting a single document group using v2 endpoint.""" data: DocumentGroupV2Data = Field(..., description="Document group data as returned by v2 endpoint") class TemplateShortThumbnail(BaseModel): """Thumbnail information for template in document group template response.""" large: HttpUrl = Field(..., description="Large thumbnail URL") class TemplateShort(BaseModel): """Short template information in document group template response.""" id: str = Field(..., description="Template ID (40-character HEX)") template_name: str = Field(..., description="Template name") thumbnail: TemplateShortThumbnail = Field(..., description="Template thumbnail with large URL") roles: list[str] = Field(..., description="Roles defined for this template") class GetDocumentGroupTemplateResponse(BaseModel): """Response model for getting a single document group template by ID.""" id: str = Field(..., description="Document group template ID") group_name: str = Field(..., description="Name of the template group") templates: list[TemplateShort] = Field(..., description="List of templates in this group")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mihasicehcek/sn-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server