@assinafy/sdk 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +469 -0
- package/README.md +240 -63
- package/SECURITY.md +59 -0
- package/dist/index.d.mts +3845 -495
- package/dist/index.d.ts +3845 -495
- package/dist/index.js +3931 -364
- package/dist/index.mjs +3930 -364
- package/docs/API_COVERAGE.md +209 -0
- package/docs/COMPATIBILITY.md +285 -0
- package/docs/RELEASING.md +138 -0
- package/package.json +27 -15
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# API coverage
|
|
2
|
+
|
|
3
|
+
This ledger maps the official Assinafy OpenAPI document to the public SDK API.
|
|
4
|
+
It was reconciled on 2026-08-06 against
|
|
5
|
+
[`GET /v1/docs/openapi.json`](https://api.assinafy.com.br/v1/docs/openapi.json):
|
|
6
|
+
68 paths, 89 HTTP operations, and 37 component schemas. The audited response's
|
|
7
|
+
SHA-256 digest is
|
|
8
|
+
`7e5957082002e8e96c5abc2cadf7b4b463eaa5bd61b76e26f64b90a8b922088c`.
|
|
9
|
+
|
|
10
|
+
All paths below include the `/v1` prefix shown by the OpenAPI document. The
|
|
11
|
+
SDK's default `baseUrl` already ends in `/v1`, so resource implementations use
|
|
12
|
+
the corresponding relative path without repeating that prefix.
|
|
13
|
+
|
|
14
|
+
Status meanings:
|
|
15
|
+
|
|
16
|
+
- **Covered** — a public, typed SDK method sends the operation.
|
|
17
|
+
- **URL helper** — the operation is a browser redirect/callback; the SDK builds
|
|
18
|
+
its absolute URL instead of following it inside the server process.
|
|
19
|
+
- **Live extension** — verified route retained for compatibility, but absent
|
|
20
|
+
from the current OpenAPI path set and excluded from the 89-operation total.
|
|
21
|
+
|
|
22
|
+
## Accounts — 10/10
|
|
23
|
+
|
|
24
|
+
| Method | Path | SDK method | Status |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| `GET` | `/v1/accounts` | `client.workspaces.list()` | Covered |
|
|
27
|
+
| `POST` | `/v1/accounts` | `client.workspaces.create(payload)` | Covered |
|
|
28
|
+
| `GET` | `/v1/accounts/{accountId}` | `client.workspaces.get(accountId)` | Covered |
|
|
29
|
+
| `PUT` | `/v1/accounts/{accountId}` | `client.workspaces.update(accountId, payload)` | Covered |
|
|
30
|
+
| `DELETE` | `/v1/accounts/{accountId}` | `client.workspaces.delete(accountId, options?)` | Covered |
|
|
31
|
+
| `GET` | `/v1/accounts/{accountId}/theme` | `client.workspaces.getTheme(accountId)` | Covered |
|
|
32
|
+
| `GET` | `/v1/accounts/{accountId}/logo` | `client.workspaces.downloadLogo(accountId)` | Covered |
|
|
33
|
+
| `POST` | `/v1/accounts/{accountId}/logo` | `client.workspaces.uploadLogo(accountId, source)` | Covered |
|
|
34
|
+
| `DELETE` | `/v1/accounts/{accountId}/logo` | `client.workspaces.deleteLogo(accountId)` | Covered |
|
|
35
|
+
| `GET` | `/v1/accounts/{accountId}/stats` | `client.workspaces.getStats(accountId, params?)` | Covered |
|
|
36
|
+
|
|
37
|
+
## Assignments — 7/7
|
|
38
|
+
|
|
39
|
+
| Method | Path | SDK method | Status |
|
|
40
|
+
| --- | --- | --- | --- |
|
|
41
|
+
| `GET` | `/v1/assignments` | `client.assignments.list(params?, accountId?)` | Covered |
|
|
42
|
+
| `POST` | `/v1/documents/{documentId}/assignments` | `client.assignments.create(documentId, payload)` | Covered |
|
|
43
|
+
| `POST` | `/v1/documents/{documentId}/assignments/estimate-cost` | `client.assignments.estimateCost(documentId, payload)` | Covered |
|
|
44
|
+
| `PUT` | `/v1/documents/{documentId}/assignments/{assignmentId}/signers/{signerId}/resend` | `client.assignments.resendNotification(documentId, assignmentId, signerId)` | Covered |
|
|
45
|
+
| `POST` | `/v1/documents/{documentId}/assignments/{assignmentId}/signers/{signerId}/estimate-resend-cost` | `client.assignments.estimateResendCost(documentId, assignmentId, signerId)` | Covered |
|
|
46
|
+
| `PUT` | `/v1/documents/{documentId}/assignments/{assignmentId}/reset-expiration` | `client.assignments.resetExpiration(documentId, assignmentId, expiresAt)` | Covered |
|
|
47
|
+
| `GET` | `/v1/documents/{documentId}/assignments/{assignmentId}/whatsapp-notifications` | `client.assignments.listWhatsAppNotifications(documentId, assignmentId)` | Covered |
|
|
48
|
+
|
|
49
|
+
## Authentication — 11/11
|
|
50
|
+
|
|
51
|
+
| Method | Path | SDK method | Status |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| `GET` | `/v1/auth/authenticate` | `client.auth.getSocialLoginUrl(authClient?)` | URL helper |
|
|
54
|
+
| `GET` | `/v1/login-callback` | `client.auth.getSocialLoginCallbackUrl()` | URL helper |
|
|
55
|
+
| `POST` | `/v1/login` | `client.auth.login(email, password)` | Covered |
|
|
56
|
+
| `PUT` | `/v1/authentication/request-password-reset` | `client.auth.requestPasswordReset(email)` | Covered |
|
|
57
|
+
| `PUT` | `/v1/authentication/reset-password` | `client.auth.resetPassword(payload)` | Covered |
|
|
58
|
+
| `PUT` | `/v1/authentication/change-password` | `client.auth.changePassword(payload)` | Covered |
|
|
59
|
+
| `POST` | `/v1/authentication/social-login` | `client.auth.socialLogin(payload)` | Covered |
|
|
60
|
+
| `POST` | `/v1/auth/link-social-login` | `client.auth.linkSocialLogin(payload)` | Covered |
|
|
61
|
+
| `GET` | `/v1/users/api-keys` | `client.auth.getApiKey()` | Covered |
|
|
62
|
+
| `POST` | `/v1/users/api-keys` | `client.auth.createApiKey(password)` | Covered |
|
|
63
|
+
| `DELETE` | `/v1/users/api-keys` | `client.auth.deleteApiKey()` | Covered |
|
|
64
|
+
|
|
65
|
+
## Documents — 18/18
|
|
66
|
+
|
|
67
|
+
| Method | Path | SDK method | Status |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| `GET` | `/v1/accounts/{accountId}/documents` | `client.documents.list(params?, accountId?)` | Covered |
|
|
70
|
+
| `POST` | `/v1/accounts/{accountId}/documents` | `client.documents.upload(source, options?)` | Covered |
|
|
71
|
+
| `GET` | `/v1/accounts/{accountId}/documents/search` | `client.documents.search(params?, accountId?)` | Covered |
|
|
72
|
+
| `GET` | `/v1/documents/statuses` | `client.documents.statuses()` | Covered |
|
|
73
|
+
| `GET` | `/v1/documents/{documentId}` | `client.documents.details(documentId)` / `get(documentId)` | Covered |
|
|
74
|
+
| `DELETE` | `/v1/documents/{documentId}` | `client.documents.delete(documentId)` | Covered |
|
|
75
|
+
| `PATCH` | `/v1/documents/{documentId}` | `client.documents.rename(documentId, name)` | Covered |
|
|
76
|
+
| `GET` | `/v1/documents/{documentId}/activities` | `client.documents.activities(documentId)` | Covered |
|
|
77
|
+
| `GET` | `/v1/documents/{documentId}/download/{artifactName}` | `client.documents.download(documentId, artifactName)` | Covered |
|
|
78
|
+
| `GET` | `/v1/documents/{documentSignatureHash}/verify` | `client.documents.verify(documentSignatureHash)` | Covered |
|
|
79
|
+
| `GET` | `/v1/documents/{documentId}/thumbnail` | `client.documents.thumbnail(documentId)` | Covered |
|
|
80
|
+
| `GET` | `/v1/documents/{documentId}/pages/{pageId}/download` | `client.documents.downloadPage(documentId, pageId)` | Covered |
|
|
81
|
+
| `GET` | `/v1/accounts/{accountId}/documents/{documentId}/tags` | `client.documents.listTags(documentId, accountId?)` | Covered |
|
|
82
|
+
| `PUT` | `/v1/accounts/{accountId}/documents/{documentId}/tags` | `client.documents.replaceTags(documentId, tagIds, accountId?)` | Covered |
|
|
83
|
+
| `POST` | `/v1/accounts/{accountId}/documents/{documentId}/tags` | `client.documents.addTags(documentId, tagIds, accountId?)` | Covered |
|
|
84
|
+
| `DELETE` | `/v1/accounts/{accountId}/documents/{documentId}/tags/{tagId}` | `client.documents.detachTag(documentId, tagId, accountId?)` | Covered |
|
|
85
|
+
| `POST` | `/v1/accounts/{accountId}/templates/{templateId}/documents` | `client.documents.createFromTemplate(templateId, signers, options?, accountId?)` | Covered |
|
|
86
|
+
| `POST` | `/v1/accounts/{accountId}/templates/{templateId}/documents/estimate-cost` | `client.documents.estimateCostFromTemplate(templateId, signers, accountId?)` | Covered |
|
|
87
|
+
|
|
88
|
+
## Fields — 8/8
|
|
89
|
+
|
|
90
|
+
| Method | Path | SDK method | Status |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| `GET` | `/v1/accounts/{accountId}/fields` | `client.fields.list(params?, accountId?)` | Covered |
|
|
93
|
+
| `POST` | `/v1/accounts/{accountId}/fields` | `client.fields.create(payload, accountId?)` | Covered |
|
|
94
|
+
| `GET` | `/v1/accounts/{accountId}/fields/{fieldId}` | `client.fields.get(fieldId, accountId?)` | Covered |
|
|
95
|
+
| `PUT` | `/v1/accounts/{accountId}/fields/{fieldId}` | `client.fields.update(fieldId, payload, accountId?)` | Covered |
|
|
96
|
+
| `DELETE` | `/v1/accounts/{accountId}/fields/{fieldId}` | `client.fields.delete(fieldId, accountId?)` | Covered |
|
|
97
|
+
| `POST` | `/v1/accounts/{accountId}/fields/{fieldId}/validate` | `client.fields.validate(fieldId, value, options?)` | Covered |
|
|
98
|
+
| `POST` | `/v1/accounts/{accountId}/fields/validate-multiple` | `client.fields.validateMultiple(entries, options?)` | Covered |
|
|
99
|
+
| `GET` | `/v1/field-types` | `client.fields.listTypes()` | Covered |
|
|
100
|
+
|
|
101
|
+
## Signers — 5/5
|
|
102
|
+
|
|
103
|
+
| Method | Path | SDK method | Status |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| `GET` | `/v1/accounts/{accountId}/signers` | `client.signers.list(params?, accountId?)` | Covered |
|
|
106
|
+
| `POST` | `/v1/accounts/{accountId}/signers` | `client.signers.create(payload, accountId?)` | Covered |
|
|
107
|
+
| `GET` | `/v1/accounts/{accountId}/signers/{signerId}` | `client.signers.get(signerId, accountId?)` | Covered |
|
|
108
|
+
| `PUT` | `/v1/accounts/{accountId}/signers/{signerId}` | `client.signers.update(signerId, payload, accountId?)` | Covered |
|
|
109
|
+
| `DELETE` | `/v1/accounts/{accountId}/signers/{signerId}` | `client.signers.delete(signerId, accountId?)` | Covered |
|
|
110
|
+
|
|
111
|
+
## Signing and public flows — 17/17
|
|
112
|
+
|
|
113
|
+
All methods in this section use the auth-free transport. Most signer operations
|
|
114
|
+
authenticate with the `signer-access-code` query parameter required by the
|
|
115
|
+
OpenAPI security scheme. The artifact download is explicitly public and accepts
|
|
116
|
+
an optional fourth access-code argument only for legacy compatibility.
|
|
117
|
+
|
|
118
|
+
| Method | Path | SDK method | Status |
|
|
119
|
+
| --- | --- | --- | --- |
|
|
120
|
+
| `GET` | `/v1/public/documents/{documentId}` | `client.documents.getPublic(documentId)` | Covered |
|
|
121
|
+
| `PUT` | `/v1/public/documents/{documentId}/send-token` | `client.documents.sendToken(documentId, email)` | Covered |
|
|
122
|
+
| `GET` | `/v1/signers/self` | `client.signerDocuments.self(accessCode)` | Covered |
|
|
123
|
+
| `GET` | `/v1/signers/{signerId}/document` | `client.signerDocuments.getCurrent(signerId, accessCode)` | Covered |
|
|
124
|
+
| `GET` | `/v1/sign` | `client.signerDocuments.getAssignment(accessCode, hasAcceptedTerms?)` | Covered |
|
|
125
|
+
| `POST` | `/v1/documents/{documentId}/assignments/{assignmentId}` | `client.signerDocuments.sign(documentId, assignmentId, accessCode, entries)` | Covered |
|
|
126
|
+
| `PUT` | `/v1/documents/{documentId}/assignments/{assignmentId}/reject` | `client.signerDocuments.decline(documentId, assignmentId, accessCode, reason)` | Covered |
|
|
127
|
+
| `PUT` | `/v1/signers/documents/sign-multiple` | `client.signerDocuments.signMultiple(documentIds, accessCode)` | Covered |
|
|
128
|
+
| `PUT` | `/v1/signers/documents/decline-multiple` | `client.signerDocuments.declineMultiple(documentIds, reason, accessCode)` | Covered |
|
|
129
|
+
| `POST` | `/v1/verify` | `client.signerDocuments.verifyEmail(payload)` | Covered |
|
|
130
|
+
| `PUT` | `/v1/documents/{documentId}/signers/confirm-data` | `client.signerDocuments.confirmData(documentId, accessCode, payload)` | Covered |
|
|
131
|
+
| `PUT` | `/v1/signers/accept-terms` | `client.signerDocuments.acceptTerms(accessCode)` | Covered |
|
|
132
|
+
| `POST` | `/v1/signature` | `client.signerDocuments.uploadSignature(accessCode, image, options?)` | Covered |
|
|
133
|
+
| `GET` | `/v1/signature/{signatureType}` | `client.signerDocuments.downloadSignature(accessCode, signatureType)` | Covered |
|
|
134
|
+
| `GET` | `/v1/signers/{signerId}/documents` | `client.signerDocuments.list(signerId, accessCode, params?)` | Covered |
|
|
135
|
+
| `GET` | `/v1/signers/{signerId}/documents/search` | `client.signerDocuments.search(signerId, accessCode, search)` | Covered |
|
|
136
|
+
| `GET` | `/v1/signers/{signerId}/documents/{documentId}/download/{artifactName}` | `client.signerDocuments.download(signerId, documentId, artifactName)` | Covered |
|
|
137
|
+
|
|
138
|
+
## Tags — 4/4
|
|
139
|
+
|
|
140
|
+
| Method | Path | SDK method | Status |
|
|
141
|
+
| --- | --- | --- | --- |
|
|
142
|
+
| `GET` | `/v1/accounts/{accountId}/tags` | `client.tags.list(params?, accountId?)` | Covered |
|
|
143
|
+
| `POST` | `/v1/accounts/{accountId}/tags` | `client.tags.create(payload, accountId?)` | Covered |
|
|
144
|
+
| `PUT` | `/v1/accounts/{accountId}/tags/{tagId}` | `client.tags.update(tagId, payload, accountId?)` | Covered |
|
|
145
|
+
| `DELETE` | `/v1/accounts/{accountId}/tags/{tagId}` | `client.tags.delete(tagId, options?)` | Covered |
|
|
146
|
+
|
|
147
|
+
## Templates — 1/1 official
|
|
148
|
+
|
|
149
|
+
| Method | Path | SDK method | Status |
|
|
150
|
+
| --- | --- | --- | --- |
|
|
151
|
+
| `GET` | `/v1/accounts/{accountId}/templates` | `client.templates.list(params?, accountId?)` | Covered |
|
|
152
|
+
|
|
153
|
+
Five additional live routes are documented separately under
|
|
154
|
+
[Live template extensions](#live-template-extensions).
|
|
155
|
+
|
|
156
|
+
## Users — 2/2
|
|
157
|
+
|
|
158
|
+
| Method | Path | SDK method | Status |
|
|
159
|
+
| --- | --- | --- | --- |
|
|
160
|
+
| `GET` | `/v1/users/self` | `client.users.getCurrent()` | Covered |
|
|
161
|
+
| `GET` | `/v1/users/self/stats` | `client.users.getStats(params?)` | Covered |
|
|
162
|
+
|
|
163
|
+
## Webhooks — 6/6
|
|
164
|
+
|
|
165
|
+
| Method | Path | SDK method | Status |
|
|
166
|
+
| --- | --- | --- | --- |
|
|
167
|
+
| `GET` | `/v1/accounts/{accountId}/webhooks/subscriptions` | `client.webhooks.get(accountId?)` | Covered |
|
|
168
|
+
| `PUT` | `/v1/accounts/{accountId}/webhooks/subscriptions` | `client.webhooks.register(payload, accountId?)` | Covered |
|
|
169
|
+
| `PUT` | `/v1/accounts/{accountId}/webhooks/inactivate` | `client.webhooks.inactivate(accountId?)` | Covered |
|
|
170
|
+
| `GET` | `/v1/webhooks/event-types` | `client.webhooks.listEventTypes()` | Covered |
|
|
171
|
+
| `GET` | `/v1/accounts/{accountId}/webhooks` | `client.webhooks.listDispatches(params?, accountId?)` | Covered |
|
|
172
|
+
| `POST` | `/v1/accounts/{accountId}/webhooks/{historyId}/retry` | `client.webhooks.retryDispatch(historyId, accountId?)` | Covered |
|
|
173
|
+
|
|
174
|
+
## Live template extensions
|
|
175
|
+
|
|
176
|
+
These routes are available in the live API and covered by the SDK, but they do
|
|
177
|
+
not appear in the 2026-08-06 OpenAPI path set. They are intentionally excluded
|
|
178
|
+
from the official 89-operation coverage count.
|
|
179
|
+
|
|
180
|
+
| Method | Live path | SDK method | Status |
|
|
181
|
+
| --- | --- | --- | --- |
|
|
182
|
+
| `POST` | `/v1/accounts/{accountId}/templates` | `client.templates.create(source, options?)` | Live extension |
|
|
183
|
+
| `GET` | `/v1/accounts/{accountId}/templates/{templateId}` | `client.templates.get(templateId, accountId?)` | Live extension |
|
|
184
|
+
| `PUT` | `/v1/accounts/{accountId}/templates/{templateId}` | `client.templates.update(templateId, payload, accountId?)` | Live extension |
|
|
185
|
+
| `DELETE` | `/v1/accounts/{accountId}/templates/{templateId}` | `client.templates.delete(templateId, accountId?)` | Live extension |
|
|
186
|
+
| `GET` | `/v1/accounts/{accountId}/templates/{templateId}/pages/{pageId}/download` | `client.templates.downloadPage(templateId, pageId, accountId?)` | Live extension |
|
|
187
|
+
|
|
188
|
+
## SDK conveniences
|
|
189
|
+
|
|
190
|
+
These helpers compose or derive official operations and therefore do not add to
|
|
191
|
+
the endpoint count:
|
|
192
|
+
|
|
193
|
+
- `client.uploadAndRequestSignatures(options)` validates the complete input,
|
|
194
|
+
uploads a document, waits for metadata readiness, reuses or creates signers,
|
|
195
|
+
creates an assignment, and optionally fetches the final document snapshot.
|
|
196
|
+
- `client.documents.waitUntilReady(documentId, options?)` polls the official
|
|
197
|
+
document-details operation with terminal-state and timeout handling.
|
|
198
|
+
- `client.documents.isFullySigned(documentId)` and
|
|
199
|
+
`getSigningProgress(documentId)` derive state from document details.
|
|
200
|
+
- `client.signers.findByEmail(email, accountId?)` uses the official signer list.
|
|
201
|
+
- `client.webhookVerifier` parses webhook envelopes and optionally verifies a
|
|
202
|
+
caller-configured HMAC contract; signature verification itself is not in the
|
|
203
|
+
current OpenAPI document.
|
|
204
|
+
|
|
205
|
+
For request and response payload definitions, use the exported TypeScript
|
|
206
|
+
interfaces and each method's JSDoc examples together with the
|
|
207
|
+
[official API reference](https://api.assinafy.com.br/v1/docs). Contract
|
|
208
|
+
differences that require compatibility handling are recorded in
|
|
209
|
+
[COMPATIBILITY.md](COMPATIBILITY.md).
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# API compatibility
|
|
2
|
+
|
|
3
|
+
The SDK targets the official Assinafy contract at
|
|
4
|
+
[`/v1/docs/openapi.json`](https://api.assinafy.com.br/v1/docs/openapi.json) and
|
|
5
|
+
keeps compatibility behavior narrow, explicit, and typed. This document records
|
|
6
|
+
the differences observed during the 2026-08-06 contract and sandbox audit. It
|
|
7
|
+
contains no credentials, account identifiers, signer data, or reusable test
|
|
8
|
+
artifacts. The audited OpenAPI response's SHA-256 digest is
|
|
9
|
+
`7e5957082002e8e96c5abc2cadf7b4b463eaa5bd61b76e26f64b90a8b922088c`.
|
|
10
|
+
|
|
11
|
+
The governing rule is simple: new integrations should send the published
|
|
12
|
+
contract. A compatibility path is used only when the caller selects it
|
|
13
|
+
explicitly or the server returns a validation error that unambiguously requests
|
|
14
|
+
the older shape.
|
|
15
|
+
|
|
16
|
+
## Template management live extensions
|
|
17
|
+
|
|
18
|
+
The current OpenAPI document contains only:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
GET /v1/accounts/{accountId}/templates
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The live API additionally exposes five routes used by existing integrations:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
POST /v1/accounts/{accountId}/templates
|
|
28
|
+
GET /v1/accounts/{accountId}/templates/{templateId}
|
|
29
|
+
PUT /v1/accounts/{accountId}/templates/{templateId}
|
|
30
|
+
DELETE /v1/accounts/{accountId}/templates/{templateId}
|
|
31
|
+
GET /v1/accounts/{accountId}/templates/{templateId}/pages/{pageId}/download
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
They map to `client.templates.create`, `get`, `update`, `delete`, and
|
|
35
|
+
`downloadPage`. They are documented and tested as **live compatibility
|
|
36
|
+
extensions**, not counted as official OpenAPI operations. Their absence from a
|
|
37
|
+
future schema is not by itself grounds for removal; removal requires a live
|
|
38
|
+
regression test, a deprecation period, and a major-version decision.
|
|
39
|
+
|
|
40
|
+
Template status examples have also differed in casing (`Uploaded`/`Ready` in
|
|
41
|
+
live extension responses versus `uploaded`/`ready` in the published schema).
|
|
42
|
+
The exported type intentionally remains `string`. Applications should normalize
|
|
43
|
+
before comparing:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
if (template.status.toLowerCase() === 'ready') {
|
|
47
|
+
// rendered pages are available
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Public send-token request
|
|
52
|
+
|
|
53
|
+
The official operation is:
|
|
54
|
+
|
|
55
|
+
```http
|
|
56
|
+
PUT /v1/public/documents/{documentId}/send-token
|
|
57
|
+
Content-Type: application/json
|
|
58
|
+
|
|
59
|
+
{ "email": "signer@example.com" }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
That is the default SDK call:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
await client.documents.sendToken(documentId, 'signer@example.com');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Some older environments require `{ recipient, channel }`. The explicit
|
|
69
|
+
three-argument overload sends that shape:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
await client.documents.sendToken(documentId, '+5511999990000', 'whatsapp');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For a two-argument call, the SDK starts with `{ email }` and retries the older
|
|
76
|
+
email shape only when the API's validation body specifically says that
|
|
77
|
+
`recipient` or `channel` is required. Unrelated errors are never swallowed or
|
|
78
|
+
retried under this compatibility rule.
|
|
79
|
+
|
|
80
|
+
## Document tag identifiers
|
|
81
|
+
|
|
82
|
+
The current OpenAPI request schemas for replacing and attaching document tags
|
|
83
|
+
define `tags` as an array of existing **tag IDs**. The SDK follows that contract:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const tag = await client.tags.create({ name: 'Contracts' });
|
|
87
|
+
await client.documents.addTags(documentId, [tag.id]);
|
|
88
|
+
await client.documents.replaceTags(documentId, [tag.id]);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Older environments have accepted tag names and auto-created unknown names. The
|
|
92
|
+
wire type remains `string[]` so those deployments are not broken, but name-based
|
|
93
|
+
attachment is a legacy extension and is not the documented default. Production
|
|
94
|
+
code should create/list tags first and submit IDs.
|
|
95
|
+
|
|
96
|
+
## Account branding fields on create and update
|
|
97
|
+
|
|
98
|
+
The official `Account` response schema includes `primary_color` and
|
|
99
|
+
`secondary_color`, while the current create/update request schemas list only
|
|
100
|
+
`name` and `notification_sender_type`. The sandbox also accepts the two color
|
|
101
|
+
fields on create/update, and the SDK preserves them for existing integrations.
|
|
102
|
+
They must be six hexadecimal characters without a leading `#`.
|
|
103
|
+
|
|
104
|
+
The sandbox audited on 2026-08-06 rejects the official optional
|
|
105
|
+
`notification_sender_type` field with `400` on account creation, while accepting
|
|
106
|
+
the same field on update. The SDK still exposes and sends it because it is part
|
|
107
|
+
of the production OpenAPI contract. The live audit creates its prerequisite
|
|
108
|
+
workspace with a name only, then tests the field independently via update so
|
|
109
|
+
the create-side deployment lag cannot prevent the rest of the suite.
|
|
110
|
+
|
|
111
|
+
The branding read and file operations—`getTheme`, `downloadLogo`, `uploadLogo`,
|
|
112
|
+
and `deleteLogo`—are official operations and are not extensions.
|
|
113
|
+
|
|
114
|
+
## Field-definition request extensions
|
|
115
|
+
|
|
116
|
+
The official field-create body defines `type`, `name`, nullable `regex`, and
|
|
117
|
+
`is_required`; the update body defines `name`, nullable `regex`, and
|
|
118
|
+
`is_active`. The audited sandbox also accepts `is_active` on create and
|
|
119
|
+
`type`/`is_required` on update. Those three properties remain typed as explicit
|
|
120
|
+
live extensions so existing integrations keep working. New code should prefer
|
|
121
|
+
the operation-specific official fields.
|
|
122
|
+
|
|
123
|
+
The field-validation schemas also omit the `signer-access-code` query parameter
|
|
124
|
+
accepted by signer-portal deployments. `fields.validate` and `validateMultiple`
|
|
125
|
+
retain the typed `signerAccessCode` option for those deployments. The 2026-08-06
|
|
126
|
+
full audit exercised account-authenticated validation; it did not have the
|
|
127
|
+
signer-code fixture needed to re-certify this compatibility query.
|
|
128
|
+
|
|
129
|
+
## Retained signer request compatibility
|
|
130
|
+
|
|
131
|
+
The current signer create/update schemas use `full_name`, `email`, and
|
|
132
|
+
`whatsapp_phone_number`. The SDK also retains three older integration inputs:
|
|
133
|
+
|
|
134
|
+
- `phone` is a client-only alias normalized to `whatsapp_phone_number` before
|
|
135
|
+
transmission;
|
|
136
|
+
- `cpf` is normalized to digits and forwarded; and
|
|
137
|
+
- create-time `metadata` is forwarded unchanged.
|
|
138
|
+
|
|
139
|
+
These inputs remain source-compatible because removing them without a live
|
|
140
|
+
regression would break existing consumers. They were unit/request-contract
|
|
141
|
+
tested but were not separately re-probed in the 2026-08-06 disposable signer
|
|
142
|
+
matrix, so new integrations should prefer only the published fields.
|
|
143
|
+
|
|
144
|
+
The official signer `confirm-data` body contains only `full_name`, `email`, and
|
|
145
|
+
`government_id`. Its primary overload exposes exactly those fields. A deprecated
|
|
146
|
+
compatibility overload retains `whatsapp_phone_number`, which was not live-
|
|
147
|
+
certified in this audit. It also preserves the pre-audit `has_accepted_terms`
|
|
148
|
+
pass-through because that behavior could not be live-tested with the supplied
|
|
149
|
+
fixtures. This field is outside the current contract and must **not** be treated
|
|
150
|
+
as legal consent or as a substitute for the separate official `acceptTerms()`
|
|
151
|
+
request. Production signer UIs should call `acceptTerms()` explicitly.
|
|
152
|
+
|
|
153
|
+
## Signature-image media type
|
|
154
|
+
|
|
155
|
+
`POST /signature` officially accepts a raw `image/png` body. That is the SDK's
|
|
156
|
+
typed/default request and the only media type claimed by the API contract. The
|
|
157
|
+
deprecated `contentType` compatibility overload is retained so older consumers
|
|
158
|
+
are not silently broken, but non-PNG values were not live-certified because the
|
|
159
|
+
provided audit fixtures contained no signer access code or legal-consent flow.
|
|
160
|
+
Do not use the override in new integrations without verifying the target
|
|
161
|
+
deployment.
|
|
162
|
+
|
|
163
|
+
## Document upload metadata
|
|
164
|
+
|
|
165
|
+
The multipart upload schema documents the PDF file but not the SDK's optional
|
|
166
|
+
JSON `metadata` part. The audited sandbox accepted and processed a disposable
|
|
167
|
+
document carrying metadata on 2026-08-06. The option remains an explicit live
|
|
168
|
+
extension; callers should treat metadata keys and values as application-owned,
|
|
169
|
+
opaque JSON.
|
|
170
|
+
|
|
171
|
+
## Reset-expiration null and public signer-download compatibility
|
|
172
|
+
|
|
173
|
+
The reset-expiration schema declares `expires_at` as a date-time string. The SDK
|
|
174
|
+
retains `null` as a compatibility value used by older integrations to clear an
|
|
175
|
+
expiration, but the full live audit tested only a future timestamp; `null` is
|
|
176
|
+
unit/request-contract tested and remains live-unverified.
|
|
177
|
+
|
|
178
|
+
The signer artifact download is the opposite case: OpenAPI explicitly marks it
|
|
179
|
+
public and defines no `signer-access-code` query. The official three-argument SDK
|
|
180
|
+
call therefore sends no code. An optional fourth code remains available for
|
|
181
|
+
older deployments, but it is a compatibility query rather than part of the
|
|
182
|
+
published operation.
|
|
183
|
+
|
|
184
|
+
## Resend-cost response variants
|
|
185
|
+
|
|
186
|
+
The published
|
|
187
|
+
`POST /documents/{documentId}/assignments/{assignmentId}/signers/{signerId}/estimate-resend-cost`
|
|
188
|
+
response references the full `CostEstimate` schema. A smaller resend-specific
|
|
189
|
+
shape has also been observed live. The SDK therefore returns the honest union
|
|
190
|
+
`IResendCostEstimate`:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const estimate = await client.assignments.estimateResendCost(
|
|
194
|
+
documentId,
|
|
195
|
+
assignmentId,
|
|
196
|
+
signerId,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
if ('total_credits' in estimate) {
|
|
200
|
+
console.log(estimate.has_sufficient_resources);
|
|
201
|
+
} else {
|
|
202
|
+
console.log(estimate.total, estimate.has_sufficient_credits);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The SDK does not synthesize missing fields, so callers never mistake invented
|
|
207
|
+
zeroes for server-provided balances.
|
|
208
|
+
|
|
209
|
+
## Public-document response variants
|
|
210
|
+
|
|
211
|
+
The official `GET /public/documents/{documentId}` response references the full
|
|
212
|
+
`Document` schema. Older public responses can be compact and expose only fields
|
|
213
|
+
such as `id`, `name`, `page_count`, and `created_by`. `IPublicDocumentInfo`
|
|
214
|
+
requires the stable `id` and `name`, makes expanded document fields optional,
|
|
215
|
+
and retains the compact fields. Check optional fields before using them:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const document = await client.documents.getPublic(documentId);
|
|
219
|
+
if (document.pages) {
|
|
220
|
+
console.log(document.pages.length);
|
|
221
|
+
} else {
|
|
222
|
+
console.log(Number(document.page_count ?? 0));
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Empty acknowledgements
|
|
227
|
+
|
|
228
|
+
Several write operations return a successful status/message envelope with no
|
|
229
|
+
`data` field, while a few older responses use an empty array or object. Methods
|
|
230
|
+
whose contract has no meaningful result resolve to `Promise<void>` and validate
|
|
231
|
+
the HTTP/envelope status. This applies to token dispatch, signer OTP/terms,
|
|
232
|
+
signature-image upload, bulk signer actions, and deletion operations. Success is
|
|
233
|
+
not represented as a fabricated object.
|
|
234
|
+
|
|
235
|
+
## Webhook signature verification is not in the OpenAPI contract
|
|
236
|
+
|
|
237
|
+
The official webhook operations define subscription management, event types,
|
|
238
|
+
delivery history, and retry. The current OpenAPI document does **not** define a
|
|
239
|
+
shared-secret field, signature algorithm, digest encoding, or signature header
|
|
240
|
+
for incoming deliveries.
|
|
241
|
+
|
|
242
|
+
`client.webhookVerifier` is retained as an opt-in HMAC-SHA256 utility for
|
|
243
|
+
environments whose separate Assinafy agreement provides a shared secret and a
|
|
244
|
+
hex digest. Confirm the header name and signing procedure with Assinafy for the
|
|
245
|
+
target environment before enforcing it. Do not assume an
|
|
246
|
+
`X-Assinafy-Signature` header solely from this SDK.
|
|
247
|
+
|
|
248
|
+
## Authentication isolation
|
|
249
|
+
|
|
250
|
+
Public documents, login/social login, password-reset, OAuth URL, and
|
|
251
|
+
signer-access-code flows use a separate HTTP transport without `X-Api-Key` or
|
|
252
|
+
`Authorization` defaults. This is a security boundary rather than a
|
|
253
|
+
wire-contract deviation: a credentialless `new AssinafyClient()` can drive
|
|
254
|
+
those flows, and credentials configured for protected resources are not leaked
|
|
255
|
+
to them.
|
|
256
|
+
|
|
257
|
+
Protected methods still use the authenticated transport and receive the API's
|
|
258
|
+
normal `401` response if credentials are absent or invalid.
|
|
259
|
+
|
|
260
|
+
## Sandbox user and statistics deployment lag
|
|
261
|
+
|
|
262
|
+
The current OpenAPI schema defines `GET /users/self` as a direct `AuthUser`
|
|
263
|
+
payload. The sandbox audited on 2026-08-06 still wraps that value as
|
|
264
|
+
`{ user, accounts }` and adds `user.is_password_set`. `users.getCurrent()`
|
|
265
|
+
normalizes both forms to `IAuthenticatedUser`; `is_password_set` is an optional
|
|
266
|
+
live-compatibility field.
|
|
267
|
+
|
|
268
|
+
The same sandbox returns `404` for the official `GET /users/self/stats` and
|
|
269
|
+
`GET /accounts/{accountId}/stats` routes. The production host recognizes both
|
|
270
|
+
routes (an unauthenticated probe receives `401`), so the SDK retains the exact
|
|
271
|
+
published paths and types. The live audit reports those sandbox-only `404`s as
|
|
272
|
+
explicit `SKIP`s rather than claiming they passed or rewriting calls to an
|
|
273
|
+
undocumented route.
|
|
274
|
+
|
|
275
|
+
## Updating this record
|
|
276
|
+
|
|
277
|
+
When the upstream API changes:
|
|
278
|
+
|
|
279
|
+
1. Diff the new official OpenAPI paths and schemas against the snapshot date
|
|
280
|
+
above.
|
|
281
|
+
2. Add or update typed methods and request/response tests.
|
|
282
|
+
3. Verify live-only behavior in the sandbox without logging secrets or tokens.
|
|
283
|
+
4. Update [API_COVERAGE.md](API_COVERAGE.md) and this file in the same change.
|
|
284
|
+
5. Keep compatibility behavior isolated and feature-detectable; do not silently
|
|
285
|
+
broaden retries or coerce malformed success payloads.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
GitLab is the canonical repository and push-mirrors branches and tags to
|
|
4
|
+
GitHub. Publishing is performed by `.github/workflows/release.yml` when GitHub
|
|
5
|
+
receives a tag matching `v*`; a mirrored tag does not create a GitHub `release`
|
|
6
|
+
event, and the workflow intentionally does not depend on one.
|
|
7
|
+
|
|
8
|
+
## Release support matrix
|
|
9
|
+
|
|
10
|
+
| Runtime | Release responsibility |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| Bun 1.3.14 | Locked install, tests, build, audit, and packaging |
|
|
13
|
+
| Node.js 22 | Minimum supported consumer runtime |
|
|
14
|
+
| Node.js 24 LTS | Packaging and registry publishing runtime |
|
|
15
|
+
| Node.js 26 Current | Forward-compatibility consumer test |
|
|
16
|
+
|
|
17
|
+
Keep this table, `package.json`, GitLab CI, and the GitHub workflows synchronized
|
|
18
|
+
when changing runtime support.
|
|
19
|
+
|
|
20
|
+
## One-time registry setup
|
|
21
|
+
|
|
22
|
+
### npm trusted publishing
|
|
23
|
+
|
|
24
|
+
Configure the npm package `@assinafy/sdk` with a GitHub Actions trusted
|
|
25
|
+
publisher using these repository coordinates:
|
|
26
|
+
|
|
27
|
+
| npm setting | Value |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Organization or user | `assinafy` |
|
|
30
|
+
| Repository | `typescript-sdk` |
|
|
31
|
+
| Workflow filename | `release.yml` |
|
|
32
|
+
| Environment | Leave unset unless the workflow is updated to use one |
|
|
33
|
+
|
|
34
|
+
The `publish-npm` job grants only `contents: read` and `id-token: write`.
|
|
35
|
+
Modern npm exchanges GitHub's short-lived OIDC identity for publish credentials;
|
|
36
|
+
no long-lived `NPM_TOKEN` is required. Test trusted publishing before deleting a
|
|
37
|
+
legacy token, then remove that token from repository and organization secrets.
|
|
38
|
+
|
|
39
|
+
### GitHub Packages
|
|
40
|
+
|
|
41
|
+
The `publish-gh` job uses the workflow-scoped `GITHUB_TOKEN` with
|
|
42
|
+
`packages: write`. Confirm that organization policy permits Actions to publish
|
|
43
|
+
the `@assinafy` scope and that the package remains linked to this repository.
|
|
44
|
+
No separate personal access token should be stored.
|
|
45
|
+
|
|
46
|
+
### Mirror and tag protection
|
|
47
|
+
|
|
48
|
+
The GitLab push mirror must include tags and be able to update the GitHub
|
|
49
|
+
repository. Protect release tags in GitLab so only release maintainers can
|
|
50
|
+
create patterns matching `v*`. GitHub Actions must be enabled on the mirror.
|
|
51
|
+
|
|
52
|
+
## Preparing a release
|
|
53
|
+
|
|
54
|
+
1. Merge the complete change through GitLab and confirm both GitLab and mirrored
|
|
55
|
+
GitHub CI are green.
|
|
56
|
+
2. Choose the semantic version and update `package.json`. Keep the tag exactly
|
|
57
|
+
`v<package-version>`; the workflow rejects a mismatch.
|
|
58
|
+
3. Update `CHANGELOG.md`, API coverage, compatibility notes, and public examples
|
|
59
|
+
for all user-visible changes.
|
|
60
|
+
4. Install and run the complete local release gate from a clean checkout:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
bun install --frozen-lockfile
|
|
64
|
+
bun run verify
|
|
65
|
+
bun run audit
|
|
66
|
+
bun run audit:api
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
5. For API changes, run the live audit against a dedicated sandbox. Start
|
|
70
|
+
read-only:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
ASSINAFY_API_KEY='...' \
|
|
74
|
+
ASSINAFY_ACCOUNT_ID='...' \
|
|
75
|
+
ASSINAFY_BASE_URL='https://sandbox.assinafy.com.br/v1' \
|
|
76
|
+
bun scripts/live-smoke.ts
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then run the reversible suite with two controlled recipients:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
ASSINAFY_API_KEY='...' \
|
|
83
|
+
ASSINAFY_ACCOUNT_ID='...' \
|
|
84
|
+
ASSINAFY_BASE_URL='https://sandbox.assinafy.com.br/v1' \
|
|
85
|
+
ASSINAFY_TEST_EMAIL_PRIMARY='first@example.com' \
|
|
86
|
+
ASSINAFY_TEST_EMAIL_SECONDARY='second@example.com' \
|
|
87
|
+
bun scripts/live-smoke.ts --all
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The suite creates and force-deletes a disposable workspace, but an
|
|
91
|
+
interrupted process can still leave fixtures behind; inspect the sandbox
|
|
92
|
+
before releasing. Treat every `FAIL` as a release blocker and review each
|
|
93
|
+
`SKIP` to confirm its password, provider-token, signer-code/OTP, legal-action,
|
|
94
|
+
final-artifact, or webhook-receiver prerequisite was intentionally absent.
|
|
95
|
+
Never use production credentials or uncontrolled recipients.
|
|
96
|
+
|
|
97
|
+
6. Commit the version and release notes, merge them to the canonical default
|
|
98
|
+
branch, then create a signed or annotated `v<version>` tag on that exact
|
|
99
|
+
commit and push the tag to GitLab.
|
|
100
|
+
7. Confirm that the tag reaches GitHub and starts the **Release** workflow. Do
|
|
101
|
+
not create or move a second tag to work around mirror delay.
|
|
102
|
+
|
|
103
|
+
## What the workflow publishes
|
|
104
|
+
|
|
105
|
+
The workflow serializes releases repository-wide and performs these steps:
|
|
106
|
+
|
|
107
|
+
1. verify that the tag and `package.json` versions match;
|
|
108
|
+
2. install from `bun.lock`, run `verify` and `audit`, and build once;
|
|
109
|
+
3. create one `.tgz` with lifecycle scripts disabled and record its SHA-256;
|
|
110
|
+
4. upload that archive and checksum as a one-day workflow artifact;
|
|
111
|
+
5. verify and publish the archive to npm through trusted-publisher OIDC; and
|
|
112
|
+
6. verify and publish the **same bytes** to GitHub Packages using
|
|
113
|
+
`GITHUB_TOKEN`.
|
|
114
|
+
|
|
115
|
+
The GitHub Packages job depends on npm publishing, preventing a GitHub-only
|
|
116
|
+
release when npm fails. Both registry jobs validate `SHA256SUMS`; neither
|
|
117
|
+
rebuilds or repacks the SDK. This immutable-artifact flow is part of the release
|
|
118
|
+
contract and must be preserved when editing the workflow.
|
|
119
|
+
|
|
120
|
+
## Verification and recovery
|
|
121
|
+
|
|
122
|
+
After publishing, confirm that the expected version appears on npm and GitHub
|
|
123
|
+
Packages and that a clean Node.js consumer can import both the ESM and CommonJS
|
|
124
|
+
entrypoints. Compare the downloaded artifacts when registry tooling permits.
|
|
125
|
+
|
|
126
|
+
If packaging or npm publishing fails, fix the source, increment or retain the
|
|
127
|
+
version as registry state allows, and create a new tag only after review. Never
|
|
128
|
+
move a tag that has published a package.
|
|
129
|
+
|
|
130
|
+
If npm succeeds and GitHub Packages fails, rerun only the failed job while the
|
|
131
|
+
original one-day workflow artifact is retained. This preserves the exact
|
|
132
|
+
archive already published to npm. Do not repack an approximation or unpublish a
|
|
133
|
+
released npm version. If the artifact has expired, stop and review recovery with
|
|
134
|
+
the maintainers before changing workflow dependencies or registry state.
|
|
135
|
+
|
|
136
|
+
For a defective published release, prefer deprecating the affected version and
|
|
137
|
+
shipping a reviewed patch. Record the incident and remediation in the
|
|
138
|
+
changelog and any applicable security advisory.
|