Skip to content

VCSP

vericlient.vcsp.client.VcspClient

Bases: Client

Class to interact with the VCSP API.

Source code in src/vericlient/vcsp/client.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
class VcspClient(Client):
    """Class to interact with the VCSP API."""

    def __init__(
        self,
        apikey: str | None = None,
        timeout: int | None = None,
        environment: str | None = None,
        location: str | None = None,
        url: str | None = None,
        headers: dict | None = None,
    ) -> None:
        """Create the VcspClient class.

        Args:
            apikey: The API key to use
            timeout: The timeout to use in the requests
            environment: The environment to use
            location: The location to use
            url: The URL to use in case of a custom target
            headers: The headers to be used in the requests

        """
        super().__init__(
            api=APIs.VCSP,
            apikey=apikey,
            timeout=timeout,
            environment=environment,
            location=location,
            url=url,
            headers=headers,
        )
        self._exceptions = {
            "empty_file": EmptyFileError,
            "invalid_claims": InvalidClaimsError,
            "invalid_assurance": InvalidAssuranceError,
            "invalid_tags": InvalidTagsError,
            "invalid_credential_configuration_urn": InvalidCredentialConfigurationUrnError,
            "invalid_assurance_method_urn": InvalidAssuranceMethodUrnError,
            "credential_configuration_urn_already_assigned": CredentialConfigurationUrnAlreadyAssignedError,
            "invalid_audio_format": InvalidAudioFormatError,
            "invalid_signal_noise_ratio": InvalidSnrError,
            "voice_duration_is_not_enough": VoiceDurationIsNotEnoughError,
            "insufficient_quality": InsufficientQualityError,
            "face_not_found": FaceNotFoundError,
            "more_than_one_face": MoreThanOneFaceError,
            "face_too_small_for_ias": FaceTooSmallError,
            "face_alignment": FaceAlignmentError,
            "assurance_validation_error": AssuranceValidationError,
            "assurance_method_not_found": AssuranceMethodNotFoundError,
            "account_not_found": AccountNotFoundError,
            "credential_not_found": CredentialNotFoundError,
            "request_validation_error": RequestValidationError,
            "unsupported_media_type": UnsupportedMediaTypeError,
            "groups_limit_exceeded": GroupsLimitExceededError,
            "enrollments_limit_exceeded": EnrollmentsLimitExceededError,
            "group_already_exists": GroupAlreadyExistsError,
            "group_not_found": GroupNotFoundError,
            "tags_limit_exceeded": TagsLimitExceededError,
            "tag_list_empty": TagListEmptyError,
            "tags_already_exist": TagAlreadyExistsError,
            "task_not_found": TaskNotFoundError,
            "invalid_batch_file": InvalidBatchFileError,
            "clustering_not_supported": ClusteringNotSupportedError,
        }

    def alive(self) -> bool:
        """Check if the service is alive.

        Returns
            bool: True if the service is alive, False otherwise

        """
        response = self._get(endpoint=VcspEndpoints.ALIVE.value)
        accepted_status_code = 204
        return response.status_code == accepted_status_code

    def _handle_error_response(self, response: Response) -> None:
        """Handle error responses from the API."""
        response_json = self._error_payload(response)

        exception = response_json.get("error")
        if not exception or exception not in self._exceptions:
            self._raise_server_error(response)

        if exception == "request_validation_error":
            raise RequestValidationError(response_json["details"])

        handler = self._exceptions[exception]
        raise handler()

    def list_credentials(self, data_model: ListCredentialsInput | None = None) -> ListCredentialsOutput:
        """List credentials across the whole system, optionally filtered.

        Unlike `get_all_subject_credentials`, this is not scoped to one account. Deployments
        hold a lot of credentials, so filter and page rather than walking everything.

        Args:
            data_model: The filters to apply. Omit it to list without filtering

        Returns:
            ListCredentialsOutput: A page of credentials

        """
        data_model = data_model or ListCredentialsInput()
        response = self._get(
            endpoint=VcspEndpoints.ALL_CREDENTIALS.value,
            params=data_model.model_dump(exclude_none=True),
        )
        return ListCredentialsOutput(**response.json())

    def delete_credentials(self, data_model: DeleteCredentialsInput) -> None:
        """Delete every credential in a group.

        Irreversible. The credentials are removed from any other group they belong to, and
        with `delete_empty_accounts` the accounts left holding nothing go too.

        Args:
            data_model: The group to empty, and whether to remove the accounts left behind

        Raises:
            GroupNotFoundError: If no group exists with that name

        """
        self._delete(
            endpoint=VcspEndpoints.ALL_CREDENTIALS.value,
            json_=data_model.model_dump(),
        )

    def get_credential_sample(self, data_model: GetCredentialSampleInput) -> GetCredentialSampleOutput:
        """Get the sample a credential was created from.

        The service answers with the raw bytes rather than JSON, so the media type comes
        from the response header.

        Args:
            data_model: The subject and credential to retrieve the sample of

        Returns:
            GetCredentialSampleOutput: The sample and its media type

        Raises:
            AccountNotFoundError: If the account is not found
            CredentialNotFoundError: If the credential is not found

        """
        endpoint = VcspEndpoints.CREDENTIAL_SAMPLE.value.replace("<subject_id>", data_model.subject_id)
        endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
        response = self._get(endpoint=endpoint)
        return GetCredentialSampleOutput(
            content=response.content,
            content_type=response.headers.get("content-type", DEFAULT_CONTENT_TYPE),
        )

    def get_credential_configuration(self, data_model: CredentialConfigurationInput) -> CredentialConfigurationOutput:
        """Get one credential configuration, including the schema its claims must satisfy.

        Args:
            data_model: The urn of the credential configuration

        Returns:
            CredentialConfigurationOutput: The configuration and its claims schema

        Raises:
            InvalidCredentialConfigurationUrnError: If no configuration exists with that urn

        """
        endpoint = VcspEndpoints.CREDENTIAL_CONFIGURATION_URN.value.replace("<urn>", data_model.urn)
        response = self._get(endpoint=endpoint)
        return CredentialConfigurationOutput(**response.json())

    def enroll_batch(self, data_model: BatchEnrollmentInput) -> BatchEnrollmentOutput:
        """Enrol several applicants at once.

        The work happens asynchronously. Follow it with `get_task`, or block on
        `wait_for_task`, and collect the outcome with `get_task_result`.

        Pass `applicants` and the client builds the archive the service expects. Neither the
        `applicants.json` name nor the `file://` reference its entries use is documented;
        both were found by reading the service's errors.

        Args:
            data_model: The enrolments to perform, or a prepared TAR archive

        Returns:
            BatchEnrollmentOutput: The task the enrolments run under

        Raises:
            InvalidBatchFileError: If the archive is malformed or a sample is missing

        """
        if data_model.batch_file is not None:
            archive = get_virtual_file(data_model.batch_file)
        else:
            entries = [
                (
                    sample_filename(applicant.sample, index, applicant.filename),
                    get_virtual_file(applicant.sample),
                    applicant.applicant.model_dump(exclude_none=True),
                )
                for index, applicant in enumerate(data_model.applicants)
            ]
            archive = build_batch_archive(entries)

        response = self._post(
            endpoint=VcspEndpoints.ENROLLMENTS_BATCH.value,
            files={"batch_file": ("batch.tar", archive, "application/x-tar")},
        )
        return BatchEnrollmentOutput(**response.json())

    def get_tasks(self) -> GetTasksOutput:
        """List the asynchronous tasks the service is still holding.

        Returns:
            GetTasksOutput: The active tasks, paginated

        """
        response = self._get(endpoint=VcspEndpoints.TASKS.value)
        return GetTasksOutput(**response.json())

    def get_task(self, data_model: TaskInput) -> TaskOutput:
        """Get the state of one asynchronous task.

        Args:
            data_model: The task to look up

        Returns:
            TaskOutput: Its status and progress

        Raises:
            TaskNotFoundError: If no task exists with that identifier

        """
        endpoint = VcspEndpoints.TASK_ID.value.replace("<task_id>", data_model.task_id)
        response = self._get(endpoint=endpoint)
        return TaskOutput(**response.json())

    def delete_task(self, data_model: TaskInput) -> None:
        """Delete a task and its result.

        Tasks expire on their own, but a long-running caller is better off tidying up.

        Args:
            data_model: The task to delete

        Raises:
            TaskNotFoundError: If no task exists with that identifier

        """
        endpoint = VcspEndpoints.TASK_ID.value.replace("<task_id>", data_model.task_id)
        self._delete(endpoint=endpoint)

    def get_task_result(self, data_model: TaskInput) -> GetTaskResultOutput:
        """Get the outcome of a finished task.

        The shape depends on what created the task, so it comes back as a dictionary.

        Args:
            data_model: The task to collect

        Returns:
            GetTaskResultOutput: The outcome, as the service returned it

        Raises:
            TaskNotFoundError: If no task exists with that identifier

        """
        endpoint = VcspEndpoints.TASK_RESULT.value.replace("<task_id>", data_model.task_id)
        response = self._get(endpoint=endpoint)
        return GetTaskResultOutput(result=response.json())

    def wait_for_task(
        self,
        data_model: TaskInput,
        timeout: float = 300,
        poll_interval: float = 2,
    ) -> TaskOutput:
        """Block until a task finishes, and return its final state.

        Saves every caller writing the same polling loop. It returns on failure as well as on
        success, so check `succeeded` on the result.

        Args:
            data_model: The task to wait for
            timeout: How long to wait, in seconds, before giving up
            poll_interval: How long to sleep between checks, in seconds

        Returns:
            TaskOutput: The task in its final state

        Raises:
            TaskNotFoundError: If no task exists with that identifier
            TimeoutError: If the task has not finished within `timeout`

        """
        deadline = time.monotonic() + timeout
        while True:
            task = self.get_task(data_model=data_model)
            if task.is_finished:
                return task
            if time.monotonic() >= deadline:
                error = f"Task {data_model.task_id} did not finish within {timeout} seconds"
                raise TimeoutError(error)
            time.sleep(poll_interval)

    def match(self, data_model: MatchingInput) -> MatchingOutput | TaskCreatedOutput:
        """Match a sample against one subject or against a whole group.

        Pass a `SubjectClaimant` for 1:1 or a `GroupClaimant` for 1:N. Small operations
        answer straight away with a `MatchingOutput`; a large one is accepted and run
        asynchronously, answering with a `TaskCreatedOutput` to follow with `wait_for_task`.

        Args:
            data_model: The sample and what to match it against

        Returns:
            MatchingOutput when the service answered directly, TaskCreatedOutput when it
            queued the work

        Raises:
            AccountNotFoundError: If the subject does not exist
            GroupNotFoundError: If the group does not exist
            InvalidAssuranceError: If the assurance does not satisfy its method's schema

        """
        filename, sample, content_type = self._get_sample(data_model.sample, data_model.content_type)
        data = {"claimant": json.dumps(data_model.claimant.model_dump(exclude_none=True))}
        if data_model.sample_processing is not None:
            data["sample_processing"] = json.dumps(data_model.sample_processing)

        response = self._post(
            endpoint=VcspEndpoints.MATCHINGS.value,
            files={"sample": (filename, sample, content_type)},
            data=data,
        )
        accepted = 202
        if response.status_code == accepted:
            return TaskCreatedOutput(**response.json())
        return MatchingOutput(**response.json())

    def modify_group(self, data_model: ModifyGroupInput) -> GetGroupOutput | TaskCreatedOutput:
        """Add credentials to a group, remove them, or change the group's own details.

        A small change answers directly with the group; a large population is accepted and
        run asynchronously.

        Args:
            data_model: The group, the action, and what it applies to

        Returns:
            GetGroupOutput when the service answered directly, TaskCreatedOutput when it
            queued the work

        Raises:
            GroupNotFoundError: If the group does not exist
            AccountNotFoundError: If one of the subjects does not exist

        """
        endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
        body = data_model.model_dump(exclude_none=True, by_alias=True, exclude={"name"})
        response = self._patch(endpoint=endpoint, json_=body)
        accepted = 202
        if response.status_code == accepted:
            return TaskCreatedOutput(**response.json())
        return GetGroupOutput(**response.json())

    def modify_credential_tags(self, data_model: ModifyCredentialTagsInput) -> GetCredentialOutput:
        """Add or remove tags on one credential.

        The tags have to exist already: create them with `create_tags` first.

        Args:
            data_model: The credential, the action, and the tags

        Returns:
            GetCredentialOutput: The credential as it now stands

        Raises:
            CredentialNotFoundError: If the credential is not found
            AccountNotFoundError: If the account is not found
            InvalidTagsError: If one of the tags does not exist

        """
        endpoint = VcspEndpoints.CREDENTIAL_TAGS.value.replace("<subject_id>", data_model.subject_id)
        endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
        response = self._patch(
            endpoint=endpoint,
            json_={"action": data_model.action, "tags": data_model.tags},
        )
        return GetCredentialOutput(**response.json())

    def start_clustering(self, data_model: ClusteringInput) -> TaskCreatedOutput:
        """Start a clustering task over a group.

        Only groups of face credentials can be clustered; a voice group is rejected.

        Args:
            data_model: The group and the clustering assurance method to apply

        Returns:
            TaskCreatedOutput: The task the clustering runs under

        Raises:
            GroupNotFoundError: If the group does not exist
            ClusteringNotSupportedError: If the group does not hold face credentials

        """
        endpoint = VcspEndpoints.GROUP_CLUSTERING.value.replace("<group_name>", data_model.name)
        response = self._post(
            endpoint=endpoint,
            json_={
                "assurance_method_urn": data_model.assurance_method_urn,
                "properties": data_model.properties,
            },
        )
        return TaskCreatedOutput(**response.json())

    def get_credential_configurations(self) -> CredentialConfigurationsOutput:
        """Get all credential configurations.

        Returns:
            CredentialConfigurationsOutput: The output of the credential configurations

        """
        endpoint = VcspEndpoints.CREDENTIAL_CONFIGURATIONS.value
        response = self._get(endpoint=endpoint)
        return CredentialConfigurationsOutput(
            credential_configurations=response.json(),
        )

    def get_assurance_methods(self) -> AssuranceMethodsOutput:
        """Get all assurance methods.

        Returns:
            AssuranceMethodsOutput: The output of the assurance methods

        """
        endpoint = VcspEndpoints.ASSURANCE_METHODS.value
        response = self._get(endpoint=endpoint)
        return AssuranceMethodsOutput(
            assurance_methods=response.json(),
        )

    def get_assurance_method_info(self, data_model: AssuranceMethodInput) -> AssuranceMethodOutput:
        """Get an assurance method.

        Args:
            data_model: The input to get the assurance method

        Returns:
            AssuranceMethodOutput: The output of the assurance method

        """
        endpoint = VcspEndpoints.ASSURANCE_METHOD_URN.value.replace("<urn>", data_model.urn)
        response = self._get(endpoint=endpoint)
        return AssuranceMethodOutput(**response.json())

    def enroll_subject(self, data_model: EnrollmentInput) -> EnrollmentOutput:
        """Enroll a subject.

        Args:
            data_model: The input to enroll the subject

        Returns:
            EnrollmentOutput: The output of the enrollment

        Raises:
            EmptyFileError: If the file is empty
            InvalidClaimsError: If the claims are invalid
            InvalidAssuranceError: If the assurance is invalid
            InvalidTagsError: If the tags are invalid
            InvalidCredentialConfigurationUrnError: If the credential configuration urn is invalid
            InvalidAssuranceMethodUrnError: If the assurance method urn is invalid
            CredentialConfigurationUrnAlreadyAssignedError: If the credential configuration urn is already assigned
            InvalidAudioFormatError: If the audio format is invalid
            InvalidSnrError: If the signal noise ratio is invalid
            VoiceDurationIsNotEnoughError: If the voice duration is not enough
            InsufficientQualityError: If the quality is insufficient
            FaceAlignmentError: If the face is not aligned
            FaceNotFoundError: If the face is not found
            FaceTooSmallError: If the face is too small
            MoreThanOneFaceError: If there is more than one face
            AssuranceValidationError: If the assurance is invalid
            RequestValidationError: If the request is invalid
            UnsupportedMediaTypeError: If the media type is not supported

        """
        endpoint = VcspEndpoints.ENROLLMENTS.value
        sample = self._get_sample(data_model.sample, data_model.content_type)
        files = {"sample": sample}
        data = {"applicant": json.dumps(data_model.applicant.model_dump(exclude_none=True))}
        response = self._post(
            endpoint=endpoint,
            files=files,
            data=data,
        )
        return EnrollmentOutput(**response.json())

    def _get_sample(self, sample: str | bytes, content_type: str | None = None) -> tuple[str, bytes, str]:
        """Return the filename, the content and the media type of a sample.

        Args:
            sample: A path to a file, or the content itself as bytes
            content_type: Media type to declare. When omitted it is taken from the file
                extension for a path, and from the magic bytes for a bytes object

        Returns:
            The filename, the content and the media type to send

        Raises:
            TypeError: If `sample` is neither a string nor a bytes object

        """
        if isinstance(sample, str):
            filename = os.path.basename(sample)
            with open(sample, "rb") as f:
                file = f.read()
            guessed = mimetypes.guess_type(sample)[0]
        elif isinstance(sample, bytes):
            filename = "sample"
            file = sample
            guessed = guess_content_type(sample)
        else:
            error = "sample must be a string or a bytes object"
            raise TypeError(error)
        return filename, file, content_type or guessed or DEFAULT_CONTENT_TYPE

    def get_account(self, data_model: GetAccountInput) -> GetAccountOutput:
        """Get an account.

        Args:
            data_model: The input to get the account

        Returns:
            GetAccountOutput: The output of the account

        Raises:
            AccountNotFoundError: If the account is not found

        """
        endpoint = VcspEndpoints.ACCOUNTS.value.replace("<subject_id>", data_model.subject_id)
        response = self._get(endpoint=endpoint)
        return GetAccountOutput(**response.json())

    def delete_account(self, data_model: DeleteAccountInput) -> None:
        """Delete an account.

        Args:
            data_model: The input to delete the account

        Raises:
            AccountNotFoundError: If the account is not found

        """
        endpoint = VcspEndpoints.ACCOUNTS.value.replace("<subject_id>", data_model.subject_id)
        self._delete(endpoint=endpoint)

    def get_all_subject_credentials(self, data_model: GetCredentialsInput) -> GetCredentialsOutput:
        """Get all credentials for a subject.

        Args:
            data_model: The input to get all credentials for the subject

        Returns:
            GetCredentialsOutput: The output of the credentials

        Raises:
            AccountNotFoundError: If the account is not found

        """
        endpoint = VcspEndpoints.CREDENTIALS.value.replace("<subject_id>", data_model.subject_id)
        response = self._get(endpoint=endpoint)
        return GetCredentialsOutput(credentials=response.json())

    def get_credential(self, data_model: GetCredentialInput) -> GetCredentialOutput:
        """Get a credential.

        Args:
            data_model: The input to get the credential

        Returns:
            GetCredentialOutput: The output of the credential

        Raises:
            CredentialNotFoundError: If the credential is not found
            AccountNotFoundError: If the account is not found

        """
        endpoint = VcspEndpoints.CREDENTIAL_ID.value.replace("<subject_id>", data_model.subject_id)
        endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
        response = self._get(endpoint=endpoint)
        return GetCredentialOutput(**response.json())

    def delete_credential(self, data_model: DeleteCredentialInput) -> None:
        """Delete a credential.

        Args:
            data_model: The input to delete the credential

        """
        endpoint = VcspEndpoints.CREDENTIAL_ID.value.replace("<subject_id>", data_model.subject_id)
        endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
        self._delete(endpoint=endpoint)

    def create_tags(self, data_model: CreateTagsInput) -> CreateTagsOutput:
        """Create tags.

        Args:
            data_model: The input to create the tags

        Returns:
            CreateTagsOutput: The output of the tags creation

        Raises:
            TagsLimitExceededError: If the tag limit is exceeded
            TagAlreadyExistsError: If the tag already exists
            TagListEmptyError: If the tag list is empty

        """
        endpoint = VcspEndpoints.TAGS.value
        response = self._post(endpoint=endpoint, json_=data_model.model_dump())
        return CreateTagsOutput(**response.json())

    def get_tags(self) -> GetTagsOutput:
        """Get every tag created in the system.

        Returns:
            GetTagsOutput: The tags, paginated

        """
        endpoint = VcspEndpoints.TAGS.value
        response = self._get(endpoint=endpoint)
        return GetTagsOutput(**response.json())

    def delete_tag(self, data_model: DeleteTagInput) -> None:
        """Delete a tag.

        Args:
            data_model: The input to delete the tag

        Raises:
            InvalidTagsError: If the tag is invalid

        """
        endpoint = VcspEndpoints.TAGS_NAME.value.replace("<tag_name>", data_model.name)
        self._delete(endpoint=endpoint)

    def create_group(self, data_model: CreateGroupInput) -> CreateGroupOutput:
        """Create a group.

        Args:
            data_model: The input to create the group

        Returns:
            CreateGroupOutput: The output of the group creation

        Raises:
            GroupsLimitExceededError: If the group limit is exceeded
            GroupAlreadyExistsError: If the group already exists
            InvalidCredentialConfigurationUrnError: If the credential configuration urn is invalid

        """
        endpoint = VcspEndpoints.GROUPS.value
        response = self._post(endpoint=endpoint, json_=data_model.model_dump(exclude_none=True))
        return CreateGroupOutput(**response.json())

    def get_groups(self, data_model: GetGroupsInput) -> GetGroupsOutput:
        """Get all groups.

        Args:
            data_model: The input to get the groups

        Returns:
            GetGroupsOutput: The output of the groups

        """
        endpoint = VcspEndpoints.GROUPS.value
        endpoint = endpoint + f"?size={data_model.size}&page={data_model.page}"
        response = self._get(endpoint=endpoint)
        items = response.json()["items"]
        total = response.json()["total"]
        page = response.json()["page"]
        size = response.json()["size"]
        pages = response.json()["pages"]
        return GetGroupsOutput(
            items=items,
            total=total,
            page=page,
            size=size,
            pages=pages,
        )

    def get_group(self, data_model: GetGroupInput) -> GetGroupOutput:
        """Get a group.

        Args:
            data_model: The input to get the group

        Returns:
            GetGroupOutput: The output of the group

        Raises:
            GroupNotFoundError: If the group is not found

        """
        endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
        response = self._get(endpoint=endpoint)
        return GetGroupOutput(**response.json())

    def delete_group(self, data_model: DeleteGroupInput) -> None:
        """Delete a group.

        Args:
            data_model: The input to delete the group

        Raises:
            GroupNotFoundError: If the group is not found

        """
        endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
        self._delete(endpoint=endpoint)

    def get_group_members(self, data_model: GetGroupMembersInput) -> GetGroupMembersOutput:
        """Get the members of a group.

        Args:
            data_model: The input to get the members of the group

        Returns:
            GetGroupMembersOutput: The output of the group members

        Raises:
            GroupNotFoundError: If the group is not found

        """
        endpoint = VcspEndpoints.GROUP_MEMBERS.value.replace("<group_name>", data_model.name)
        response = self._get(endpoint=endpoint)
        return GetGroupMembersOutput(**response.json())

