assinafy 0.1.2

Idiomatic async Rust SDK for the Assinafy electronic signature API (https://api.assinafy.com.br/v1).
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
//! Assignment (signature-request) models.

use std::fmt;

use serde::{Deserialize, Serialize};

/// Delivery method for an assignment.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AssignmentMethod {
    /// Signers are notified and sign remotely.
    Virtual,
    /// Signers sign in-person on the document owner's device.
    Collect,
}

impl AssignmentMethod {
    /// Wire-format string.
    pub fn as_str(&self) -> &'static str {
        match self {
            AssignmentMethod::Virtual => "virtual",
            AssignmentMethod::Collect => "collect",
        }
    }
}

impl fmt::Display for AssignmentMethod {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

/// Verification method applied to a signer.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum VerificationMethod {
    /// Email code.
    Email,
    /// WhatsApp code.
    Whatsapp,
    /// Skip verification (only allowed in specific configurations).
    Bypass,
    /// Any value the SDK does not yet model.
    #[serde(untagged)]
    Other(String),
}

impl VerificationMethod {
    /// Wire-format string.
    pub fn as_str(&self) -> &str {
        match self {
            VerificationMethod::Email => "Email",
            VerificationMethod::Whatsapp => "Whatsapp",
            VerificationMethod::Bypass => "Bypass",
            VerificationMethod::Other(s) => s.as_str(),
        }
    }
}

/// Notification channel.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum NotificationMethod {
    /// Email channel.
    Email,
    /// WhatsApp channel.
    Whatsapp,
    /// Any value the SDK does not yet model.
    #[serde(untagged)]
    Other(String),
}

impl NotificationMethod {
    /// Wire-format string.
    pub fn as_str(&self) -> &str {
        match self {
            NotificationMethod::Email => "Email",
            NotificationMethod::Whatsapp => "Whatsapp",
            NotificationMethod::Other(s) => s.as_str(),
        }
    }
}

/// Status of a notification delivery attempt.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum NotificationStatus {
    /// Notification was successfully sent.
    Sent,
    /// Notification delivery failed.
    Failed,
    /// Any value the SDK does not yet model.
    #[serde(untagged)]
    Other(String),
}

/// Notification event type.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationEvent {
    /// Initial signature request dispatched.
    SignatureRequest,
    /// Document close to expiring.
    DocumentAboutToExpire,
    /// Document has expired.
    DocumentExpired,
    /// Document was cancelled by the owner.
    DocumentCanceled,
    /// Document was declined by a signer.
    DocumentDeclined,
    /// Signed copy delivered.
    SignedDelivery,
    /// Any value the SDK does not yet model.
    #[serde(untagged)]
    Unknown(String),
}

/// Single notification delivery attempt for a signer.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct NotificationHistoryEntry {
    /// Event triggering the notification.
    pub event: NotificationEvent,
    /// Delivery status.
    pub status: NotificationStatus,
    /// Provider error code (when failed).
    #[serde(default)]
    pub error_code: Option<String>,
    /// Provider error message (when failed).
    #[serde(default)]
    pub error_message: Option<String>,
    /// Timestamp the notification was sent (when status is `Sent`).
    #[serde(default)]
    pub sent_at: Option<String>,
    /// Timestamp the notification failed (when status is `Failed`).
    #[serde(default)]
    pub failed_at: Option<String>,
}

/// Signer assigned to an assignment.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AssignmentSigner {
    /// Signer identifier.
    pub id: String,
    /// Full name.
    pub full_name: String,
    /// Email address.
    #[serde(default)]
    pub email: Option<String>,
    /// WhatsApp phone number (E.164).
    #[serde(default)]
    pub whatsapp_phone_number: Option<String>,
    /// Whether the signer has accepted the terms.
    #[serde(default)]
    pub has_accepted_terms: bool,
    /// Method used to verify the signer's identity.
    #[serde(default)]
    pub verification_method: Option<VerificationMethod>,
    /// Notification channels used to reach the signer.
    #[serde(default)]
    pub notification_methods: Option<Vec<NotificationMethod>>,
    /// 1-based signing order, when sequential signing is in effect.
    #[serde(default)]
    pub step: Option<u32>,
    /// Whether the initial notification was dispatched.
    #[serde(default)]
    pub notified: Option<bool>,
    /// Whether all items assigned to this signer are completed.
    #[serde(default)]
    pub completed: Option<bool>,
    /// Delivery history for notifications sent to this signer.
    #[serde(default)]
    pub notification_history: Vec<NotificationHistoryEntry>,
}

/// Copy-only recipient who receives the final signed document.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct CopyReceiver {
    /// Recipient identifier.
    pub id: String,
    /// Full name.
    pub full_name: String,
    /// Email address.
    #[serde(default)]
    pub email: Option<String>,
    /// WhatsApp phone number (E.164).
    #[serde(default)]
    pub whatsapp_phone_number: Option<String>,
    /// Whether the recipient has accepted the terms.
    #[serde(default)]
    pub has_accepted_terms: bool,
}

/// A single item within an assignment (signature placeholder, field, etc.).
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AssignmentItem {
    /// Item identifier.
    pub id: String,
    /// Page the item lives on, if any.
    #[serde(default)]
    pub page: Option<serde_json::Value>,
    /// Signer the item is assigned to.
    #[serde(default)]
    pub signer: Option<serde_json::Value>,
    /// Field definition, if applicable.
    #[serde(default)]
    pub field: Option<serde_json::Value>,
    /// Display settings for the item.
    #[serde(default)]
    pub display_settings: Option<serde_json::Value>,
    /// Captured value.
    #[serde(default)]
    pub value: Option<serde_json::Value>,
    /// Whether the item is completed.
    #[serde(default)]
    pub completed: bool,
}

