@verdocs/js-sdk 6.2.0-beta.1 → 6.2.0-beta.11

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/dist/index.mjs CHANGED
@@ -1686,8 +1686,8 @@ const updateEnvelope = async (endpoint, envelopeId, params) => endpoint.api //
1686
1686
  * @apiBody value . Value to set.
1687
1687
  * @apiSuccess IEnvelopeField . A copy of the newly-updated field.
1688
1688
  */
1689
- const updateEnvelopeField = async (endpoint, envelopeId, roleName, fieldName, value) => endpoint.api //
1690
- .put(`/v2/envelopes/${envelopeId}/recipients/${roleName}/fields/${fieldName}`, { value })
1689
+ const updateEnvelopeField = async (endpoint, envelopeId, roleName, fieldName, value, prepared) => endpoint.api //
1690
+ .put(`/v2/envelopes/${envelopeId}/recipients/${roleName}/fields/${fieldName}`, { value, prepared })
1691
1691
  .then((r) => r.data);
1692
1692
  /**
1693
1693
  * Upload an attachment to an attachment field.
@@ -1695,6 +1695,7 @@ const updateEnvelopeField = async (endpoint, envelopeId, roleName, fieldName, va
1695
1695
  const uploadEnvelopeFieldAttachment = async (endpoint, envelopeId, roleName, fieldName, file, onUploadProgress) => {
1696
1696
  const formData = new FormData();
1697
1697
  formData.append('document', file, file.name);
1698
+ formData.append('value', '');
1698
1699
  return endpoint.api //
1699
1700
  .put(`/v2/envelopes/${envelopeId}/recipients/${roleName}/fields/${fieldName}`, formData, {
1700
1701
  timeout: 120000,
@@ -1761,1721 +1762,1802 @@ const getEnvelopeDocumentPageDisplayUri = async (endpoint, documentId, page, var
1761
1762
  const getEnvelopes = (endpoint, params) => endpoint.api //
1762
1763
  .get('/v2/envelopes', { params })
1763
1764
  .then((r) => r.data);
1764
-
1765
1765
  /**
1766
- * Create an initials block. In a typical signing workflow, the user is asked at the beginning of the process to
1767
- * "adopt" an initials block to be used for all initials fields in the document. Thus, this is typically called
1768
- * one time to create and store an initials block. Thereafter, the ID of the initials block may be re-used for each
1769
- * initials field to be "stamped" by the user.
1770
- *
1771
- * Note: Both "guest" signers and authenticated users can create initials blocks. Guest signers
1772
- * typically only ever have one, tied to that session. But authenticated users can create more than
1773
- * one, and can use them interchangeably.
1774
- *
1775
- * @group Signatures and Initials
1776
- * @api POST /v2/profiles/initials Create Initial Block
1777
- * @apiBody string initial Blob containing initials image to store.
1778
- * @apiSuccess IInitial . The newly-created initial block.
1766
+ * Generate a ZIP file containing all data for the specified envelopes. The caller must be the
1767
+ * owner of each envelope. The returned ZIP file contains a folder for each envelope.
1779
1768
  */
1780
- const createInitials = (endpoint, name, initials) => {
1781
- const data = new FormData();
1782
- data.append('initial', initials, name);
1783
- return endpoint.api //
1784
- .post(`/v2/profiles/initials`, data)
1785
- .then((r) => r.data);
1769
+ const getEnvelopesZip = (endpoint, envelope_ids) => endpoint.api //
1770
+ .get(`/v2/envelopes/zip/${envelope_ids.join(',')}`, { responseType: 'blob', timeout: 120000 });
1771
+
1772
+ const canPerformTemplateAction = (profile, action, template) => {
1773
+ if (!template && !action.includes('create')) {
1774
+ return { canPerform: false, message: 'Missing required template object' };
1775
+ }
1776
+ // We use BOGUS here to force the option-chain in things like template?.profile_id to NOT match profile?.profile_id because if both
1777
+ // were undefined, they would actually match.
1778
+ const profile_id = profile?.id || 'BOGUS';
1779
+ const organization_id = profile?.organization_id || 'BOGUS';
1780
+ const isCreator = template?.profile_id === profile_id;
1781
+ const isSameOrg = template?.organization_id === organization_id;
1782
+ const isPersonal = template?.is_personal ?? false;
1783
+ const isPublic = template?.is_public ?? false;
1784
+ const permissionsRequired = [];
1785
+ switch (action) {
1786
+ case 'create_personal':
1787
+ permissionsRequired.push('template:creator:create:personal');
1788
+ break;
1789
+ case 'create_org':
1790
+ permissionsRequired.push('template:creator:create:org');
1791
+ break;
1792
+ case 'create_public':
1793
+ permissionsRequired.push('template:creator:create:public');
1794
+ break;
1795
+ case 'read':
1796
+ if (!isCreator) {
1797
+ if ((!isPersonal && isSameOrg) || !isPublic) {
1798
+ permissionsRequired.push('template:member:read');
1799
+ }
1800
+ }
1801
+ break;
1802
+ case 'write':
1803
+ if (!isCreator) {
1804
+ permissionsRequired.push('template:member:read');
1805
+ permissionsRequired.push('template:member:write');
1806
+ }
1807
+ break;
1808
+ case 'change_visibility_personal':
1809
+ if (isCreator) {
1810
+ permissionsRequired.push('template:creator:create:personal');
1811
+ }
1812
+ else {
1813
+ permissionsRequired.push('template:member:visibility');
1814
+ }
1815
+ break;
1816
+ case 'change_visibility_org':
1817
+ if (isCreator) {
1818
+ permissionsRequired.push('template:creator:create:org');
1819
+ }
1820
+ else {
1821
+ permissionsRequired.push('template:member:visibility');
1822
+ }
1823
+ break;
1824
+ case 'change_visibility_public':
1825
+ if (isCreator) {
1826
+ permissionsRequired.push('template:creator:create:public');
1827
+ permissionsRequired.push('template:creator:visibility');
1828
+ }
1829
+ else {
1830
+ permissionsRequired.push('template:member:visibility');
1831
+ }
1832
+ break;
1833
+ case 'delete':
1834
+ if (isCreator) {
1835
+ permissionsRequired.push('template:creator:delete');
1836
+ }
1837
+ else {
1838
+ permissionsRequired.push('template:member:delete');
1839
+ }
1840
+ break;
1841
+ default:
1842
+ return { canPerform: false, message: 'Action is not defined' };
1843
+ }
1844
+ if (hasRequiredPermissions(profile, permissionsRequired)) {
1845
+ return { canPerform: true, message: '' };
1846
+ }
1847
+ return { canPerform: false, message: `Insufficient access to perform '${action}'. Needed permissions: ${permissionsRequired.toString()}` };
1786
1848
  };
1849
+ const hasRequiredPermissions = (profile, permissions) => permissions.every((perm) => (profile?.permissions || []).includes(perm));
1787
1850
 
1788
1851
  /**
1789
- * Get the current KBA status. Note that this may only be called by the recipient and requires a
1790
- * valid signing session to proceed. Although the Recipient object itself contains indications of
1791
- * whether KBA is required, it will not contain the current status of the process. If
1792
- * `recipient.auth_methods` is set (not empty), and `recipient.kba_completed` is false, this endpoint
1793
- * should be called to determine the next KBA step required.
1852
+ * Add a field to a template.
1853
+ *
1854
+ * ```typescript
1855
+ * import {createField} from '@verdocs/js-sdk/Templates';
1856
+ *
1857
+ * await createField((VerdocsEndpoint.getDefault(), template_id, { ... });
1858
+ * ```
1859
+ *
1860
+ * @group Fields
1861
+ * @api POST /v2/fields/:template_id Add a field to a template
1862
+ * @apiBody string name Name for the new field. Field names must be unique within a template. Although special characters are allowed, they must be URL-encoded in subsequent requests, so it is recommended to use only alphanumeric characters and hyphens if possible.
1863
+ * @apiBody string role_name Role to assign to the field. Role names must be valid, so it is recommended to create roles before fields.
1864
+ * @apiBody string document_id ID of the document upon which to place the field.
1865
+ * @apiBody string(enum: 'signature' | 'initial' | 'checkbox' | 'radio' | 'textbox' | 'timestamp' | 'date' | 'dropdown' | 'textarea' | 'attachment' | 'payment') type Type of field to create
1866
+ * @apiBody boolean(default: false) required Whether the field is required
1867
+ * @apiBody integer(min: 0) page 0-based page number upon which to place the field
1868
+ * @apiBody integer(min: 0) x X position for the field (left to right)
1869
+ * @apiBody integer(min: 0) y Y position for the field (_bottom to top!_)
1870
+ * @apiBody string label? Optional label to display above the field
1871
+ * @apiBody integer(min: 50) width? Width of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
1872
+ * @apiBody integer(min: 15) height? Height of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
1873
+ * @apiBody string placeholder? Optional placeholder to display in text fields
1874
+ * @apiBody string group? For fields that support grouping (radio buttons and check boxes) the value selected will be stored under this name
1875
+ * @apiBody array(items:IDropdownOption) options? For dropdown fields, the options to display
1876
+ * @apiBody string value? Optional default value to set on the field
1877
+ * @apiSuccess ITemplateField . Template field
1794
1878
  */
1795
- const getKbaStep = (endpoint, envelope_id, role_name) => endpoint.api //
1796
- .get(`/v2/kba/${envelope_id}/${encodeURIComponent(role_name)}`)
1879
+ const createField = (endpoint, templateId, params) => endpoint.api //
1880
+ .post(`/v2/fields/${templateId}`, params)
1797
1881
  .then((r) => r.data);
1798
1882
  /**
1799
- * Submit a response to a KBA PIN challenge.
1883
+ * Update a template field.
1884
+ *
1885
+ * ```typescript
1886
+ * import {updateField} from '@verdocs/js-sdk/Templates';
1887
+ *
1888
+ * await updateField((VerdocsEndpoint.getDefault(), template_id, field_name, { ... });
1889
+ * ```
1890
+ *
1891
+ * @group Fields
1892
+ * @api PATCH /v2/fields/:template_id/:field_name Update a field. See createField for additional details on the supported parameters.
1893
+ * @apiBody string name? Rename the field. Note that template field names must be unique within a template.
1894
+ * @apiBody string role_name Role to assign to the field.
1895
+ * @apiBody string document_id ID of the document upon which to place the field.
1896
+ * @apiBody string(enum: 'signature' | 'initial' | 'checkbox' | 'radio' | 'textbox' | 'timestamp' | 'date' | 'dropdown' | 'textarea' | 'attachment' | 'payment') type? Change the field type. Note that while this is technically allowed, fields have different behaviors, validators, default sizes, etc. It is usually easier to add a new field and delete the old one.
1897
+ * @apiBody boolean(default: false) required? Whether the field is required
1898
+ * @apiBody integer(min: 0) page? 0-based page number upon which to place the field
1899
+ * @apiBody integer(min: 0) x? X position for the field (left to right)
1900
+ * @apiBody integer(min: 0) y? Y position for the field (_bottom to top!_)
1901
+ * @apiBody string label? Optional label to display above the field
1902
+ * @apiBody integer(min: 50) width? Width of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
1903
+ * @apiBody integer(min: 15) height? Height of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
1904
+ * @apiBody string placeholder? Optional placeholder to display in text fields
1905
+ * @apiBody string group? For fields that support grouping (radio buttons and check boxes) the value selected will be stored under this name
1906
+ * @apiBody array(items:IDropdownOption) options? For dropdown fields, the options to display
1907
+ * @apiBody string value? Optional default value to set on the field
1908
+ * @apiSuccess ITemplateField . Updated template field
1800
1909
  */
1801
- const submitKbaPin = (endpoint, envelope_id, role_name, pin) => endpoint.api //
1802
- .post(`/v2/kba/pin`, { envelope_id, role_name, pin })
1910
+ const updateField = (endpoint, templateId, name, params) => endpoint.api //
1911
+ .patch(`/v2/fields/${templateId}/${encodeURIComponent(name)}`, params)
1803
1912
  .then((r) => r.data);
1804
1913
  /**
1805
- * Submit an identity response to a KBA challenge.
1914
+ * Remove a field from a template.
1915
+ *
1916
+ * ```typescript
1917
+ * import {deleteField} from '@verdocs/js-sdk/Templates';
1918
+ *
1919
+ * await deleteField((VerdocsEndpoint.getDefault(), template_id, field_name);
1920
+ * ```
1921
+ *
1922
+ * @group Fields
1923
+ * @api DELETE /v2/fields/:template_id/:field_name Delete a field
1924
+ * @apiSuccess string . Success
1806
1925
  */
1807
- const submitKbaIdentity = (endpoint, envelope_id, role_name, identity) => endpoint.api //
1808
- .post(`/v2/kba/identity`, { envelope_id, role_name, identity })
1926
+ const deleteField = (endpoint, templateId, name) => endpoint.api //
1927
+ .delete(`/v2/fields/${templateId}/${encodeURIComponent(name)}`)
1809
1928
  .then((r) => r.data);
1929
+
1810
1930
  /**
1811
- * Submit an identity response to a KBA challenge. Answers should be submitted in the same order as
1812
- * the challenges were listed in `IRecipientKbaStepChallenge.questions`.
1931
+ * A map of the permissions each role confers.
1813
1932
  */
1814
- const submitKbaChallengeResponse = (endpoint, envelope_id, role_name, responses) => endpoint.api //
1815
- .post(`/v2/kba/response`, { envelope_id, role_name, responses })
1816
- .then((r) => r.data);
1933
+ const RolePermissions = {
1934
+ owner: [
1935
+ 'template:creator:create:public',
1936
+ 'template:creator:create:org',
1937
+ 'template:creator:create:personal',
1938
+ 'template:creator:delete',
1939
+ 'template:creator:visibility',
1940
+ 'template:member:read',
1941
+ 'template:member:write',
1942
+ 'template:member:delete',
1943
+ 'template:member:visibility',
1944
+ 'owner:add',
1945
+ 'owner:remove',
1946
+ 'admin:add',
1947
+ 'admin:remove',
1948
+ 'member:view',
1949
+ 'member:add',
1950
+ 'member:remove',
1951
+ 'org:create',
1952
+ 'org:view',
1953
+ 'org:update',
1954
+ 'org:delete',
1955
+ 'org:transfer',
1956
+ 'org:list',
1957
+ 'envelope:create',
1958
+ 'envelope:cancel',
1959
+ 'envelope:view',
1960
+ ],
1961
+ admin: [
1962
+ 'template:creator:create:public',
1963
+ 'template:creator:create:org',
1964
+ 'template:creator:create:personal',
1965
+ 'template:creator:delete',
1966
+ 'template:creator:visibility',
1967
+ 'template:member:read',
1968
+ 'template:member:write',
1969
+ 'template:member:delete',
1970
+ 'template:member:visibility',
1971
+ 'admin:add',
1972
+ 'admin:remove',
1973
+ 'member:view',
1974
+ 'member:add',
1975
+ 'member:remove',
1976
+ 'org:create',
1977
+ 'org:view',
1978
+ 'org:update',
1979
+ 'org:list',
1980
+ 'envelope:create',
1981
+ 'envelope:cancel',
1982
+ 'envelope:view',
1983
+ ],
1984
+ member: [
1985
+ 'template:creator:create:public',
1986
+ 'template:creator:create:org',
1987
+ 'template:creator:create:personal',
1988
+ 'template:creator:delete',
1989
+ 'template:creator:visibility',
1990
+ 'template:member:read',
1991
+ 'template:member:write',
1992
+ 'template:member:delete',
1993
+ 'member:view',
1994
+ 'org:create',
1995
+ 'org:view',
1996
+ 'org:list',
1997
+ 'envelope:create',
1998
+ 'envelope:cancel',
1999
+ 'envelope:view',
2000
+ ],
2001
+ basic_user: ['template:member:read', 'member:view', 'org:view', 'org:list'],
2002
+ contact: ['org:view', 'org:list', 'org:create'],
2003
+ };
2004
+ /**
2005
+ * Confirm whether the user has all of the specified permissions.
2006
+ */
2007
+ const userHasPermissions = (profile, permissions) => {
2008
+ // No need to de-dupe here, we're just checking present-at-least-once set membership.
2009
+ const netPermissions = [...(profile?.permissions || [])];
2010
+ (profile?.roles || []).forEach((role) => {
2011
+ netPermissions.push(...(RolePermissions[role] || []));
2012
+ });
2013
+ (profile?.group_profiles || []).forEach((groupProfile) => {
2014
+ netPermissions.push(...(groupProfile.group?.permissions || []));
2015
+ });
2016
+ return permissions.every((perm) => netPermissions.includes(perm));
2017
+ };
1817
2018
 
1818
2019
  /**
1819
- * Agree to electronic signing dislosures.
2020
+ * Various helpers to identify available operations for a template by a user.
1820
2021
  *
1821
- * @group Recipients
1822
- * @api POST /envelopes/:envelope_id/recipients/:role_name/agree Agree to e-Signing Disclosures
1823
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1824
- * @apiParam string role_name The role to operate on.
1825
- * @apiSuccess IRecipient . The updated Recipient.
2022
+ * @module
1826
2023
  */
1827
- const envelopeRecipientAgree = (endpoint, envelopeId, roleName, disclosures) => endpoint.api //
1828
- .post(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/agree`, { disclosures })
2024
+ /**
2025
+ * Check to see if the user created the template.
2026
+ */
2027
+ const userIsTemplateCreator = (profile, template) => profile && template && profile.id === template.profile_id;
2028
+ /**
2029
+ * Check to see if a template is "shared" with the user.
2030
+ */
2031
+ const userHasSharedTemplate = (profile, template) => profile && template && !template.is_personal && profile.organization_id === template.organization_id;
2032
+ /**
2033
+ * Check to see if the user can create a personal/private template.
2034
+ */
2035
+ const userCanCreatePersonalTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:personal']);
2036
+ /**
2037
+ * Check to see if the user can create an org-shared template.
2038
+ */
2039
+ const userCanCreateOrgTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:org']);
2040
+ /**
2041
+ * Check to see if the user can create a public template.
2042
+ */
2043
+ const userCanCreatePublicTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:public']);
2044
+ /**
2045
+ * Check to see if the user can read/view a template.
2046
+ */
2047
+ const userCanReadTemplate = (profile, template) => template.is_public ||
2048
+ userIsTemplateCreator(profile, template) ||
2049
+ (userHasSharedTemplate(profile, template) && userHasPermissions(profile, ['template:member:read']));
2050
+ /**
2051
+ * Check to see if the user can update a tempate.
2052
+ */
2053
+ const userCanUpdateTemplate = (profile, template) => userIsTemplateCreator(profile, template) ||
2054
+ (userHasSharedTemplate(profile, template) && userHasPermissions(profile, ['template:member:read', 'template:member:write']));
2055
+ /**
2056
+ * Check to see if the user can change whether a template is personal vs org-shared.
2057
+ */
2058
+ const userCanMakeTemplatePrivate = (profile, template) => userIsTemplateCreator(profile, template)
2059
+ ? userHasPermissions(profile, ['template:creator:create:personal'])
2060
+ : userHasPermissions(profile, ['template:member:visibility']);
2061
+ /**
2062
+ * Check to see if the user can change whether a template is personal vs org-shared.
2063
+ */
2064
+ const userCanMakeTemplateShared = (profile, template) => userIsTemplateCreator(profile, template)
2065
+ ? userHasPermissions(profile, ['template:creator:create:org'])
2066
+ : userHasPermissions(profile, ['template:member:visibility']);
2067
+ /**
2068
+ * Check to see if the user can change whether a template is personal vs org-shared.
2069
+ */
2070
+ const userCanMakeTemplatePublic = (profile, template) => userIsTemplateCreator(profile, template)
2071
+ ? userHasPermissions(profile, ['template:creator:create:public'])
2072
+ : userHasPermissions(profile, ['template:member:visibility']);
2073
+ /**
2074
+ * Check to see if the user can change whether a template is personal vs org-shared.
2075
+ */
2076
+ const userCanChangeOrgVisibility = (profile, template) => userIsTemplateCreator(profile, template) && userHasPermissions(profile, ['template:creator:create:personal']);
2077
+ /**
2078
+ * Check to see if the user can change whether a template is personal vs org-shared.
2079
+ */
2080
+ const userCanDeleteTemplate = (profile, template) => userIsTemplateCreator(profile, template)
2081
+ ? userHasPermissions(profile, ['template:creator:delete'])
2082
+ : userHasPermissions(profile, ['template:member:delete']);
2083
+ /**
2084
+ * Confirm whether the user can create an envelope using the specified template.
2085
+ */
2086
+ const userCanSendTemplate = (profile, template) => {
2087
+ switch (template.visibility) {
2088
+ case 'private':
2089
+ return userIsTemplateCreator(profile, template);
2090
+ case 'shared':
2091
+ return userIsTemplateCreator(profile, template) || template.organization_id === profile?.organization_id;
2092
+ case 'public':
2093
+ return true;
2094
+ }
2095
+ };
2096
+ /**
2097
+ * Confirm whether the user can create a new template.
2098
+ */
2099
+ const userCanCreateTemplate = (profile) => userCanCreatePersonalTemplate(profile) || userCanCreateOrgTemplate(profile) || userCanCreatePublicTemplate(profile);
2100
+ /**
2101
+ * Check to see if the user can "build" the template (use the field builder). The user must have write access to the
2102
+ * template, and the template must have at least one signer role.
2103
+ */
2104
+ const userCanBuildTemplate = (profile, template) => userCanUpdateTemplate(profile, template) && (template.roles || []).filter((role) => role.type === 'signer').length > 0;
2105
+ const getFieldsForRole = (template, role_name) => (template.fields || []).filter((field) => field.role_name === role_name);
2106
+ /**
2107
+ * Check to see if the user can preview the template. The user must have read access to the template, the template must
2108
+ * have at least one signer, and every signer must have at least one field.
2109
+ */
2110
+ const userCanPreviewTemplate = (profile, template) => {
2111
+ const hasPermission = userCanReadTemplate(profile, template);
2112
+ const signers = (template.roles || []).filter((role) => role.type === 'signer');
2113
+ return hasPermission && signers.length > 0 && signers.every((signer) => getFieldsForRole(template, signer.name).length > 0);
2114
+ };
2115
+
2116
+ /**
2117
+ * A "role" is an individual participant in a signing flow, such as a signer or CC contact.
2118
+ * A role is a placeholder that will eventually become a named recipient. For example, "Tenant 1"
2119
+ * might be replaced with "John Smith" when the document is sent out for signature.
2120
+ *
2121
+ * Role names must be unique within a template, e.g. 'Recipient 1'. They may contain any [a-zA-Z0-9_- ]
2122
+ * characters, although it is recommended to keep them simple and human-readable, and to avoid
2123
+ * spaces (although they are allowed). If spaces are used in role names, be sure to URL-encode them
2124
+ * when calling endpoints like `updateRole()` e.g. 'Recipient%201'.
2125
+ *
2126
+ * NOTE: Roles are always enumerated under Template objects, so there are no "list" or "get" endpoints
2127
+ * for them. To get a template's latest role list, simply call `getTemplate()`.
2128
+ *
2129
+ * @module
2130
+ */
2131
+ /**
2132
+ * Create a role.
2133
+ *
2134
+ * ```typescript
2135
+ * import {createTemplateRole} from '@verdocs/js-sdk';
2136
+ *
2137
+ * const role = await createTemplateRole(VerdocsEndpoint.getDefault(), template_id, params...);
2138
+ * ```
2139
+ *
2140
+ * @group Roles
2141
+ * @api POST /v2/roles/:template_id Add a role to a template
2142
+ * @apiBody string name Name for the new role. Must be unique within the template. May include spaces, but later calls must URL-encode any references to this role, so it is recomended that special characters be avoided.
2143
+ * @apiBody string(enum:'signer' | 'cc' | 'approver') type Type of role to create. Signers act on documents by filling and signing fields. CC recipients receive a copy but do not act on the document. Approvers control the final submission of a document, but do not have fields of their own to fill out.
2144
+ * @apiBody string full_name? Default full name for the role. May be completed/overridden later, when envelopes are made from the template.
2145
+ * @apiBody string email? Default email address for the role. May be completed/overridden later, when envelopes are made from the template.
2146
+ * @apiBody string phone? Default (SMS-capable) phone number for the role. May be completed/overridden later, when envelopes are made from the template.
2147
+ * @apiBody string message? Optional message to include in email and SMS signing invitations.
2148
+ * @apiBody integer(min: 1, default: 1) sequence? Optional 1-based sequence number for the role. Roles that share the same sequence number act in parallel, and will receive invitations at the same time.
2149
+ * @apiBody integer(min: 1, default: 1) order? Optional 1-based order number for the role. Controls the left-to-right display order of roles at the same sequence number in the UI components e.g. `<verdocs-template-roles />`.
2150
+ * @apiBody boolean delegator? If true, the role may delegate their signing responsibility to another party.
2151
+ * @apiSuccess IRole . The newly-created role
2152
+ */
2153
+ const createTemplateRole = (endpoint, template_id, params) => endpoint.api //
2154
+ .post(`/v2/roles/${template_id}`, params)
1829
2155
  .then((r) => r.data);
1830
2156
  /**
1831
- * Decline electronic signing dislosures. Note that if any recipient declines, the entire envelope
1832
- * becomes non-viable and later recipients may no longer act. The creator will receive a notification
1833
- * when this occurs.
2157
+ * Update a role.
1834
2158
  *
1835
- * @group Recipients
1836
- * @api POST /envelopes/:envelope_id/recipients/:role_name/decline Decline e-Signing Disclosures
1837
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1838
- * @apiParam string role_name The role to adjust.
1839
- * @apiSuccess IRecipient . The updated Recipient.
2159
+ * ```typescript
2160
+ * import {updateTemplateRole} from '@verdocs/js-sdk';
2161
+ *
2162
+ * const role = await updateTemplateRole(VerdocsEndpoint.getDefault(), template_id, name, params...);
2163
+ * ```
2164
+ *
2165
+ * @group Roles
2166
+ * @api PATCH /v2/roles/:template_id/:role_id Update a role. See createRole for additional details on the parameters available.
2167
+ * @apiBody string name? Rename the role. Note that role names must be unique within a template, so this may fail if the new name is already in use.
2168
+ * @apiBody string(enum:'signer' | 'cc' | 'approver') type? Type of role.
2169
+ * @apiBody string full_name? Default full name for the role.
2170
+ * @apiBody string email? Default email address for the role.
2171
+ * @apiBody string phone? Default (SMS-capable) phone number for the role.
2172
+ * @apiBody string message? Optional message to include in email and SMS signing invitations.
2173
+ * @apiBody integer(min: 1, default: 1) sequence? Optional 1-based sequence number for the role.
2174
+ * @apiBody integer(min: 1, default: 1) order? Optional 1-based order number for the role.
2175
+ * @apiBody boolean delegator? If true, the role may delegate their signing responsibility to another party.
2176
+ * @apiBody string(enum:'pin'|'identity'|'') kba_method? Active PIN- or Identity-based KBA for the role.
2177
+ * @apiSuccess IRole . The newly-created role
1840
2178
  */
1841
- const envelopeRecipientDecline = (endpoint, envelopeId, roleName) => endpoint.api //
1842
- .post(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/decline`)
2179
+ const updateTemplateRole = (endpoint, template_id, name, params) => endpoint.api //
2180
+ .patch(`/v2/roles/${template_id}/${encodeURIComponent(name)}`, params)
1843
2181
  .then((r) => r.data);
1844
2182
  /**
1845
- * Submit an envelope (signing is finished). Note that all fields must be valid/completed for this to succeed.
2183
+ * Delete a role.
1846
2184
  *
1847
- * @group Recipients
1848
- * @api POST /envelopes/:envelope_id/recipients/:role_name/submit Submit envelope
1849
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1850
- * @apiParam string role_name The role to submit.
1851
- * @apiSuccess IRecipient . The updated Recipient.
2185
+ * ```typescript
2186
+ * import {deleteTemplateRole} from '@verdocs/js-sdk';
2187
+ *
2188
+ * const profiles = await deleteTemplateRole(VerdocsEndpoint.getDefault(), template_id, name);
2189
+ * ```
2190
+ *
2191
+ * @group Roles
2192
+ * @api DELETE /v2/roles/:template_id/:role_id Delete a role.
2193
+ * @apiSuccess string . Success
1852
2194
  */
1853
- const envelopeRecipientSubmit = (endpoint, envelopeId, roleName) => endpoint.api //
1854
- .put(`/v2/envelopes/${envelopeId}/recipients/${roleName}/submit`)
2195
+ const deleteTemplateRole = (endpoint, template_id, name) => endpoint.api //
2196
+ .delete(`/v2/roles/${template_id}/${encodeURIComponent(name)}`)
1855
2197
  .then((r) => r.data);
2198
+
1856
2199
  /**
1857
- * Begin a signing session for an Envelope. This path requires an invite code, and should generally
1858
- * be called with a NON-default Endpoint to avoid conflicting with any active user session the user
1859
- * may have. To initiate in-person signing by an authenticated user (e.g. self-signing), call
1860
- * getInPersonLink() instead. The response from that call includes both a link for direct signing
1861
- * via a Web browser as well as an in-person access_key. That access_key.key may be used here as well.
2200
+ * A Template defines how a Verdocs signing flow will be performed, including attachments, signing fields, and
2201
+ * recipients.
2202
+ *
2203
+ * @module
2204
+ */
2205
+ /**
2206
+ * Get all templates accessible by the caller, with optional filters.
2207
+ *
2208
+ * ```typescript
2209
+ * import {getTemplates} from '@verdocs/js-sdk/Templates';
2210
+ *
2211
+ * await getTemplates((VerdocsEndpoint.getDefault());
2212
+ * await getTemplates((VerdocsEndpoint.getDefault(), { is_starred: true });
2213
+ * await getTemplates((VerdocsEndpoint.getDefault(), { is_creator: true });
2214
+ * await getTemplates((VerdocsEndpoint.getDefault(), { is_organization: true });
2215
+ * ```
2216
+ *
2217
+ * @group Templates
2218
+ * @api GET /v2/templates Get Templates
2219
+ * @apiQuery string q? Find templates whose names/descriptions contain the specified query string
2220
+ * @apiQuery boolean is_starred? If true, returns only templates with at least one "star".
2221
+ * @apiQuery boolean is_creator? If true, returns only templates that the caller created.
2222
+ * @apiQuery string(enum: 'private_shared' | 'private' | 'shared' | 'public') visibility? Return only templates with the specified visibility.
2223
+ * @apiQuery string(enum: 'created_at' | 'updated_at' | 'name' | 'last_used_at' | 'counter' | 'star_counter') sort_by? Return results sorted by this criteria
2224
+ * @apiQuery boolean ascending? Set true/false to override the sort direction. Note that the default depends on `sort_by`. Date-based sorts default to descending, while name defaults to ascending.
2225
+ * @apiQuery integer(default: 20) rows? Limit the number of rows returned
2226
+ * @apiQuery integer(default: 0) page? Specify which page of results to return
2227
+ * @apiSuccess integer(format: int32) count The total number of records matching the query, helpful for pagination
2228
+ * @apiSuccess integer(format: int32) rows The number of rows returned in this response page
2229
+ * @apiSuccess integer(format: int32) page The page number of this response
2230
+ * @apiSuccess array(items: ITemplate) templates List of templates found
2231
+ */
2232
+ const getTemplates = (endpoint, params) => endpoint.api //
2233
+ .get('/v2/templates', { params })
2234
+ .then((r) => r.data);
2235
+ /**
2236
+ * Get one template by its ID.
1862
2237
  *
1863
- * @group Recipients
1864
- * @api POST /v2/sign/unauth/:envelope_id/:role_name/:key Start Signing Session
1865
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1866
- * @apiParam string role_name The role to request.
1867
- * @apiParam string key Access key generated by the envelope creator or email/SMS invite.
1868
- * @apiSuccess ISignerTokenResponse . Signing session token and envelope/recipient metadata.
2238
+ * ```typescript
2239
+ * import {getTemplate} from '@verdocs/js-sdk/Templates';
2240
+ *
2241
+ * const template = await getTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2242
+ * ```
2243
+ *
2244
+ * @group Templates
2245
+ * @api GET /v2/templates/:template_id Get a template. Note that the caller must have at least View access to the template.
2246
+ * @apiSuccess ITemplate . The requested template
1869
2247
  */
1870
- const startSigningSession = async (endpoint, envelope_id, role_name, key) => {
2248
+ const getTemplate = (endpoint, templateId) => {
1871
2249
  return endpoint.api //
1872
- .post(`/v2/sign/unauth/${envelope_id}/${encodeURIComponent(role_name)}/${key}`)
2250
+ .get(`/v2/templates/${templateId}`)
1873
2251
  .then((r) => {
1874
- endpoint.setToken(r.data.access_token, 'signing');
1875
- return r.data;
2252
+ const template = r.data;
2253
+ // Post-process the template to upgrade to new data fields
2254
+ if (!template.documents && template.template_documents) {
2255
+ template.documents = template.template_documents;
2256
+ }
2257
+ template.documents?.forEach((document) => {
2258
+ if (!document.order) {
2259
+ document.order = 0;
2260
+ }
2261
+ if (document.page_numbers) {
2262
+ document.pages = document.page_numbers;
2263
+ }
2264
+ });
2265
+ // Temporary upgrade from legacy app
2266
+ template.fields?.forEach((field) => {
2267
+ if (field.setting) {
2268
+ field.settings = field.setting;
2269
+ }
2270
+ });
2271
+ return template;
1876
2272
  });
1877
2273
  };
2274
+ const ALLOWED_CREATE_FIELDS = [
2275
+ 'name',
2276
+ 'is_personal',
2277
+ 'is_public',
2278
+ 'sender',
2279
+ 'description',
2280
+ 'roles',
2281
+ 'fields',
2282
+ ];
1878
2283
  /**
1879
- * Get an in-person signing link. Must be called by the owner/creator of the envelope. The response
1880
- * also includes the raw access key that may be used to directly initiate a signing session (see
1881
- * `startSigningSession`) as well as an access token representing a valid signing session for
1882
- * immediate use in embeds or other applications. Note that in-person signing is considered a
1883
- * lower-security operation than authenticated signing, and the final envelope certificate will
1884
- * reflect this.
2284
+ * Create a template.
1885
2285
  *
1886
- * @group Recipients
1887
- * @api POST /v2/sign/in-person/:envelope_id/:role_name Get In-Person Signing Link
1888
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1889
- * @apiParam string role_name The role to request.
1890
- * @apiSuccess IInPersonLinkResponse . Signing session token and envelope/recipient metadata.
2286
+ * ```typescript
2287
+ * import {createTemplate} from '@verdocs/js-sdk/Templates';
2288
+ *
2289
+ * const newTemplate = await createTemplate((VerdocsEndpoint.getDefault(), {...});
2290
+ * ```
2291
+ *
2292
+ * @group Templates
2293
+ * @api POST /v2/templates Create a template
2294
+ * @apiBody string name Template name
2295
+ * @apiBody string description? Optional description
2296
+ * @apiBody TTemplateVisibility visibility? Visibility setting
2297
+ * @apiBody boolean is_personal? Deprecated. If true, the template is personal and can only be seen by the caller. (Use "visibility" for new calls.)
2298
+ * @apiBody boolean is_public? Deprecated. If true, the template is public and can be seen by anybody. (Use "visibility" for new calls.)
2299
+ * @apiBody TTemplateSender sender? Who may send envelopes using this template
2300
+ * @apiBody number initial_reminder? Delay (in seconds) before the first reminder is sent (min: 4hrs). Set to 0 or null to disable.
2301
+ * @apiBody number followup_reminders? Delay (in seconds) before the subsequent reminders are sent (min: 12hrs). Set to 0 or null to disable.
2302
+ * @apiBody array(items:object) documents? Optional list of documents to attach to the template
2303
+ * @apiBody array(items:IRole) roles? Optional list of roles to create. Note that if roles are not included in the request, fields will be ignored.
2304
+ * @apiBody array(fields:ITemplateField) fields? Optional list of fields to create. Note that if fields that do not match a role will be ignored.
2305
+ * @apiSuccess ITemplate . The newly-created template
1891
2306
  */
1892
- const getInPersonLink = (endpoint, envelope_id, role_name) => endpoint.api //
1893
- .post(`/v2/sign/in-person/${envelope_id}/${encodeURIComponent(role_name)}`)
1894
- .then((r) => r.data);
2307
+ const createTemplate = (endpoint, params, onUploadProgress) => {
2308
+ const options = {
2309
+ timeout: 120000,
2310
+ onUploadProgress: (event) => {
2311
+ const total = event.total || 1;
2312
+ const loaded = event.loaded || 0;
2313
+ onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
2314
+ },
2315
+ };
2316
+ if (params.documents && params.documents[0] instanceof File) {
2317
+ const formData = new FormData();
2318
+ ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
2319
+ if (params[allowedKey] !== undefined) {
2320
+ formData.append(allowedKey, params[allowedKey]);
2321
+ }
2322
+ });
2323
+ params.documents.forEach((file) => {
2324
+ formData.append('documents', file, file.name);
2325
+ });
2326
+ return endpoint.api.post('/v2/templates', formData, options).then((r) => r.data);
2327
+ }
2328
+ else {
2329
+ return endpoint.api.post('/v2/templates', params, options).then((r) => r.data);
2330
+ }
2331
+ };
1895
2332
  /**
1896
- * Verify a recipient within a signing session. All signing sessions use an invite code at a minimum,
1897
- * but many scenarios require more robust verification of recipients, so one or more verification
1898
- * methods may be attached to each recipient. If an authentication method is enabled, the
1899
- * signer must first accept the e-signature disclosures, then complete each verification step
1900
- * before attempting to view/display documents, complete any fields, or submit the envelope.
1901
- * This endpoint should be called to complete each step. If the call fails an error will be
1902
- * thrown.
2333
+ * Duplicate a template. Creates a complete clone, including all settings (e.g. reminders), fields,
2334
+ * roles, and documents.
1903
2335
  *
1904
- * @group Recipients
1905
- * @api POST /v2/sign/verify Verify recipient/signer
1906
- * @apiParam string(enum:'passcode'|'email'|'sms'|'kba'|'id') auth_method The authentication method being completed
1907
- * @apiParam string code? The passcode or OTP entered. Required for passcode, email, and SMS methods.
1908
- * @apiParam boolean resend? For SMS or email methods, set to send a new code.
1909
- * @apiParam boolean first_name? For KBA, the recipient's first name
1910
- * @apiParam boolean last_name? For KBA, the recipient's last name
1911
- * @apiParam boolean address? For KBA, the recipient's address
1912
- * @apiParam boolean city? For KBA, the recipient's city
1913
- * @apiParam boolean state? For KBA, the recipient's state
1914
- * @apiParam boolean zip? For KBA, the recipient's zip code
1915
- * @apiParam boolean ssn_last_4? For KBA, the last 4 digits of the recipient's SSN
1916
- * @apiParam boolean dob? For KBA, the recipient's date of birth
1917
- * @apiParam array(items:IKBAResponse) responses? For KBA, responses to any challenge questions presented
1918
- * @apiSuccess ISignerTokenResponse . Updated signing session.
2336
+ * ```typescript
2337
+ * import {duplicateTemplate} from '@verdocs/js-sdk/Templates';
2338
+ *
2339
+ * const newTemplate = await duplicateTemplate((VerdocsEndpoint.getDefault(), originalTemplateId, 'My Template Copy');
2340
+ * ```
2341
+ *
2342
+ * @group Templates
2343
+ * @api PUT /v2/templates/:template_id Perform an operation on a template
2344
+ * @apiBody string(enum:'duplicate') action Action to perform
2345
+ * @apiBody string name? If duplicating the template, a name for the new copy
2346
+ * @apiSuccess ITemplate . The newly-copied template
1919
2347
  */