alive

alive()

Check if the service is alive.

Returns bool: True if the service is alive, False otherwise

Source code in src/vericlient/vcsp/client.py
def alive(self) -> bool:
    """Check if the service is alive.

    Returns
        bool: True if the service is alive, False otherwise

    """
    response = self._get(endpoint=VcspEndpoints.ALIVE.value)
    accepted_status_code = 204
    return response.status_code == accepted_status_code

list_credentials

list_credentials(data_model=None)

List credentials across the whole system, optionally filtered.

Unlike get_all_subject_credentials, this is not scoped to one account. Deployments hold a lot of credentials, so filter and page rather than walking everything.

Parameters:

Name Type Description Default
data_model ListCredentialsInput | None

The filters to apply. Omit it to list without filtering

None

Returns:

Name Type Description
ListCredentialsOutput ListCredentialsOutput

A page of credentials

Source code in src/vericlient/vcsp/client.py
def list_credentials(self, data_model: ListCredentialsInput | None = None) -> ListCredentialsOutput:
    """List credentials across the whole system, optionally filtered.

    Unlike `get_all_subject_credentials`, this is not scoped to one account. Deployments
    hold a lot of credentials, so filter and page rather than walking everything.

    Args:
        data_model: The filters to apply. Omit it to list without filtering

    Returns:
        ListCredentialsOutput: A page of credentials

    """
    data_model = data_model or ListCredentialsInput()
    response = self._get(
        endpoint=VcspEndpoints.ALL_CREDENTIALS.value,
        params=data_model.model_dump(exclude_none=True),
    )
    return ListCredentialsOutput(**response.json())

delete_credentials

delete_credentials(data_model)

Delete every credential in a group.

Irreversible. The credentials are removed from any other group they belong to, and with delete_empty_accounts the accounts left holding nothing go too.

Parameters:

Name Type Description Default
data_model DeleteCredentialsInput

The group to empty, and whether to remove the accounts left behind

required

Raises:

Type Description
GroupNotFoundError

If no group exists with that name

Source code in src/vericlient/vcsp/client.py
def delete_credentials(self, data_model: DeleteCredentialsInput) -> None:
    """Delete every credential in a group.

    Irreversible. The credentials are removed from any other group they belong to, and
    with `delete_empty_accounts` the accounts left holding nothing go too.

    Args:
        data_model: The group to empty, and whether to remove the accounts left behind

    Raises:
        GroupNotFoundError: If no group exists with that name

    """
    self._delete(
        endpoint=VcspEndpoints.ALL_CREDENTIALS.value,
        json_=data_model.model_dump(),
    )

get_credential_sample

get_credential_sample(data_model)

Get the sample a credential was created from.

The service answers with the raw bytes rather than JSON, so the media type comes from the response header.

Parameters:

Name Type Description Default
data_model GetCredentialSampleInput

The subject and credential to retrieve the sample of

required

Returns:

Name Type Description
GetCredentialSampleOutput GetCredentialSampleOutput

The sample and its media type

Raises:

Type Description
AccountNotFoundError

If the account is not found

CredentialNotFoundError

If the credential is not found

Source code in src/vericlient/vcsp/client.py
def get_credential_sample(self, data_model: GetCredentialSampleInput) -> GetCredentialSampleOutput:
    """Get the sample a credential was created from.

    The service answers with the raw bytes rather than JSON, so the media type comes
    from the response header.

    Args:
        data_model: The subject and credential to retrieve the sample of

    Returns:
        GetCredentialSampleOutput: The sample and its media type

    Raises:
        AccountNotFoundError: If the account is not found
        CredentialNotFoundError: If the credential is not found

    """
    endpoint = VcspEndpoints.CREDENTIAL_SAMPLE.value.replace("<subject_id>", data_model.subject_id)
    endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
    response = self._get(endpoint=endpoint)
    return GetCredentialSampleOutput(
        content=response.content,
        content_type=response.headers.get("content-type", DEFAULT_CONTENT_TYPE),
    )