/// Pre-built direct signing URL for one of the assignment signers.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SigningUrl {
    /// Signer identifier.
    pub signer_id: String,
    /// Direct signing URL.
    pub url: String,
}

/// Aggregated completion summary returned with an assignment.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AssignmentSummary {
    /// Total signers in the assignment.
    pub signer_count: u32,
    /// Number of signers that have completed all their items.
    pub completed_count: u32,
    /// Per-signer summary.
    #[serde(default)]
    pub signers: Vec<AssignmentSummarySigner>,
}

/// A single signer entry inside [`AssignmentSummary`].
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AssignmentSummarySigner {
    /// Signer identifier.
    pub id: String,
    /// Full name.
    pub full_name: String,
    /// Email address.
    #[serde(default)]
    pub email: Option<String>,
    /// Whether the signer accepted the terms.
    #[serde(default)]
    pub has_accepted_terms: bool,
    /// Whether the signer has completed all of their items.
    pub completed: bool,
}

/// A signature request attached to a document.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Assignment {
    /// Resource discriminator (always `"assignment"` when present).
    #[serde(default)]
    pub resource: Option<String>,
    /// Assignment identifier.
    pub id: String,
    /// Document identifier.
    #[serde(default)]
    pub document_id: Option<String>,
    /// Email of the user that created the assignment.
    #[serde(default)]
    pub sender_email: Option<String>,
    /// Delivery method.
    #[serde(default)]
    pub method: Option<AssignmentMethod>,
    /// Assignment status, when returned.
    #[serde(default)]
    pub status: Option<String>,
    /// Expiration timestamp using the legacy field name, when returned.
    #[serde(default)]
    pub expiration: Option<String>,
    /// Expiry timestamp (ISO-8601).
    #[serde(default)]
    pub expires_at: Option<String>,
    /// Optional invitation message.
    #[serde(default)]
    pub message: Option<String>,
    /// Signers assigned to the document.
    #[serde(default)]
    pub signers: Vec<AssignmentSigner>,
    /// Copy-only recipients.
    #[serde(default)]
    pub copy_receivers: Vec<CopyReceiver>,
    /// Assignment items.
    #[serde(default)]
    pub items: Vec<AssignmentItem>,
    /// Completion summary.
    #[serde(default)]
    pub summary: Option<AssignmentSummary>,
    /// Direct signing URLs.
    #[serde(default)]
    pub signing_urls: Vec<SigningUrl>,
    /// Completion timestamp.
    #[serde(default)]
    pub completed_at: Option<serde_json::Value>,
    /// Creation timestamp.
    #[serde(default)]
    pub created_at: Option<serde_json::Value>,
    /// Last-modification timestamp.
    #[serde(default)]
    pub updated_at: Option<serde_json::Value>,
}

/// Response returned by assignment notification resend endpoints.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ResendNotificationResult {
    /// Whether a notification was sent.
    #[serde(default)]
    pub is_sent: bool,
    /// Document identifier.
    #[serde(default)]
    pub document_id: Option<String>,
    /// Signer identifier.
    #[serde(default)]
    pub signer_id: Option<String>,
}

/// Itemized cost line returned by assignment notification resend estimates.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ResendCostBreakdownItem {
    /// Stable cost identifier.
    pub code: String,
    /// Human-readable cost name.
    pub name: String,
    /// Cost in credits.
    pub cost: f64,
}

/// Cost estimate returned before resending one signer notification.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ResendCostEstimate {
    /// Total cost in credits.
    pub total: f64,
    /// Itemized cost lines.
    #[serde(default)]
    pub breakdown: Vec<ResendCostBreakdownItem>,
    /// Current account credit balance.
    pub credit_balance: f64,
    /// Whether the account has enough credits to resend.
    pub has_sufficient_credits: bool,
}

/// One filled field submitted by the signer-facing sign endpoint.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignDocumentItem {
    /// Assignment item identifier.
    #[serde(rename = "itemId")]
    pub item_id: String,
    /// Field definition identifier.
    #[serde(rename = "fieldId")]
    pub field_id: String,
    /// Document page identifier.
    #[serde(rename = "pageId")]
    pub page_id: String,
    /// Value supplied by the signer.
    pub value: String,
}

impl SignDocumentItem {
    /// Build one signer-filled item.
    pub fn new<I, F, P, V>(item_id: I, field_id: F, page_id: P, value: V) -> Self
    where
        I: Into<String>,
        F: Into<String>,
        P: Into<String>,
        V: Into<String>,
    {
        Self {
            item_id: item_id.into(),
            field_id: field_id.into(),
            page_id: page_id.into(),
            value: value.into(),
        }
    }
}

/// WhatsApp message metadata returned for assignment notifications.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct WhatsAppNotification {
    /// Sent timestamp.
    pub sent_at: serde_json::Value,
    /// Message header.
    pub header: String,
    /// Message body.
    pub body: String,
    /// Buttons shown in the message.
    #[serde(default)]
    pub buttons: Vec<WhatsAppButton>,
    /// Destination phone number.
    pub phone_number: String,
    /// Signer identifier.
    pub signer_id: String,
}

/// Button embedded in a WhatsApp notification.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct WhatsAppButton {
    /// Button text.
    pub text: String,
    /// Button URL, when present.
    #[serde(default)]
    pub url: Option<String>,
}