@evid-ai/capture-sdk
v0.1.6
Published
Headless browser SDK for capturing evidence (photo + GPS + metadata) for the Evid-AI platform.
Readme
@evid-ai/capture-sdk
JavaScript/TypeScript SDK for integrating with the Evid-AI platform — manage task groups, teams, tasks, and submit evidence with tags from your own application.
Install
npm install @evid-ai/capture-sdk
# or
yarn add @evid-ai/capture-sdkSetup
import { CaptureSDK } from "@evid-ai/capture-sdk";
const sdk = new CaptureSDK({
apiKey: "pk_live_xxx",
gatewayUrl: "https://your-gateway.example.com",
});Authentication
Most resource methods require a user access token. Call sdk.auth.login() once and the SDK stores the token automatically for subsequent calls.
const { user } = await sdk.auth.login({
identifier: "[email protected]",
password: "secret",
});You can also pass an existing token at construction time:
const sdk = new CaptureSDK({
apiKey: "pk_live_xxx",
gatewayUrl: "https://your-gateway.example.com",
accessToken: "existing-token",
});Two-factor authentication (2FA)
If the account has TOTP 2FA enabled, login() returns twoFactorRequired: true and a short-lived challengeToken instead of a token. Collect the user's 6-digit TOTP code and call verify2FA() to finish.
const result = await sdk.auth.login({
identifier: "[email protected]",
password: "secret",
});
if (result.twoFactorRequired) {
const { user } = await sdk.auth.verify2FA({
challengeToken: result.challengeToken!,
code: "123456",
});
}challengeToken expires after 5 minutes; on timeout, re-run login().
Resources
sdk.teams
// List teams (paginated)
const page = await sdk.teams.list({ page: 1, pageSize: 20, search: "alpha" });
// Get a single team
const team = await sdk.teams.get("team-id");
// Create a team — requires API key scope: team:create
const team = await sdk.teams.create({
name: "Team Alpha",
members: ["user-id-1", "user-id-2"], // optional, user IDs
});
// Update a team — requires API key scope: team:update
await sdk.teams.update("team-id", {
name: "Team Alpha v2",
members: ["user-id-1", "user-id-3"],
});CreateTeamInput
| Field | Type | Required |
| --------- | ---------- | -------- |
| name | string | Yes |
| members | string[] | No |
UpdateTeamInput — all fields optional.
sdk.taskGroups
// List task groups, optionally filter by team
const page = await sdk.taskGroups.list({
teamId: "team-id",
page: 1,
pageSize: 20,
});
// Get a single task group
const group = await sdk.taskGroups.get("task-group-id");
// Create a task group — requires API key scope: task-group:create
const group = await sdk.taskGroups.create({
name: "Anexo A",
description: "Main annexe", // optional
shortName: "A", // optional
assignedTeams: ["team-id"], // optional, team IDs
autoAssignTeamMembers: true, // optional — auto-populate assignedUsers from team members
});
// Update a task group — requires API key scope: task-group:update
await sdk.taskGroups.update("task-group-id", {
name: "Anexo A (updated)",
assignedTeams: ["team-id-1", "team-id-2"],
autoAssignTeamMembers: true, // re-sync assignedUsers from new teams
});CreateTaskGroupInput
| Field | Type | Required | Description |
| ------------------------ | ---------- | -------- | ------------------------------------------------------------------------- |
| name | string | Yes | |
| description | string | No | |
| shortName | string | No | |
| assignedTeams | string[] | No | Team IDs to assign |
| autoAssignTeamMembers | boolean | No | When true and assignedUsers is empty, auto-populate from team members |
UpdateTaskGroupInput — all fields optional.
| Field | Type | Description |
| ------------------------ | ---------- | ------------------------------------------------------------------------- |
| name | string | |
| description | string | |
| shortName | string | |
| assignedTeams | string[] | Team IDs to assign |
| autoAssignTeamMembers | boolean | When true and assignedUsers is empty, auto-populate from team members |
sdk.tasks
// List tasks, optionally filter by task group or team
const page = await sdk.tasks.list({ taskGroupId: "tg-id", teamId: "team-id" });
// Get a single task
const task = await sdk.tasks.get("task-id");sdk.evidence
List evidence
const page = await sdk.evidence.list({
taskId: "task-id",
page: 1,
pageSize: 20,
});Create evidence
sdk.evidence.create() accepts any file type — photo, video, audio, or document.
const result = await sdk.evidence.create({
taskGroup: "task-group-id",
team: "team-id", // optional
task: "task-id", // optional
evidence: {
file: {
blob: file,
mimeType: file.type,
capturedAt: new Date().toISOString(),
name: file.name,
},
device: {
userAgent: navigator.userAgent,
language: navigator.language,
},
captureSurface: "headless",
metadata: {},
},
});
console.log(result.id);Multiple files in one call:
await sdk.evidence.create({
taskGroup: "task-group-id",
evidence: files.map((file) => ({
file: { blob: file, mimeType: file.type, capturedAt: new Date().toISOString() },
device: { userAgent: navigator.userAgent, language: navigator.language },
captureSurface: "headless",
metadata: {},
})),
});GPS coordinates are captured automatically before uploading. Pass
skipLocation: trueto submit without location data.
Tags
Attach typed metadata tags to evidence at creation time.
await sdk.evidence.create({
taskGroup: "task-group-id",
evidence: capturedEvidence,
tags: [
// General tag — text value
{
name: "Site name",
value: "Building A",
type: "text",
usagePurpose: "generalTag",
},
// General tag — numeric value
{
name: "Temperature",
value: 36.5,
type: "float",
usagePurpose: "generalTag",
},
// ESG tag
{
name: "CO2 emissions",
value: 120,
type: "integer",
usagePurpose: "esgTag",
esgPillar: "environment",
esgStandard: "gri",
unitOfMeasure: "kg",
},
],
});TagInput
| Field | Type | Required |
| ---------------- | --------------------------------- | -------- |
| name | string | Yes |
| value | string \| number \| boolean | Yes |
| type | TagType | Yes |
| usagePurpose | "generalTag" \| "esgTag" | Yes |
| esgPillar | EsgPillar | No |
| esgStandard | EsgStandard | No |
| unitOfMeasure | string | No |
TagType
| Value | Description |
| ---------- | ------------------- |
| text | String value |
| integer | Integer number |
| float | Decimal number |
| boolean | true / false |
| datetime | ISO 8601 string |
| gps | GPS coordinates |
EsgPillar: "environment" | "social" | "governance"
EsgStandard: "general" | "gri" | "sasb" | "cdp" | "tcfd" | "ir" | "un_sdgs" | "iso_26000" | "aa1000" | "iirc" | "eu_taxonomy"
CreateEvidenceInput
| Field | Type | Required |
| -------------- | ------------------------------------ | -------- |
| taskGroup | string | Yes |
| team | string | No |
| task | string | No |
| platform | 'web' \| 'mobile' \| 'capture-sdk' | No |
| tags | TagInput[] | No |
| evidence | EvidenceInput \| EvidenceInput[] | Yes |
| skipLocation | boolean | No |
API key scopes
Write operations require the API key to include specific scopes. Scopes are set when creating or rotating the key from the Strapi admin panel.
| Scope | Grants |
| ------------------- | ----------------------------- |
| evidence:create | Submit evidence |
| task-group:create | Create task groups |
| task-group:update | Update task groups |
| team:create | Create teams |
| team:update | Update teams |
Error handling
All SDK errors are CaptureSDKError with a typed code:
import { CaptureSDKError } from "@evid-ai/capture-sdk";
try {
await sdk.evidence.create({ ... });
} catch (err) {
if (err instanceof CaptureSDKError) {
console.error(err.code, err.message);
}
}| Code | Description |
| ----------------------- | -------------------------------------------- |
| UPLOAD_FAILED | Evidence submission to the server failed |
| GEO_UNAVAILABLE | Geolocation API not supported by the browser |
| GEO_PERMISSION_DENIED | User denied location permission |
| GEO_TIMEOUT | Geolocation request timed out |
| INVALID_CONFIG | Missing or invalid SDK configuration |
TypeScript
The SDK ships with full TypeScript declarations. All resource types are exported:
import type {
// Auth
LoginInput,
LoginResult,
Verify2FAInput,
AuthUser,
// Teams
Team,
ListTeamsParams,
CreateTeamInput,
UpdateTeamInput,
// Task groups
TaskGroup,
ListTaskGroupsParams,
CreateTaskGroupInput,
UpdateTaskGroupInput,
// Tasks
Task,
ListTasksParams,
// Evidence
MediaFile,
EvidenceInput,
CreateEvidenceInput,
EvidenceRecord,
// Tags
TagInput,
TagType,
TagUsagePurpose,
EsgPillar,
EsgStandard,
} from "@evid-ai/capture-sdk";Requirements
- Modern browser or Node.js 18+
- HTTPS (or
localhost) required for location access