get_credential_configuration

get_credential_configuration(data_model)

Get one credential configuration, including the schema its claims must satisfy.

Parameters:

Name Type Description Default
data_model CredentialConfigurationInput

The urn of the credential configuration

required

Returns:

Name Type Description
CredentialConfigurationOutput CredentialConfigurationOutput

The configuration and its claims schema

Raises:

Type Description
InvalidCredentialConfigurationUrnError

If no configuration exists with that urn

Source code in src/vericlient/vcsp/client.py
def get_credential_configuration(self, data_model: CredentialConfigurationInput) -> CredentialConfigurationOutput:
    """Get one credential configuration, including the schema its claims must satisfy.

    Args:
        data_model: The urn of the credential configuration

    Returns:
        CredentialConfigurationOutput: The configuration and its claims schema

    Raises:
        InvalidCredentialConfigurationUrnError: If no configuration exists with that urn

    """
    endpoint = VcspEndpoints.CREDENTIAL_CONFIGURATION_URN.value.replace("<urn>", data_model.urn)
    response = self._get(endpoint=endpoint)
    return CredentialConfigurationOutput(**response.json())

enroll_batch

enroll_batch(data_model)

Enrol several applicants at once.

The work happens asynchronously. Follow it with get_task, or block on wait_for_task, and collect the outcome with get_task_result.

Pass applicants and the client builds the archive the service expects. Neither the applicants.json name nor the file:// reference its entries use is documented; both were found by reading the service's errors.

Parameters:

Name Type Description Default
data_model BatchEnrollmentInput

The enrolments to perform, or a prepared TAR archive

required

Returns:

Name Type Description
BatchEnrollmentOutput BatchEnrollmentOutput

The task the enrolments run under

Raises:

Type Description
InvalidBatchFileError

If the archive is malformed or a sample is missing

Source code in src/vericlient/vcsp/client.py
def enroll_batch(self, data_model: BatchEnrollmentInput) -> BatchEnrollmentOutput:
    """Enrol several applicants at once.

    The work happens asynchronously. Follow it with `get_task`, or block on
    `wait_for_task`, and collect the outcome with `get_task_result`.

    Pass `applicants` and the client builds the archive the service expects. Neither the
    `applicants.json` name nor the `file://` reference its entries use is documented;
    both were found by reading the service's errors.

    Args:
        data_model: The enrolments to perform, or a prepared TAR archive

    Returns:
        BatchEnrollmentOutput: The task the enrolments run under

    Raises:
        InvalidBatchFileError: If the archive is malformed or a sample is missing

    """
    if data_model.batch_file is not None:
        archive = get_virtual_file(data_model.batch_file)
    else:
        entries = [
            (
                sample_filename(applicant.sample, index, applicant.filename),
                get_virtual_file(applicant.sample),
                applicant.applicant.model_dump(exclude_none=True),
            )
            for index, applicant in enumerate(data_model.applicants)
        ]
        archive = build_batch_archive(entries)

    response = self._post(
        endpoint=VcspEndpoints.ENROLLMENTS_BATCH.value,
        files={"batch_file": ("batch.tar", archive, "application/x-tar")},
    )
    return BatchEnrollmentOutput(**response.json())

get_tasks

get_tasks()

List the asynchronous tasks the service is still holding.

Returns:

Name Type Description
GetTasksOutput GetTasksOutput

The active tasks, paginated

Source code in src/vericlient/vcsp/client.py
def get_tasks(self) -> GetTasksOutput:
    """List the asynchronous tasks the service is still holding.

    Returns:
        GetTasksOutput: The active tasks, paginated

    """
    response = self._get(endpoint=VcspEndpoints.TASKS.value)
    return GetTasksOutput(**response.json())

get_task

get_task(data_model)

Get the state of one asynchronous task.

Parameters:

Name Type Description Default
data_model TaskInput

The task to look up

required

Returns:

Name Type Description
TaskOutput TaskOutput

Its status and progress

Raises:

Type Description
TaskNotFoundError

If no task exists with that identifier

Source code in src/vericlient/vcsp/client.py
def get_task(self, data_model: TaskInput) -> TaskOutput:
    """Get the state of one asynchronous task.

    Args:
        data_model: The task to look up

    Returns:
        TaskOutput: Its status and progress

    Raises:
        TaskNotFoundError: If no task exists with that identifier

    """
    endpoint = VcspEndpoints.TASK_ID.value.replace("<task_id>", data_model.task_id)
    response = self._get(endpoint=endpoint)
    return TaskOutput(**response.json())

delete_task

delete_task(data_model)

Delete a task and its result.

Tasks expire on their own, but a long-running caller is better off tidying up.

Parameters:

Name Type Description Default
data_model TaskInput

The task to delete

required

Raises:

Type Description
TaskNotFoundError

If no task exists with that identifier

Source code in src/vericlient/vcsp/client.py
def delete_task(self, data_model: TaskInput) -> None:
    """Delete a task and its result.

    Tasks expire on their own, but a long-running caller is better off tidying up.

    Args:
        data_model: The task to delete

    Raises:
        TaskNotFoundError: If no task exists with that identifier

    """
    endpoint = VcspEndpoints.TASK_ID.value.replace("<task_id>", data_model.task_id)
    self._delete(endpoint=endpoint)

get_task_result

get_task_result(data_model)

Get the outcome of a finished task.

The shape depends on what created the task, so it comes back as a dictionary.

Parameters:

Name Type Description Default
data_model TaskInput

The task to collect

required

Returns:

Name Type Description
GetTaskResultOutput GetTaskResultOutput

The outcome, as the service returned it

Raises:

Type Description
TaskNotFoundError

If no task exists with that identifier

Source code in src/vericlient/vcsp/client.py
def get_task_result(self, data_model: TaskInput) -> GetTaskResultOutput:
    """Get the outcome of a finished task.

    The shape depends on what created the task, so it comes back as a dictionary.

    Args:
        data_model: The task to collect

    Returns:
        GetTaskResultOutput: The outcome, as the service returned it

    Raises:
        TaskNotFoundError: If no task exists with that identifier

    """
    endpoint = VcspEndpoints.TASK_RESULT.value.replace("<task_id>", data_model.task_id)
    response = self._get(endpoint=endpoint)
    return GetTaskResultOutput(result=response.json())

wait_for_task

wait_for_task(data_model, timeout=300, poll_interval=2)

Block until a task finishes, and return its final state.

Saves every caller writing the same polling loop. It returns on failure as well as on success, so check succeeded on the result.

Parameters:

Name Type Description Default
data_model TaskInput

The task to wait for

required
timeout float

How long to wait, in seconds, before giving up

300
poll_interval float

How long to sleep between checks, in seconds

2

Returns:

Name Type Description
TaskOutput TaskOutput

The task in its final state

Raises:

Type Description
TaskNotFoundError

If no task exists with that identifier

TimeoutError

If the task has not finished within timeout

Source code in src/vericlient/vcsp/client.py
def wait_for_task(
    self,
    data_model: TaskInput,
    timeout: float = 300,
    poll_interval: float = 2,
) -> TaskOutput:
    """Block until a task finishes, and return its final state.

    Saves every caller writing the same polling loop. It returns on failure as well as on
    success, so check `succeeded` on the result.

    Args:
        data_model: The task to wait for
        timeout: How long to wait, in seconds, before giving up
        poll_interval: How long to sleep between checks, in seconds

    Returns:
        TaskOutput: The task in its final state

    Raises:
        TaskNotFoundError: If no task exists with that identifier
        TimeoutError: If the task has not finished within `timeout`

    """
    deadline = time.monotonic() + timeout
    while True:
        task = self.get_task(data_model=data_model)
        if task.is_finished:
            return task
        if time.monotonic() >= deadline:
            error = f"Task {data_model.task_id} did not finish within {timeout} seconds"
            raise TimeoutError(error)
        time.sleep(poll_interval)

match

match(data_model)

Match a sample against one subject or against a whole group.

Pass a SubjectClaimant for 1:1 or a GroupClaimant for 1:N. Small operations answer straight away with a MatchingOutput; a large one is accepted and run asynchronously, answering with a TaskCreatedOutput to follow with wait_for_task.

Parameters:

Name Type Description Default
data_model MatchingInput

The sample and what to match it against

required

Returns:

Type Description
MatchingOutput | TaskCreatedOutput

MatchingOutput when the service answered directly, TaskCreatedOutput when it

MatchingOutput | TaskCreatedOutput

queued the work

Raises:

Type Description
AccountNotFoundError

If the subject does not exist

GroupNotFoundError

If the group does not exist

InvalidAssuranceError

If the assurance does not satisfy its method's schema

Source code in src/vericlient/vcsp/client.py
def match(self, data_model: MatchingInput) -> MatchingOutput | TaskCreatedOutput:
    """Match a sample against one subject or against a whole group.

    Pass a `SubjectClaimant` for 1:1 or a `GroupClaimant` for 1:N. Small operations
    answer straight away with a `MatchingOutput`; a large one is accepted and run
    asynchronously, answering with a `TaskCreatedOutput` to follow with `wait_for_task`.

    Args:
        data_model: The sample and what to match it against

    Returns:
        MatchingOutput when the service answered directly, TaskCreatedOutput when it
        queued the work

    Raises:
        AccountNotFoundError: If the subject does not exist
        GroupNotFoundError: If the group does not exist
        InvalidAssuranceError: If the assurance does not satisfy its method's schema

    """
    filename, sample, content_type = self._get_sample(data_model.sample, data_model.content_type)
    data = {"claimant": json.dumps(data_model.claimant.model_dump(exclude_none=True))}
    if data_model.sample_processing is not None:
        data["sample_processing"] = json.dumps(data_model.sample_processing)

    response = self._post(
        endpoint=VcspEndpoints.MATCHINGS.value,
        files={"sample": (filename, sample, content_type)},
        data=data,
    )
    accepted = 202
    if response.status_code == accepted:
        return TaskCreatedOutput(**response.json())
    return MatchingOutput(**response.json())

modify_group

modify_group(data_model)

Add credentials to a group, remove them, or change the group's own details.

A small change answers directly with the group; a large population is accepted and run asynchronously.

Parameters:

Name Type Description Default
data_model ModifyGroupInput

The group, the action, and what it applies to

required

Returns:

Type Description
GetGroupOutput | TaskCreatedOutput

GetGroupOutput when the service answered directly, TaskCreatedOutput when it

GetGroupOutput | TaskCreatedOutput

queued the work

Raises:

Type Description
GroupNotFoundError

If the group does not exist

AccountNotFoundError

If one of the subjects does not exist

Source code in src/vericlient/vcsp/client.py
def modify_group(self, data_model: ModifyGroupInput) -> GetGroupOutput | TaskCreatedOutput:
    """Add credentials to a group, remove them, or change the group's own details.

    A small change answers directly with the group; a large population is accepted and
    run asynchronously.

    Args:
        data_model: The group, the action, and what it applies to

    Returns:
        GetGroupOutput when the service answered directly, TaskCreatedOutput when it
        queued the work

    Raises:
        GroupNotFoundError: If the group does not exist
        AccountNotFoundError: If one of the subjects does not exist

    """
    endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
    body = data_model.model_dump(exclude_none=True, by_alias=True, exclude={"name"})
    response = self._patch(endpoint=endpoint, json_=body)
    accepted = 202
    if response.status_code == accepted:
        return TaskCreatedOutput(**response.json())
    return GetGroupOutput(**response.json())

modify_credential_tags

modify_credential_tags(data_model)

Add or remove tags on one credential.

The tags have to exist already: create them with create_tags first.

Parameters:

Name Type Description Default
data_model ModifyCredentialTagsInput

The credential, the action, and the tags

required

Returns:

Name Type Description
GetCredentialOutput GetCredentialOutput

The credential as it now stands

Raises:

Type Description
CredentialNotFoundError

If the credential is not found

AccountNotFoundError

If the account is not found

InvalidTagsError

If one of the tags does not exist

Source code in src/vericlient/vcsp/client.py
def modify_credential_tags(self, data_model: ModifyCredentialTagsInput) -> GetCredentialOutput:
    """Add or remove tags on one credential.

    The tags have to exist already: create them with `create_tags` first.

    Args:
        data_model: The credential, the action, and the tags

    Returns:
        GetCredentialOutput: The credential as it now stands

    Raises:
        CredentialNotFoundError: If the credential is not found
        AccountNotFoundError: If the account is not found
        InvalidTagsError: If one of the tags does not exist

    """
    endpoint = VcspEndpoints.CREDENTIAL_TAGS.value.replace("<subject_id>", data_model.subject_id)
    endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
    response = self._patch(
        endpoint=endpoint,
        json_={"action": data_model.action, "tags": data_model.tags},
    )
    return GetCredentialOutput(**response.json())

start_clustering

start_clustering(data_model)

Start a clustering task over a group.

Only groups of face credentials can be clustered; a voice group is rejected.

Parameters:

Name Type Description Default
data_model ClusteringInput

The group and the clustering assurance method to apply

required

Returns:

Name Type Description
TaskCreatedOutput TaskCreatedOutput

The task the clustering runs under

Raises:

Type Description
GroupNotFoundError

If the group does not exist

ClusteringNotSupportedError

If the group does not hold face credentials