1920
- const verifySigner = (endpoint, params) => endpoint.api //
1921
- .post(`/v2/sign/verify`, params)
2348
+ const duplicateTemplate = (endpoint, templateId, name) => endpoint.api //
2349
+ .put(`/v2/templates/${templateId}`, { action: 'duplicate', name })
1922
2350
  .then((r) => r.data);
1923
2351
  /**
1924
- * Delegate a recipient's signing responsibility. The envelope sender must enable this before the
1925
- * recipient calls this endpoint, and only the recipient may call it, or the call will be rejected.
1926
- * The recipient's role will be renamed and configured to indicate to whom the delegation was made,
1927
- * and a new recipient entry with the updated details (e.g. name and email address) will be added
1928
- * to the flow with the same role_name, order, and sequence of the original recipient. Unless
1929
- * no_contact is set on the envelope, the delegation recipient and envelope creator will also be
1930
- * notified.
2352
+ * Create a template from a Sharepoint asset.
1931
2353
  *
1932
- * @group Recipients
1933
- * @api PUT /v2/envelopes/:envelope_id/recipients/:role_name Delegate Recipient
1934
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1935
- * @apiParam string role_name The role to operate on.
1936
- * @apiBody string(enum:'delegate') action The operation to perform (delegate).
1937
- * @apiBody string first_name The first name of the new recipient.
1938
- * @apiBody string last_name The last name of the new recipient.
1939
- * @apiBody string email The email address of the new recipient.
1940
- * @apiBody string phone? Optional phone number for the new recipient.
1941
- * @apiBody string message? Optional phone number for the new recipient's invitation.
1942
- * @apiSuccess string . Success message.
2354
+ * ```typescript
2355
+ * import {createTemplateFromSharepoint} from '@verdocs/js-sdk/Templates';
2356
+ *
2357
+ * const newTemplate = await createTemplateFromSharepoint((VerdocsEndpoint.getDefault(), {...});
2358
+ * ```
2359
+ *
2360
+ * @group Templates
2361
+ * @api POST /v2/templates/from-sharepoint Create a template from an asset in Sharepoint
2362
+ * @apiBody string name Name for the new template
2363
+ * @apiBody string siteId Name for the new template
2364
+ * @apiBody string itemId Name for the new template
2365
+ * @apiBody string oboToken On-Behalf-Of token for calls to Sharepoint. Should be generated as a short-expiration token with at least Read privileges to the siteId/itemId. This token will be discarded after being used.
2366
+ * @apiSuccess ITemplate . The newly-created template
1943
2367
  */
1944
- const delegateRecipient = (endpoint, envelopeId, roleName, params) => endpoint.api //
1945
- .put(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'delegate', ...params })
1946
- .then((r) => r.data);
2368
+ const createTemplateFromSharepoint = (endpoint, params) => {
2369
+ const options = {
2370
+ timeout: 120000,
2371
+ };
2372
+ return endpoint.api.post('/v2/templates/from-sharepoint', params, options).then((r) => r.data);
2373
+ };
1947
2374
  /**
1948
- * Update a recipient. NOTE: User interfaces should rate-limit this operation to avoid spamming recipients.
1949
- * Excessive use of this endpoint may result in Verdocs rate-limiting the calling application to prevent
1950
- * abuse. This endpoint will return a 200 OK even if the no_contact flag is set on the envelope (in which
1951
- * case the call will be silently ignored).
2375
+ * Update a template.
1952
2376
  *
1953
- * @group Recipients
1954
- * @api PATCH /envelopes/:envelope_id/recipients/:role_name Update Recipient
1955
- * @apiParam string(format:uuid) envelope_id The envelope to operate on.
1956
- * @apiParam string role_name The role name to update.
1957
- * @apiBody string(enum:'remind'|'reset') action? Trigger a reminder, or fully reset the recipient
1958
- * @apiBody string first_name? Update the recipient's first name.
1959
- * @apiBody string last_name? Update the recipient's last name.
1960
- * @apiBody string email? Update the recipient's email address.
1961
- * @apiBody string message? Update the recipient's invite message.
1962
- * @apiBody string phone? Update the recipient's phone number.
1963
- * @apiBody string passcode? If passcode authentication is used, the recipient's address to prefill. May only be changed if the recipient has not already completed passcode-based auth.
1964
- * @apiBody string address? If KBA-based authentication is used, the recipient's address to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1965
- * @apiBody string city? If KBA-based authentication is used, the recipient's city to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1966
- * @apiBody string state? If KBA-based authentication is used, the recipient's state to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1967
- * @apiBody string zip? If KBA-based authentication is used, the recipient's zip code to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1968
- * @apiBody string dob? If KBA-based authentication is used, the recipient's date of birth to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1969
- * @apiBody string ssn_last_4? If KBA-based authentication is used, the recipient's SSN-last-4 to prefill. May only be changed if the recipient has not already completed KBA-based auth.
1970
- * @apiSuccess IRecipient . The updated Recipient.
2377
+ * ```typescript
2378
+ * import {updateTemplate} from '@verdocs/js-sdk/Templates';
2379
+ *
2380
+ * const updatedTemplate = await updateTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9', { name: 'New Name' });
2381
+ * ```
2382
+ *
2383
+ * @group Templates
2384
+ * @api PATCH /v2/templates/:template_id Update a template
2385
+ * @apiBody string name? Template name
2386
+ * @apiBody string description? Optional description
2387
+ * @apiBody TTemplateVisibility visibility? Visibility setting
2388
+ * @apiBody boolean is_personal? Deprecated. If true, the template is personal and can only be seen by the caller. (Use "visibility" for new calls.)
2389
+ * @apiBody boolean is_public? Deprecated. If true, the template is public and can be seen by anybody. (Use "visibility" for new calls.)
2390
+ * @apiBody TTemplateSender sender? Who may send envelopes using this template
2391
+ * @apiBody number initial_reminder? Delay (in seconds) before the first reminder is sent (min: 4hrs). Set to 0 or null to disable.
2392
+ * @apiBody number followup_reminders? Delay (in seconds) before the subsequent reminders are sent (min: 12hrs). Set to 0 or null to disable.
2393
+ * @apiSuccess ITemplate . The updated template
1971
2394
  */
1972
- const updateRecipient = (endpoint, envelopeId, roleName, params) => endpoint.api //
1973
- .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, params)
2395
+ const updateTemplate = (endpoint, templateId, params) => endpoint.api //
2396
+ .patch(`/v2/templates/${templateId}`, params)
1974
2397
  .then((r) => r.data);
1975
2398
  /**
1976
- * Send a reminder to a recipient. The recipient must still be an active member of the signing flow
1977
- * (e.g. not declined, already submitted, etc.)
2399
+ * Delete a template.
2400
+ *
2401
+ * ```typescript
2402
+ * import {deleteTemplate} from '@verdocs/js-sdk/Templates';
2403
+ *
2404
+ * await deleteTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2405
+ * ```
2406
+ *
2407
+ * @group Templates
2408
+ * @api DELETE /v2/templates/:template_id Delete a template
2409
+ * @apiSuccess string . Success
1978
2410
  */
1979
- const remindRecipient = (endpoint, envelopeId, roleName) => endpoint.api //
1980
- .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'remind' })
2411
+ const deleteTemplate = (endpoint, templateId) => endpoint.api //
2412
+ .delete(`/v2/templates/${templateId}`)
1981
2413
  .then((r) => r.data);
1982
- /**
1983
- * Fully reset a recipient. This allows the recipient to restart failed KBA flows, change
1984
- * fields they may have filled in incorrectly while signing, etc. This cannot be used on a
1985
- * canceled or completed envelope, but may be used to restart an envelope marked declined.
2414
+ /**
2415
+ * Toggle the template star for a template.
2416
+ *
2417
+ * ```typescript
2418
+ * import {toggleTemplateStar} from '@verdocs/js-sdk/Templates';
2419
+ *
2420
+ * await toggleTemplateStar((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
2421
+ * ```
2422
+ *
2423
+ * @group Templates
2424
+ * @api POST /v2/templates/:template_id/star Star or unstar a template (toggle state)
2425
+ * @apiSuccess ITemplate . Success
1986
2426
  */
1987
- const resetRecipient = (endpoint, envelopeId, roleName) => endpoint.api //
1988
- .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'reset' })
2427
+ const toggleTemplateStar = (endpoint, templateId) => endpoint.api //
2428
+ .post(`/v2/templates/${templateId}/stars/toggle`)
1989
2429
  .then((r) => r.data);
1990
2430
 
1991
2431
  /**
1992
- * Various helpers to identify available operations for an envelope by a user.
2432
+ * A TemplateDocument represents a PDF or other attachment in a Template.
1993
2433
  *
1994
2434
  * @module
1995
2435
  */