Source code in src/vericlient/vcsp/client.py
def start_clustering(self, data_model: ClusteringInput) -> TaskCreatedOutput:
    """Start a clustering task over a group.

    Only groups of face credentials can be clustered; a voice group is rejected.

    Args:
        data_model: The group and the clustering assurance method to apply

    Returns:
        TaskCreatedOutput: The task the clustering runs under

    Raises:
        GroupNotFoundError: If the group does not exist
        ClusteringNotSupportedError: If the group does not hold face credentials

    """
    endpoint = VcspEndpoints.GROUP_CLUSTERING.value.replace("<group_name>", data_model.name)
    response = self._post(
        endpoint=endpoint,
        json_={
            "assurance_method_urn": data_model.assurance_method_urn,
            "properties": data_model.properties,
        },
    )
    return TaskCreatedOutput(**response.json())

get_credential_configurations

get_credential_configurations()

Get all credential configurations.

Returns:

Name Type Description
CredentialConfigurationsOutput CredentialConfigurationsOutput

The output of the credential configurations

Source code in src/vericlient/vcsp/client.py
def get_credential_configurations(self) -> CredentialConfigurationsOutput:
    """Get all credential configurations.

    Returns:
        CredentialConfigurationsOutput: The output of the credential configurations

    """
    endpoint = VcspEndpoints.CREDENTIAL_CONFIGURATIONS.value
    response = self._get(endpoint=endpoint)
    return CredentialConfigurationsOutput(
        credential_configurations=response.json(),
    )

get_assurance_methods

get_assurance_methods()

Get all assurance methods.

Returns:

Name Type Description
AssuranceMethodsOutput AssuranceMethodsOutput

The output of the assurance methods

Source code in src/vericlient/vcsp/client.py
def get_assurance_methods(self) -> AssuranceMethodsOutput:
    """Get all assurance methods.

    Returns:
        AssuranceMethodsOutput: The output of the assurance methods

    """
    endpoint = VcspEndpoints.ASSURANCE_METHODS.value
    response = self._get(endpoint=endpoint)
    return AssuranceMethodsOutput(
        assurance_methods=response.json(),
    )

get_assurance_method_info

get_assurance_method_info(data_model)

Get an assurance method.

Parameters:

Name Type Description Default
data_model AssuranceMethodInput

The input to get the assurance method

required

Returns:

Name Type Description
AssuranceMethodOutput AssuranceMethodOutput

The output of the assurance method

Source code in src/vericlient/vcsp/client.py
def get_assurance_method_info(self, data_model: AssuranceMethodInput) -> AssuranceMethodOutput:
    """Get an assurance method.

    Args:
        data_model: The input to get the assurance method

    Returns:
        AssuranceMethodOutput: The output of the assurance method

    """
    endpoint = VcspEndpoints.ASSURANCE_METHOD_URN.value.replace("<urn>", data_model.urn)
    response = self._get(endpoint=endpoint)
    return AssuranceMethodOutput(**response.json())

enroll_subject

enroll_subject(data_model)

Enroll a subject.

Parameters:

Name Type Description Default
data_model EnrollmentInput

The input to enroll the subject

required

Returns:

Name Type Description
EnrollmentOutput EnrollmentOutput

The output of the enrollment

Raises:

Type Description
EmptyFileError

If the file is empty

InvalidClaimsError

If the claims are invalid

InvalidAssuranceError

If the assurance is invalid

InvalidTagsError

If the tags are invalid

InvalidCredentialConfigurationUrnError

If the credential configuration urn is invalid

InvalidAssuranceMethodUrnError

If the assurance method urn is invalid

CredentialConfigurationUrnAlreadyAssignedError

If the credential configuration urn is already assigned

InvalidAudioFormatError

If the audio format is invalid

InvalidSnrError

If the signal noise ratio is invalid

VoiceDurationIsNotEnoughError

If the voice duration is not enough

InsufficientQualityError

If the quality is insufficient

FaceAlignmentError

If the face is not aligned

FaceNotFoundError

If the face is not found

FaceTooSmallError

If the face is too small

MoreThanOneFaceError

If there is more than one face

AssuranceValidationError

If the assurance is invalid

RequestValidationError

If the request is invalid

UnsupportedMediaTypeError

If the media type is not supported

Source code in src/vericlient/vcsp/client.py
def enroll_subject(self, data_model: EnrollmentInput) -> EnrollmentOutput:
    """Enroll a subject.

    Args:
        data_model: The input to enroll the subject

    Returns:
        EnrollmentOutput: The output of the enrollment

    Raises:
        EmptyFileError: If the file is empty
        InvalidClaimsError: If the claims are invalid
        InvalidAssuranceError: If the assurance is invalid
        InvalidTagsError: If the tags are invalid
        InvalidCredentialConfigurationUrnError: If the credential configuration urn is invalid
        InvalidAssuranceMethodUrnError: If the assurance method urn is invalid
        CredentialConfigurationUrnAlreadyAssignedError: If the credential configuration urn is already assigned
        InvalidAudioFormatError: If the audio format is invalid
        InvalidSnrError: If the signal noise ratio is invalid
        VoiceDurationIsNotEnoughError: If the voice duration is not enough
        InsufficientQualityError: If the quality is insufficient
        FaceAlignmentError: If the face is not aligned
        FaceNotFoundError: If the face is not found
        FaceTooSmallError: If the face is too small
        MoreThanOneFaceError: If there is more than one face
        AssuranceValidationError: If the assurance is invalid
        RequestValidationError: If the request is invalid
        UnsupportedMediaTypeError: If the media type is not supported

    """
    endpoint = VcspEndpoints.ENROLLMENTS.value
    sample = self._get_sample(data_model.sample, data_model.content_type)
    files = {"sample": sample}
    data = {"applicant": json.dumps(data_model.applicant.model_dump(exclude_none=True))}
    response = self._post(
        endpoint=endpoint,
        files=files,
        data=data,
    )
    return EnrollmentOutput(**response.json())

get_account

get_account(data_model)

Get an account.

Parameters:

Name Type Description Default
data_model GetAccountInput

The input to get the account

required

Returns:

Name Type Description
GetAccountOutput GetAccountOutput

The output of the account

Raises:

Type Description
AccountNotFoundError

If the account is not found

Source code in src/vericlient/vcsp/client.py
def get_account(self, data_model: GetAccountInput) -> GetAccountOutput:
    """Get an account.

    Args:
        data_model: The input to get the account

    Returns:
        GetAccountOutput: The output of the account

    Raises:
        AccountNotFoundError: If the account is not found

    """
    endpoint = VcspEndpoints.ACCOUNTS.value.replace("<subject_id>", data_model.subject_id)
    response = self._get(endpoint=endpoint)
    return GetAccountOutput(**response.json())

delete_account

delete_account(data_model)

Delete an account.

Parameters:

Name Type Description Default
data_model DeleteAccountInput

The input to delete the account

required

Raises:

Type Description
AccountNotFoundError

If the account is not found

Source code in src/vericlient/vcsp/client.py
def delete_account(self, data_model: DeleteAccountInput) -> None:
    """Delete an account.

    Args:
        data_model: The input to delete the account

    Raises:
        AccountNotFoundError: If the account is not found

    """
    endpoint = VcspEndpoints.ACCOUNTS.value.replace("<subject_id>", data_model.subject_id)
    self._delete(endpoint=endpoint)

get_all_subject_credentials

get_all_subject_credentials(data_model)

Get all credentials for a subject.

Parameters:

Name Type Description Default
data_model GetCredentialsInput

The input to get all credentials for the subject

required

Returns:

Name Type Description
GetCredentialsOutput GetCredentialsOutput

The output of the credentials

Raises:

Type Description
AccountNotFoundError

If the account is not found

Source code in src/vericlient/vcsp/client.py
def get_all_subject_credentials(self, data_model: GetCredentialsInput) -> GetCredentialsOutput:
    """Get all credentials for a subject.

    Args:
        data_model: The input to get all credentials for the subject

    Returns:
        GetCredentialsOutput: The output of the credentials

    Raises:
        AccountNotFoundError: If the account is not found

    """
    endpoint = VcspEndpoints.CREDENTIALS.value.replace("<subject_id>", data_model.subject_id)
    response = self._get(endpoint=endpoint)
    return GetCredentialsOutput(credentials=response.json())

get_credential

get_credential(data_model)

Get a credential.

Parameters:

Name Type Description Default
data_model GetCredentialInput

The input to get the credential

required

Returns:

Name Type Description
GetCredentialOutput GetCredentialOutput

The output of the credential

Raises:

Type Description
CredentialNotFoundError

If the credential is not found

AccountNotFoundError

If the account is not found

Source code in src/vericlient/vcsp/client.py
def get_credential(self, data_model: GetCredentialInput) -> GetCredentialOutput:
    """Get a credential.

    Args:
        data_model: The input to get the credential

    Returns:
        GetCredentialOutput: The output of the credential

    Raises:
        CredentialNotFoundError: If the credential is not found
        AccountNotFoundError: If the account is not found

    """
    endpoint = VcspEndpoints.CREDENTIAL_ID.value.replace("<subject_id>", data_model.subject_id)
    endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
    response = self._get(endpoint=endpoint)
    return GetCredentialOutput(**response.json())

delete_credential

delete_credential(data_model)

Delete a credential.

Parameters:

Name Type Description Default
data_model DeleteCredentialInput

The input to delete the credential

required
Source code in src/vericlient/vcsp/client.py
def delete_credential(self, data_model: DeleteCredentialInput) -> None:
    """Delete a credential.

    Args:
        data_model: The input to delete the credential

    """
    endpoint = VcspEndpoints.CREDENTIAL_ID.value.replace("<subject_id>", data_model.subject_id)
    endpoint = endpoint.replace("<credential_id>", data_model.credential_id)
    self._delete(endpoint=endpoint)

create_tags

create_tags(data_model)

Create tags.

Parameters:

Name Type Description Default
data_model CreateTagsInput

The input to create the tags

required

Returns:

Name Type Description
CreateTagsOutput CreateTagsOutput

The output of the tags creation

Raises:

Type Description
TagsLimitExceededError

If the tag limit is exceeded

TagAlreadyExistsError

If the tag already exists

TagListEmptyError

If the tag list is empty

Source code in src/vericlient/vcsp/client.py
def create_tags(self, data_model: CreateTagsInput) -> CreateTagsOutput:
    """Create tags.

    Args:
        data_model: The input to create the tags

    Returns:
        CreateTagsOutput: The output of the tags creation

    Raises:
        TagsLimitExceededError: If the tag limit is exceeded
        TagAlreadyExistsError: If the tag already exists
        TagListEmptyError: If the tag list is empty

    """
    endpoint = VcspEndpoints.TAGS.value
    response = self._post(endpoint=endpoint, json_=data_model.model_dump())
    return CreateTagsOutput(**response.json())

get_tags

get_tags()

Get every tag created in the system.

Returns:

Name Type Description
GetTagsOutput GetTagsOutput

The tags, paginated

Source code in src/vericlient/vcsp/client.py
def get_tags(self) -> GetTagsOutput:
    """Get every tag created in the system.

    Returns:
        GetTagsOutput: The tags, paginated

    """
    endpoint = VcspEndpoints.TAGS.value
    response = self._get(endpoint=endpoint)
    return GetTagsOutput(**response.json())

delete_tag

delete_tag(data_model)

Delete a tag.

Parameters:

Name Type Description Default
data_model DeleteTagInput

The input to delete the tag

required

Raises:

Type Description
InvalidTagsError

If the tag is invalid

Source code in src/vericlient/vcsp/client.py
def delete_tag(self, data_model: DeleteTagInput) -> None:
    """Delete a tag.

    Args:
        data_model: The input to delete the tag

    Raises:
        InvalidTagsError: If the tag is invalid

    """
    endpoint = VcspEndpoints.TAGS_NAME.value.replace("<tag_name>", data_model.name)
    self._delete(endpoint=endpoint)

create_group

create_group(data_model)

Create a group.

Parameters:

Name Type Description Default
data_model CreateGroupInput

The input to create the group

required

Returns:

Name Type Description
CreateGroupOutput CreateGroupOutput

The output of the group creation

Raises:

Type Description
GroupsLimitExceededError

If the group limit is exceeded

GroupAlreadyExistsError

If the group already exists

InvalidCredentialConfigurationUrnError

If the credential configuration urn is invalid

Source code in src/vericlient/vcsp/client.py
def create_group(self, data_model: CreateGroupInput) -> CreateGroupOutput:
    """Create a group.

    Args:
        data_model: The input to create the group

    Returns:
        CreateGroupOutput: The output of the group creation

    Raises:
        GroupsLimitExceededError: If the group limit is exceeded
        GroupAlreadyExistsError: If the group already exists
        InvalidCredentialConfigurationUrnError: If the credential configuration urn is invalid

    """
    endpoint = VcspEndpoints.GROUPS.value
    response = self._post(endpoint=endpoint, json_=data_model.model_dump(exclude_none=True))
    return CreateGroupOutput(**response.json())

get_groups

get_groups(data_model)

Get all groups.

Parameters:

Name Type Description Default
data_model GetGroupsInput

The input to get the groups

required

Returns:

Name Type Description
GetGroupsOutput GetGroupsOutput

The output of the groups

Source code in src/vericlient/vcsp/client.py
def get_groups(self, data_model: GetGroupsInput) -> GetGroupsOutput:
    """Get all groups.

    Args:
        data_model: The input to get the groups

    Returns:
        GetGroupsOutput: The output of the groups

    """
    endpoint = VcspEndpoints.GROUPS.value
    endpoint = endpoint + f"?size={data_model.size}&page={data_model.page}"
    response = self._get(endpoint=endpoint)
    items = response.json()["items"]
    total = response.json()["total"]
    page = response.json()["page"]
    size = response.json()["size"]
    pages = response.json()["pages"]
    return GetGroupsOutput(
        items=items,
        total=total,
        page=page,
        size=size,
        pages=pages,
    )

get_group

get_group(data_model)

Get a group.

Parameters:

Name Type Description Default
data_model GetGroupInput

The input to get the group

required

Returns:

Name Type Description
GetGroupOutput GetGroupOutput

The output of the group

Raises:

Type Description
GroupNotFoundError

If the group is not found

Source code in src/vericlient/vcsp/client.py
def get_group(self, data_model: GetGroupInput) -> GetGroupOutput:
    """Get a group.

    Args:
        data_model: The input to get the group

    Returns:
        GetGroupOutput: The output of the group

    Raises:
        GroupNotFoundError: If the group is not found

    """
    endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
    response = self._get(endpoint=endpoint)
    return GetGroupOutput(**response.json())

delete_group

delete_group(data_model)

Delete a group.

Parameters:

Name Type Description Default
data_model DeleteGroupInput

The input to delete the group

required

Raises:

Type Description
GroupNotFoundError

If the group is not found

Source code in src/vericlient/vcsp/client.py
def delete_group(self, data_model: DeleteGroupInput) -> None:
    """Delete a group.

    Args:
        data_model: The input to delete the group

    Raises:
        GroupNotFoundError: If the group is not found

    """
    endpoint = VcspEndpoints.GROUP_NAME.value.replace("<group_name>", data_model.name)
    self._delete(endpoint=endpoint)

get_group_members

get_group_members(data_model)

Get the members of a group.

Parameters:

Name Type Description Default
data_model GetGroupMembersInput

The input to get the members of the group

required

Returns:

Name Type Description
GetGroupMembersOutput GetGroupMembersOutput

The output of the group members

Raises:

Type Description
GroupNotFoundError

If the group is not found

Source code in src/vericlient/vcsp/client.py
def get_group_members(self, data_model: GetGroupMembersInput) -> GetGroupMembersOutput:
    """Get the members of a group.

    Args:
        data_model: The input to get the members of the group

    Returns:
        GetGroupMembersOutput: The output of the group members

    Raises:
        GroupNotFoundError: If the group is not found

    """
    endpoint = VcspEndpoints.GROUP_MEMBERS.value.replace("<group_name>", data_model.name)
    response = self._get(endpoint=endpoint)
    return GetGroupMembersOutput(**response.json())

vericlient.vcsp.models

Module to define the models for the VCSP API.

VcspResponse

Bases: BaseModel

Base class for the VCSP API responses.

Carries no fields of its own: it exists so every VCSP response shares a type, and so anything the API starts returning across the board has somewhere to go.

Source code in src/vericlient/vcsp/models.py
class VcspResponse(BaseModel):
    """Base class for the VCSP API responses.

    Carries no fields of its own: it exists so every VCSP response shares a type, and so
    anything the API starts returning across the board has somewhere to go.
    """

CredentialConfigurationsOutput

Bases: VcspResponse

Output class for the credential configurations endpoint.

Attributes:

Name Type Description
credential_configurations list[str]

The credential configurations

Source code in src/vericlient/vcsp/models.py
class CredentialConfigurationsOutput(VcspResponse):
    """Output class for the credential configurations endpoint.

    Attributes:
        credential_configurations: The credential configurations

    """

    credential_configurations: list[str]

AssuranceMethodsOutput

Bases: VcspResponse

Output class for the assurance methods endpoint.

Attributes:

Name Type Description
assurance_methods list[str]

The assurance methods

Source code in src/vericlient/vcsp/models.py
class AssuranceMethodsOutput(VcspResponse):
    """Output class for the assurance methods endpoint.

    Attributes:
        assurance_methods: The assurance methods

    """

    assurance_methods: list[str]

AssuranceMethodSchema

Bases: BaseModel

Schema class for the assurance method.

Attributes:

Name Type Description
json_schema str

The JSON schema of the assurance method, serialised as $schema

title str

The title of the assurance method

type str

The type of the assurance method

properties dict

The properties of the assurance method

required list[str] | None

The required properties of the assurance method

additionalProperties bool

Whether additional properties are allowed

Source code in src/vericlient/vcsp/models.py
class AssuranceMethodSchema(BaseModel):
    """Schema class for the assurance method.

    Attributes:
        json_schema: The JSON schema of the assurance method, serialised as `$schema`
        title: The title of the assurance method
        type: The type of the assurance method
        properties: The properties of the assurance method
        required: The required properties of the assurance method
        additionalProperties: Whether additional properties are allowed

    """

    model_config = ConfigDict(populate_by_name=True)

    json_schema: str = Field(alias="$schema")
    title: str
    type: str
    properties: dict
    required: list[str] | None = None
    additionalProperties: bool  # noqa: N815

AssuranceMethodInput

Bases: BaseModel

Input class for the assurance method endpoint.

Attributes:

Name Type Description
urn str

The urn of the assurance method

Source code in src/vericlient/vcsp/models.py
class AssuranceMethodInput(BaseModel):
    """Input class for the assurance method endpoint.

    Attributes:
        urn: The urn of the assurance method

    """

    urn: str

AssuranceMethodOutput

Bases: VcspResponse

Output class for the assurance method endpoint.

Attributes:

Name Type Description
urn str

The urn of the assurance method

json_schema AssuranceMethodSchema

The schema of the assurance method, serialised as schema

Source code in src/vericlient/vcsp/models.py
class AssuranceMethodOutput(VcspResponse):
    """Output class for the assurance method endpoint.

    Attributes:
        urn: The urn of the assurance method
        json_schema: The schema of the assurance method, serialised as `schema`

    """

    model_config = ConfigDict(populate_by_name=True)

    urn: str
    json_schema: AssuranceMethodSchema = Field(alias="schema")

Sample

Bases: BaseModel

Base class for the Sample.

Attributes:

Name Type Description
valid_from str

The date from which the sample is valid

valid_until str

The date until which the sample is valid

type str

The type of the sample, e.g. "voice", "face"

content_type str

The content type of the sample, e.g. "audio/wav", "image/jpeg"

analysis dict

The analysis of the sample

Source code in src/vericlient/vcsp/models.py
class Sample(BaseModel):
    """Base class for the Sample.

    Attributes:
        valid_from: The date from which the sample is valid
        valid_until: The date until which the sample is valid
        type: The type of the sample, e.g. "voice", "face"
        content_type: The content type of the sample, e.g. "audio/wav", "image/jpeg"
        analysis: The analysis of the sample

    """

    valid_from: str
    valid_until: str
    type: str
    content_type: str
    analysis: dict

Applicant

Bases: BaseModel

Base class for the Applicant.

Attributes:

Name Type Description
subject_id str | None

The subject_id of the applicant (optional). If not provided, it will be generated by the system and returned in the response

credential_configuration_urn str

The credential configuration urn

tags list[str] | None

The tags of the applicant

claims dict | None

The claims of the applicant

assurance_method_urn str

The assurance method urn

assurance dict

The assurance of the applicant

Source code in src/vericlient/vcsp/models.py
class Applicant(BaseModel):
    """Base class for the Applicant.

    Attributes:
        subject_id: The subject_id of the applicant (optional). If not provided, it will
            be generated by the system and returned in the response
        credential_configuration_urn: The credential configuration urn
        tags: The tags of the applicant
        claims: The claims of the applicant
        assurance_method_urn: The assurance method urn
        assurance: The assurance of the applicant

    """

    subject_id: str | None = None
    credential_configuration_urn: str
    tags: list[str] | None = []
    claims: dict | None = {}
    assurance_method_urn: str
    assurance: dict

EnrollmentInput

Bases: BaseModel

Input class for the enrollment endpoint.

Attributes:

Name Type Description
sample str | bytes

The sample to generate the credential with. It can be a path to a file or a bytes object with the audio content

applicant Applicant

The applicant to enroll

content_type str | None

The media type to declare for the sample, such as audio/wav or image/jpeg. Optional: it is inferred from the file extension for a path and from the magic bytes for a bytes object. Set it when the guess would be wrong, since VCSP answers with a 500 if the declared type does not match the content

Source code in src/vericlient/vcsp/models.py
class EnrollmentInput(BaseModel):
    """Input class for the enrollment endpoint.

    Attributes:
        sample: The sample to generate the credential with.
            It can be a path to a file or a bytes object
            with the audio content
        applicant: The applicant to enroll
        content_type: The media type to declare for the sample, such as `audio/wav` or
            `image/jpeg`. Optional: it is inferred from the file extension for a path and
            from the magic bytes for a bytes object. Set it when the guess would be wrong,
            since VCSP answers with a 500 if the declared type does not match the content

    """

    sample: str | bytes
    applicant: Applicant
    content_type: str | None = None

    @field_validator("sample")
    def must_be_str_or_bytes(cls, value: object):
        if not isinstance(value, (str, bytes)):
            error = "sample must be a string or a bytes object"
            raise TypeError(error)
        return value

    model_config = ConfigDict(arbitrary_types_allowed=True)

EnrollmentOutput

Bases: BaseModel

Output class for the enrollment endpoint.

Attributes:

Name Type Description
credential_id str

The credential_id of the applicant

subject_id str

The subject_id of the applicant

Source code in src/vericlient/vcsp/models.py
class EnrollmentOutput(BaseModel):
    """Output class for the enrollment endpoint.

    Attributes:
        credential_id: The credential_id of the applicant
        subject_id: The subject_id of the applicant

    """

    credential_id: str
    subject_id: str

SubjectInput

Bases: BaseModel

Input class to define a subject.

Attributes:

Name Type Description
subject_id str

The subject_id of the applicant

Source code in src/vericlient/vcsp/models.py
class SubjectInput(BaseModel):
    """Input class to define a subject.

    Attributes:
        subject_id: The subject_id of the applicant

    """

    subject_id: str

CredentialInput

Bases: BaseModel

Input class to define a credential.

Attributes:

Name Type Description
credential_id str

The credential_id of the applicant

Source code in src/vericlient/vcsp/models.py
class CredentialInput(BaseModel):
    """Input class to define a credential.

    Attributes:
        credential_id: The credential_id of the applicant

    """

    credential_id: str

DeleteSubjectInput

Bases: SubjectInput

Input class for the delete account endpoint.

Attributes:

Name Type Description
subject_id str

The account_id to delete

Source code in src/vericlient/vcsp/models.py
class DeleteSubjectInput(SubjectInput):
    """Input class for the delete account endpoint.

    Attributes:
        subject_id: The account_id to delete

    """

DeleteCredentialInput

Bases: SubjectInput, CredentialInput

Input class for the delete credential endpoint.

Attributes:

Name Type Description
credential_id str

The credential_id to delete

subject_id str

The subject from which the credential will be deleted

Source code in src/vericlient/vcsp/models.py
class DeleteCredentialInput(SubjectInput, CredentialInput):
    """Input class for the delete credential endpoint.

    Attributes:
        credential_id: The credential_id to delete
        subject_id: The subject from which the credential will be deleted

    """

GetAccountInput

Bases: SubjectInput

Input class for the get account endpoint.

Attributes:

Name Type Description
subject_id str

The account_id to get

Source code in src/vericlient/vcsp/models.py
class GetAccountInput(SubjectInput):
    """Input class for the get account endpoint.

    Attributes:
        subject_id: The account_id to get

    """

GetCredentialInput

Bases: SubjectInput, CredentialInput

Input class for the get a specific credential endpoint.

Attributes:

Name Type Description
subject_id str

The subject_id to get the credential from

credential_id str

The credential_id to get

Source code in src/vericlient/vcsp/models.py
class GetCredentialInput(SubjectInput, CredentialInput):
    """Input class for the get a specific credential endpoint.

    Attributes:
        subject_id: The subject_id to get the credential from
        credential_id: The credential_id to get

    """

GetCredentialOutput

Bases: BaseModel

Output class for the get credential endpoint.

Attributes:

Name Type Description
sample Sample

The sample of the applicant

groups list[str]

The groups of the applicant

issuer str

The issuer

id str

The id of the applicant

updated_at str

The updated_at date

created_at str

The created_at date

valid_from str

The valid_from date

valid_until str

The valid_until date

credential_configuration_urn str

The credential_configuration_urn

tags list[str]

The tags of the applicant

claims dict

The claims of the applicant

Source code in src/vericlient/vcsp/models.py
class GetCredentialOutput(BaseModel):
    """Output class for the get credential endpoint.

    Attributes:
        sample: The sample of the applicant
        groups: The groups of the applicant
        issuer: The issuer
        id: The id of the applicant
        updated_at: The updated_at date
        created_at: The created_at date
        valid_from: The valid_from date
        valid_until: The valid_until date
        credential_configuration_urn: The credential_configuration_urn
        tags: The tags of the applicant
        claims: The claims of the applicant

    """

    sample: Sample
    groups: list[str]
    issuer: str
    id: str
    updated_at: str
    created_at: str
    valid_from: str
    valid_until: str
    credential_configuration_urn: str
    tags: list[str]
    claims: dict

GetAccountOutput

Bases: VcspResponse

Output class for the get account endpoint.

Attributes:

Name Type Description
credentials list[str]

The credentials of the applicant

updated_at str

The updated_at date

created_at str

The created_at date

subject_id str

The subject_id of the applicant

Source code in src/vericlient/vcsp/models.py
class GetAccountOutput(VcspResponse):
    """Output class for the get account endpoint.

    Attributes:
        credentials: The credentials of the applicant
        updated_at: The updated_at date
        created_at: The created_at date
        subject_id: The subject_id of the applicant

    """

    credentials: list[str]
    updated_at: str
    created_at: str
    subject_id: str