1996
2436
  /**
1997
- * Check to see if the profile ID owns the envelope.
1998
- */
1999
- const isEnvelopeOwner = (profile_id, envelope) => envelope.profile_id === profile_id;
2000
- /**
2001
- * Check to see if the profile ID is a recipient within the envelope.
2002
- */
2003
- const isEnvelopeRecipient = (profile_id, envelope) => (envelope.recipients || []).some((recipient) => recipient.profile_id === profile_id);
2004
- /**
2005
- * Check to see if the profile ID is the envelope's sender or one of the recipients.
2006
- */
2007
- const canAccessEnvelope = (profile_id, envelope) => isEnvelopeOwner(profile_id, envelope) || isEnvelopeRecipient(profile_id, envelope);
2008
- /**
2009
- * Check to see if the user owns the envelope.
2010
- */
2011
- const userIsEnvelopeOwner = (profile, envelope) => envelope.profile_id === profile?.id;
2012
- /**
2013
- * Check to see if the user is a recipient within the envelope.
2014
- */
2015
- const userIsEnvelopeRecipient = (profile, envelope) => (envelope.recipients || []).some((recipient) => recipient.profile_id === profile?.id);
2016
- /**
2017
- * Check to see if the profile ID is the envelope's sender or one of the recipients.
2437
+ * Create a Document for a particular Template.
2438
+ *
2439
+ * ```typescript
2440
+ * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
2441
+ *
2442
+ * await TemplateDocument.createDocument(VerdocsEndpoint.getDefault(), templateID, params);
2443
+ * ```
2444
+ *
2445
+ * @group Template Documents
2446
+ * @api POST /v2/templates/:template_id/documents Attach a document to a template
2447
+ * @apiBody string(format:binary) file Document file to attach. The file name will automatically be used as the document name.
2448
+ * @apiBody string(format:uuid) template_id Template ID to attach the document to
2449
+ * @apiSuccess ITemplateDocument . Template document
2018
2450
  */
2019
- const useCanAccessEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) || userIsEnvelopeRecipient(profile, envelope);
2451
+ const createTemplateDocument = (endpoint, template_id, file, onUploadProgress) => {
2452
+ const formData = new FormData();
2453
+ formData.append('file', file, file.name);
2454
+ formData.append('template_id', template_id);
2455
+ return endpoint.api //
2456
+ .post(`/v2/template-documents`, formData, {
2457
+ timeout: 120000,
2458
+ onUploadProgress: (event) => {
2459
+ const total = event.total || 1;
2460
+ const loaded = event.loaded || 0;
2461
+ onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
2462
+ },
2463
+ })
2464
+ .then((r) => r.data);
2465
+ };
2020
2466
  /**
2021
- * Check to see if the envelope has pending actions.
2467
+ * Delete a specific Document.
2468
+ *
2469
+ * ```typescript
2470
+ * import {deleteTemplateDocument} from '@verdocs/js-sdk/Templates';
2471
+ *
2472
+ * await deleteTemplateDocument(VerdocsEndpoint.getDefault(), documentID);
2473
+ * ```
2474
+ *
2475
+ * @group Template Documents
2476
+ * @api DELETE /v2/template-documents/:document_id Delete a template document
2477
+ * @apiSuccess string . Success
2022
2478
  */
2023
- const envelopeIsActive = (envelope) => envelope.status !== 'complete' && envelope.status !== 'declined' && envelope.status !== 'canceled';
2479
+ const deleteTemplateDocument = (endpoint, documentId) => endpoint.api //
2480
+ .delete(`/v2/template-documents/${documentId}`)
2481
+ .then((r) => r.data);
2024
2482
  /**
2025
- * Check to see if the envelope has been completed.
2483
+ * Get all metadata for a template document. Note that when called by non-creators (e.g. Org Collaborators)
2484
+ * this will return only the **metadata** the caller is allowed to view.
2485
+ *
2486
+ * @group Template Documents
2487
+ * @api GET /v2/envelope-documents/:id Get envelope document
2488
+ * @apiParam string(format: 'uuid') document_id The ID of the document to retrieve.
2489
+ * @apiSuccess IEnvelopeDocument . The detailed metadata for the document requested
2026
2490
  */
2027
- const envelopeIsComplete = (envelope) => envelope.status !== 'complete';
2491
+ const getTemplateDocument = async (endpoint, documentId) => endpoint.api //
2492
+ .get(`/v2/template-documents/${documentId}`)
2493
+ .then((r) => r.data);
2028
2494
  /**
2029
- * Check to see if the user owns the envelope.
2495
+ * Download a document directly.
2030
2496
  */
2031
- const userCanCancelEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) &&
2032
- envelope.status !== 'complete' &&
2033
- envelope.status !== 'declined' &&
2034
- envelope.status !== 'canceled';
2497
+ const downloadTemplateDocument = async (endpoint, documentId) => endpoint.api //
2498
+ .get(`/v2/template-documents/${documentId}?type=file`, { responseType: 'blob' })
2499
+ .then((r) => r.data);
2035
2500
  /**
2036
- * Check to see if the user owns the envelope.
2501
+ * Get an envelope document's metadata, or the document itself. If no "type" parameter is specified,
2502
+ * the document metadata is returned. If "type" is set to "file", the document binary content is
2503
+ * returned with Content-Type set to the MIME type of the file. If "type" is set to "download", a
2504
+ * string download link will be returned. If "type" is set to "preview" a string preview link will
2505
+ * be returned. This link expires quickly, so it should be accessed immediately and never shared.
2506
+ *
2507
+ * @group Template Documents
2508
+ * @api GET /v2/envelope-documents/:document_id Preview, Download, or Link to a Document
2509
+ * @apiParam string(format: 'uuid') document_id The ID of the document to retrieve.
2510
+ * @apiQuery string(enum:'file'|'download'|'preview') type? Download the file directly, generate a download link, or generate a preview link.
2511
+ * @apiSuccess string . The generated link.
2037
2512
  */
2038
- const userCanFinishEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) &&
2039
- envelope.status !== 'complete' &&
2040
- envelope.status !== 'declined' &&
2041
- envelope.status !== 'canceled';
2513
+ const getTemplateDocumentDownloadLink = async (endpoint, _envelopeId, documentId) => endpoint.api //
2514
+ .get(`/v2/template-documents/${documentId}?type=download`)
2515
+ .then((r) => r.data);
2042
2516
  /**
2043
- * Returns true if the recipient has a pending action. Note that this does not necessarily mean the recipient can act (yet).
2517
+ * Get a pre-signed preview link for an Envelope Document. This link expires quickly, so it should
2518
+ * be accessed immediately and never shared. Content-Disposition will be set to "inline".
2044
2519
  */
2045
- const recipientHasAction = (recipient) => !['submitted', 'canceled', 'declined'].includes(recipient.status);
2520
+ const getTemplateDocumentPreviewLink = async (endpoint, _envelopeId, documentId) => endpoint.api //
2521
+ .get(`/v2/envelope-documents/${documentId}?type=preview`)
2522
+ .then((r) => r.data);
2046
2523
  /**
2047
- * Returns the recipients who still have a pending action. Note that not all of these recipients may be able to act (yet).
2524
+ * Get (binary download) a file attached to a Template. It is important to use this method
2525
+ * rather than a direct A HREF or similar link to set the authorization headers for the
2526
+ * request.
2048
2527
  */
2049
- const getRecipientsWithActions = (envelope) => ['complete', 'declined', 'canceled'].includes(envelope.status) ? [] : (envelope?.recipients || []).filter(recipientHasAction);
2528
+ const getTemplateDocumentFile = async (endpoint, templateId, documentId) => endpoint.api //
2529
+ .get(`/v2/templates/${templateId}/documents/${documentId}?file=true`, { responseType: 'blob' })
2530
+ .then((r) => r.data);
2050
2531
  /**
2051
- * Returns true if the recipient can act.
2532
+ * Get (binary download) a file attached to a Template. It is important to use this method
2533
+ * rather than a direct A HREF or similar link to set the authorization headers for the
2534
+ * request.
2052
2535
  */
2053
- const recipientCanAct = (recipient, recipientsWithActions) => recipient.sequence === recipientsWithActions?.[0]?.sequence;
2536
+ const getTemplateDocumentThumbnail = async (endpoint, templateId, documentId) => endpoint.api //
2537
+ .get(`/v2/templates/${templateId}/documents/${documentId}?thumbnail=true`, { responseType: 'blob' })
2538
+ .then((r) => r.data);
2054
2539
  /**
2055
- * Returns true if the user can act.
2540
+ * Get a display URI for a given page in a file attached to a template document. These pages are rendered server-side
2541
+ * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
2542
+ * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants. The
2543
+ * original asset may be obtained by calling `getTemplateDocumentFile()` or similar.
2056
2544
  */
2057
- const userCanAct = (email, recipientsWithActions) => {
2058
- const recipient = recipientsWithActions.find((r) => r.email === email);
2059
- return recipient && recipient.sequence === recipientsWithActions?.[0]?.sequence;
2545
+ const getTemplateDocumentPageDisplayUri = async (endpoint, documentId, page, variant = 'original') => endpoint.api.get(`/v2/template-documents/page-image/${documentId}/${variant}/${page}`, { timeout: 20000 }).then((r) => r.data);
2546
+
2547
+ const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2548
+ // @see https://www.regextester.com/1978
2549
+ const PHONE_REGEX = /((?:\+|00)[17](?: |\-)?|(?:\+|00)[1-9]\d{0,2}(?: |\-)?|(?:\+|00)1\-\d{3}(?: |\-)?)?(0\d|\([0-9]{3}\)|[1-9]{0,3})(?:((?: |\-)[0-9]{2}){4}|((?:[0-9]{2}){4})|((?: |\-)[0-9]{3}(?: |\-)[0-9]{4})|([0-9]{7}))/;
2550
+ const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
2551
+ const POSTAL_CODE_REGEX = /^[A-Za-z0-9-\s]{3,10}$/;
2552
+ const NUMBER_REGEX = /^\d+$/;
2553
+ const DATE_REGEX = /^(\d{4}[-\/]\d{2}[-\/]\d{2})|(\d{2}[-\/]\d{2}[-\/]\d{4})$/;
2554
+ const VALIDATORS = {
2555
+ email: { regex: EMAIL_REGEX, label: 'Email Address' },
2556
+ phone: { regex: PHONE_REGEX, label: 'Phone Number' },
2557
+ url: { regex: URL_REGEX, label: 'URL' },
2558
+ postal_code: { regex: POSTAL_CODE_REGEX, label: 'Zip/Postal Code' },
2559
+ number: { regex: NUMBER_REGEX, label: 'Number' },
2560
+ date: { regex: DATE_REGEX, label: 'Date' },
2060
2561
  };
2562
+ const isValidInput = (value, validator) => Object.keys(VALIDATORS).includes(validator) && VALIDATORS[validator].regex.test(value);
2061
2563
  /**
2062
- * Returns true if the user can act.
2564
+ * Get a list of available validators for field inputs. Note that validators always check strings,
2565
+ * because that is all a user can enter in an HTML input field. Numeric-format validators should
2566
+ * perform any necessary conversions internally. Validators never throw - they just return a boolean.
2567
+ * indicating whether the value is valid.
2063
2568
  */
2064
- const userCanSignNow = (profile, envelope) => {
2065
- if (!profile) {
2066
- return false;
2569
+ const getValidators = () => Object.keys(VALIDATORS);
2570
+ const isValidEmail = (email) => !!email && EMAIL_REGEX.test(email);
2571
+ const isValidPhone = (phone) => !!phone && PHONE_REGEX.test(phone);
2572
+ const isValidRoleName = (value, roles) => roles.findIndex((role) => role.name === value) !== -1;
2573
+ const TagRegEx = /^[a-zA-Z0-9-]{0,32}$/;
2574
+ const isValidTag = (value, tags) => TagRegEx.test(value) || tags.findIndex((tag) => tag === value) !== -1;
2575
+
2576
+ const isFieldFilled = (field, allRecipientFields) => {
2577
+ const { value = '' } = field;
2578
+ switch (field.type) {
2579
+ case 'textarea':
2580
+ case 'textbox':
2581
+ switch (field.validator || '') {
2582
+ case 'email':
2583
+ return value && isValidInput(value, 'email');
2584
+ case 'phone':
2585
+ return value && isValidInput(value, 'phone');
2586
+ default:
2587
+ return (value || '').trim() !== '';
2588
+ }
2589
+ case 'signature':
2590
+ return value === 'signed';
2591
+ case 'initial':
2592
+ return value === 'initialed';
2593
+ // Timestamp fields get automatically filled when the envelope is submitted.
2594
+ case 'timestamp':
2595
+ return true;
2596
+ case 'date':
2597
+ return !!value;
2598
+ case 'attachment':
2599
+ return value === 'attached';
2600
+ case 'dropdown':
2601
+ return value !== '';
2602
+ case 'checkbox':
2603
+ return value === 'true';
2604
+ case 'radio':
2605
+ if (!!field.group) {
2606
+ return allRecipientFields.filter((f) => f.group === field.group).some((field) => field.value === 'true');
2607
+ }
2608
+ return field.value === 'true';
2609
+ default:
2610
+ return false;
2067
2611
  }
2068
- const recipientsWithActions = getRecipientsWithActions(envelope);
2069
- const myRecipient = recipientsWithActions.find((r) => r.profile_id === profile?.id || r.email === profile?.email);
2070
- return (myRecipient &&
2071
- envelopeIsActive(envelope) &&
2072
- userIsEnvelopeRecipient(profile, envelope) &&
2073
- recipientCanAct(myRecipient, recipientsWithActions));
2074
2612
  };
2075
- const getNextRecipient = (envelope) => {
2076
- const recipientsWithActions = getRecipientsWithActions(envelope);
2077
- return recipientsWithActions?.[0];
2613
+ // TODO: Only allow !required to bypass validation if the field is empty.
2614
+ const isFieldValid = (field, allRecipientFields) => {
2615
+ return !field.required || isFieldFilled(field, allRecipientFields);
2078
2616
  };
2079
2617
 
2080
2618
  /**
2081
- * Create a signature block. In a typical signing workflow, the user is asked at the beginning of the process to
2082
- * "adopt" a signature block to be used for all signature fields in the document. Thus, this is typically called one
2083
- * time to create and store a signature block. Thereafter, the ID of the signature block may be re-used for each
2084
- * signature field to be "stamped" by the user.
2619
+ * Create an initials block. In a typical signing workflow, the user is asked at the beginning of the process to
2620
+ * "adopt" an initials block to be used for all initials fields in the document. Thus, this is typically called
2621
+ * one time to create and store an initials block. Thereafter, the ID of the initials block may be re-used for each
2622
+ * initials field to be "stamped" by the user.
2085
2623
  *
2086
2624
  * Note: Both "guest" signers and authenticated users can create initials blocks. Guest signers
2087
2625
  * typically only ever have one, tied to that session. But authenticated users can create more than
2088
2626
  * one, and can use them interchangeably.
2089
2627
  *
2090
2628
  * @group Signatures and Initials
2091
- * @api POST /v2/profiles/signatures Create Signature Block
2092
- * @apiBody string signature Blob containing signature image to store.
2093
- * @apiSuccess ISignature . The newly-created signature block.
2629
+ * @api POST /v2/profiles/initials Create Initial Block
2630
+ * @apiBody string initial Blob containing initials image to store.
2631
+ * @apiSuccess IInitial . The newly-created initial block.
2094
2632
  */
2095
- const createSignature = (endpoint, name, signature) => {
2633
+ const createInitials = (endpoint, name, initials) => {
2096
2634
  const data = new FormData();
2097
- data.append('signature', signature, name);
2635
+ data.append('initial', initials, name);
2098
2636
  return endpoint.api //
2099
- .post(`/v2/profiles/signatures`, data)
2637
+ .post(`/v2/profiles/initials`, data)
2100
2638
  .then((r) => r.data);
2101
2639
  };
2102
2640
 
2103
2641
  /**
2104
- * API keys are used to authenticate server-to-server calls. (API keys should **never** be used for client-to-server operations!)
2105
- * To generate a key, either use the Verdocs admin interface and make note of the client_id and client_secret generated, or call
2106
- * createKey as shown below. Then call {@link Users.Auth.authenticateApp} to obtain an access token using the provided ID and
2107
- * secret. Note that server-to-server authentication requests return shorter-lived tokens, so it is important to check the `exp`
2108
- * field and re-authenticate as needed for subsequent calls.
2109
- *
2110
- * API keys may be updated or rotated at any time. Regular rotation is recommended. Rotation will not expire or invalidate
2111
- * existing server-to-server sessions, so it may be done at any time without disrupting your application.
2112
- *
2113
- * @module
2114
- */
2115
- /**
2116
- * Get a list of keys for a given organization. The caller must have admin access to the organization.
2117
- *
2118
- * ```typescript
2119
- * import {getApiKeys} from '@verdocs/js-sdk';
2120
- *
2121
- * const keys = await getApiKeys(ORGID);
2122
- * ```
2123
- *
2124
- * @group API Keys
2125
- * @api GET /v2/api-keys Get API keys
2126
- * @apiSuccess array(items: IApiKey) . A list of the API keys for the caller's organization. Secrets will not be included.
2127
- */
2128
- const getApiKeys = (endpoint) => endpoint.api //
2129
- .get(`/v2/api-keys`)
2130
- .then((r) => r.data);
2131
- /**
2132
- * Create an API key.
2133
- *
2134
- * ```typescript
2135
- * import {createApiKey} from '@verdocs/js-sdk';
2136
- *
2137
- * await createApiKey(ORGID, {name: NEWNAME});
2138
- * ```
2139
- *
2140
- * @group API Keys
2141
- * @api POST /v2/api-keys Create API key
2142
- * @apiBody string name A name used to identify the key in the Verdocs Web App
2143
- * @apiBody string(format:uuid) profile_id The profile ID that calls made using the key will act as
2144
- * @apiBody array(items:string) permission An array of permissions to assign to the new key. Extends (but does not override) the API key's profile permissions.
2145
- * @apiSuccess IApiKey . The newly-created API key, including its secret.
2642
+ * Get the current KBA status. Note that this may only be called by the recipient and requires a
2643
+ * valid signing session to proceed. Although the Recipient object itself contains indications of
2644
+ * whether KBA is required, it will not contain the current status of the process. If
2645
+ * `recipient.auth_methods` is set (not empty), and `recipient.kba_completed` is false, this endpoint
2646
+ * should be called to determine the next KBA step required.
2146
2647
  */
2147
- const createApiKey = (endpoint, params) => endpoint.api //
2148
- .post('/v2/api-keys', params)
2648
+ const getKbaStep = (endpoint, envelope_id, role_name) => endpoint.api //
2649
+ .get(`/v2/kba/${envelope_id}/${encodeURIComponent(role_name)}`)
2149
2650
  .then((r) => r.data);
2150
2651
  /**
2151
- * Rotate the secret for an API key. The caller must have admin access to the organization.
2152
- *
2153
- * ```typescript
2154
- * import {rotateApiKey} from '@verdocs/js-sdk';
2155
- *
2156
- * const {client_secret: newSecret} = await rotateApiKey(ORGID, CLIENTID);
2157
- * ```
2158
- *
2159
- * @group API Keys
2160
- * @api POST /v2/api-keys/:client_id/rotate Rotate API key
2161
- * @apiParam string(format:uuid) client_id The client ID of the key to rotate
2162
- * @apiSuccess IApiKey . The updated API key with its new secret.
2652
+ * Submit a response to a KBA PIN challenge.
2163
2653
  */
2164
- const rotateApiKey = (endpoint, clientId) => endpoint.api //
2165
- .post(`/v2/api-keys/${clientId}/rotate`)
2654
+ const submitKbaPin = (endpoint, envelope_id, role_name, pin) => endpoint.api //
2655
+ .post(`/v2/kba/pin`, { envelope_id, role_name, pin })
2166
2656
  .then((r) => r.data);
2167
2657
  /**
2168
- * Update an API key to change its assigned Profile ID or Name.
2169
- *
2170
- * ```typescript
2171
- * import {updateApiKey} from '@verdocs/js-sdk';
2172
- *
2173
- * await updateApiKey(ORGID, CLIENTID, {name: NEWNAME});
2174
- * ```
2175
- *
2176
- * @group API Keys
2177
- * @api PATCH /v2/api-keys/:client_id Update API key
2178
- * @apiBody string name? New name for the API key
2179
- * @apiBody array(items:string) permission New array of permissions to assign to the new key. Extends (but does not override) the API key's profile permissions.
2180
- * @apiSuccess IApiKey . The updated API key. The secret will not be included.
2658
+ * Submit an identity response to a KBA challenge.
2181
2659
  */
2182
- const updateApiKey = (endpoint, clientId, params) => endpoint.api //
2183
- .patch(`/v2/api-keys/${clientId}`, params)
2660
+ const submitKbaIdentity = (endpoint, envelope_id, role_name, identity) => endpoint.api //
2661
+ .post(`/v2/kba/identity`, { envelope_id, role_name, identity })
2184
2662
  .then((r) => r.data);
2185
2663
  /**
2186
- * Delete an API key.
2187
- *
2188
- * ```typescript
2189
- * import {deleteApiKey} from '@verdocs/js-sdk';
2190
- *
2191
- * await deleteApiKey(ORGID, CLIENTID);
2192
- * ```
2193
- *
2194
- * @group API Keys
2195
- * @api DELETE /v2/api-keys/:client_id Delete API key
2196
- * @apiSuccess string . Success.
2664
+ * Submit an identity response to a KBA challenge. Answers should be submitted in the same order as
2665
+ * the challenges were listed in `IRecipientKbaStepChallenge.questions`.
2197
2666
  */
2198
- const deleteApiKey = (endpoint, clientId) => endpoint.api //
2199
- .delete(`/v2/api-keys/${clientId}`)
2667
+ const submitKbaChallengeResponse = (endpoint, envelope_id, role_name, responses) => endpoint.api //
2668
+ .post(`/v2/kba/response`, { envelope_id, role_name, responses })
2200
2669
  .then((r) => r.data);
2201
2670
 
2202
2671
  /**
2203
- * An Organization Contact (aka Profile) is an individual user with no access to an organization. These entries
2204
- * appear only in contact lists, usually to populate quick-search dropdowns when sending envelopes.
2672
+ * Agree to electronic signing dislosures.
2205
2673
  *
2206
- * @module
2674
+ * @group Recipients
2675
+ * @api POST /envelopes/:envelope_id/recipients/:role_name/agree Agree to e-Signing Disclosures
2676
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2677
+ * @apiParam string role_name The role to operate on.
2678
+ * @apiSuccess IRecipient . The updated Recipient.
2207
2679
  */
2680
+ const envelopeRecipientAgree = (endpoint, envelopeId, roleName, disclosures) => endpoint.api //
2681
+ .post(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/agree`, { disclosures })
2682
+ .then((r) => r.data);
2208
2683
  /**
2209
- * Get a list of the contacts in the caller's organization.
2210
- *
2211
- * ```typescript
2212
- * import {getOrganizationContacts} from '@verdocs/js-sdk';
2213
- *
2214
- * const members = await getOrganizationContacts(VerdocsEndpoint.getDefault()});
2215
- * ```
2684
+ * Decline electronic signing dislosures. Note that if any recipient declines, the entire envelope
2685
+ * becomes non-viable and later recipients may no longer act. The creator will receive a notification
2686
+ * when this occurs.
2216
2687
  *
2217
- * @group Organization Contacts
2218
- * @api GET /v2/organization-contacts Get a list of organization contacts
2219
- * @apiBody string email Email address for the invitee
2220
- * @apiBody string token Invite token for the invitee
2221
- * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
2688
+ * @group Recipients
2689
+ * @api POST /envelopes/:envelope_id/recipients/:role_name/decline Decline e-Signing Disclosures
2690
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2691
+ * @apiParam string role_name The role to adjust.
2692
+ * @apiSuccess IRecipient . The updated Recipient.
2222
2693
  */
2223
- const getOrganizationContacts = (endpoint) => endpoint.api //
2224
- .get(`/v2/organization-contacts`)
2694
+ const envelopeRecipientDecline = (endpoint, envelopeId, roleName) => endpoint.api //
2695
+ .post(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}/decline`)
2225
2696
  .then((r) => r.data);
2226
2697
  /**
2227
- * Delete a contact from the caller's organization. Note that the caller must be an admin or owner.
2228
- *
2229
- * ```typescript
2230
- * import {deleteOrganizationContact} from '@verdocs/js-sdk';
2231
- *
2232
- * await deleteOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID'});
2233
- * ```
2698
+ * Submit an envelope (signing is finished). Note that all fields must be valid/completed for this to succeed.
2234
2699
  *
2235
- * @group Organization Contacts
2236
- * @api POST /v2/organization-invitations/decline GET a list of pending invitations
2237
- * @apiBody string email Email address for the invitee
2238
- * @apiBody string token Invite token for the invitee
2239
- * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
2700
+ * @group Recipients
2701
+ * @api POST /envelopes/:envelope_id/recipients/:role_name/submit Submit envelope
2702
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2703
+ * @apiParam string role_name The role to submit.
2704
+ * @apiSuccess IRecipient . The updated Recipient.
2240
2705
  */
2241
- const deleteOrganizationContact = (endpoint, profileId) => endpoint.api //
2242
- .delete(`/v2/organization-contacts/${profileId}`)
2706
+ const envelopeRecipientSubmit = (endpoint, envelopeId, roleName) => endpoint.api //
2707
+ .post(`/v2/envelopes/${envelopeId}/recipients/${roleName}/submit`)
2243
2708
  .then((r) => r.data);
2244
2709
  /**
2245
- * Update a member.
2246
- *
2247
- * ```typescript
2248
- * import {createOrganizationContact} from '@verdocs/js-sdk';
2710
+ * Begin a signing session for an Envelope. This path requires an invite code, and should generally
2711
+ * be called with a NON-default Endpoint to avoid conflicting with any active user session the user
2712
+ * may have. To initiate in-person signing by an authenticated user (e.g. self-signing), call
2713
+ * getInPersonLink() instead. The response from that call includes both a link for direct signing
2714
+ * via a Web browser as well as an in-person access_key. That access_key.key may be used here as well.
2249
2715
  *
2250
- * const result = await createOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID', {first_name:'First', last_name:'Last', email:'a@b.com'});
2251
- * ```
2716
+ * @group Recipients
2717
+ * @api POST /v2/sign/unauth/:envelope_id/:role_name/:key Start Signing Session
2718
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2719
+ * @apiParam string role_name The role to request.
2720
+ * @apiParam string key Access key generated by the envelope creator or email/SMS invite.
2721
+ * @apiSuccess ISignerTokenResponse . Signing session token and envelope/recipient metadata.
2252
2722
  */
2253
- const createOrganizationContact = (endpoint, params) => endpoint.api //
2254
- .post(`/v2/organization-contacts`, params)
2255
- .then((r) => r.data);
2723
+ const startSigningSession = async (endpoint, envelope_id, role_name, key) => {
2724
+ return endpoint.api //
2725
+ .post(`/v2/sign/unauth/${envelope_id}/${encodeURIComponent(role_name)}/${key}`)
2726
+ .then((r) => {
2727
+ endpoint.setToken(r.data.access_token, 'signing');
2728
+ return r.data;
2729
+ });
2730
+ };
2256
2731
  /**
2257
- * Update a member.
2258
- *
2259
- * ```typescript
2260
- * import {updateOrganizationContact} from '@verdocs/js-sdk';
2732
+ * Get an in-person signing link. Must be called by the owner/creator of the envelope. The response
2733
+ * also includes the raw access key that may be used to directly initiate a signing session (see
2734
+ * `startSigningSession`) as well as an access token representing a valid signing session for
2735
+ * immediate use in embeds or other applications. Note that in-person signing is considered a
2736
+ * lower-security operation than authenticated signing, and the final envelope certificate will
2737
+ * reflect this.
2261
2738
  *
2262
- * const result = await updateOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID', {first_name:'NewFirst'});
2263
- * ```
2739
+ * @group Recipients
2740
+ * @api POST /v2/sign/in-person/:envelope_id/:role_name Get In-Person Signing Link
2741
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2742
+ * @apiParam string role_name The role to request.
2743
+ * @apiSuccess IInPersonLinkResponse . Signing session token and envelope/recipient metadata.
2264
2744
  */
2265
- const updateOrganizationContact = (endpoint, profileId, params) => endpoint.api //
2266
- .patch(`/v2/organization-contacts/${profileId}`, params)
2745
+ const getInPersonLink = (endpoint, envelope_id, role_name) => endpoint.api //
2746
+ .post(`/v2/sign/in-person/${envelope_id}/${encodeURIComponent(role_name)}`)
2267
2747
  .then((r) => r.data);
2268
-
2269
2748
  /**
2270
- * Organizations may contain "Groups" of user profiles, called Members. Groups may have permissions assigned that
2271
- * apply to all Members, making it easy to configure role-based access control (RBAC) within an Organization. Note
2272
- * that permissions are **additive**. A user may be a member of more than one group, and may also have permissions
2273
- * assigned directly. In that case, the user will have the combined set of all permissions inherited from all
2274
- * sources.
2749
+ * Verify a recipient within a signing session. All signing sessions use an invite code at a minimum,
2750
+ * but many scenarios require more robust verification of recipients, so one or more verification
2751
+ * methods may be attached to each recipient. If an authentication method is enabled, the
2752
+ * signer must first accept the e-signature disclosures, then complete each verification step
2753
+ * before attempting to view/display documents, complete any fields, or submit the envelope.
2754
+ * This endpoint should be called to complete each step. If the call fails an error will be
2755
+ * thrown.
2275
2756
  *
2276
- * @module
2757
+ * @group Recipients
2758
+ * @api POST /v2/sign/verify Verify recipient/signer
2759
+ * @apiParam string(enum:'passcode'|'email'|'sms'|'kba'|'id') auth_method The authentication method being completed
2760
+ * @apiParam string code? The passcode or OTP entered. Required for passcode, email, and SMS methods.
2761
+ * @apiParam boolean resend? For SMS or email methods, set to send a new code.
2762
+ * @apiParam boolean first_name? For KBA, the recipient's first name
2763
+ * @apiParam boolean last_name? For KBA, the recipient's last name
2764
+ * @apiParam boolean address? For KBA, the recipient's address
2765
+ * @apiParam boolean city? For KBA, the recipient's city
2766
+ * @apiParam boolean state? For KBA, the recipient's state
2767
+ * @apiParam boolean zip? For KBA, the recipient's zip code
2768
+ * @apiParam boolean ssn_last_4? For KBA, the last 4 digits of the recipient's SSN
2769
+ * @apiParam boolean dob? For KBA, the recipient's date of birth
2770
+ * @apiParam array(items:IKBAResponse) responses? For KBA, responses to any challenge questions presented
2771
+ * @apiSuccess ISignerTokenResponse . Updated signing session.
2277
2772
  */
2773
+ const verifySigner = (endpoint, params) => endpoint.api //
2774
+ .post(`/v2/sign/verify`, params)
2775
+ .then((r) => r.data);
2278
2776
  /**
2279
- * Get a list of groups for the caller's organization. NOTE: Any organization member may request
2280
- * the list of groups, but only Owners and Admins may update them.
2281
- *
2282
- * ```typescript
2283
- * import {getGroups} from '@verdocs/js-sdk';
2777
+ * Delegate a recipient's signing responsibility. The envelope sender must enable this before the
2778
+ * recipient calls this endpoint, and only the recipient may call it, or the call will be rejected.
2779
+ * The recipient's role will be renamed and configured to indicate to whom the delegation was made,
2780
+ * and a new recipient entry with the updated details (e.g. name and email address) will be added
2781
+ * to the flow with the same role_name, order, and sequence of the original recipient. Unless
2782
+ * no_contact is set on the envelope, the delegation recipient and envelope creator will also be
2783
+ * notified.
2284
2784
  *
2285
- * const groups = await getGroups();
2286
- * ```
2785
+ * @group Recipients
2786
+ * @api PUT /v2/envelopes/:envelope_id/recipients/:role_name Delegate Recipient
2787
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2788
+ * @apiParam string role_name The role to operate on.
2789
+ * @apiBody string(enum:'delegate') action The operation to perform (delegate).
2790
+ * @apiBody string first_name The first name of the new recipient.
2791
+ * @apiBody string last_name The last name of the new recipient.
2792
+ * @apiBody string email The email address of the new recipient.
2793
+ * @apiBody string phone? Optional phone number for the new recipient.
2794
+ * @apiBody string message? Optional phone number for the new recipient's invitation.
2795
+ * @apiSuccess string . Success message.
2287
2796
  */
2288
- const getGroups = (endpoint) => endpoint.api //
2289
- .get(`/v2/organization-groups`)
2797
+ const delegateRecipient = (endpoint, envelopeId, roleName, params) => endpoint.api //
2798
+ .put(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'delegate', ...params })
2290
2799
  .then((r) => r.data);
2291
2800
  /**
2292
- * Get the details for a group, including its member profiles and list of permissions.
2293
- *
2294
- * ```typescript
2295
- * import {getGroup} from '@verdocs/js-sdk/v2/organization-groups';
2801
+ * Update a recipient. NOTE: User interfaces should rate-limit this operation to avoid spamming recipients.
2802
+ * Excessive use of this endpoint may result in Verdocs rate-limiting the calling application to prevent
2803
+ * abuse. This endpoint will return a 200 OK even if the no_contact flag is set on the envelope (in which
2804
+ * case the call will be silently ignored).
2296
2805
  *
2297
- * const group = await getGroup(GROUPID);
2298
- * ```
2806
+ * @group Recipients
2807
+ * @api PATCH /envelopes/:envelope_id/recipients/:role_name Update Recipient
2808
+ * @apiParam string(format:uuid) envelope_id The envelope to operate on.
2809
+ * @apiParam string role_name The role name to update.
2810
+ * @apiBody string(enum:'remind'|'reset') action? Trigger a reminder, or fully reset the recipient
2811
+ * @apiBody string first_name? Update the recipient's first name.
2812
+ * @apiBody string last_name? Update the recipient's last name.
2813
+ * @apiBody string email? Update the recipient's email address.
2814
+ * @apiBody string message? Update the recipient's invite message.
2815
+ * @apiBody string phone? Update the recipient's phone number.
2816
+ * @apiBody string passcode? If passcode authentication is used, the recipient's address to prefill. May only be changed if the recipient has not already completed passcode-based auth.
2817
+ * @apiBody string address? If KBA-based authentication is used, the recipient's address to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2818
+ * @apiBody string city? If KBA-based authentication is used, the recipient's city to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2819
+ * @apiBody string state? If KBA-based authentication is used, the recipient's state to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2820
+ * @apiBody string zip? If KBA-based authentication is used, the recipient's zip code to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2821
+ * @apiBody string dob? If KBA-based authentication is used, the recipient's date of birth to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2822
+ * @apiBody string ssn_last_4? If KBA-based authentication is used, the recipient's SSN-last-4 to prefill. May only be changed if the recipient has not already completed KBA-based auth.
2823
+ * @apiSuccess IRecipient . The updated Recipient.
2299
2824
  */
2300
- const getGroup = (endpoint, groupId) => endpoint.api //
2301
- .get(`/v2/organization-groups/${groupId}`)
2825
+ const updateRecipient = (endpoint, envelopeId, roleName, params) => endpoint.api //
2826
+ .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, params)
2302
2827
  .then((r) => r.data);
2303
2828
  /**
2304
- * Create a group. Note that "everyone" is a reserved name and may not be created.
2305
- *
2306
- * ```typescript
2307
- * import {createGroup} from '@verdocs/js-sdk';
2308
- *
2309
- * const group = await createGroup(VerdocsEndpoint.getDefault(), {name:'newgroup'});
2310
- * ```
2829
+ * Send a reminder to a recipient. The recipient must still be an active member of the signing flow
2830
+ * (e.g. not declined, already submitted, etc.)
2311
2831
  */
2312
- const createGroup = (endpoint, params) => endpoint.api //
2313
- .post('/v2/organization-groups', params)
2832
+ const remindRecipient = (endpoint, envelopeId, roleName) => endpoint.api //
2833
+ .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'remind' })
2314
2834
  .then((r) => r.data);
2315
2835
  /**
2316
- * Update a group. Note that "everyone" is a reserved name and may not be changed.
2317
- *
2318
- * ```typescript
2319
- * import {updateGroup} from '@verdocs/js-sdk';
2320
- *
2321
- * const updated = await updateGroup(VerdocsEndpoint.getDefault(), {name:'newname'});
2322
- * ```
2836
+ * Fully reset a recipient. This allows the recipient to restart failed KBA flows, change
2837
+ * fields they may have filled in incorrectly while signing, etc. This cannot be used on a
2838
+ * canceled or completed envelope, but may be used to restart an envelope marked declined.
2323
2839
  */
2324
- const updateGroup = (endpoint, groupId, params) => endpoint.api //
2325
- .patch(`/v2/organization-groups/${groupId}`, params)
2840
+ const resetRecipient = (endpoint, envelopeId, roleName) => endpoint.api //
2841
+ .patch(`/v2/envelopes/${envelopeId}/recipients/${encodeURIComponent(roleName)}`, { action: 'reset' })
2326
2842
  .then((r) => r.data);
2843
+
2327
2844
  /**
2328
- * Get an organization by ID. Note that the "everyone" group cannot be deleted.
2329
- *
2330
- * ```typescript
2331
- * import {deleteGroup} from '@verdocs/js-sdk';
2845
+ * Various helpers to identify available operations for an envelope by a user.
2332
2846
  *
2333
- * await deleteGroup(VerdocsEndpoint.getDefault(), 'ORGID');
2334
- * ```
2847
+ * @module
2335
2848
  */
2336
- const deleteGroup = (endpoint, groupId) => endpoint.api //
2337
- .delete(`/v2/organization-groups/${groupId}`)
2338
- .then((r) => r.data);
2339
2849
  /**
2340
- * Add a member to a group.
2341
- *
2342
- * ```typescript
2343
- * import {addGroupMember} from '@verdocs/js-sdk';
2344
- *
2345
- * await addGroupMember(VerdocsEndpoint.getDefault(), 'GROUPID', 'PROFILEID');
2346
- * ```
2850
+ * Check to see if the profile ID owns the envelope.
2347
2851
  */
2348
- const addGroupMember = (endpoint, groupId, profile_id) => endpoint.api //
2349
- .post(`/v2/organization-groups/${groupId}/members`, { profile_id })
2350
- .then((r) => r.data);
2852
+ const isEnvelopeOwner = (profile_id, envelope) => envelope.profile_id === profile_id;
2351
2853
  /**
2352
- * Remove a member from a group.
2353
- *
2354
- * ```typescript
2355
- * import {deleteGroupMember} from '@verdocs/js-sdk';
2356
- *
2357
- * await deleteGroupMember(VerdocsEndpoint.getDefault(), 'GROUPID', 'PROFILEID');
2358
- * ```
2854
+ * Check to see if the profile ID is a recipient within the envelope.
2359
2855
  */
2360
- const deleteGroupMember = (endpoint, groupId, profile_id) => endpoint.api //
2361
- .delete(`/v2/organization-groups/${groupId}/members/${profile_id}`)
2362
- .then((r) => r.data);
2363
-
2856
+ const isEnvelopeRecipient = (profile_id, envelope) => (envelope.recipients || []).some((recipient) => recipient.profile_id === profile_id);
2364
2857
  /**
2365
- * An invitation represents an opportunity for a Member to join an Organization.
2366
- *
2367
- * @module
2858
+ * Check to see if the profile ID is the envelope's sender or one of the recipients.
2368
2859
  */
2860
+ const canAccessEnvelope = (profile_id, envelope) => isEnvelopeOwner(profile_id, envelope) || isEnvelopeRecipient(profile_id, envelope);
2369
2861
  /**
2370
- * Get a list of invitations pending for the caller's organization. The caller must be an admin or owner.
2371
- *
2372
- * @group Organization Invitations
2373
- * @api GET /v2/organization-invitations Get a list of pending invitations
2374
- * @apiBody array(items:TRole) roles URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
2375
- * @apiBody string first_name First name. The user may override this after accepting the invitation.
2376
- * @apiBody string last_name Last name. The user may override this after accepting the invitation.
2377
- * @apiSuccess array(items:IProfile) . List of caller's current organization's members
2862
+ * Check to see if the user owns the envelope.
2378
2863
  */
2379
- const getOrganizationInvitations = (endpoint) => endpoint.api //
2380
- .get(`/v2/organization-invitations`)
2381
- .then((r) => r.data);
2864
+ const userIsEnvelopeOwner = (profile, envelope) => envelope.profile_id === profile?.id;
2382
2865
  /**
2383
- * Invite a new user to join the organization.
2384
- *
2385
- * @group Organization Invitations
2386
- * @api POST /v2/organization-invitations Invite a new user to join the organization
2387
- * @apiBody string email Email address to send the invitation to
2388
- * @apiBody string first_name First name. The user may override this after accepting the invitation.
2389
- * @apiBody string last_name Last name. The user may override this after accepting the invitation.
2390
- * @apiBody TRole role Initial role to assign to the user once they accept.
2391
- * @apiSuccess IOrganizationInvitation . The newly-created invitation.
2866
+ * Check to see if the user is a recipient within the envelope.
2392
2867
  */
2393
- const createOrganizationInvitation = (endpoint, params) => endpoint.api //
2394
- .post(`/v2/organization-invitations`, params)
2395
- .then((r) => r.data);
2868
+ const userIsEnvelopeRecipient = (profile, envelope) => (envelope.recipients || []).some((recipient) => recipient.profile_id === profile?.id);
2396
2869
  /**
2397
- * Delete an invitation. Note that no cancellation message will be sent. Invitations are also one-time-use.
2398
- * If the invitee attempts to join after the invitation is deleted, accepted, or decline, they will be
2399
- * shown an error.
2400
- *
2401
- * @group Organization Invitations
2402
- * @api DELETE /v2/organization-invitations/:email Delete a pending invitation
2403
- * @apiSuccess string . Success
2870
+ * Check to see if the profile ID is the envelope's sender or one of the recipients.
2404
2871
  */
2405
- const deleteOrganizationInvitation = (endpoint, email) => endpoint.api //
2406
- .delete(`/v2/organization-invitations/${email}`)
2407
- .then((r) => r.data);
2872
+ const useCanAccessEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) || userIsEnvelopeRecipient(profile, envelope);
2408
2873
  /**
2409
- * Update an invitation. Note that email may not be changed after the invite is sent. To change
2410
- * an invitee's email, delete the incorrect entry and create one with the correct value.
2411
- *
2412
- * @group Organization Invitations
2413
- * @api PATCH /v2/organization-invitations/:email Update a pending invitation
2414
- * @apiBody string first_name First name. The user may override this after accepting the invitation.
2415
- * @apiBody string last_name Last name. The user may override this after accepting the invitation.
2416
- * @apiBody TRole role Initial role to assign to the user once they accept.
2417
- * @apiSuccess IOrganizationInvitation . The updated invitation.
2874
+ * Check to see if the envelope has pending actions.
2418
2875
  */
2419
- const updateOrganizationInvitation = (endpoint, email, params) => endpoint.api //
2420
- .patch(`/v2/organization-invitations/${email}`, params)
2421
- .then((r) => r.data);
2876
+ const envelopeIsActive = (envelope) => envelope.status !== 'complete' && envelope.status !== 'declined' && envelope.status !== 'canceled';
2422
2877
  /**
2423
- * Send a reminder to the invitee to join the organization.
2424
- *
2425
- * @group Organization Invitations
2426
- * @api POST /v2/organization-invitations/resend Send a reminder to a pending invitee
2427
- * @apiBody string email The recipient to send the reminder to
2428
- * @apiSuccess IOrganizationInvitation . The updated invitation
2878
+ * Check to see if the envelope has been completed.
2429
2879
  */
2430
- const resendOrganizationInvitation = (endpoint, email) => endpoint.api //
2431
- .post('/v2/organization-invitations/resend', { email })
2432
- .then((r) => r.data);
2880
+ const envelopeIsComplete = (envelope) => envelope.status !== 'complete';
2433
2881
  /**
2434
- * Get an invitation's details. This is generally used as the first step of accepting the invite.
2435
- * A successful response will indicate that the invite token is still valid, and include some
2436
- * metadata for the organization to style the acceptance screen.
2437
- *
2438
- * @group Organization Invitations
2439
- * @api GET /v2/organization-invitations/:email/:token Get a pending invitation (_Authenticated via invite token, not an active session._). Intended to be called by the invitee to get details about the invitation they are about to accept.
2440
- * @apiSuccess IOrganizationInvitation . Requested invitation's details. Will always include summary details for the organization, to be used for branding the accept-invite view.
2882
+ * Check to see if the user owns the envelope.
2441
2883
  */
2442
- const getOrganizationInvitation = (endpoint, email, token) => endpoint.api //
2443
- .get(`/v2/organization-invitations/${email}/${token}`)
2444
- .then((r) => r.data);
2884
+ const userCanCancelEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) &&
2885
+ envelope.status !== 'complete' &&
2886
+ envelope.status !== 'declined' &&
2887
+ envelope.status !== 'canceled';
2445
2888
  /**
2446
- * Accept an invitation. This will automatically create a user record for the caller as well as a profile
2447
- * with the appropriate role as specified in the invite. The profile will be set as "current" for the caller,
2448
- * and session tokens will be returned to access the new profile. The profile's email_verified flag will
2449
- * also be set to true.
2450
- *
2451
- * @group Organization Invitations
2452
- * @api POST /v2/organization-invitations/accept Accept an invitation
2453
- * @apiBody string email Email address for the invitee
2454
- * @apiBody string token Invite token for the invitee
2455
- * @apiBody string first_name First name
2456
- * @apiBody string last_name Last name
2457
- * @apiBody string password Password
2458
- * @apiSuccess IAuthenticateResponse . Session credentials for the newly-created user's profile. If the user already had a profile for another organization, the new profile will be made "current" automatically.
2889
+ * Check to see if the user owns the envelope.
2459
2890
  */
2460
- const acceptOrganizationInvitation = (endpoint, params) => endpoint.api //
2461
- .post('/v2/organization-invitations/accept', params)
2462
- .then((r) => r.data);
2891
+ const userCanFinishEnvelope = (profile, envelope) => userIsEnvelopeOwner(profile, envelope) &&
2892
+ envelope.status !== 'complete' &&
2893
+ envelope.status !== 'declined' &&
2894
+ envelope.status !== 'canceled';
2463
2895
  /**
2464
- * Decline an invitation. This will mark the status "declined," providing a visual indication to the
2465
- * organization's admins that the invite was declined, preventing further invites from being created
2466
- * to the same email address, and also preventing the invitee from receiving reminders to join.
2467
- *
2468
- * @group Organization Invitations
2469
- * @api POST /v2/organization-invitations/decline Decline an invitation
2470
- * @apiDescription Mark the status "declined," providing a visual indication to the organization's admins that the invite was declined, preventing further invites from being created to the same email address, and also preventing the invitee from receiving reminders to join.
2471
- * @apiBody string email Email address for the invitee
2472
- * @apiBody string token Invite token for the invitee
2473
- * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
2896
+ * Returns true if the recipient has a pending action. Note that this does not necessarily mean the recipient can act (yet).
2474
2897
  */
2475
- const declineOrganizationInvitation = (endpoint, email, token) => endpoint.api //
2476
- .post('/v2/organization-invitations/decline', { email, token })
2477
- .then((r) => r.data);
2478
-
2898
+ const recipientHasAction = (recipient) => !['submitted', 'canceled', 'declined'].includes(recipient.status);
2479
2899
  /**
2480
- * An Organization Member (aka Profile) is an individual user with access to an organization.
2481
- *
2482
- * @module
2900
+ * Returns the recipients who still have a pending action. Note that not all of these recipients may be able to act (yet).
2483
2901
  */
2902
+ const getRecipientsWithActions = (envelope) => ['complete', 'declined', 'canceled'].includes(envelope.status) ? [] : (envelope?.recipients || []).filter(recipientHasAction);
2484
2903
  /**
2485
- * Get a list of the members in the caller's organization.
2486
- *
2487
- * ```typescript
2488
- * import {getOrganizationMembers} from '@verdocs/js-sdk';
2489
- *
2490
- * const members = await getOrganizationMembers(VerdocsEndpoint.getDefault()});
2491
- * ```
2492
- *
2493
- * @group Organization Members
2494
- * @api GET /v2/organization-members List current organization's members
2495
- * @apiSuccess array(items:IProfile) . List of caller's current organization's members
2904
+ * Returns true if the recipient can act.
2496
2905
  */
2497
- const getOrganizationMembers = (endpoint) => endpoint.api //
2498
- .get(`/v2/organization-members`)
2499
- .then((r) => r.data);
2906
+ const recipientCanAct = (recipient, recipientsWithActions) => recipient.sequence === recipientsWithActions?.[0]?.sequence;
2500
2907
  /**
2501
- * Delete a member from the caller's organization. Note that the caller must be an admin or owner,
2502
- * may not delete him/herself.
2503
- *
2504
- * ```typescript
2505
- * import {deleteOrganizationMember} from '@verdocs/js-sdk';
2506
- *
2507
- * await deleteOrganizationMember(VerdocsEndpoint.getDefault(), 'PROFILEID'});
2508
- * ```
2509
- *
2510
- * @group Organization Members
2511
- * @api DELETE /v2/organization-members/:profile_id Delete a member from the organization
2512
- * @apiSuccess string . Success
2908
+ * Returns true if the user can act.
2513
2909
  */