DeleteAccountInput

Bases: SubjectInput

Input class for the delete account endpoint.

Attributes:

Name Type Description
subject_id str

The account_id to delete

Source code in src/vericlient/vcsp/models.py
class DeleteAccountInput(SubjectInput):
    """Input class for the delete account endpoint.

    Attributes:
        subject_id: The account_id to delete

    """

GetCredentialsInput

Bases: SubjectInput

Input class for the get all credentials from a subject endpoint.

Attributes:

Name Type Description
subject_id str

The account_id to get the credentials from

Source code in src/vericlient/vcsp/models.py
class GetCredentialsInput(SubjectInput):
    """Input class for the get all credentials from a subject endpoint.

    Attributes:
        subject_id: The account_id to get the credentials from

    """

GetCredentialsOutput

Bases: VcspResponse

Output class for the get all credentials from a subject endpoint.

Attributes:

Name Type Description
credentials list[GetCredentialOutput]

The credentials of the applicant

Source code in src/vericlient/vcsp/models.py
class GetCredentialsOutput(VcspResponse):
    """Output class for the get all credentials from a subject endpoint.

    Attributes:
        credentials: The credentials of the applicant

    """

    credentials: list[GetCredentialOutput]

TagInput

Bases: BaseModel

Input class for the tag endpoint.

Attributes:

Name Type Description
name str

The name of the tag

Source code in src/vericlient/vcsp/models.py
class TagInput(BaseModel):
    """Input class for the tag endpoint.

    Attributes:
        name: The name of the tag

    """

    name: str

TagOutput

Bases: TagInput

Output class for the tag endpoint.

Attributes:

Name Type Description
name str

The name of the tag

created_at str

The created_at date

Source code in src/vericlient/vcsp/models.py
class TagOutput(TagInput):
    """Output class for the tag endpoint.

    Attributes:
        name: The name of the tag
        created_at: The created_at date

    """

    created_at: str

CreateTagsInput

Bases: BaseModel

Input class for the create tag endpoint.

Attributes:

Name Type Description
tags list[str]

The tags to create

Source code in src/vericlient/vcsp/models.py
class CreateTagsInput(BaseModel):
    """Input class for the create tag endpoint.

    Attributes:
        tags: The tags to create

    """

    tags: list[str]

CreateTagsOutput

Bases: VcspResponse

Output class for the create tag endpoint.

Attributes:

Name Type Description
tags list[str]

The tags created

created_at str

The created_at date

Source code in src/vericlient/vcsp/models.py
class CreateTagsOutput(VcspResponse):
    """Output class for the create tag endpoint.

    Attributes:
        tags: The tags created
        created_at: The created_at date

    """

    tags: list[str]
    created_at: str

GetTagsOutput

Bases: VcspResponse

Output class for the get tags endpoint.

Attributes:

Name Type Description
items list[TagOutput]

The tags

total int

The total number of tags

page int

The page number

size int

The size of the tags

pages int

The total number of pages

Source code in src/vericlient/vcsp/models.py
class GetTagsOutput(VcspResponse):
    """Output class for the get tags endpoint.

    Attributes:
        items: The tags
        total: The total number of tags
        page: The page number
        size: The size of the tags
        pages: The total number of pages

    """

    items: list[TagOutput]
    total: int
    page: int
    size: int
    pages: int

DeleteTagInput

Bases: TagInput

Input class for the delete tag endpoint.

Attributes:

Name Type Description
name str

The name of the tag

Source code in src/vericlient/vcsp/models.py
class DeleteTagInput(TagInput):
    """Input class for the delete tag endpoint.

    Attributes:
        name: The name of the tag

    """

GroupInput

Bases: BaseModel

Input class for the group endpoint.

Attributes:

Name Type Description
name str

The name of the group

Source code in src/vericlient/vcsp/models.py
class GroupInput(BaseModel):
    """Input class for the group endpoint.

    Attributes:
        name: The name of the group

    """

    name: str

CreateGroupInput

Bases: GroupInput

Input class for the create group endpoint.

Attributes:

Name Type Description
name str

The name of the group. Must match ^[a-zA-Z_][a-zA-Z0-9_]{2,63}$, so letters, digits and underscores only, starting with a letter or an underscore

credential_configuration_urn str

The credential configuration the group holds

description str | None

A free-text description. Defaults to empty on the service

expired_at str | None

How long credentials are retained in the group, as an ISO 8601 duration such as P1Y or P30D — not a date. The service answers with the resulting timestamp. Defaults to five years

Source code in src/vericlient/vcsp/models.py
class CreateGroupInput(GroupInput):
    """Input class for the create group endpoint.

    Attributes:
        name: The name of the group. Must match `^[a-zA-Z_][a-zA-Z0-9_]{2,63}$`, so letters,
            digits and underscores only, starting with a letter or an underscore
        credential_configuration_urn: The credential configuration the group holds
        description: A free-text description. Defaults to empty on the service
        expired_at: How long credentials are retained in the group, as an **ISO 8601
            duration** such as `P1Y` or `P30D` — not a date. The service answers with the
            resulting timestamp. Defaults to five years

    """

    credential_configuration_urn: str
    description: str | None = None
    expired_at: str | None = None

CreateGroupOutput

Bases: VcspResponse

Output class for the create group endpoint.

Attributes:

Name Type Description
size int

The number of credentials in the group

created_at str

The created_at date

updated_at str

The updated_at date

credential_configuration_urn str

The credential configuration the group holds

name str

The name of the group

description str

The description of the group

expired_at str

The date the credentials expire. Note the asymmetry with the input, which takes a duration rather than a date

Source code in src/vericlient/vcsp/models.py
class CreateGroupOutput(VcspResponse):
    """Output class for the create group endpoint.

    Attributes:
        size: The number of credentials in the group
        created_at: The created_at date
        updated_at: The updated_at date
        credential_configuration_urn: The credential configuration the group holds
        name: The name of the group
        description: The description of the group
        expired_at: The date the credentials expire. Note the asymmetry with the input,
            which takes a duration rather than a date

    """

    size: int
    created_at: str
    updated_at: str
    credential_configuration_urn: str
    name: str
    description: str
    expired_at: str

GetGroupsInput

Bases: BaseModel

Input class for the get groups endpoint.

Attributes:

Name Type Description
size int | None

The size of the groups (optional), default is 100

page int | None

The page number (optional), default is 1

Source code in src/vericlient/vcsp/models.py
class GetGroupsInput(BaseModel):
    """Input class for the get groups endpoint.

    Attributes:
        size: The size of the groups (optional), default is 100
        page: The page number (optional), default is 1

    """

    size: int | None = 100
    page: int | None = 1

GetGroupsOutput

Bases: VcspResponse

Output class for the get groups endpoint.

Attributes:

Name Type Description
items list[CreateGroupOutput]

The items of the groups

total int

The total number of groups

page int

The page number

size int

The size of the groups

pages int

The total number of pages

Source code in src/vericlient/vcsp/models.py
class GetGroupsOutput(VcspResponse):
    """Output class for the get groups endpoint.

    Attributes:
        items: The items of the groups
        total: The total number of groups
        page: The page number
        size: The size of the groups
        pages: The total number of pages

    """

    items: list[CreateGroupOutput]
    total: int
    page: int
    size: int
    pages: int

GetGroupInput

Bases: GroupInput

Input class for the get a specific group endpoint.

Source code in src/vericlient/vcsp/models.py
class GetGroupInput(GroupInput):
    """Input class for the get a specific group endpoint."""

GetGroupOutput

Bases: CreateGroupOutput

Output class for the get a specific group endpoint.

Attributes:

Name Type Description
size int

The size of the group

created_at str

The created_at date

updated_at str

The updated_at date

credential_configuration_urn str

The credential configuration urn

name str

The name of the group

description str

The description of the group

expired_at str

The expired_at date

Source code in src/vericlient/vcsp/models.py
class GetGroupOutput(CreateGroupOutput):
    """Output class for the get a specific group endpoint.

    Attributes:
        size: The size of the group
        created_at: The created_at date
        updated_at: The updated_at date
        credential_configuration_urn: The credential configuration urn
        name: The name of the group
        description: The description of the group
        expired_at: The expired_at date

    """

DeleteGroupInput

Bases: GroupInput

Input class for the delete group endpoint.

Attributes:

Name Type Description
name str

The name of the group

Source code in src/vericlient/vcsp/models.py
class DeleteGroupInput(GroupInput):
    """Input class for the delete group endpoint.

    Attributes:
        name: The name of the group

    """

    name: str

GetGroupMembersInput

Bases: GroupInput

Input class for the get group members endpoint.

Source code in src/vericlient/vcsp/models.py
class GetGroupMembersInput(GroupInput):
    """Input class for the get group members endpoint."""

GroupMember

Bases: BaseModel

Base class for the group member.

Attributes:

Name Type Description
subject_id str

The subject_id of the group member

credential_id str

The credential_id of the group member

expired_in_group str

The expired_in_group of the group member

claims dict

The claims of the group member

tags list[str]

The tags of the group member

Source code in src/vericlient/vcsp/models.py
class GroupMember(BaseModel):
    """Base class for the group member.

    Attributes:
        subject_id: The subject_id of the group member
        credential_id: The credential_id of the group member
        expired_in_group: The expired_in_group of the group member
        claims: The claims of the group member
        tags: The tags of the group member

    """

    subject_id: str
    credential_id: str
    expired_in_group: str
    claims: dict
    tags: list[str]

GetGroupMembersOutput

Bases: VcspResponse

Output class for the get group members endpoint.

Attributes:

Name Type Description
items list[GroupMember]

The items of the group members

total int

The total number of group members

page int

The page number

size int

The size of the group members

pages int

The total number of pages

Source code in src/vericlient/vcsp/models.py
class GetGroupMembersOutput(VcspResponse):
    """Output class for the get group members endpoint.

    Attributes:
        items: The items of the group members
        total: The total number of group members
        page: The page number
        size: The size of the group members
        pages: The total number of pages

    """

    items: list[GroupMember]
    total: int
    page: int
    size: int
    pages: int

ListedCredential

Bases: GetCredentialOutput

A credential as it appears in the system-wide credential listing.

Attributes:

Name Type Description
subject_id str

The account the credential belongs to

Source code in src/vericlient/vcsp/models.py
class ListedCredential(GetCredentialOutput):
    """A credential as it appears in the system-wide credential listing.

    Attributes:
        subject_id: The account the credential belongs to

    """

    subject_id: str

ListCredentialsInput

Bases: BaseModel

Input class for the system-wide credential listing.

Every field is a filter, and all of them are optional. Listing without one walks the whole system, which on a busy deployment is a lot of pages.

Attributes:

Name Type Description
credential_configuration_urn str | None

Only credentials created with this configuration

tags list[str] | None

Only credentials carrying these tags

page int | None

The page to retrieve, starting at 1

size int | None

How many credentials per page

Source code in src/vericlient/vcsp/models.py
class ListCredentialsInput(BaseModel):
    """Input class for the system-wide credential listing.

    Every field is a filter, and all of them are optional. Listing without one walks the
    whole system, which on a busy deployment is a lot of pages.

    Attributes:
        credential_configuration_urn: Only credentials created with this configuration
        tags: Only credentials carrying these tags
        page: The page to retrieve, starting at 1
        size: How many credentials per page

    """

    credential_configuration_urn: str | None = None
    tags: list[str] | None = None
    page: int | None = None
    size: int | None = None

ListCredentialsOutput

Bases: VcspResponse

Output class for the system-wide credential listing.

Attributes:

Name Type Description
items list[ListedCredential]

The credentials on this page

total int

The number of credentials matching the filters

page int

The page returned

size int

The page size

pages int

The number of pages

Source code in src/vericlient/vcsp/models.py
class ListCredentialsOutput(VcspResponse):
    """Output class for the system-wide credential listing.

    Attributes:
        items: The credentials on this page
        total: The number of credentials matching the filters
        page: The page returned
        size: The page size
        pages: The number of pages

    """

    items: list[ListedCredential]
    total: int
    page: int
    size: int
    pages: int

DeleteCredentialsInput

Bases: BaseModel

Input class for bulk credential deletion.

A group is the only filter the service accepts, and the operation is irreversible. Credentials in the group are deleted and removed from any other group they belong to.

Attributes:

Name Type Description
group_name str

The group whose credentials are deleted

delete_empty_accounts bool

Whether to delete an account left with no credentials

Source code in src/vericlient/vcsp/models.py
class DeleteCredentialsInput(BaseModel):
    """Input class for bulk credential deletion.

    A group is the only filter the service accepts, and the operation is irreversible.
    Credentials in the group are deleted and removed from any other group they belong to.

    Attributes:
        group_name: The group whose credentials are deleted
        delete_empty_accounts: Whether to delete an account left with no credentials

    """

    group_name: str
    delete_empty_accounts: bool = False

GetCredentialSampleInput

Bases: SubjectInput, CredentialInput

Input class for retrieving the sample behind a credential.

Attributes:

Name Type Description
subject_id str

The subject the credential belongs to

credential_id str

The credential whose sample to retrieve

Source code in src/vericlient/vcsp/models.py
class GetCredentialSampleInput(SubjectInput, CredentialInput):
    """Input class for retrieving the sample behind a credential.

    Attributes:
        subject_id: The subject the credential belongs to
        credential_id: The credential whose sample to retrieve

    """

GetCredentialSampleOutput

Bases: VcspResponse

Output class for retrieving the sample behind a credential.

The service answers with the raw bytes it was enrolled with, not with JSON.

Attributes:

Name Type Description
content bytes

The sample itself

content_type str

Its media type, such as audio/wav or image/jpeg

Source code in src/vericlient/vcsp/models.py
class GetCredentialSampleOutput(VcspResponse):
    """Output class for retrieving the sample behind a credential.

    The service answers with the raw bytes it was enrolled with, not with JSON.

    Attributes:
        content: The sample itself
        content_type: Its media type, such as `audio/wav` or `image/jpeg`

    """

    content: bytes
    content_type: str

CredentialConfigurationInput

Bases: BaseModel

Input class for retrieving one credential configuration.

Attributes:

Name Type Description
urn str

The urn of the credential configuration

Source code in src/vericlient/vcsp/models.py
class CredentialConfigurationInput(BaseModel):
    """Input class for retrieving one credential configuration.

    Attributes:
        urn: The urn of the credential configuration

    """

    urn: str

CredentialConfigurationOutput

Bases: VcspResponse

Output class for retrieving one credential configuration.

Attributes:

Name Type Description
urn str

The urn of the credential configuration

claims_schema dict

The JSON schema the claims of an enrolment must satisfy

Source code in src/vericlient/vcsp/models.py
class CredentialConfigurationOutput(VcspResponse):
    """Output class for retrieving one credential configuration.

    Attributes:
        urn: The urn of the credential configuration
        claims_schema: The JSON schema the `claims` of an enrolment must satisfy

    """

    urn: str
    claims_schema: dict

TaskStatus

Bases: StrEnum

The states an asynchronous task moves through.

TaskOutput.status is a plain string rather than this enum, so a state the service adds later does not break deserialisation. Compare against these members.

Source code in src/vericlient/vcsp/models.py
class TaskStatus(StrEnum):
    """The states an asynchronous task moves through.

    `TaskOutput.status` is a plain string rather than this enum, so a state the service adds
    later does not break deserialisation. Compare against these members.
    """

    PENDING = "PENDING"
    IN_PROGRESS = "IN_PROGRESS"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"

TaskInput

Bases: BaseModel

Input class for the task endpoints.

Attributes:

Name Type Description
task_id str

The identifier the service returned when the task was created

Source code in src/vericlient/vcsp/models.py
class TaskInput(BaseModel):
    """Input class for the task endpoints.

    Attributes:
        task_id: The identifier the service returned when the task was created

    """

    task_id: str

TaskOutput

Bases: VcspResponse

Output class describing one asynchronous task.

Attributes:

Name Type Description
task_id str

The identifier of the task

status str

One of the TaskStatus values

progress float

How far along the task is, from 0 to 100

created_at str | None

When the task was accepted

started_at str | None

When the task started, if it has

finished_at str | None

When the task finished, if it has

expired_at str | None

When the service will drop the task and its result

Source code in src/vericlient/vcsp/models.py
class TaskOutput(VcspResponse):
    """Output class describing one asynchronous task.

    Attributes:
        task_id: The identifier of the task
        status: One of the `TaskStatus` values
        progress: How far along the task is, from 0 to 100
        created_at: When the task was accepted
        started_at: When the task started, if it has
        finished_at: When the task finished, if it has
        expired_at: When the service will drop the task and its result

    """

    task_id: str
    status: str
    progress: float
    created_at: str | None = None
    started_at: str | None = None
    finished_at: str | None = None
    expired_at: str | None = None

    @property
    def is_finished(self) -> bool:
        """Whether the task has stopped running, successfully or not."""
        return self.status in (TaskStatus.COMPLETED, TaskStatus.FAILED)

    @property
    def succeeded(self) -> bool:
        """Whether the task finished successfully."""
        return self.status == TaskStatus.COMPLETED

is_finished property

is_finished

Whether the task has stopped running, successfully or not.

succeeded property

succeeded

Whether the task finished successfully.

GetTasksOutput

Bases: VcspResponse

Output class for the task listing.

Attributes:

Name Type Description
items list[TaskOutput]

The tasks on this page

total int

The number of active tasks

page int

The page returned

size int

The page size

pages int

The number of pages

Source code in src/vericlient/vcsp/models.py
class GetTasksOutput(VcspResponse):
    """Output class for the task listing.

    Attributes:
        items: The tasks on this page
        total: The number of active tasks
        page: The page returned
        size: The page size
        pages: The number of pages

    """

    items: list[TaskOutput]
    total: int
    page: int
    size: int
    pages: int

GetTaskResultOutput

Bases: VcspResponse

Output class for the outcome of a finished task.

The shape depends on what created the task — a batch enrolment, a matching or a clustering all answer differently — so it is handed back as-is rather than forced into one model.

Attributes:

Name Type Description
result dict

The outcome, as the service returned it

Source code in src/vericlient/vcsp/models.py
class GetTaskResultOutput(VcspResponse):
    """Output class for the outcome of a finished task.

    The shape depends on what created the task — a batch enrolment, a matching or a
    clustering all answer differently — so it is handed back as-is rather than forced into
    one model.

    Attributes:
        result: The outcome, as the service returned it

    """

    result: dict

BatchApplicant

Bases: BaseModel

One enrolment inside a batch.

Attributes:

Name Type Description
sample str | bytes

The biometric sample, as a path or as bytes

applicant Applicant

The applicant to enrol, exactly as for a single enrolment

filename str | None

The name the sample takes inside the archive. Derived from the path, or generated for bytes, when omitted. It only has to be unique within the batch

Source code in src/vericlient/vcsp/models.py
class BatchApplicant(BaseModel):
    """One enrolment inside a batch.

    Attributes:
        sample: The biometric sample, as a path or as bytes
        applicant: The applicant to enrol, exactly as for a single enrolment
        filename: The name the sample takes inside the archive. Derived from the path, or
            generated for bytes, when omitted. It only has to be unique within the batch

    """

    sample: str | bytes
    applicant: Applicant
    filename: str | None = None

    model_config = ConfigDict(arbitrary_types_allowed=True)

BatchEnrollmentInput

Bases: BaseModel

Input class for batch enrolment.

The service takes a TAR archive holding the samples and an applicants.json that points at them. Pass applicants and the client builds it; pass batch_file if you have one already, which avoids holding a large batch in memory twice.

Attributes:

Name Type Description
applicants list[BatchApplicant] | None

The enrolments to perform

batch_file str | bytes | None

A prepared TAR archive, as a path or as bytes

Source code in src/vericlient/vcsp/models.py
class BatchEnrollmentInput(BaseModel):
    """Input class for batch enrolment.

    The service takes a TAR archive holding the samples and an `applicants.json` that points
    at them. Pass `applicants` and the client builds it; pass `batch_file` if you have one
    already, which avoids holding a large batch in memory twice.

    Attributes:
        applicants: The enrolments to perform
        batch_file: A prepared TAR archive, as a path or as bytes

    """

    applicants: list[BatchApplicant] | None = None
    batch_file: str | bytes | None = None

    model_config = ConfigDict(arbitrary_types_allowed=True)

    @field_validator("batch_file")
    def exactly_one_source(cls, value: object, info: object):
        if value is None and not info.data.get("applicants"):
            error = "provide either applicants or batch_file"
            raise ValueError(error)
        if value is not None and info.data.get("applicants"):
            error = "provide applicants or batch_file, not both"
            raise ValueError(error)
        return value

TaskCreatedOutput

Bases: VcspResponse

Output class for any operation the service accepts and runs asynchronously.

Batch enrolment, clustering, and a large group population all answer this way. Follow the work with get_task or wait_for_task, and collect it with get_task_result.

Attributes:

Name Type Description
task_id str

The task the work runs under

created_at str

When the task was accepted

Source code in src/vericlient/vcsp/models.py
class TaskCreatedOutput(VcspResponse):
    """Output class for any operation the service accepts and runs asynchronously.

    Batch enrolment, clustering, and a large group population all answer this way. Follow the
    work with `get_task` or `wait_for_task`, and collect it with `get_task_result`.

    Attributes:
        task_id: The task the work runs under
        created_at: When the task was accepted

    """

    task_id: str
    created_at: str

SubjectClaimant

Bases: BaseModel

The reference for a 1:1 matching: one subject's credential.

Attributes:

Name Type Description
subject_id str

The subject to match against

credential_configuration_urn str

Which of the subject's credentials to use

assurance_method_urn str

The assurance method to apply

assurance dict

The values that method requires, such as {"biometric_threshold": 0.5}

Source code in src/vericlient/vcsp/models.py
class SubjectClaimant(BaseModel):
    """The reference for a 1:1 matching: one subject's credential.

    Attributes:
        subject_id: The subject to match against
        credential_configuration_urn: Which of the subject's credentials to use
        assurance_method_urn: The assurance method to apply
        assurance: The values that method requires, such as `{"biometric_threshold": 0.5}`

    """

    subject_id: str
    credential_configuration_urn: str
    assurance_method_urn: str
    assurance: dict

GroupClaimant

Bases: BaseModel

The reference for a 1:N matching: every credential in a group.

Attributes:

Name Type Description
group_name str

The group to match against

assurance_method_urn str

The assurance method to apply

assurance dict

The values that method requires

limit int | None

How many results to return, best first

filter dict | None

A JsonLogic expression narrowing the group, such as {"AND": [{"tag": "role:employee"}]}

Source code in src/vericlient/vcsp/models.py
class GroupClaimant(BaseModel):
    """The reference for a 1:N matching: every credential in a group.

    Attributes:
        group_name: The group to match against
        assurance_method_urn: The assurance method to apply
        assurance: The values that method requires
        limit: How many results to return, best first
        filter: A JsonLogic expression narrowing the group, such as
            `{"AND": [{"tag": "role:employee"}]}`

    """

    group_name: str
    assurance_method_urn: str
    assurance: dict
    limit: int | None = None
    filter: dict | None = None

MatchingInput

Bases: BaseModel

Input class for a matching operation.

Attributes:

Name Type Description
sample str | bytes

The biometric sample to match, as a path or as bytes

claimant SubjectClaimant | GroupClaimant

What to match it against — a SubjectClaimant for 1:1, a GroupClaimant for 1:N

sample_processing dict | None

Options for reading the sample, such as {"nchannel": 1}

content_type str | None

The media type to declare for the sample. Inferred when omitted

Source code in src/vericlient/vcsp/models.py
class MatchingInput(BaseModel):
    """Input class for a matching operation.

    Attributes:
        sample: The biometric sample to match, as a path or as bytes
        claimant: What to match it against — a `SubjectClaimant` for 1:1, a `GroupClaimant`
            for 1:N
        sample_processing: Options for reading the sample, such as `{"nchannel": 1}`
        content_type: The media type to declare for the sample. Inferred when omitted

    """

    sample: str | bytes
    claimant: SubjectClaimant | GroupClaimant
    sample_processing: dict | None = None
    content_type: str | None = None

    model_config = ConfigDict(arbitrary_types_allowed=True)

MatchingResult

Bases: BaseModel

One candidate a matching operation scored.

Attributes:

Name Type Description
subject_id str

The subject the matched credential belongs to

biometrics_score float

How closely the sample matched, from 0 to 1

match_status str

HIT or MISS, against the assurance thresholds

Source code in src/vericlient/vcsp/models.py
class MatchingResult(BaseModel):
    """One candidate a matching operation scored.

    Attributes:
        subject_id: The subject the matched credential belongs to
        biometrics_score: How closely the sample matched, from 0 to 1
        match_status: `HIT` or `MISS`, against the assurance thresholds

    """

    subject_id: str
    biometrics_score: float
    match_status: str

MatchedSample

Bases: BaseModel

What the service made of the sample it was given.

Attributes:

Name Type Description
type str

voice or face

content_type str

The media type it was read as

analysis dict

Quality figures, such as net speech duration or an authenticity score

sample_processing dict | None

The processing options that were applied

Source code in src/vericlient/vcsp/models.py
class MatchedSample(BaseModel):
    """What the service made of the sample it was given.

    Attributes:
        type: `voice` or `face`
        content_type: The media type it was read as
        analysis: Quality figures, such as net speech duration or an authenticity score
        sample_processing: The processing options that were applied

    """

    type: str
    content_type: str
    analysis: dict
    sample_processing: dict | None = None

MatchingOutput

Bases: VcspResponse

Output class for a matching operation.

Attributes:

Name Type Description
results list[MatchingResult]

The candidates, best first

nhits int

How many of them are a HIT

sample MatchedSample

What the service made of the sample

Source code in src/vericlient/vcsp/models.py
class MatchingOutput(VcspResponse):
    """Output class for a matching operation.

    Attributes:
        results: The candidates, best first
        nhits: How many of them are a `HIT`
        sample: What the service made of the sample

    """

    results: list[MatchingResult]
    nhits: int
    sample: MatchedSample

GroupAction

Bases: StrEnum

The actions modify_group can perform.

Source code in src/vericlient/vcsp/models.py
class GroupAction(StrEnum):
    """The actions `modify_group` can perform."""

    POPULATE = "populate"
    REMOVE = "remove"
    UPDATE_INFO = "update_info"

GroupMembershipSource

Bases: BaseModel

Which credentials a populate or remove applies to.

At least one of the two is required.

Attributes:

Name Type Description
subjects list[str] | None

Subject ids whose credentials to add or remove

tags list[str] | None

Tags whose credentials to add or remove

Source code in src/vericlient/vcsp/models.py
class GroupMembershipSource(BaseModel):
    """Which credentials a populate or remove applies to.

    At least one of the two is required.

    Attributes:
        subjects: Subject ids whose credentials to add or remove
        tags: Tags whose credentials to add or remove

    """

    subjects: list[str] | None = None
    tags: list[str] | None = None