2514
- const deleteOrganizationMember = (endpoint, profileId) => endpoint.api //
2515
- .delete(`/v2/organization-members/${profileId}`)
2516
- .then((r) => r.data);
2910
+ const userCanAct = (email, recipientsWithActions) => {
2911
+ const recipient = recipientsWithActions.find((r) => r.email === email);
2912
+ return recipient && recipient.sequence === recipientsWithActions?.[0]?.sequence;
2913
+ };
2517
2914
  /**
2518
- * Update a member.
2519
- *
2520
- * ```typescript
2521
- * import {updateOrganizationMember} from '@verdocs/js-sdk';
2915
+ * Returns true if the user can act.
2916
+ */
2917
+ const userCanSignNow = (profile, envelope) => {
2918
+ if (!profile) {
2919
+ return false;
2920
+ }
2921
+ const recipientsWithActions = getRecipientsWithActions(envelope);
2922
+ const myRecipient = recipientsWithActions.find((r) => r.profile_id === profile?.id || r.email === profile?.email);
2923
+ return (myRecipient &&
2924
+ envelopeIsActive(envelope) &&
2925
+ userIsEnvelopeRecipient(profile, envelope) &&
2926
+ recipientCanAct(myRecipient, recipientsWithActions));
2927
+ };
2928
+ const getNextRecipient = (envelope) => {
2929
+ const recipientsWithActions = getRecipientsWithActions(envelope);
2930
+ return recipientsWithActions?.[0];
2931
+ };
2932
+
2933
+ /**
2934
+ * Create a signature block. In a typical signing workflow, the user is asked at the beginning of the process to
2935
+ * "adopt" a signature block to be used for all signature fields in the document. Thus, this is typically called one
2936
+ * time to create and store a signature block. Thereafter, the ID of the signature block may be re-used for each
2937
+ * signature field to be "stamped" by the user.
2522
2938
  *
2523
- * const result = await updateOrganizationMember(VerdocsEndpoint.getDefault(), 'PROFILEID', {roles:['member']});
2524
- * ```
2939
+ * Note: Both "guest" signers and authenticated users can create initials blocks. Guest signers
2940
+ * typically only ever have one, tied to that session. But authenticated users can create more than
2941
+ * one, and can use them interchangeably.
2525
2942
  *
2526
- * @group Organization Members
2527
- * @api PATCH /v2/organization-members/:profile_id Update an organization member.
2528
- * @apiBody array(items:TRole) roles URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
2529
- * @apiBody string first_name Set to true to enable Webhooks calls.
2530
- * @apiBody string last_name Record<TWebhookEvent, boolean> map of events to enable/disable.
2531
- * @apiSuccess array(items:IProfile) . List of caller's current organization's members
2943
+ * @group Signatures and Initials
2944
+ * @api POST /v2/profiles/signatures Create Signature Block
2945
+ * @apiBody string signature Blob containing signature image to store.
2946
+ * @apiSuccess ISignature . The newly-created signature block.
2532
2947
  */
2533
- const updateOrganizationMember = (endpoint, profileId, params) => endpoint.api //
2534
- .patch(`/v2/organization-members/${profileId}`, params)
2535
- .then((r) => r.data);
2948
+ const createSignature = (endpoint, name, signature) => {
2949
+ const data = new FormData();
2950
+ data.append('signature', signature, name);
2951
+ return endpoint.api //
2952
+ .post(`/v2/profiles/signatures`, data)
2953
+ .then((r) => r.data);
2954
+ };
2536
2955
 
2537
2956
  /**
2538
- * An Organization is the top level object for ownership for Members, Documents, and Templates.
2539
- *
2540
- * NOTE: There is no call specifically to create an organization. Every organization must have
2541
- * at least one "owner" type member. To create a new organization, call createProfile() with
2542
- * the desired new orgName to create. The caller will become the first owner of the new org, and
2543
- * can then invite new members to join as well.
2957
+ * These disclosures will be used if no overrides are supplied by the caller. Overrides must
2958
+ * be applied at the Organization level before creating an envelope.
2959
+ */
2960
+ const DEFAULT_DISCLOSURES = `
2961
+ <ul>
2962
+ <li>
2963
+ Agree to use electronic records and signatures, and confirm you have read the
2964
+ <a href="https://verdocs.com/en/electronic-record-signature-disclosure/" target="_blank">
2965
+ Electronic Record and Signatures Disclosure</a>.</li>
2966
+ <li>
2967
+ Agree to Verdocs'
2968
+ <a href="https://verdocs.com/en/eula" target="_blank">
2969
+ End User License Agreement</a>
2970
+ and confirm you have read Verdocs'
2971
+ <a href="https://verdocs.com/en/privacy-policy/" target="_blank">
2972
+ Privacy Policy</a>.
2973
+ </li>
2974
+ </ul>`;
2975
+
2976
+ /**
2977
+ * API keys are used to authenticate server-to-server calls. (API keys should **never** be used for client-to-server operations!)
2978
+ * To generate a key, either use the Verdocs admin interface and make note of the client_id and client_secret generated, or call
2979
+ * createKey as shown below. Then call {@link Users.Auth.authenticateApp} to obtain an access token using the provided ID and
2980
+ * secret. Note that server-to-server authentication requests return shorter-lived tokens, so it is important to check the `exp`
2981
+ * field and re-authenticate as needed for subsequent calls.
2544
2982
  *
2545
- * NOTE: There is no call to delete an organization. For safety, this is a manual process. Please
2546
- * contact support@verdocs.com if you wish to completely delete an organization and all its records.
2983
+ * API keys may be updated or rotated at any time. Regular rotation is recommended. Rotation will not expire or invalidate
2984
+ * existing server-to-server sessions, so it may be done at any time without disrupting your application.
2547
2985
  *
2548
2986
  * @module
2549
2987
  */
2550
2988
  /**
2551
- * Get an organization by ID. Note that this endpoint will return only a subset of fields
2552
- * if the caller is not a member of the organization (the public fields).
2989
+ * Get a list of keys for a given organization. The caller must have admin access to the organization.
2553
2990
  *
2554
2991
  * ```typescript
2555
- * import {getOrganization} from '@verdocs/js-sdk';
2992
+ * import {getApiKeys} from '@verdocs/js-sdk';
2556
2993
  *
2557
- * const organizations = await getOrganization(VerdocsEndpoint.getDefault(), 'ORGID');
2994
+ * const keys = await getApiKeys(ORGID);
2558
2995
  * ```
2559
2996
  *
2560
- * @group Organizations
2561
- * @api GET /v2/organizations/:organization_id Get organization
2562
- * @apiSuccess IOrganization . The requested organization. The caller must be a member.
2997
+ * @group API Keys
2998
+ * @api GET /v2/api-keys Get API keys
2999
+ * @apiSuccess array(items: IApiKey) . A list of the API keys for the caller's organization. Secrets will not be included.
2563
3000
  */
2564
- const getOrganization = (endpoint, organizationId) => endpoint.api //
2565
- .get(`/v2/organizations/${organizationId}`)
3001
+ const getApiKeys = (endpoint) => endpoint.api //
3002
+ .get(`/v2/api-keys`)
2566
3003
  .then((r) => r.data);
2567
3004
  /**
2568
- * Get an organization's "children".
3005
+ * Create an API key.
2569
3006
  *
2570
3007
  * ```typescript
2571
- * import {getOrganizationChildren} from '@verdocs/js-sdk';
3008
+ * import {createApiKey} from '@verdocs/js-sdk';
2572
3009
  *
2573
- * const children = await getOrganizationChildren(VerdocsEndpoint.getDefault(), 'ORGID');
3010
+ * await createApiKey(ORGID, {name: NEWNAME});
2574
3011
  * ```
2575
3012
  *
2576
- * @group Organizations
2577
- * @api GET /v2/organizations/:organization_id/children Get an organization's children
2578
- * @apiSuccess IOrganization[] . Any child organizations found.
3013
+ * @group API Keys
3014
+ * @api POST /v2/api-keys Create API key
3015
+ * @apiBody string name A name used to identify the key in the Verdocs Web App
3016
+ * @apiBody string(format:uuid) profile_id The profile ID that calls made using the key will act as
3017
+ * @apiBody array(items:string) permission An array of permissions to assign to the new key. Extends (but does not override) the API key's profile permissions.
3018
+ * @apiSuccess IApiKey . The newly-created API key, including its secret.
2579
3019
  */
2580
- const getOrganizationChildren = (endpoint, organizationId) => endpoint.api //
2581
- .get(`/v2/organizations/${organizationId}/children`)
3020
+ const createApiKey = (endpoint, params) => endpoint.api //
3021
+ .post('/v2/api-keys', params)
2582
3022
  .then((r) => r.data);
2583
3023
  /**
2584
- * Get an organization's usage data. If the organization is a parent, usage data for children
2585
- * will be included as well. The response will be a nested object keyed by organization ID,
2586
- * with each entry being a dictionary of usageType:count entries.
3024
+ * Rotate the secret for an API key. The caller must have admin access to the organization.
2587
3025
  *
2588
3026
  * ```typescript
2589
- * import {getOrganizationUsage} from '@verdocs/js-sdk';
3027
+ * import {rotateApiKey} from '@verdocs/js-sdk';
2590
3028
  *
2591
- * const usage = await getOrganizationUsage(VerdocsEndpoint.getDefault(), 'ORGID');
3029
+ * const {client_secret: newSecret} = await rotateApiKey(ORGID, CLIENTID);
2592
3030
  * ```
2593
3031
  *
2594
- * @group Organizations
2595
- * @api GET /v2/organizations/:organization_id/usage Get an organization's usage metrics
2596
- * @apiSuccess TOrganizationUsage . Usage data grouped by organization ID
3032
+ * @group API Keys
3033
+ * @api POST /v2/api-keys/:client_id/rotate Rotate API key
3034
+ * @apiParam string(format:uuid) client_id The client ID of the key to rotate
3035
+ * @apiSuccess IApiKey . The updated API key with its new secret.
2597
3036
  */
2598
- const getOrganizationUsage = (endpoint, organizationId, params) => endpoint.api //
2599
- .get(`/v2/organizations/${organizationId}/usage`, { params })
3037
+ const rotateApiKey = (endpoint, clientId) => endpoint.api //
3038
+ .post(`/v2/api-keys/${clientId}/rotate`)
2600
3039
  .then((r) => r.data);
2601
3040
  /**
2602
- * Create an organization. The caller will be assigned an "Owner" profile in the new organization,
2603
- * and it will be set to "current" automatically. A new set of session tokens will be issued to
2604
- * the caller, and the caller should update their endpoint to use the new tokens.
3041
+ * Update an API key to change its assigned Profile ID or Name.
2605
3042
  *
2606
3043
  * ```typescript
2607
- * import {createOrganization} from '@verdocs/js-sdk';
3044
+ * import {updateApiKey} from '@verdocs/js-sdk';
2608
3045
  *
2609
- * const organization = await createOrganization(VerdocsEndpoint.getDefault(), {name: 'NewOrg'});
3046
+ * await updateApiKey(ORGID, CLIENTID, {name: NEWNAME});
2610
3047
  * ```
2611
3048
  *
2612
- * @group Organizations
2613
- * @api POST /v2/organizations Create organization
2614
- * @apiDescription The caller will be assigned an "Owner" profile in the new organization, and it will be set to "current" automatically. A new set of session tokens will be issued to the caller, and the caller should update their endpoint to use the new tokens.
2615
- * @apiBody string name The name of the new organization
2616
- * @apiBody string parent_id? If set, the new organization will be created as a child of the specified parent organization. The caller must be an admin of the parent organization.
2617
- * @apiBody string contact_email? Contact email for the new organization
2618
- * @apiBody string url? URL for the new organization
2619
- * @apiBody string full_logo_url? URL of a large-format PNG logo
2620
- * @apiBody string thumbnail_url? URL of a small-format (square is recommended) PNG logo
2621
- * @apiBody string primary_color? URL of a small-format (square is recommended) PNG logo
2622
- * @apiBody string secondary_color? URL of a small-format (square is recommended) PNG logo
2623
- * @apiSuccess IAuthenticateResponse . Authentication credentials for user in the new organization. The user will be made an Owner automatically.
3049
+ * @group API Keys
3050
+ * @api PATCH /v2/api-keys/:client_id Update API key
3051
+ * @apiBody string name? New name for the API key
3052
+ * @apiBody array(items:string) permission New array of permissions to assign to the new key. Extends (but does not override) the API key's profile permissions.
3053
+ * @apiSuccess IApiKey . The updated API key. The secret will not be included.
2624
3054
  */
2625
- const createOrganization = (endpoint, params) => endpoint.api //
2626
- .post(`/v2/organizations`, params)
3055
+ const updateApiKey = (endpoint, clientId, params) => endpoint.api //
3056
+ .patch(`/v2/api-keys/${clientId}`, params)
2627
3057
  .then((r) => r.data);
2628
3058
  /**
2629
- * Update an organization. This can only be called by an admin or owner.
3059
+ * Delete an API key.
2630
3060
  *
2631
3061
  * ```typescript
2632
- * import {updateOrganization} from '@verdocs/js-sdk';
3062
+ * import {deleteApiKey} from '@verdocs/js-sdk';
2633
3063
  *
2634
- * const organizations = await updateOrganization(VerdocsEndpoint.getDefault(), organizationId, {name:'ORGNAME'});
3064
+ * await deleteApiKey(ORGID, CLIENTID);
2635
3065
  * ```
2636
3066
  *
2637
- * @group Organizations
2638
- * @api PATCH /v2/organizations/:organization_id Update organization
2639
- * @apiBody string name The name of the new organization
2640
- * @apiBody string contact_email? Contact email for the new organization
2641
- * @apiBody string url? URL for the new organization
2642
- * @apiBody string full_logo_url? URL of a large-format PNG logo
2643
- * @apiBody string thumbnail_url? URL of a small-format (square is recommended) PNG logo
2644
- * @apiBody string primary_color? URL of a small-format (square is recommended) PNG logo
2645
- * @apiBody string secondary_color? URL of a small-format (square is recommended) PNG logo
2646
- * @apiSuccess IOrganization . The details for the updated organization
3067
+ * @group API Keys
3068
+ * @api DELETE /v2/api-keys/:client_id Delete API key
3069
+ * @apiSuccess string . Success.
2647
3070
  */
2648
- const updateOrganization = (endpoint, organizationId, params) => endpoint.api //
2649
- .patch(`/v2/organizations/${organizationId}`, params)
3071
+ const deleteApiKey = (endpoint, clientId) => endpoint.api //
3072
+ .delete(`/v2/api-keys/${clientId}`)
2650
3073
  .then((r) => r.data);
3074
+
2651
3075
  /**
2652
- * Delete an organization. This can only be called by an owner. Inclusion of the organization ID to delete
2653
- * is just a safety check. The caller may only delete the organization they have currently selected.
3076
+ * An Organization Contact (aka Profile) is an individual user with no access to an organization. These entries
3077
+ * appear only in contact lists, usually to populate quick-search dropdowns when sending envelopes.
3078
+ *
3079
+ * @module
3080
+ */
3081
+ /**
3082
+ * Get a list of the contacts in the caller's organization.
2654
3083
  *
2655
3084
  * ```typescript
2656
- * import {deleteOrganization} from '@verdocs/js-sdk';
3085
+ * import {getOrganizationContacts} from '@verdocs/js-sdk';
2657
3086
  *
2658
- * const newSession = await deleteOrganization(VerdocsEndpoint.getDefault(), organizationId);
3087
+ * const members = await getOrganizationContacts(VerdocsEndpoint.getDefault()});
2659
3088
  * ```
2660
3089
  *
2661
- * @group Organizations
2662
- * @api DELETE /v2/organizations/:organization_id Delete organization
2663
- * @apiSuccess IAuthenticateResponse . If the caller is a member of another organization, authentication credentials for the next organization available. If not, this will be null and the caller will be logged out.
3090
+ * @group Organization Contacts
3091
+ * @api GET /v2/organization-contacts Get a list of organization contacts
3092
+ * @apiBody string email Email address for the invitee
3093
+ * @apiBody string token Invite token for the invitee
3094
+ * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
2664
3095
  */
2665
- const deleteOrganization = (endpoint, organizationId) => endpoint.api //
2666
- .delete(`/v2/organizations/${organizationId}`)
3096
+ const getOrganizationContacts = (endpoint) => endpoint.api //
3097
+ .get(`/v2/organization-contacts`)
2667
3098
  .then((r) => r.data);
2668
3099
  /**
2669
- * Update the organization's full or thumbnail logo. This can only be called by an admin or owner.
3100
+ * Delete a contact from the caller's organization. Note that the caller must be an admin or owner.
2670
3101
  *
2671
3102
  * ```typescript
2672
- * import {updateOrganizationLogo} from '@verdocs/js-sdk';
3103
+ * import {deleteOrganizationContact} from '@verdocs/js-sdk';
2673
3104
  *
2674
- * await updateOrganizationLogo((VerdocsEndpoint.getDefault(), organizationId, file);
3105
+ * await deleteOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID'});
2675
3106
  * ```
2676
3107
  *
2677
- * @group Organizations
2678
- * @api PATCH /v2/organizations/:organization_id Update organization full or thumbnail logo.
2679
- * @apiBody image/png logo? Form-url-encoded file to upload
2680
- * @apiBody image/png thumbnail? Form-url-encoded file to upload
2681
- * @apiSuccess IOrganization . The updated organization.
3108
+ * @group Organization Contacts
3109
+ * @api POST /v2/organization-invitations/decline GET a list of pending invitations
3110
+ * @apiBody string email Email address for the invitee
3111
+ * @apiBody string token Invite token for the invitee
3112
+ * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
2682
3113
  */
2683
- const updateOrganizationLogo = (endpoint, organizationId, file, onUploadProgress) => {
2684
- const formData = new FormData();
2685
- formData.append('logo', file, file.name);
2686
- return endpoint.api //
2687
- .patch(`/v2/organizations/${organizationId}`, formData, {
2688
- timeout: 120000,
2689
- onUploadProgress: (event) => {
2690
- const total = event.total || 1;
2691
- const loaded = event.loaded || 0;
2692
- onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
2693
- },
2694
- })
2695
- .then((r) => r.data);
2696
- };
3114
+ const deleteOrganizationContact = (endpoint, profileId) => endpoint.api //
3115
+ .delete(`/v2/organization-contacts/${profileId}`)
3116
+ .then((r) => r.data);
2697
3117
  /**
2698
- * Update the organization's thumbnail. This can only be called by an admin or owner.
3118
+ * Update a member.
2699
3119
  *
2700
3120
  * ```typescript
2701
- * import {updateOrganizationThumbnail} from '@verdocs/js-sdk';
3121
+ * import {createOrganizationContact} from '@verdocs/js-sdk';
2702
3122
  *
2703
- * await updateOrganizationThumbnail((VerdocsEndpoint.getDefault(), organizationId, file);
3123
+ * const result = await createOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID', {first_name:'First', last_name:'Last', email:'a@b.com'});
2704
3124
  * ```
2705
3125
  */
2706
- const updateOrganizationThumbnail = (endpoint, organizationId, file, onUploadProgress) => {
2707
- const formData = new FormData();
2708
- formData.append('thumbnail', file, file.name);
2709
- return endpoint.api //
2710
- .patch(`/v2/organizations/${organizationId}`, formData, {
2711
- timeout: 120000,
2712
- onUploadProgress: (event) => {
2713
- const total = event.total || 1;
2714
- const loaded = event.loaded || 0;
2715
- onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
2716
- },
2717
- })
2718
- .then((r) => r.data);
2719
- };
2720
- const getEntitlements = async (endpoint) => endpoint.api.get(`/v2/organizations/entitlements`).then((r) => r.data);
3126
+ const createOrganizationContact = (endpoint, params) => endpoint.api //
3127
+ .post(`/v2/organization-contacts`, params)
3128
+ .then((r) => r.data);
2721
3129
  /**
2722
- * Largely intended to be used internally by Web SDK components but may be informative for other cases.
2723
- * Entitlements are feature grants such as "ID-based KBA" that require paid contracts to enable, typically
2724
- * because the underlying services that support them are fee-based. Entitlements may run concurrently,
2725
- * and may have different start/end dates e.g. "ID-based KBA" may run 1/1/2026-12/31/2026 while
2726
- * "SMS Authentication" may be added later and run 6/1/2026-5/31/2027. The entitlements list is a simple
2727
- * array of enablements and may include entries that are not YET enabled or have now expired.
2728
- *
2729
- * In client code it is helpful to simply know "is XYZ feature currently enabled?" This function collapses
2730
- * the entitlements list to a simplified dictionary of current/active entitlements. Note that it is async
2731
- * because it calls the server to obtain the "most current" entitlements list. Existence of an entry in the
2732
- * resulting dictionary implies the feature is active. Metadata inside each entry can be used to determine
2733
- * limits, etc.
3130
+ * Update a member.
2734
3131
  *
2735
3132
  * ```typescript
2736
- * import {getActiveEntitlements} from '@verdocs/js-sdk';
3133
+ * import {updateOrganizationContact} from '@verdocs/js-sdk';
2737
3134
  *
2738
- * const activeEntitlements = await getActiveEntitlements((VerdocsEndpoint.getDefault());
2739
- * const isSMSEnabled = !!activeEntitlements.sms_auth;
2740
- * const monthlyKBALimit = activeEntitlements.kba_auth?.monthly_max;
2741
- * ```
2742
- */
2743
- const getActiveEntitlements = async (endpoint) => {
2744
- if (!endpoint.session) {
2745
- throw new Error('No active session');
2746
- }
2747
- const entitlements = await getEntitlements(endpoint);
2748
- return collapseEntitlements(entitlements);
2749
- };
3135
+ * const result = await updateOrganizationContact(VerdocsEndpoint.getDefault(), 'PROFILEID', {first_name:'NewFirst'});
3136
+ * ```
3137
+ */
3138
+ const updateOrganizationContact = (endpoint, profileId, params) => endpoint.api //
3139
+ .patch(`/v2/organization-contacts/${profileId}`, params)
3140
+ .then((r) => r.data);
2750
3141
 
2751
3142
  /**
2752
- * Webhooks are callback triggers from Verdocs to your servers that notify your applications
2753
- * of various events, such as signing operations.
3143
+ * Organizations may contain "Groups" of user profiles, called Members. Groups may have permissions assigned that
3144
+ * apply to all Members, making it easy to configure role-based access control (RBAC) within an Organization. Note
3145
+ * that permissions are **additive**. A user may be a member of more than one group, and may also have permissions
3146
+ * assigned directly. In that case, the user will have the combined set of all permissions inherited from all
3147
+ * sources.
2754
3148
  *
2755
3149
  * @module
2756
3150
  */
2757
3151
  /**
2758
- * Get the registered Webhook configuration for the caller's organization.
3152
+ * Get a list of groups for the caller's organization. NOTE: Any organization member may request
3153
+ * the list of groups, but only Owners and Admins may update them.
2759
3154
  *
2760
3155
  * ```typescript
2761
- * import {getWebhooks} from '@verdocs/js-sdk';
3156
+ * import {getGroups} from '@verdocs/js-sdk';
2762
3157
  *
2763
- * await getWebhooks(ORGID, params);
3158
+ * const groups = await getGroups();
2764
3159
  * ```
2765
- *
2766
- * @group Webhooks
2767
- * @api GET /v2/webhooks Get organization Webhooks config
2768
- * @apiSuccess IWebhook . The current Webhooks config for the caller's organization.
2769
3160
  */
2770
- const getWebhooks = (endpoint) => endpoint.api //
2771
- .get(`/v2/webhooks`)
3161
+ const getGroups = (endpoint) => endpoint.api //
3162
+ .get(`/v2/organization-groups`)
2772
3163
  .then((r) => r.data);
2773
3164
  /**
2774
- * Update the registered Webhook configuration for the caller's organization. Note that
2775
- * Webhooks cannot currently be deleted, but may be easily disabled by setting `active`
2776
- * to `false` and/or setting the `url` to an empty string.
3165
+ * Get the details for a group, including its member profiles and list of permissions.
2777
3166
  *
2778
3167
  * ```typescript
2779
- * import {setWebhooks} from '@verdocs/js-sdk';
3168
+ * import {getGroup} from '@verdocs/js-sdk/v2/organization-groups';
2780
3169
  *
2781
- * await setWebhooks(ORGID, params);
3170
+ * const group = await getGroup(GROUPID);
2782
3171
  * ```
2783
- *
2784
- * @group Webhooks
2785
- * @api PATCH /v2/webhooks Update organization Webhooks config
2786
- * @apiDescription Note that Webhooks cannot currently be deleted, but may be easily disabled by setting `active` to `false` and/or setting the `url` to an empty string.
2787
- * @apiBody string url URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
2788
- * @apiBody boolean active Set to true to enable Webhooks calls.
2789
- * @apiBody object events Record<TWebhookEvent, boolean> map of events to enable/disable.
2790
- * @apiSuccess IWebhook . The updated Webhooks config for the caller's organization.
2791
3172
  */
2792
- const setWebhooks = (endpoint, params) => endpoint.api //
2793
- .patch(`/v2/webhooks`, params)
3173
+ const getGroup = (endpoint, groupId) => endpoint.api //
3174
+ .get(`/v2/organization-groups/${groupId}`)
2794
3175
  .then((r) => r.data);
2795
-
2796
- /**
2797
- * A map of the permissions each role confers.
2798
- */
2799
- const RolePermissions = {
2800
- owner: [
2801
- 'template:creator:create:public',
2802
- 'template:creator:create:org',
2803
- 'template:creator:create:personal',
2804
- 'template:creator:delete',
2805
- 'template:creator:visibility',
2806
- 'template:member:read',
2807
- 'template:member:write',
2808
- 'template:member:delete',
2809
- 'template:member:visibility',
2810
- 'owner:add',
2811
- 'owner:remove',
2812
- 'admin:add',
2813
- 'admin:remove',
2814
- 'member:view',
2815
- 'member:add',
2816
- 'member:remove',
2817
- 'org:create',
2818
- 'org:view',
2819
- 'org:update',
2820
- 'org:delete',
2821
- 'org:transfer',
2822
- 'org:list',
2823
- 'envelope:create',
2824
- 'envelope:cancel',
2825
- 'envelope:view',
2826
- ],
2827
- admin: [
2828
- 'template:creator:create:public',
2829
- 'template:creator:create:org',
2830
- 'template:creator:create:personal',
2831
- 'template:creator:delete',
2832
- 'template:creator:visibility',
2833
- 'template:member:read',
2834
- 'template:member:write',
2835
- 'template:member:delete',
2836
- 'template:member:visibility',
2837
- 'admin:add',
2838
- 'admin:remove',
2839
- 'member:view',
2840
- 'member:add',
2841
- 'member:remove',
2842
- 'org:create',
2843
- 'org:view',
2844
- 'org:update',
2845
- 'org:list',
2846
- 'envelope:create',
2847
- 'envelope:cancel',
2848
- 'envelope:view',
2849
- ],
2850
- member: [
2851
- 'template:creator:create:public',
2852
- 'template:creator:create:org',
2853
- 'template:creator:create:personal',
2854
- 'template:creator:delete',
2855
- 'template:creator:visibility',
2856
- 'template:member:read',
2857
- 'template:member:write',
2858
- 'template:member:delete',
2859
- 'member:view',
2860
- 'org:create',
2861
- 'org:view',
2862
- 'org:list',
2863
- 'envelope:create',
2864
- 'envelope:cancel',
2865
- 'envelope:view',
2866
- ],
2867
- basic_user: ['template:member:read', 'member:view', 'org:view', 'org:list'],
2868
- contact: ['org:view', 'org:list', 'org:create'],
2869
- };
2870
3176
  /**
2871
- * Confirm whether the user has all of the specified permissions.
3177
+ * Create a group. Note that "everyone" is a reserved name and may not be created.
3178
+ *
3179
+ * ```typescript
3180
+ * import {createGroup} from '@verdocs/js-sdk';
3181
+ *
3182
+ * const group = await createGroup(VerdocsEndpoint.getDefault(), {name:'newgroup'});
3183
+ * ```
2872
3184
  */
2873
- const userHasPermissions = (profile, permissions) => {
2874
- // No need to de-dupe here, we're just checking present-at-least-once set membership.
2875
- const netPermissions = [...(profile?.permissions || [])];
2876
- (profile?.roles || []).forEach((role) => {
2877
- netPermissions.push(...(RolePermissions[role] || []));
2878
- });
2879
- (profile?.group_profiles || []).forEach((groupProfile) => {
2880
- netPermissions.push(...(groupProfile.group?.permissions || []));
2881
- });
2882
- return permissions.every((perm) => netPermissions.includes(perm));
2883
- };
2884
-
2885
- const canPerformTemplateAction = (profile, action, template) => {
2886
- if (!template && !action.includes('create')) {
2887
- return { canPerform: false, message: 'Missing required template object' };
2888
- }
2889
- // We use BOGUS here to force the option-chain in things like template?.profile_id to NOT match profile?.profile_id because if both
2890
- // were undefined, they would actually match.
2891
- const profile_id = profile?.id || 'BOGUS';
2892
- const organization_id = profile?.organization_id || 'BOGUS';
2893
- const isCreator = template?.profile_id === profile_id;
2894
- const isSameOrg = template?.organization_id === organization_id;
2895
- const isPersonal = template?.is_personal ?? false;
2896
- const isPublic = template?.is_public ?? false;
2897
- const permissionsRequired = [];
2898
- switch (action) {
2899
- case 'create_personal':
2900
- permissionsRequired.push('template:creator:create:personal');
2901
- break;
2902
- case 'create_org':
2903
- permissionsRequired.push('template:creator:create:org');
2904
- break;
2905
- case 'create_public':
2906
- permissionsRequired.push('template:creator:create:public');
2907
- break;
2908
- case 'read':
2909
- if (!isCreator) {
2910
- if ((!isPersonal && isSameOrg) || !isPublic) {
2911
- permissionsRequired.push('template:member:read');
2912
- }
2913
- }
2914
- break;
2915
- case 'write':
2916
- if (!isCreator) {
2917
- permissionsRequired.push('template:member:read');
2918
- permissionsRequired.push('template:member:write');
2919
- }
2920
- break;
2921
- case 'change_visibility_personal':
2922
- if (isCreator) {
2923
- permissionsRequired.push('template:creator:create:personal');
2924
- }
2925
- else {
2926
- permissionsRequired.push('template:member:visibility');
2927
- }
2928
- break;
2929
- case 'change_visibility_org':
2930
- if (isCreator) {
2931
- permissionsRequired.push('template:creator:create:org');
2932
- }
2933
- else {
2934
- permissionsRequired.push('template:member:visibility');
2935
- }
2936
- break;
2937
- case 'change_visibility_public':
2938
- if (isCreator) {
2939
- permissionsRequired.push('template:creator:create:public');
2940
- permissionsRequired.push('template:creator:visibility');
2941
- }
2942
- else {
2943
- permissionsRequired.push('template:member:visibility');
2944
- }
2945
- break;
2946
- case 'delete':
2947
- if (isCreator) {
2948
- permissionsRequired.push('template:creator:delete');
2949
- }
2950
- else {
2951
- permissionsRequired.push('template:member:delete');
2952
- }
2953
- break;
2954
- default:
2955
- return { canPerform: false, message: 'Action is not defined' };
2956
- }
2957
- if (hasRequiredPermissions(profile, permissionsRequired)) {
2958
- return { canPerform: true, message: '' };
2959
- }
2960
- return { canPerform: false, message: `Insufficient access to perform '${action}'. Needed permissions: ${permissionsRequired.toString()}` };
2961
- };
2962
- const hasRequiredPermissions = (profile, permissions) => permissions.every((perm) => (profile?.permissions || []).includes(perm));
2963
-
3185
+ const createGroup = (endpoint, params) => endpoint.api //
3186
+ .post('/v2/organization-groups', params)
3187
+ .then((r) => r.data);
2964
3188
  /**
2965
- * Add a field to a template.
3189
+ * Update a group. Note that "everyone" is a reserved name and may not be changed.
2966
3190
  *
2967
3191
  * ```typescript
2968
- * import {createField} from '@verdocs/js-sdk/Templates';
3192
+ * import {updateGroup} from '@verdocs/js-sdk';
2969
3193
  *