ModifyGroupInput

Bases: GroupInput

Input class for modifying a group.

Attributes:

Name Type Description
name str

The group to modify

action str

populate, remove or update_info

from_ GroupMembershipSource | None

Which credentials to add or remove. Required for populate and remove, and serialised as from, which is a reserved word in Python

credential_ttl str | None

How long added credentials stay in the group, as an ISO 8601 duration such as P30D

description str | None

A new description, for update_info

expired_at str | None

A new retention period, for update_info, as an ISO 8601 duration

Source code in src/vericlient/vcsp/models.py
class ModifyGroupInput(GroupInput):
    """Input class for modifying a group.

    Attributes:
        name: The group to modify
        action: `populate`, `remove` or `update_info`
        from_: Which credentials to add or remove. Required for populate and remove, and
            serialised as `from`, which is a reserved word in Python
        credential_ttl: How long added credentials stay in the group, as an ISO 8601
            duration such as `P30D`
        description: A new description, for `update_info`
        expired_at: A new retention period, for `update_info`, as an ISO 8601 duration

    """

    action: str
    from_: GroupMembershipSource | None = Field(default=None, alias="from")
    credential_ttl: str | None = None
    description: str | None = None
    expired_at: str | None = None

    model_config = ConfigDict(populate_by_name=True)

CredentialTagAction

Bases: StrEnum

The actions modify_credential_tags can perform.

Source code in src/vericlient/vcsp/models.py
class CredentialTagAction(StrEnum):
    """The actions `modify_credential_tags` can perform."""

    ADD = "add"
    REMOVE = "remove"

ModifyCredentialTagsInput

Bases: SubjectInput, CredentialInput

Input class for changing the tags on a credential.

Attributes:

Name Type Description
subject_id str

The subject the credential belongs to

credential_id str

The credential to change

action str

add or remove

tags list[str]

The tags to add or remove. They must already exist in the system

Source code in src/vericlient/vcsp/models.py
class ModifyCredentialTagsInput(SubjectInput, CredentialInput):
    """Input class for changing the tags on a credential.

    Attributes:
        subject_id: The subject the credential belongs to
        credential_id: The credential to change
        action: `add` or `remove`
        tags: The tags to add or remove. They must already exist in the system

    """

    action: str
    tags: list[str]

ClusteringInput

Bases: GroupInput

Input class for starting a clustering task on a group.

Clustering is only supported for groups of face credentials; a voice group is rejected with ClusteringNotSupportedError.

Attributes:

Name Type Description
name str

The group to cluster

assurance_method_urn str

The clustering assurance method to apply

properties dict

The values that method requires, such as {"similarity_threshold": 0.5, "mode": "similarity_based"}. Note the service calls this properties, not assurance as everywhere else

Source code in src/vericlient/vcsp/models.py
class ClusteringInput(GroupInput):
    """Input class for starting a clustering task on a group.

    Clustering is only supported for groups of face credentials; a voice group is rejected
    with `ClusteringNotSupportedError`.

    Attributes:
        name: The group to cluster
        assurance_method_urn: The clustering assurance method to apply
        properties: The values that method requires, such as
            `{"similarity_threshold": 0.5, "mode": "similarity_based"}`. Note the service
            calls this `properties`, not `assurance` as everywhere else

    """

    assurance_method_urn: str
    properties: dict

vericlient.vcsp.exceptions

Module to define the exceptions for the VCSP API.

VcspError

Bases: VeriClientError

Base class for exceptions in the VCSP API.

Source code in src/vericlient/vcsp/exceptions.py
class VcspError(VeriClientError):
    """Base class for exceptions in the VCSP API."""

    def __init__(self, message: str) -> None:
        super().__init__(message)

EmptyFileError

Bases: VcspError

Exception raised for empty files.

Source code in src/vericlient/vcsp/exceptions.py
class EmptyFileError(VcspError):
    """Exception raised for empty files."""

    def __init__(self) -> None:
        message = "The file provided is empty"
        super().__init__(message)

RequestValidationError

Bases: VcspError

Exception raised for request validation.

Source code in src/vericlient/vcsp/exceptions.py
class RequestValidationError(VcspError):
    """Exception raised for request validation."""

    def __init__(self, details: list[dict]) -> None:
        message = f"The request is invalid. Details: {details}"
        super().__init__(message)

UnsupportedMediaTypeError

Bases: VcspError

Exception raised for unsupported media type.

Source code in src/vericlient/vcsp/exceptions.py
class UnsupportedMediaTypeError(VcspError):
    """Exception raised for unsupported media type."""

    def __init__(self) -> None:
        message = "The media type is not supported"
        super().__init__(message)

InvalidClaimsError

Bases: VcspError

Exception raised for invalid claims.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidClaimsError(VcspError):
    """Exception raised for invalid claims."""

    def __init__(self) -> None:
        message = "The claims provided don't match the required schema"
        super().__init__(message)

InvalidAssuranceError

Bases: VcspError

Exception raised for invalid assurance.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidAssuranceError(VcspError):
    """Exception raised for invalid assurance."""

    def __init__(self) -> None:
        message = "The assurance provided doesn't match the required schema"
        super().__init__(message)

InvalidTagsError

Bases: VcspError

Exception raised for invalid tags.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidTagsError(VcspError):
    """Exception raised for invalid tags."""

    def __init__(self) -> None:
        message = "Specified tags don't exist"
        super().__init__(message)

InvalidCredentialConfigurationUrnError

Bases: VcspError

Exception raised for invalid credential configuration urn.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidCredentialConfigurationUrnError(VcspError):
    """Exception raised for invalid credential configuration urn."""

    def __init__(self) -> None:
        message = "Specified credential configuration URN doesn't exist"
        super().__init__(message)

InvalidAssuranceMethodUrnError

Bases: VcspError

Exception raised for invalid assurance method.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidAssuranceMethodUrnError(VcspError):
    """Exception raised for invalid assurance method."""

    def __init__(self) -> None:
        message = "Specified assurance method URN doesn't exist"
        super().__init__(message)

CredentialConfigurationUrnAlreadyAssignedError

Bases: VcspError

Exception raised for already assigned credential configuration urn.

Source code in src/vericlient/vcsp/exceptions.py
class CredentialConfigurationUrnAlreadyAssignedError(VcspError):
    """Exception raised for already assigned credential configuration urn."""

    def __init__(self) -> None:
        message = "The specified credential configuration URN is already assigned to the applicant"
        super().__init__(message)

InvalidAudioFormatError

Bases: VcspError

Exception raised for invalid audio format.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidAudioFormatError(VcspError):
    """Exception raised for invalid audio format."""

    def __init__(self) -> None:
        message = "The audio format is not supported"
        super().__init__(message)

InvalidSnrError

Bases: VcspError

Exception raised for invalid signal noise ratio.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidSnrError(VcspError):
    """Exception raised for invalid signal noise ratio."""

    def __init__(self) -> None:
        message = "Invalid signal noise ratio"
        super().__init__(message)

VoiceDurationIsNotEnoughError

Bases: VcspError

Exception raised for voice duration not enough.

Source code in src/vericlient/vcsp/exceptions.py
class VoiceDurationIsNotEnoughError(VcspError):
    """Exception raised for voice duration not enough."""

    def __init__(self) -> None:
        message = "Voice duration is not enough"
        super().__init__(message)

InsufficientQualityError

Bases: VcspError

Exception raised for insufficient quality.

Source code in src/vericlient/vcsp/exceptions.py
class InsufficientQualityError(VcspError):
    """Exception raised for insufficient quality."""

    def __init__(self) -> None:
        message = "The audio quality is insufficient or may contain more than one speaker"
        super().__init__(message)

FaceNotFoundError

Bases: VcspError

Exception raised for face not found.

Source code in src/vericlient/vcsp/exceptions.py
class FaceNotFoundError(VcspError):
    """Exception raised for face not found."""

    def __init__(self) -> None:
        message = "Face not found"
        super().__init__(message)

MoreThanOneFaceError

Bases: VcspError

Exception raised for more than one face.

Source code in src/vericlient/vcsp/exceptions.py
class MoreThanOneFaceError(VcspError):
    """Exception raised for more than one face."""

    def __init__(self) -> None:
        message = "More than one face found"
        super().__init__(message)

FaceTooSmallError

Bases: VcspError

Exception raised for face too small.

Source code in src/vericlient/vcsp/exceptions.py
class FaceTooSmallError(VcspError):
    """Exception raised for face too small."""

    def __init__(self) -> None:
        message = "Face too small"
        super().__init__(message)

FaceAlignmentError

Bases: VcspError

Exception raised for face alignment error.

Source code in src/vericlient/vcsp/exceptions.py
class FaceAlignmentError(VcspError):
    """Exception raised for face alignment error."""

    def __init__(self) -> None:
        message = "Face alignment error"
        super().__init__(message)

AssuranceMethodNotFoundError

Bases: VcspError

Exception raised for assurance method not found.

Source code in src/vericlient/vcsp/exceptions.py
class AssuranceMethodNotFoundError(VcspError):
    """Exception raised for assurance method not found."""

    def __init__(self) -> None:
        message = "Assurance method not found"
        super().__init__(message)

AssuranceValidationError

Bases: VcspError

Exception raised for assurance validation error.

Source code in src/vericlient/vcsp/exceptions.py
class AssuranceValidationError(VcspError):
    """Exception raised for assurance validation error."""

    def __init__(self) -> None:
        message = "Assurance validation error"
        super().__init__(message)

AccountNotFoundError

Bases: VcspError

Exception raised for account not found.

Source code in src/vericlient/vcsp/exceptions.py
class AccountNotFoundError(VcspError):
    """Exception raised for account not found."""

    def __init__(self) -> None:
        message = "Account not found"
        super().__init__(message)

CredentialNotFoundError

Bases: VcspError

Exception raised for credential not found.

Source code in src/vericlient/vcsp/exceptions.py
class CredentialNotFoundError(VcspError):
    """Exception raised for credential not found."""

    def __init__(self) -> None:
        message = "Credential not found"
        super().__init__(message)

GroupNotFoundError

Bases: VcspError

Exception raised for group not found.

Source code in src/vericlient/vcsp/exceptions.py
class GroupNotFoundError(VcspError):
    """Exception raised for group not found."""

    def __init__(self) -> None:
        message = "Group not found"
        super().__init__(message)

GroupsLimitExceededError

Bases: VcspError

Exception raised for group limit exceeded.

Source code in src/vericlient/vcsp/exceptions.py
class GroupsLimitExceededError(VcspError):
    """Exception raised for group limit exceeded."""

    def __init__(self) -> None:
        message = "Group limit exceeded"
        super().__init__(message)

EnrollmentsLimitExceededError

Bases: VcspError

Exception raised for enrollment limit exceeded.

Source code in src/vericlient/vcsp/exceptions.py
class EnrollmentsLimitExceededError(VcspError):
    """Exception raised for enrollment limit exceeded."""

    def __init__(self) -> None:
        message = "Enrollment limit exceeded"
        super().__init__(message)

GroupAlreadyExistsError

Bases: VcspError

Exception raised for group already exists.

Source code in src/vericlient/vcsp/exceptions.py
class GroupAlreadyExistsError(VcspError):
    """Exception raised for group already exists."""

    def __init__(self) -> None:
        message = "Group already exists"
        super().__init__(message)

TagsLimitExceededError

Bases: VcspError

Exception raised for tags limit exceeded.

Source code in src/vericlient/vcsp/exceptions.py
class TagsLimitExceededError(VcspError):
    """Exception raised for tags limit exceeded."""

    def __init__(self) -> None:
        message = "Tags limit exceeded"
        super().__init__(message)

TagAlreadyExistsError

Bases: VcspError

Exception raised for tag already exists.

Source code in src/vericlient/vcsp/exceptions.py
class TagAlreadyExistsError(VcspError):
    """Exception raised for tag already exists."""

    def __init__(self) -> None:
        message = "Tag already exists"
        super().__init__(message)

TagListEmptyError

Bases: VcspError

Exception raised for tag list empty.

Source code in src/vericlient/vcsp/exceptions.py
class TagListEmptyError(VcspError):
    """Exception raised for tag list empty."""

    def __init__(self) -> None:
        message = "Tag list is empty"
        super().__init__(message)

TaskNotFoundError

Bases: VcspError

Exception raised when no task exists with the given identifier.

Source code in src/vericlient/vcsp/exceptions.py
class TaskNotFoundError(VcspError):
    """Exception raised when no task exists with the given identifier."""

    def __init__(self) -> None:
        message = "No task exists with that task_id."
        super().__init__(message)

InvalidBatchFileError

Bases: VcspError

Exception raised when a batch enrolment archive cannot be processed.

Source code in src/vericlient/vcsp/exceptions.py
class InvalidBatchFileError(VcspError):
    """Exception raised when a batch enrolment archive cannot be processed."""

    def __init__(self) -> None:
        message = (
            "The batch archive is not valid. It must be a TAR holding the samples and an "
            "applicants.json whose entries reference them as file://<name>."
        )
        super().__init__(message)

ClusteringNotSupportedError

Bases: VcspError

Exception raised when clustering is requested on a group it cannot run on.

Source code in src/vericlient/vcsp/exceptions.py
class ClusteringNotSupportedError(VcspError):
    """Exception raised when clustering is requested on a group it cannot run on."""

    def __init__(self) -> None:
        message = "Clustering is only supported for groups of face credentials."
        super().__init__(message)