2970
- * await createField((VerdocsEndpoint.getDefault(), template_id, { ... });
3194
+ * const updated = await updateGroup(VerdocsEndpoint.getDefault(), {name:'newname'});
2971
3195
  * ```
3196
+ */
3197
+ const updateGroup = (endpoint, groupId, params) => endpoint.api //
3198
+ .patch(`/v2/organization-groups/${groupId}`, params)
3199
+ .then((r) => r.data);
3200
+ /**
3201
+ * Get an organization by ID. Note that the "everyone" group cannot be deleted.
2972
3202
  *
2973
- * @group Fields
2974
- * @api POST /v2/fields/:template_id Add a field to a template
2975
- * @apiBody string name Name for the new field. Field names must be unique within a template. Although special characters are allowed, they must be URL-encoded in subsequent requests, so it is recommended to use only alphanumeric characters and hyphens if possible.
2976
- * @apiBody string role_name Role to assign to the field. Role names must be valid, so it is recommended to create roles before fields.
2977
- * @apiBody string document_id ID of the document upon which to place the field.
2978
- * @apiBody string(enum: 'signature' | 'initial' | 'checkbox' | 'radio' | 'textbox' | 'timestamp' | 'date' | 'dropdown' | 'textarea' | 'attachment' | 'payment') type Type of field to create
2979
- * @apiBody boolean(default: false) required Whether the field is required
2980
- * @apiBody integer(min: 0) page 0-based page number upon which to place the field
2981
- * @apiBody integer(min: 0) x X position for the field (left to right)
2982
- * @apiBody integer(min: 0) y Y position for the field (_bottom to top!_)
2983
- * @apiBody string label? Optional label to display above the field
2984
- * @apiBody integer(min: 50) width? Width of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
2985
- * @apiBody integer(min: 15) height? Height of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
2986
- * @apiBody string placeholder? Optional placeholder to display in text fields
2987
- * @apiBody string group? For fields that support grouping (radio buttons and check boxes) the value selected will be stored under this name
2988
- * @apiBody array(items:IDropdownOption) options? For dropdown fields, the options to display
2989
- * @apiBody string value? Optional default value to set on the field
2990
- * @apiSuccess ITemplateField . Template field
3203
+ * ```typescript
3204
+ * import {deleteGroup} from '@verdocs/js-sdk';
3205
+ *
3206
+ * await deleteGroup(VerdocsEndpoint.getDefault(), 'ORGID');
3207
+ * ```
2991
3208
  */
2992
- const createField = (endpoint, templateId, params) => endpoint.api //
2993
- .post(`/v2/fields/${templateId}`, params)
3209
+ const deleteGroup = (endpoint, groupId) => endpoint.api //
3210
+ .delete(`/v2/organization-groups/${groupId}`)
2994
3211
  .then((r) => r.data);
2995
3212
  /**
2996
- * Update a template field.
3213
+ * Add a member to a group.
2997
3214
  *
2998
3215
  * ```typescript
2999
- * import {updateField} from '@verdocs/js-sdk/Templates';
3216
+ * import {addGroupMember} from '@verdocs/js-sdk';
3000
3217
  *
3001
- * await updateField((VerdocsEndpoint.getDefault(), template_id, field_name, { ... });
3218
+ * await addGroupMember(VerdocsEndpoint.getDefault(), 'GROUPID', 'PROFILEID');
3002
3219
  * ```
3003
- *
3004
- * @group Fields
3005
- * @api PATCH /v2/fields/:template_id/:field_name Update a field. See createField for additional details on the supported parameters.
3006
- * @apiBody string name? Rename the field. Note that template field names must be unique within a template.
3007
- * @apiBody string role_name Role to assign to the field.
3008
- * @apiBody string document_id ID of the document upon which to place the field.
3009
- * @apiBody string(enum: 'signature' | 'initial' | 'checkbox' | 'radio' | 'textbox' | 'timestamp' | 'date' | 'dropdown' | 'textarea' | 'attachment' | 'payment') type? Change the field type. Note that while this is technically allowed, fields have different behaviors, validators, default sizes, etc. It is usually easier to add a new field and delete the old one.
3010
- * @apiBody boolean(default: false) required? Whether the field is required
3011
- * @apiBody integer(min: 0) page? 0-based page number upon which to place the field
3012
- * @apiBody integer(min: 0) x? X position for the field (left to right)
3013
- * @apiBody integer(min: 0) y? Y position for the field (_bottom to top!_)
3014
- * @apiBody string label? Optional label to display above the field
3015
- * @apiBody integer(min: 50) width? Width of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
3016
- * @apiBody integer(min: 15) height? Height of the field. Note that all fields have built-in defaults, and it is recommended that this only be set on text fields.
3017
- * @apiBody string placeholder? Optional placeholder to display in text fields
3018
- * @apiBody string group? For fields that support grouping (radio buttons and check boxes) the value selected will be stored under this name
3019
- * @apiBody array(items:IDropdownOption) options? For dropdown fields, the options to display
3020
- * @apiBody string value? Optional default value to set on the field
3021
- * @apiSuccess ITemplateField . Updated template field
3022
3220
  */
3023
- const updateField = (endpoint, templateId, name, params) => endpoint.api //
3024
- .patch(`/v2/fields/${templateId}/${encodeURIComponent(name)}`, params)
3221
+ const addGroupMember = (endpoint, groupId, profile_id) => endpoint.api //
3222
+ .post(`/v2/organization-groups/${groupId}/members`, { profile_id })
3025
3223
  .then((r) => r.data);
3026
3224
  /**
3027
- * Remove a field from a template.
3225
+ * Remove a member from a group.
3028
3226
  *
3029
3227
  * ```typescript
3030
- * import {deleteField} from '@verdocs/js-sdk/Templates';
3228
+ * import {deleteGroupMember} from '@verdocs/js-sdk';
3031
3229
  *
3032
- * await deleteField((VerdocsEndpoint.getDefault(), template_id, field_name);
3230
+ * await deleteGroupMember(VerdocsEndpoint.getDefault(), 'GROUPID', 'PROFILEID');
3033
3231
  * ```
3034
- *
3035
- * @group Fields
3036
- * @api DELETE /v2/fields/:template_id/:field_name Delete a field
3037
- * @apiSuccess string . Success
3038
3232
  */
3039
- const deleteField = (endpoint, templateId, name) => endpoint.api //
3040
- .delete(`/v2/fields/${templateId}/${encodeURIComponent(name)}`)
3233
+ const deleteGroupMember = (endpoint, groupId, profile_id) => endpoint.api //
3234
+ .delete(`/v2/organization-groups/${groupId}/members/${profile_id}`)
3041
3235
  .then((r) => r.data);
3042
3236
 
3043
3237
  /**
3044
- * Various helpers to identify available operations for a template by a user.
3238
+ * An invitation represents an opportunity for a Member to join an Organization.
3045
3239
  *
3046
3240
  * @module
3047
3241
  */
3048
3242
  /**
3049
- * Check to see if the user created the template.
3050
- */
3051
- const userIsTemplateCreator = (profile, template) => profile && template && profile.id === template.profile_id;
3052
- /**
3053
- * Check to see if a template is "shared" with the user.
3054
- */
3055
- const userHasSharedTemplate = (profile, template) => profile && template && !template.is_personal && profile.organization_id === template.organization_id;
3056
- /**
3057
- * Check to see if the user can create a personal/private template.
3058
- */
3059
- const userCanCreatePersonalTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:personal']);
3060
- /**
3061
- * Check to see if the user can create an org-shared template.
3062
- */
3063
- const userCanCreateOrgTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:org']);
3064
- /**
3065
- * Check to see if the user can create a public template.
3066
- */
3067
- const userCanCreatePublicTemplate = (profile) => userHasPermissions(profile, ['template:creator:create:public']);
3068
- /**
3069
- * Check to see if the user can read/view a template.
3070
- */
3071
- const userCanReadTemplate = (profile, template) => template.is_public ||
3072
- userIsTemplateCreator(profile, template) ||
3073
- (userHasSharedTemplate(profile, template) && userHasPermissions(profile, ['template:member:read']));
3074
- /**
3075
- * Check to see if the user can update a tempate.
3076
- */
3077
- const userCanUpdateTemplate = (profile, template) => userIsTemplateCreator(profile, template) ||
3078
- (userHasSharedTemplate(profile, template) && userHasPermissions(profile, ['template:member:read', 'template:member:write']));
3079
- /**
3080
- * Check to see if the user can change whether a template is personal vs org-shared.
3081
- */
3082
- const userCanMakeTemplatePrivate = (profile, template) => userIsTemplateCreator(profile, template)
3083
- ? userHasPermissions(profile, ['template:creator:create:personal'])
3084
- : userHasPermissions(profile, ['template:member:visibility']);
3085
- /**
3086
- * Check to see if the user can change whether a template is personal vs org-shared.
3087
- */
3088
- const userCanMakeTemplateShared = (profile, template) => userIsTemplateCreator(profile, template)
3089
- ? userHasPermissions(profile, ['template:creator:create:org'])
3090
- : userHasPermissions(profile, ['template:member:visibility']);
3091
- /**
3092
- * Check to see if the user can change whether a template is personal vs org-shared.
3093
- */
3094
- const userCanMakeTemplatePublic = (profile, template) => userIsTemplateCreator(profile, template)
3095
- ? userHasPermissions(profile, ['template:creator:create:public'])
3096
- : userHasPermissions(profile, ['template:member:visibility']);
3097
- /**
3098
- * Check to see if the user can change whether a template is personal vs org-shared.
3099
- */
3100
- const userCanChangeOrgVisibility = (profile, template) => userIsTemplateCreator(profile, template) && userHasPermissions(profile, ['template:creator:create:personal']);
3101
- /**
3102
- * Check to see if the user can change whether a template is personal vs org-shared.
3103
- */
3104
- const userCanDeleteTemplate = (profile, template) => userIsTemplateCreator(profile, template)
3105
- ? userHasPermissions(profile, ['template:creator:delete'])
3106
- : userHasPermissions(profile, ['template:member:delete']);
3107
- /**
3108
- * Confirm whether the user can create an envelope using the specified template.
3243
+ * Get a list of invitations pending for the caller's organization. The caller must be an admin or owner.
3244
+ *
3245
+ * @group Organization Invitations
3246
+ * @api GET /v2/organization-invitations Get a list of pending invitations
3247
+ * @apiBody array(items:TRole) roles URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
3248
+ * @apiBody string first_name First name. The user may override this after accepting the invitation.
3249
+ * @apiBody string last_name Last name. The user may override this after accepting the invitation.
3250
+ * @apiSuccess array(items:IProfile) . List of caller's current organization's members
3109
3251
  */
3110
- const userCanSendTemplate = (profile, template) => {
3111
- switch (template.visibility) {
3112
- case 'private':
3113
- return userIsTemplateCreator(profile, template);
3114
- case 'shared':
3115
- return userIsTemplateCreator(profile, template) || template.organization_id === profile?.organization_id;
3116
- case 'public':
3117
- return true;
3118
- }
3119
- };
3252
+ const getOrganizationInvitations = (endpoint) => endpoint.api //
3253
+ .get(`/v2/organization-invitations`)
3254
+ .then((r) => r.data);
3120
3255
  /**
3121
- * Confirm whether the user can create a new template.
3256
+ * Invite a new user to join the organization.
3257
+ *
3258
+ * @group Organization Invitations
3259
+ * @api POST /v2/organization-invitations Invite a new user to join the organization
3260
+ * @apiBody string email Email address to send the invitation to
3261
+ * @apiBody string first_name First name. The user may override this after accepting the invitation.
3262
+ * @apiBody string last_name Last name. The user may override this after accepting the invitation.
3263
+ * @apiBody TRole role Initial role to assign to the user once they accept.
3264
+ * @apiSuccess IOrganizationInvitation . The newly-created invitation.
3122
3265
  */
3123
- const userCanCreateTemplate = (profile) => userCanCreatePersonalTemplate(profile) || userCanCreateOrgTemplate(profile) || userCanCreatePublicTemplate(profile);
3266
+ const createOrganizationInvitation = (endpoint, params) => endpoint.api //
3267
+ .post(`/v2/organization-invitations`, params)
3268
+ .then((r) => r.data);
3124
3269
  /**
3125
- * Check to see if the user can "build" the template (use the field builder). The user must have write access to the
3126
- * template, and the template must have at least one signer role.
3270
+ * Delete an invitation. Note that no cancellation message will be sent. Invitations are also one-time-use.
3271
+ * If the invitee attempts to join after the invitation is deleted, accepted, or decline, they will be
3272
+ * shown an error.
3273
+ *
3274
+ * @group Organization Invitations
3275
+ * @api DELETE /v2/organization-invitations/:email Delete a pending invitation
3276
+ * @apiSuccess string . Success
3127
3277
  */
3128
- const userCanBuildTemplate = (profile, template) => userCanUpdateTemplate(profile, template) && (template.roles || []).filter((role) => role.type === 'signer').length > 0;
3129
- const getFieldsForRole = (template, role_name) => (template.fields || []).filter((field) => field.role_name === role_name);
3278
+ const deleteOrganizationInvitation = (endpoint, email) => endpoint.api //
3279
+ .delete(`/v2/organization-invitations/${email}`)
3280
+ .then((r) => r.data);
3130
3281
  /**
3131
- * Check to see if the user can preview the template. The user must have read access to the template, the template must
3132
- * have at least one signer, and every signer must have at least one field.
3282
+ * Update an invitation. Note that email may not be changed after the invite is sent. To change
3283
+ * an invitee's email, delete the incorrect entry and create one with the correct value.
3284
+ *
3285
+ * @group Organization Invitations
3286
+ * @api PATCH /v2/organization-invitations/:email Update a pending invitation
3287
+ * @apiBody string first_name First name. The user may override this after accepting the invitation.
3288
+ * @apiBody string last_name Last name. The user may override this after accepting the invitation.
3289
+ * @apiBody TRole role Initial role to assign to the user once they accept.
3290
+ * @apiSuccess IOrganizationInvitation . The updated invitation.
3133
3291
  */
3134
- const userCanPreviewTemplate = (profile, template) => {
3135
- const hasPermission = userCanReadTemplate(profile, template);
3136
- const signers = (template.roles || []).filter((role) => role.type === 'signer');
3137
- return hasPermission && signers.length > 0 && signers.every((signer) => getFieldsForRole(template, signer.name).length > 0);
3138
- };
3139
-
3292
+ const updateOrganizationInvitation = (endpoint, email, params) => endpoint.api //
3293
+ .patch(`/v2/organization-invitations/${email}`, params)
3294
+ .then((r) => r.data);
3140
3295
  /**
3141
- * A "role" is an individual participant in a signing flow, such as a signer or CC contact.
3142
- * A role is a placeholder that will eventually become a named recipient. For example, "Tenant 1"
3143
- * might be replaced with "John Smith" when the document is sent out for signature.
3144
- *
3145
- * Role names must be unique within a template, e.g. 'Recipient 1'. They may contain any [a-zA-Z0-9_- ]
3146
- * characters, although it is recommended to keep them simple and human-readable, and to avoid
3147
- * spaces (although they are allowed). If spaces are used in role names, be sure to URL-encode them
3148
- * when calling endpoints like `updateRole()` e.g. 'Recipient%201'.
3149
- *
3150
- * NOTE: Roles are always enumerated under Template objects, so there are no "list" or "get" endpoints
3151
- * for them. To get a template's latest role list, simply call `getTemplate()`.
3296
+ * Send a reminder to the invitee to join the organization.
3152
3297
  *
3153
- * @module
3298
+ * @group Organization Invitations
3299
+ * @api POST /v2/organization-invitations/resend Send a reminder to a pending invitee
3300
+ * @apiBody string email The recipient to send the reminder to
3301
+ * @apiSuccess IOrganizationInvitation . The updated invitation
3154
3302
  */
3303
+ const resendOrganizationInvitation = (endpoint, email) => endpoint.api //
3304
+ .post('/v2/organization-invitations/resend', { email })
3305
+ .then((r) => r.data);
3155
3306
  /**
3156
- * Create a role.
3157
- *
3158
- * ```typescript
3159
- * import {createTemplateRole} from '@verdocs/js-sdk';
3160
- *
3161
- * const role = await createTemplateRole(VerdocsEndpoint.getDefault(), template_id, params...);
3162
- * ```
3307
+ * Get an invitation's details. This is generally used as the first step of accepting the invite.
3308
+ * A successful response will indicate that the invite token is still valid, and include some
3309
+ * metadata for the organization to style the acceptance screen.
3163
3310
  *
3164
- * @group Roles
3165
- * @api POST /v2/roles/:template_id Add a role to a template
3166
- * @apiBody string name Name for the new role. Must be unique within the template. May include spaces, but later calls must URL-encode any references to this role, so it is recomended that special characters be avoided.
3167
- * @apiBody string(enum:'signer' | 'cc' | 'approver') type Type of role to create. Signers act on documents by filling and signing fields. CC recipients receive a copy but do not act on the document. Approvers control the final submission of a document, but do not have fields of their own to fill out.
3168
- * @apiBody string full_name? Default full name for the role. May be completed/overridden later, when envelopes are made from the template.
3169
- * @apiBody string email? Default email address for the role. May be completed/overridden later, when envelopes are made from the template.
3170
- * @apiBody string phone? Default (SMS-capable) phone number for the role. May be completed/overridden later, when envelopes are made from the template.
3171
- * @apiBody string message? Optional message to include in email and SMS signing invitations.
3172
- * @apiBody integer(min: 1, default: 1) sequence? Optional 1-based sequence number for the role. Roles that share the same sequence number act in parallel, and will receive invitations at the same time.
3173
- * @apiBody integer(min: 1, default: 1) order? Optional 1-based order number for the role. Controls the left-to-right display order of roles at the same sequence number in the UI components e.g. `<verdocs-template-roles />`.
3174
- * @apiBody boolean delegator? If true, the role may delegate their signing responsibility to another party.
3175
- * @apiSuccess IRole . The newly-created role
3311
+ * @group Organization Invitations
3312
+ * @api GET /v2/organization-invitations/:email/:token Get a pending invitation (_Authenticated via invite token, not an active session._). Intended to be called by the invitee to get details about the invitation they are about to accept.
3313
+ * @apiSuccess IOrganizationInvitation . Requested invitation's details. Will always include summary details for the organization, to be used for branding the accept-invite view.
3176
3314
  */
3177
- const createTemplateRole = (endpoint, template_id, params) => endpoint.api //
3178
- .post(`/v2/roles/${template_id}`, params)
3315
+ const getOrganizationInvitation = (endpoint, email, token) => endpoint.api //
3316
+ .get(`/v2/organization-invitations/${email}/${token}`)
3179
3317
  .then((r) => r.data);
3180
3318
  /**
3181
- * Update a role.
3182
- *
3183
- * ```typescript
3184
- * import {updateTemplateRole} from '@verdocs/js-sdk';
3185
- *
3186
- * const role = await updateTemplateRole(VerdocsEndpoint.getDefault(), template_id, name, params...);
3187
- * ```
3319
+ * Accept an invitation. This will automatically create a user record for the caller as well as a profile
3320
+ * with the appropriate role as specified in the invite. The profile will be set as "current" for the caller,
3321
+ * and session tokens will be returned to access the new profile. The profile's email_verified flag will
3322
+ * also be set to true.
3188
3323
  *
3189
- * @group Roles
3190
- * @api PATCH /v2/roles/:template_id/:role_id Update a role. See createRole for additional details on the parameters available.
3191
- * @apiBody string name? Rename the role. Note that role names must be unique within a template, so this may fail if the new name is already in use.
3192
- * @apiBody string(enum:'signer' | 'cc' | 'approver') type? Type of role.
3193
- * @apiBody string full_name? Default full name for the role.
3194
- * @apiBody string email? Default email address for the role.
3195
- * @apiBody string phone? Default (SMS-capable) phone number for the role.
3196
- * @apiBody string message? Optional message to include in email and SMS signing invitations.
3197
- * @apiBody integer(min: 1, default: 1) sequence? Optional 1-based sequence number for the role.
3198
- * @apiBody integer(min: 1, default: 1) order? Optional 1-based order number for the role.
3199
- * @apiBody boolean delegator? If true, the role may delegate their signing responsibility to another party.
3200
- * @apiBody string(enum:'pin'|'identity'|'') kba_method? Active PIN- or Identity-based KBA for the role.
3201
- * @apiSuccess IRole . The newly-created role
3324
+ * @group Organization Invitations
3325
+ * @api POST /v2/organization-invitations/accept Accept an invitation
3326
+ * @apiBody string email Email address for the invitee
3327
+ * @apiBody string token Invite token for the invitee
3328
+ * @apiBody string first_name First name
3329
+ * @apiBody string last_name Last name
3330
+ * @apiBody string password Password
3331
+ * @apiSuccess IAuthenticateResponse . Session credentials for the newly-created user's profile. If the user already had a profile for another organization, the new profile will be made "current" automatically.
3202
3332
  */
3203
- const updateTemplateRole = (endpoint, template_id, name, params) => endpoint.api //
3204
- .patch(`/v2/roles/${template_id}/${encodeURIComponent(name)}`, params)
3333
+ const acceptOrganizationInvitation = (endpoint, params) => endpoint.api //
3334
+ .post('/v2/organization-invitations/accept', params)
3205
3335
  .then((r) => r.data);
3206
3336
  /**
3207
- * Delete a role.
3208
- *
3209
- * ```typescript
3210
- * import {deleteTemplateRole} from '@verdocs/js-sdk';
3211
- *
3212
- * const profiles = await deleteTemplateRole(VerdocsEndpoint.getDefault(), template_id, name);
3213
- * ```
3337
+ * Decline an invitation. This will mark the status "declined," providing a visual indication to the
3338
+ * organization's admins that the invite was declined, preventing further invites from being created
3339
+ * to the same email address, and also preventing the invitee from receiving reminders to join.
3214
3340
  *
3215
- * @group Roles
3216
- * @api DELETE /v2/roles/:template_id/:role_id Delete a role.
3217
- * @apiSuccess string . Success
3341
+ * @group Organization Invitations
3342
+ * @api POST /v2/organization-invitations/decline Decline an invitation
3343
+ * @apiDescription Mark the status "declined," providing a visual indication to the organization's admins that the invite was declined, preventing further invites from being created to the same email address, and also preventing the invitee from receiving reminders to join.
3344
+ * @apiBody string email Email address for the invitee
3345
+ * @apiBody string token Invite token for the invitee
3346
+ * @apiSuccess string . Success. The invitation will be marked declined and the token will be invalidated.
3218
3347
  */
3219
- const deleteTemplateRole = (endpoint, template_id, name) => endpoint.api //
3220
- .delete(`/v2/roles/${template_id}/${encodeURIComponent(name)}`)
3348
+ const declineOrganizationInvitation = (endpoint, email, token) => endpoint.api //
3349
+ .post('/v2/organization-invitations/decline', { email, token })
3221
3350
  .then((r) => r.data);
3222
3351
 
3223
3352
  /**
3224
- * A Template defines how a Verdocs signing flow will be performed, including attachments, signing fields, and
3225
- * recipients.
3353
+ * An Organization Member (aka Profile) is an individual user with access to an organization.
3226
3354
  *
3227
3355
  * @module
3228
3356
  */
3229
3357
  /**
3230
- * Get all templates accessible by the caller, with optional filters.
3358
+ * Get a list of the members in the caller's organization.
3231
3359
  *
3232
3360
  * ```typescript
3233
- * import {getTemplates} from '@verdocs/js-sdk/Templates';
3361
+ * import {getOrganizationMembers} from '@verdocs/js-sdk';
3234
3362
  *
3235
- * await getTemplates((VerdocsEndpoint.getDefault());
3236
- * await getTemplates((VerdocsEndpoint.getDefault(), { is_starred: true });
3237
- * await getTemplates((VerdocsEndpoint.getDefault(), { is_creator: true });
3238
- * await getTemplates((VerdocsEndpoint.getDefault(), { is_organization: true });
3363
+ * const members = await getOrganizationMembers(VerdocsEndpoint.getDefault()});
3239
3364
  * ```
3240
3365
  *
3241
- * @group Templates
3242
- * @api GET /v2/templates Get Templates
3243
- * @apiQuery string q? Find templates whose names/descriptions contain the specified query string
3244
- * @apiQuery boolean is_starred? If true, returns only templates with at least one "star".
3245
- * @apiQuery boolean is_creator? If true, returns only templates that the caller created.
3246
- * @apiQuery string(enum: 'private_shared' | 'private' | 'shared' | 'public') visibility? Return only templates with the specified visibility.
3247
- * @apiQuery string(enum: 'created_at' | 'updated_at' | 'name' | 'last_used_at' | 'counter' | 'star_counter') sort_by? Return results sorted by this criteria
3248
- * @apiQuery boolean ascending? Set true/false to override the sort direction. Note that the default depends on `sort_by`. Date-based sorts default to descending, while name defaults to ascending.
3249
- * @apiQuery integer(default: 20) rows? Limit the number of rows returned
3250
- * @apiQuery integer(default: 0) page? Specify which page of results to return
3251
- * @apiSuccess integer(format: int32) count The total number of records matching the query, helpful for pagination
3252
- * @apiSuccess integer(format: int32) rows The number of rows returned in this response page
3253
- * @apiSuccess integer(format: int32) page The page number of this response
3254
- * @apiSuccess array(items: ITemplate) templates List of templates found
3366
+ * @group Organization Members
3367
+ * @api GET /v2/organization-members List current organization's members
3368
+ * @apiSuccess array(items:IProfile) . List of caller's current organization's members
3255
3369
  */
3256
- const getTemplates = (endpoint, params) => endpoint.api //
3257
- .get('/v2/templates', { params })
3370
+ const getOrganizationMembers = (endpoint) => endpoint.api //
3371
+ .get(`/v2/organization-members`)
3258
3372
  .then((r) => r.data);
3259
3373
  /**
3260
- * Get one template by its ID.
3374
+ * Delete a member from the caller's organization. Note that the caller must be an admin or owner,
3375
+ * may not delete him/herself.
3261
3376
  *
3262
3377
  * ```typescript
3263
- * import {getTemplate} from '@verdocs/js-sdk/Templates';
3378
+ * import {deleteOrganizationMember} from '@verdocs/js-sdk';
3264
3379
  *
3265
- * const template = await getTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
3380
+ * await deleteOrganizationMember(VerdocsEndpoint.getDefault(), 'PROFILEID'});
3266
3381
  * ```
3267
3382
  *
3268
- * @group Templates
3269
- * @api GET /v2/templates/:template_id Get a template. Note that the caller must have at least View access to the template.
3270
- * @apiSuccess ITemplate . The requested template
3383
+ * @group Organization Members
3384
+ * @api DELETE /v2/organization-members/:profile_id Delete a member from the organization
3385
+ * @apiSuccess string . Success
3271
3386
  */
3272
- const getTemplate = (endpoint, templateId) => {
3273
- return endpoint.api //
3274
- .get(`/v2/templates/${templateId}`)
3275
- .then((r) => {
3276
- const template = r.data;
3277
- // Post-process the template to upgrade to new data fields
3278
- if (!template.documents && template.template_documents) {
3279
- template.documents = template.template_documents;
3280
- }
3281
- template.documents?.forEach((document) => {
3282
- if (!document.order) {
3283
- document.order = 0;
3284
- }
3285
- if (document.page_numbers) {
3286
- document.pages = document.page_numbers;
3287
- }
3288
- });
3289
- // Temporary upgrade from legacy app
3290
- template.fields?.forEach((field) => {
3291
- if (field.setting) {
3292
- field.settings = field.setting;
3293
- }
3294
- });
3295
- return template;
3296
- });
3297
- };
3298
- const ALLOWED_CREATE_FIELDS = [
3299
- 'name',
3300
- 'is_personal',
3301
- 'is_public',
3302
- 'sender',
3303
- 'description',
3304
- 'roles',
3305
- 'fields',
3306
- ];
3387
+ const deleteOrganizationMember = (endpoint, profileId) => endpoint.api //
3388
+ .delete(`/v2/organization-members/${profileId}`)
3389
+ .then((r) => r.data);
3307
3390
  /**
3308
- * Create a template.
3391
+ * Update a member.
3309
3392
  *
3310
3393
  * ```typescript
3311
- * import {createTemplate} from '@verdocs/js-sdk/Templates';
3394
+ * import {updateOrganizationMember} from '@verdocs/js-sdk';
3312
3395
  *
3313
- * const newTemplate = await createTemplate((VerdocsEndpoint.getDefault(), {...});
3396
+ * const result = await updateOrganizationMember(VerdocsEndpoint.getDefault(), 'PROFILEID', {roles:['member']});
3314
3397
  * ```
3315
3398
  *
3316
- * @group Templates
3317
- * @api POST /v2/templates Create a template
3318
- * @apiBody string name Template name
3319
- * @apiBody string description? Optional description
3320
- * @apiBody TTemplateVisibility visibility? Visibility setting
3321
- * @apiBody boolean is_personal? Deprecated. If true, the template is personal and can only be seen by the caller. (Use "visibility" for new calls.)
3322
- * @apiBody boolean is_public? Deprecated. If true, the template is public and can be seen by anybody. (Use "visibility" for new calls.)
3323
- * @apiBody TTemplateSender sender? Who may send envelopes using this template
3324
- * @apiBody number initial_reminder? Delay (in seconds) before the first reminder is sent (min: 4hrs). Set to 0 or null to disable.
3325
- * @apiBody number followup_reminders? Delay (in seconds) before the subsequent reminders are sent (min: 12hrs). Set to 0 or null to disable.
3326
- * @apiBody array(items:object) documents? Optional list of documents to attach to the template
3327
- * @apiBody array(items:IRole) roles? Optional list of roles to create. Note that if roles are not included in the request, fields will be ignored.
3328
- * @apiBody array(fields:ITemplateField) fields? Optional list of fields to create. Note that if fields that do not match a role will be ignored.
3329
- * @apiSuccess ITemplate . The newly-created template
3399
+ * @group Organization Members
3400
+ * @api PATCH /v2/organization-members/:profile_id Update an organization member.
3401
+ * @apiBody array(items:TRole) roles URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
3402
+ * @apiBody string first_name Set to true to enable Webhooks calls.
3403
+ * @apiBody string last_name Record<TWebhookEvent, boolean> map of events to enable/disable.
3404
+ * @apiSuccess array(items:IProfile) . List of caller's current organization's members
3330
3405
  */
3331
- const createTemplate = (endpoint, params, onUploadProgress) => {
3332
- const options = {
3333
- timeout: 120000,
3334
- onUploadProgress: (event) => {
3335
- const total = event.total || 1;
3336
- const loaded = event.loaded || 0;
3337
- onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
3338
- },
3339
- };
3340
- if (params.documents && params.documents[0] instanceof File) {
3341
- const formData = new FormData();
3342
- ALLOWED_CREATE_FIELDS.forEach((allowedKey) => {
3343
- if (params[allowedKey] !== undefined) {
3344
- formData.append(allowedKey, params[allowedKey]);
3345
- }
3346
- });
3347
- params.documents.forEach((file) => {
3348
- formData.append('documents', file, file.name);
3349
- });
3350
- return endpoint.api.post('/v2/templates', formData, options).then((r) => r.data);
3351
- }
3352
- else {
3353
- return endpoint.api.post('/v2/templates', params, options).then((r) => r.data);
3354
- }
3355
- };
3406
+ const updateOrganizationMember = (endpoint, profileId, params) => endpoint.api //
3407
+ .patch(`/v2/organization-members/${profileId}`, params)
3408
+ .then((r) => r.data);
3409
+
3356
3410
  /**
3357
- * Duplicate a template. Creates a complete clone, including all settings (e.g. reminders), fields,
3358
- * roles, and documents.
3411
+ * An Organization is the top level object for ownership for Members, Documents, and Templates.
3412
+ *
3413
+ * NOTE: There is no call specifically to create an organization. Every organization must have
3414
+ * at least one "owner" type member. To create a new organization, call createProfile() with
3415
+ * the desired new orgName to create. The caller will become the first owner of the new org, and
3416
+ * can then invite new members to join as well.
3417
+ *
3418
+ * NOTE: There is no call to delete an organization. For safety, this is a manual process. Please
3419
+ * contact support@verdocs.com if you wish to completely delete an organization and all its records.
3420
+ *
3421
+ * @module
3422
+ */
3423
+ /**
3424
+ * Get an organization by ID. Note that this endpoint will return only a subset of fields
3425
+ * if the caller is not a member of the organization (the public fields).
3359
3426
  *
3360
3427
  * ```typescript
3361
- * import {duplicateTemplate} from '@verdocs/js-sdk/Templates';
3428
+ * import {getOrganization} from '@verdocs/js-sdk';
3362
3429
  *
3363
- * const newTemplate = await duplicateTemplate((VerdocsEndpoint.getDefault(), originalTemplateId, 'My Template Copy');
3430
+ * const organizations = await getOrganization(VerdocsEndpoint.getDefault(), 'ORGID');
3364
3431
  * ```
3365
3432
  *
3366
- * @group Templates
3367
- * @api PUT /v2/templates/:template_id Perform an operation on a template
3368
- * @apiBody string(enum:'duplicate') action Action to perform
3369
- * @apiBody string name? If duplicating the template, a name for the new copy
3370
- * @apiSuccess ITemplate . The newly-copied template
3433
+ * @group Organizations
3434
+ * @api GET /v2/organizations/:organization_id Get organization
3435
+ * @apiSuccess IOrganization . The requested organization. The caller must be a member.
3371
3436
  */
3372
- const duplicateTemplate = (endpoint, templateId, name) => endpoint.api //
3373
- .put(`/v2/templates/${templateId}`, { action: 'duplicate', name })
3437
+ const getOrganization = (endpoint, organizationId) => endpoint.api //
3438
+ .get(`/v2/organizations/${organizationId}`)
3374
3439
  .then((r) => r.data);
3375
3440
  /**
3376
- * Create a template from a Sharepoint asset.
3441
+ * Get an organization's "children".
3377
3442
  *
3378
3443
  * ```typescript
3379
- * import {createTemplateFromSharepoint} from '@verdocs/js-sdk/Templates';
3444
+ * import {getOrganizationChildren} from '@verdocs/js-sdk';
3380
3445
  *
3381
- * const newTemplate = await createTemplateFromSharepoint((VerdocsEndpoint.getDefault(), {...});
3446
+ * const children = await getOrganizationChildren(VerdocsEndpoint.getDefault(), 'ORGID');
3382
3447
  * ```
3383
3448
  *
3384
- * @group Templates
3385
- * @api POST /v2/templates/from-sharepoint Create a template from an asset in Sharepoint
3386
- * @apiBody string name Name for the new template
3387
- * @apiBody string siteId Name for the new template
3388
- * @apiBody string itemId Name for the new template
3389
- * @apiBody string oboToken On-Behalf-Of token for calls to Sharepoint. Should be generated as a short-expiration token with at least Read privileges to the siteId/itemId. This token will be discarded after being used.
3390
- * @apiSuccess ITemplate . The newly-created template
3449
+ * @group Organizations
3450
+ * @api GET /v2/organizations/:organization_id/children Get an organization's children
3451
+ * @apiSuccess IOrganization[] . Any child organizations found.
3391
3452
  */
3392
- const createTemplateFromSharepoint = (endpoint, params) => {
3393
- const options = {
3394
- timeout: 120000,
3395
- };
3396
- return endpoint.api.post('/v2/templates/from-sharepoint', params, options).then((r) => r.data);
3397
- };
3453
+ const getOrganizationChildren = (endpoint, organizationId) => endpoint.api //
3454
+ .get(`/v2/organizations/${organizationId}/children`)
3455
+ .then((r) => r.data);
3398
3456
  /**
3399
- * Update a template.
3457
+ * Get an organization's usage data. If the organization is a parent, usage data for children
3458
+ * will be included as well. The response will be a nested object keyed by organization ID,
3459
+ * with each entry being a dictionary of usageType:count entries.
3400
3460
  *
3401
3461
  * ```typescript
3402
- * import {updateTemplate} from '@verdocs/js-sdk/Templates';
3462
+ * import {getOrganizationUsage} from '@verdocs/js-sdk';
3403
3463
  *
3404
- * const updatedTemplate = await updateTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9', { name: 'New Name' });
3464
+ * const usage = await getOrganizationUsage(VerdocsEndpoint.getDefault(), 'ORGID');
3405
3465
  * ```
3406
3466
  *
3407
- * @group Templates
3408
- * @api PATCH /v2/templates/:template_id Update a template
3409
- * @apiBody string name? Template name
3410
- * @apiBody string description? Optional description
3411
- * @apiBody TTemplateVisibility visibility? Visibility setting
3412
- * @apiBody boolean is_personal? Deprecated. If true, the template is personal and can only be seen by the caller. (Use "visibility" for new calls.)
3413
- * @apiBody boolean is_public? Deprecated. If true, the template is public and can be seen by anybody. (Use "visibility" for new calls.)
3414
- * @apiBody TTemplateSender sender? Who may send envelopes using this template
3415
- * @apiBody number initial_reminder? Delay (in seconds) before the first reminder is sent (min: 4hrs). Set to 0 or null to disable.
3416
- * @apiBody number followup_reminders? Delay (in seconds) before the subsequent reminders are sent (min: 12hrs). Set to 0 or null to disable.
3417
- * @apiSuccess ITemplate . The updated template
3418
- */
3419
- const updateTemplate = (endpoint, templateId, params) => endpoint.api //
3420
- .patch(`/v2/templates/${templateId}`, params)
3467
+ * @group Organizations
3468
+ * @api GET /v2/organizations/:organization_id/usage Get an organization's usage metrics
3469
+ * @apiSuccess TOrganizationUsage . Usage data grouped by organization ID
3470
+ */
3471
+ const getOrganizationUsage = (endpoint, organizationId, params) => endpoint.api //
3472
+ .get(`/v2/organizations/${organizationId}/usage`, { params })
3421
3473
  .then((r) => r.data);
3422
3474
  /**
3423
- * Delete a template.
3475
+ * Create an organization. The caller will be assigned an "Owner" profile in the new organization,
3476
+ * and it will be set to "current" automatically. A new set of session tokens will be issued to
3477
+ * the caller, and the caller should update their endpoint to use the new tokens.
3424
3478
  *
3425
3479
  * ```typescript
3426
- * import {deleteTemplate} from '@verdocs/js-sdk/Templates';
3480
+ * import {createOrganization} from '@verdocs/js-sdk';
3427
3481
  *
3428
- * await deleteTemplate((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
3482
+ * const organization = await createOrganization(VerdocsEndpoint.getDefault(), {name: 'NewOrg'});
3429
3483
  * ```
3430
3484
  *
3431
- * @group Templates
3432
- * @api DELETE /v2/templates/:template_id Delete a template
3433
- * @apiSuccess string . Success
3485
+ * @group Organizations
3486
+ * @api POST /v2/organizations Create organization
3487
+ * @apiDescription The caller will be assigned an "Owner" profile in the new organization, and it will be set to "current" automatically. A new set of session tokens will be issued to the caller, and the caller should update their endpoint to use the new tokens.
3488
+ * @apiBody string name The name of the new organization
3489
+ * @apiBody string parent_id? If set, the new organization will be created as a child of the specified parent organization. The caller must be an admin of the parent organization.
3490
+ * @apiBody string contact_email? Contact email for the new organization
3491
+ * @apiBody string url? URL for the new organization
3492
+ * @apiBody string full_logo_url? URL of a large-format PNG logo
3493
+ * @apiBody string thumbnail_url? URL of a small-format (square is recommended) PNG logo
3494
+ * @apiBody string primary_color? URL of a small-format (square is recommended) PNG logo
3495
+ * @apiBody string secondary_color? URL of a small-format (square is recommended) PNG logo
3496
+ * @apiSuccess IAuthenticateResponse . Authentication credentials for user in the new organization. The user will be made an Owner automatically.
3434
3497
  */
3435
- const deleteTemplate = (endpoint, templateId) => endpoint.api //
3436
- .delete(`/v2/templates/${templateId}`)
3498
+ const createOrganization = (endpoint, params) => endpoint.api //
3499
+ .post(`/v2/organizations`, params)
3437
3500
  .then((r) => r.data);
3438
3501
  /**
3439
- * Toggle the template star for a template.
3502
+ * Update an organization. This can only be called by an admin or owner.
3440
3503
  *
3441
3504
  * ```typescript
3442
- * import {toggleTemplateStar} from '@verdocs/js-sdk/Templates';
3505
+ * import {updateOrganization} from '@verdocs/js-sdk';
3443
3506
  *
3444
- * await toggleTemplateStar((VerdocsEndpoint.getDefault(), '83da3d70-7857-4392-b876-c4592a304bc9');
3507
+ * const organizations = await updateOrganization(VerdocsEndpoint.getDefault(), organizationId, {name:'ORGNAME'});
3445
3508
  * ```
3446
3509
  *
3447
- * @group Templates
3448
- * @api POST /v2/templates/:template_id/star Star or unstar a template (toggle state)
3449
- * @apiSuccess ITemplate . Success
3510
+ * @group Organizations
3511
+ * @api PATCH /v2/organizations/:organization_id Update organization
3512
+ * @apiBody string name The name of the new organization
3513
+ * @apiBody string contact_email? Contact email for the new organization
3514
+ * @apiBody string url? URL for the new organization
3515
+ * @apiBody string full_logo_url? URL of a large-format PNG logo
3516
+ * @apiBody string thumbnail_url? URL of a small-format (square is recommended) PNG logo
3517
+ * @apiBody string primary_color? URL of a small-format (square is recommended) PNG logo
3518
+ * @apiBody string secondary_color? URL of a small-format (square is recommended) PNG logo
3519
+ * @apiSuccess IOrganization . The details for the updated organization
3450
3520
  */
3451
- const toggleTemplateStar = (endpoint, templateId) => endpoint.api //
3452
- .post(`/v2/templates/${templateId}/stars/toggle`)
3521
+ const updateOrganization = (endpoint, organizationId, params) => endpoint.api //
3522
+ .patch(`/v2/organizations/${organizationId}`, params)
3453
3523
  .then((r) => r.data);
3454
-
3455
3524
  /**
3456
- * A TemplateDocument represents a PDF or other attachment in a Template.
3525
+ * Delete an organization. This can only be called by an owner. Inclusion of the organization ID to delete
3526
+ * is just a safety check. The caller may only delete the organization they have currently selected.
3457
3527
  *
3458
- * @module
3528
+ * ```typescript
3529
+ * import {deleteOrganization} from '@verdocs/js-sdk';
3530
+ *
3531
+ * const newSession = await deleteOrganization(VerdocsEndpoint.getDefault(), organizationId);
3532
+ * ```
3533
+ *
3534
+ * @group Organizations
3535
+ * @api DELETE /v2/organizations/:organization_id Delete organization
3536
+ * @apiSuccess IAuthenticateResponse . If the caller is a member of another organization, authentication credentials for the next organization available. If not, this will be null and the caller will be logged out.
3459
3537
  */
3538
+ const deleteOrganization = (endpoint, organizationId) => endpoint.api //
3539
+ .delete(`/v2/organizations/${organizationId}`)
3540
+ .then((r) => r.data);
3460
3541
  /**
3461
- * Create a Document for a particular Template.
3542
+ * Update the organization's full or thumbnail logo. This can only be called by an admin or owner.
3462
3543
  *
3463
3544
  * ```typescript
3464
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
3545
+ * import {updateOrganizationLogo} from '@verdocs/js-sdk';
3465
3546
  *
3466
- * await TemplateDocument.createDocument((VerdocsEndpoint.getDefault(), templateID, params);
3547
+ * await updateOrganizationLogo((VerdocsEndpoint.getDefault(), organizationId, file);
3467
3548
  * ```
3468
3549
  *
3469
- * @group Template Documents
3470
- * @api POST /v2/templates/:template_id/documents Attach a document to a template
3471
- * @apiBody string(format:binary) file Document file to attach. The file name will automatically be used as the document name.
3472
- * @apiSuccess ITemplateDocument . Template document
3550
+ * @group Organizations
3551
+ * @api PATCH /v2/organizations/:organization_id Update organization full or thumbnail logo.
3552
+ * @apiBody image/png logo? Form-url-encoded file to upload
3553
+ * @apiBody image/png thumbnail? Form-url-encoded file to upload
3554
+ * @apiSuccess IOrganization . The updated organization.
3473
3555
  */
3474
- const createTemplateDocument = (endpoint, file, onUploadProgress) => {
3556
+ const updateOrganizationLogo = (endpoint, organizationId, file, onUploadProgress) => {
3475
3557
  const formData = new FormData();
3476
- formData.append('document', file, file.name);
3558
+ formData.append('logo', file, file.name);
3477
3559
  return endpoint.api //
3478
- .post(`/v2/template-documents`, formData, {
3560
+ .patch(`/v2/organizations/${organizationId}`, formData, {
3479
3561
  timeout: 120000,
3480
3562
  onUploadProgress: (event) => {
3481
3563
  const total = event.total || 1;
@@ -3486,114 +3568,103 @@ const createTemplateDocument = (endpoint, file, onUploadProgress) => {
3486
3568
  .then((r) => r.data);
3487
3569
  };
3488
3570
  /**
3489
- * Delete a specific Document.
3571
+ * Update the organization's thumbnail. This can only be called by an admin or owner.
3490
3572
  *
3491
3573
  * ```typescript
3492
- * import {TemplateDocument} from '@verdocs/js-sdk/Templates';
3574
+ * import {updateOrganizationThumbnail} from '@verdocs/js-sdk';
3493
3575
  *
3494
- * await TemplateDocument.deleteDocument((VerdocsEndpoint.getDefault(), templateID, documentID);
3576
+ * await updateOrganizationThumbnail((VerdocsEndpoint.getDefault(), organizationId, file);
3495
3577
  * ```
3496
- *
3497
- * @group Template Documents
3498
- * @api DELETE /v2/templates/:temlate_id/documents/:document_id Delete a template document
3499
- * @apiSuccess string . Success
3500
3578
  */
3501
- const deleteTemplateDocument = (endpoint, templateId, documentId) => endpoint.api //
3502
- .delete(`/v2/templates/${templateId}/documents/${documentId}`)
3503
- .then((r) => r.data);
3579
+ const updateOrganizationThumbnail = (endpoint, organizationId, file, onUploadProgress) => {
3580
+ const formData = new FormData();
3581
+ formData.append('thumbnail', file, file.name);
3582
+ return endpoint.api //
3583
+ .patch(`/v2/organizations/${organizationId}`, formData, {
3584
+ timeout: 120000,
3585
+ onUploadProgress: (event) => {
3586
+ const total = event.total || 1;
3587
+ const loaded = event.loaded || 0;
3588
+ onUploadProgress?.(Math.floor((loaded * 100) / (total)), loaded, total);
3589
+ },
3590
+ })
3591
+ .then((r) => r.data);
3592
+ };
3593
+ const getEntitlements = async (endpoint) => endpoint.api.get(`/v2/organizations/entitlements`).then((r) => r.data);
3504
3594
  /**
3505
- * Get all metadata for a template document. Note that when called by non-creators (e.g. Org Collaborators)
3506
- * this will return only the **metadata** the caller is allowed to view.
3595
+ * Largely intended to be used internally by Web SDK components but may be informative for other cases.
3596
+ * Entitlements are feature grants such as "ID-based KBA" that require paid contracts to enable, typically
3597
+ * because the underlying services that support them are fee-based. Entitlements may run concurrently,
3598
+ * and may have different start/end dates e.g. "ID-based KBA" may run 1/1/2026-12/31/2026 while
3599
+ * "SMS Authentication" may be added later and run 6/1/2026-5/31/2027. The entitlements list is a simple
3600
+ * array of enablements and may include entries that are not YET enabled or have now expired.
3507
3601
  *
3508
- * @group Template Documents
3509
- * @api GET /v2/envelope-documents/:id Get envelope document
3510
- * @apiParam string(format: 'uuid') document_id The ID of the document to retrieve.
3511
- * @apiSuccess IEnvelopeDocument . The detailed metadata for the document requested
3512
- */
3513
- const getTemplateDocument = async (endpoint, documentId) => endpoint.api //
3514
- .get(`/v2/template-documents/${documentId}`)
3515
- .then((r) => r.data);
3516
- /**
3517
- * Download a document directly.
3518
- */
3519
- const downloadTemplateDocument = async (endpoint, documentId) => endpoint.api //
3520
- .get(`/v2/template-documents/${documentId}?type=file`, { responseType: 'blob' })
3521
- .then((r) => r.data);
3522
- /**
3523
- * Get an envelope document's metadata, or the document itself. If no "type" parameter is specified,
3524
- * the document metadata is returned. If "type" is set to "file", the document binary content is
3525
- * returned with Content-Type set to the MIME type of the file. If "type" is set to "download", a
3526
- * string download link will be returned. If "type" is set to "preview" a string preview link will
3527
- * be returned. This link expires quickly, so it should be accessed immediately and never shared.
3602
+ * In client code it is helpful to simply know "is XYZ feature currently enabled?" This function collapses
3603
+ * the entitlements list to a simplified dictionary of current/active entitlements. Note that it is async
3604
+ * because it calls the server to obtain the "most current" entitlements list. Existence of an entry in the
3605
+ * resulting dictionary implies the feature is active. Metadata inside each entry can be used to determine
3606
+ * limits, etc.
3528
3607
  *
3529
- * @group Template Documents
3530
- * @api GET /v2/envelope-documents/:document_id Preview, Download, or Link to a Document
3531
- * @apiParam string(format: 'uuid') document_id The ID of the document to retrieve.
3532
- * @apiQuery string(enum:'file'|'download'|'preview') type? Download the file directly, generate a download link, or generate a preview link.
3533
- * @apiSuccess string . The generated link.
3608
+ * ```typescript
3609
+ * import {getActiveEntitlements} from '@verdocs/js-sdk';
3610
+ *
3611
+ * const activeEntitlements = await getActiveEntitlements((VerdocsEndpoint.getDefault());
3612
+ * const isSMSEnabled = !!activeEntitlements.sms_auth;
3613
+ * const monthlyKBALimit = activeEntitlements.kba_auth?.monthly_max;
3614
+ * ```
3534
3615
  */
3535
- const getTemplateDocumentDownloadLink = async (endpoint, _envelopeId, documentId) => endpoint.api //
3536
- .get(`/v2/template-documents/${documentId}?type=download`)
3537
- .then((r) => r.data);
3616
+ const getActiveEntitlements = async (endpoint) => {
3617
+ if (!endpoint.session) {
3618
+ throw new Error('No active session');
3619
+ }
3620
+ const entitlements = await getEntitlements(endpoint);
3621
+ return collapseEntitlements(entitlements);
3622
+ };
3623
+
3538
3624
  /**
3539
- * Get a pre-signed preview link for an Envelope Document. This link expires quickly, so it should
3540
- * be accessed immediately and never shared. Content-Disposition will be set to "inline".
3625
+ * Webhooks are callback triggers from Verdocs to your servers that notify your applications
3626
+ * of various events, such as signing operations.
3627
+ *
3628
+ * @module
3541
3629
  */
3542
- const getTemplateDocumentPreviewLink = async (endpoint, _envelopeId, documentId) => endpoint.api //
3543
- .get(`/v2/envelope-documents/${documentId}?type=preview`)
3544
- .then((r) => r.data);
3545
3630
  /**
3546
- * Get (binary download) a file attached to a Template. It is important to use this method
3547
- * rather than a direct A HREF or similar link to set the authorization headers for the
3548
- * request.
3631
+ * Get the registered Webhook configuration for the caller's organization.
3632
+ *
3633
+ * ```typescript
3634
+ * import {getWebhooks} from '@verdocs/js-sdk';
3635
+ *
3636
+ * await getWebhooks(ORGID, params);
3637
+ * ```
3638
+ *
3639
+ * @group Webhooks
3640
+ * @api GET /v2/webhooks Get organization Webhooks config
3641
+ * @apiSuccess IWebhook . The current Webhooks config for the caller's organization.
3549
3642
  */
3550
- const getTemplateDocumentFile = async (endpoint, templateId, documentId) => endpoint.api //
3551
- .get(`/v2/templates/${templateId}/documents/${documentId}?file=true`, { responseType: 'blob' })
3643
+ const getWebhooks = (endpoint) => endpoint.api //
3644
+ .get(`/v2/webhooks`)
3552
3645
  .then((r) => r.data);
3553
3646
  /**
3554
- * Get (binary download) a file attached to a Template. It is important to use this method
3555
- * rather than a direct A HREF or similar link to set the authorization headers for the
3556
- * request.
3647
+ * Update the registered Webhook configuration for the caller's organization. Note that
3648
+ * Webhooks cannot currently be deleted, but may be easily disabled by setting `active`
3649
+ * to `false` and/or setting the `url` to an empty string.
3650
+ *
3651
+ * ```typescript
3652
+ * import {setWebhooks} from '@verdocs/js-sdk';
3653
+ *
3654
+ * await setWebhooks(ORGID, params);
3655
+ * ```
3656
+ *
3657
+ * @group Webhooks
3658
+ * @api PATCH /v2/webhooks Update organization Webhooks config
3659
+ * @apiDescription Note that Webhooks cannot currently be deleted, but may be easily disabled by setting `active` to `false` and/or setting the `url` to an empty string.
3660
+ * @apiBody string url URL to send Webhook events to. An empty or invalid URL will disable Webhook calls.
3661
+ * @apiBody boolean active Set to true to enable Webhooks calls.
3662
+ * @apiBody object events Record<TWebhookEvent, boolean> map of events to enable/disable.
3663
+ * @apiSuccess IWebhook . The updated Webhooks config for the caller's organization.
3557
3664
  */
3558
- const getTemplateDocumentThumbnail = async (endpoint, templateId, documentId) => endpoint.api //
3559
- .get(`/v2/templates/${templateId}/documents/${documentId}?thumbnail=true`, { responseType: 'blob' })
3665
+ const setWebhooks = (endpoint, params) => endpoint.api //
3666
+ .patch(`/v2/webhooks`, params)
3560
3667
  .then((r) => r.data);
3561
- /**
3562
- * Get a display URI for a given page in a file attached to a template document. These pages are rendered server-side
3563
- * into PNG resources suitable for display in IMG tags although they may be used elsewhere. Note that these are intended
3564
- * for DISPLAY ONLY, are not legally binding documents, and do not contain any encoded metadata from participants. The
3565
- * original asset may be obtained by calling `getTemplateDocumentFile()` or similar.
3566
- */
3567
- const getTemplateDocumentPageDisplayUri = async (endpoint, documentId, page, variant = 'original') => endpoint.api.get(`/v2/template-documents/page-image/${documentId}/${variant}/${page}`, { timeout: 20000 }).then((r) => r.data);
3568
-
3569
- const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
3570
- // @see https://www.regextester.com/1978
3571
- const PHONE_REGEX = /((?:\+|00)[17](?: |\-)?|(?:\+|00)[1-9]\d{0,2}(?: |\-)?|(?:\+|00)1\-\d{3}(?: |\-)?)?(0\d|\([0-9]{3}\)|[1-9]{0,3})(?:((?: |\-)[0-9]{2}){4}|((?:[0-9]{2}){4})|((?: |\-)[0-9]{3}(?: |\-)[0-9]{4})|([0-9]{7}))/;
3572
- const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
3573
- const POSTAL_CODE_REGEX = /^[A-Za-z0-9-\s]{3,10}$/;
3574
- const NUMBER_REGEX = /^\d+$/;
3575
- const DATE_REGEX = /^(\d{4}[-\/]\d{2}[-\/]\d{2})|(\d{2}[-\/]\d{2}[-\/]\d{4})$/;
3576
- const VALIDATORS = {
3577
- email: { regex: EMAIL_REGEX, label: 'Email Address' },
3578
- phone: { regex: PHONE_REGEX, label: 'Phone Number' },
3579
- url: { regex: URL_REGEX, label: 'URL' },
3580
- postal_code: { regex: POSTAL_CODE_REGEX, label: 'Zip/Postal Code' },
3581
- number: { regex: NUMBER_REGEX, label: 'Number' },
3582
- date: { regex: DATE_REGEX, label: 'Date' },
3583
- };
3584
- const isValidInput = (value, validator) => Object.keys(VALIDATORS).includes(validator) && VALIDATORS[validator].regex.test(value);
3585
- /**
3586
- * Get a list of available validators for field inputs. Note that validators always check strings,
3587
- * because that is all a user can enter in an HTML input field. Numeric-format validators should
3588
- * perform any necessary conversions internally. Validators never throw - they just return a boolean.
3589
- * indicating whether the value is valid.
3590
- */
3591
- const getValidators = () => Object.keys(VALIDATORS);
3592
- const isValidEmail = (email) => !!email && EMAIL_REGEX.test(email);
3593
- const isValidPhone = (phone) => !!phone && PHONE_REGEX.test(phone);
3594
- const isValidRoleName = (value, roles) => roles.findIndex((role) => role.name === value) !== -1;
3595
- const TagRegEx = /^[a-zA-Z0-9-]{0,32}$/;
3596
- const isValidTag = (value, tags) => TagRegEx.test(value) || tags.findIndex((tag) => tag === value) !== -1;
3597
3668
 
3598
- export { ALL_PERMISSIONS, AtoB, Countries, DEFAULT_FIELD_HEIGHTS, DEFAULT_FIELD_WIDTHS, FIELD_TYPES, RolePermissions, VerdocsEndpoint, WEBHOOK_EVENTS, acceptOrganizationInvitation, addGroupMember, authenticate, blobToBase64, canAccessEnvelope, canPerformTemplateAction, cancelEnvelope, capitalize, changePassword, collapseEntitlements, convertToE164, createApiKey, createEnvelope, createField, createGroup, createInitials, createOrganization, createOrganizationContact, createOrganizationInvitation, createProfile, createSignature, createTemplate, createTemplateDocument, createTemplateFromSharepoint, createTemplateRole, declineOrganizationInvitation, decodeAccessTokenBody, decodeJWTBody, delegateRecipient, deleteApiKey, deleteEnvelopeFieldAttachment, deleteField, deleteGroup, deleteGroupMember, deleteOrganization, deleteOrganizationContact, deleteOrganizationInvitation, deleteOrganizationMember, deleteProfile, deleteTemplate, deleteTemplateDocument, deleteTemplateRole, downloadBlob, downloadEnvelopeDocument, downloadTemplateDocument, duplicateTemplate, envelopeIsActive, envelopeIsComplete, envelopeRecipientAgree, envelopeRecipientDecline, envelopeRecipientSubmit, fileToDataUrl, formatFullName, formatInitials, formatShortTimeAgo, fullNameToInitials, getActiveEntitlements, getApiKeys, getCountryByCode, getCurrentProfile, getEntitlements, getEnvelope, getEnvelopeDocument, getEnvelopeDocumentDownloadLink, getEnvelopeDocumentPageDisplayUri, getEnvelopeDocumentPreviewLink, getEnvelopeFile, getEnvelopes, getFieldsForRole, getGroup, getGroups, getInPersonLink, getKbaStep, getMatchingCountry, getMyUser, getNextRecipient, getNotifications, getOrganization, getOrganizationChildren, getOrganizationContacts, getOrganizationInvitation, getOrganizationInvitations, getOrganizationMembers, getOrganizationUsage, getPlusOneCountry, getProfiles, getRGB, getRGBA, getRLeft, getRTop, getRValue, getRecipientsWithActions, getRoleColor, getTemplate, getTemplateDocument, getTemplateDocumentDownloadLink, getTemplateDocumentFile, getTemplateDocumentPageDisplayUri, getTemplateDocumentPreviewLink, getTemplateDocumentThumbnail, getTemplates, getValidators, getWebhooks, hasRequiredPermissions, integerSequence, isAmericanSamoa, isCanada, isDominicanRepublic, isEnvelopeOwner, isEnvelopeRecipient, isFrenchGuiana, isGuadeloupe, isMartinique, isMayotte, isPuertoRico, isValidEmail, isValidInput, isValidPhone, isValidRoleName, isValidTag, nameToRGBA, randomString, recipientCanAct, recipientHasAction, refreshToken, remindRecipient, rescale, resendOrganizationInvitation, resendVerification, resetPassword, resetRecipient, rotateApiKey, setWebhooks, sortFields, startSigningSession, submitKbaChallengeResponse, submitKbaIdentity, submitKbaPin, switchProfile, toggleTemplateStar, updateApiKey, updateEnvelope, updateEnvelopeField, updateField, updateGroup, updateOrganization, updateOrganizationContact, updateOrganizationInvitation, updateOrganizationLogo, updateOrganizationMember, updateOrganizationThumbnail, updateProfile, updateProfilePhoto, updateRecipient, updateTemplate, updateTemplateRole, uploadEnvelopeFieldAttachment, useCanAccessEnvelope, userCanAct, userCanBuildTemplate, userCanCancelEnvelope, userCanChangeOrgVisibility, userCanCreateOrgTemplate, userCanCreatePersonalTemplate, userCanCreatePublicTemplate, userCanCreateTemplate, userCanDeleteTemplate, userCanFinishEnvelope, userCanMakeTemplatePrivate, userCanMakeTemplatePublic, userCanMakeTemplateShared, userCanPreviewTemplate, userCanReadTemplate, userCanSendTemplate, userCanSignNow, userCanUpdateTemplate, userHasPermissions, userHasSharedTemplate, userIsEnvelopeOwner, userIsEnvelopeRecipient, userIsTemplateCreator, verifyEmail, verifySigner };
3669
+ export { ALL_PERMISSIONS, AtoB, Countries, DEFAULT_DISCLOSURES, DEFAULT_FIELD_HEIGHTS, DEFAULT_FIELD_WIDTHS, FIELD_TYPES, RolePermissions, VerdocsEndpoint, WEBHOOK_EVENTS, acceptOrganizationInvitation, addGroupMember, authenticate, blobToBase64, canAccessEnvelope, canPerformTemplateAction, cancelEnvelope, capitalize, changePassword, collapseEntitlements, convertToE164, createApiKey, createEnvelope, createField, createGroup, createInitials, createOrganization, createOrganizationContact, createOrganizationInvitation, createProfile, createSignature, createTemplate, createTemplateDocument, createTemplateFromSharepoint, createTemplateRole, declineOrganizationInvitation, decodeAccessTokenBody, decodeJWTBody, delegateRecipient, deleteApiKey, deleteEnvelopeFieldAttachment, deleteField, deleteGroup, deleteGroupMember, deleteOrganization, deleteOrganizationContact, deleteOrganizationInvitation, deleteOrganizationMember, deleteProfile, deleteTemplate, deleteTemplateDocument, deleteTemplateRole, downloadBlob, downloadEnvelopeDocument, downloadTemplateDocument, duplicateTemplate, envelopeIsActive, envelopeIsComplete, envelopeRecipientAgree, envelopeRecipientDecline, envelopeRecipientSubmit, fileToDataUrl, formatFullName, formatInitials, formatShortTimeAgo, fullNameToInitials, getActiveEntitlements, getApiKeys, getCountryByCode, getCurrentProfile, getEntitlements, getEnvelope, getEnvelopeDocument, getEnvelopeDocumentDownloadLink, getEnvelopeDocumentPageDisplayUri, getEnvelopeDocumentPreviewLink, getEnvelopeFile, getEnvelopes, getEnvelopesZip, getFieldsForRole, getGroup, getGroups, getInPersonLink, getKbaStep, getMatchingCountry, getMyUser, getNextRecipient, getNotifications, getOrganization, getOrganizationChildren, getOrganizationContacts, getOrganizationInvitation, getOrganizationInvitations, getOrganizationMembers, getOrganizationUsage, getPlusOneCountry, getProfiles, getRGB, getRGBA, getRLeft, getRTop, getRValue, getRecipientsWithActions, getRoleColor, getTemplate, getTemplateDocument, getTemplateDocumentDownloadLink, getTemplateDocumentFile, getTemplateDocumentPageDisplayUri, getTemplateDocumentPreviewLink, getTemplateDocumentThumbnail, getTemplates, getValidators, getWebhooks, hasRequiredPermissions, integerSequence, isAmericanSamoa, isCanada, isDominicanRepublic, isEnvelopeOwner, isEnvelopeRecipient, isFieldFilled, isFieldValid, isFrenchGuiana, isGuadeloupe, isMartinique, isMayotte, isPuertoRico, isValidEmail, isValidInput, isValidPhone, isValidRoleName, isValidTag, nameToRGBA, randomString, recipientCanAct, recipientHasAction, refreshToken, remindRecipient, rescale, resendOrganizationInvitation, resendVerification, resetPassword, resetRecipient, rotateApiKey, setWebhooks, sortFields, startSigningSession, submitKbaChallengeResponse, submitKbaIdentity, submitKbaPin, switchProfile, toggleTemplateStar, updateApiKey, updateEnvelope, updateEnvelopeField, updateField, updateGroup, updateOrganization, updateOrganizationContact, updateOrganizationInvitation, updateOrganizationLogo, updateOrganizationMember, updateOrganizationThumbnail, updateProfile, updateProfilePhoto, updateRecipient, updateTemplate, updateTemplateRole, uploadEnvelopeFieldAttachment, useCanAccessEnvelope, userCanAct, userCanBuildTemplate, userCanCancelEnvelope, userCanChangeOrgVisibility, userCanCreateOrgTemplate, userCanCreatePersonalTemplate, userCanCreatePublicTemplate, userCanCreateTemplate, userCanDeleteTemplate, userCanFinishEnvelope, userCanMakeTemplatePrivate, userCanMakeTemplatePublic, userCanMakeTemplateShared, userCanPreviewTemplate, userCanReadTemplate, userCanSendTemplate, userCanSignNow, userCanUpdateTemplate, userHasPermissions, userHasSharedTemplate, userIsEnvelopeOwner, userIsEnvelopeRecipient, userIsTemplateCreator, verifyEmail, verifySigner };
3599
3670
  //# sourceMappingURL=index.mjs.map