digid API reference

One JSON API for systems with API keys and staff sessions. Endpoints are grouped; each organization exposes the groups digid has enabled for it, and each API key calls only the groups it was given.

Base URL
https://digid-production.up.datahuru.com/api/v1
Authentication
Authorization: Bearer <credential> — an API key (sid_sk_, Settings → API keys) or a staff session token (sid_ust_).
Errors
{"error": {"code", "message", "details"?, "request_id"}} — program against code. A group that is not enabled for the organization, or not allowed on the key, is 403 api_group_disabled with details.group.
Conventions
JSON in and out; money as decimal strings in TZS; moments in ISO 8601 UTC. Idempotency-Key makes POST retries safe. 120 requests per minute per credential.
Organization path
Each organization also serves the API at /webservices/<organization>/api/v1, taking only that organization's credentials, with its own docs at /webservices/<organization>/api/docs.

Sign-in & sessions

Staff sign-in, onboarding and the session's own identity. Always available.

Always available.

POST /staff/auth/sign-in Sign in with a password

Signs a staff member in with an email or Tanzanian phone and a password and answers 201 with the staff session body (camelCase keys). A digid support person signing in by email gets 200 with a choice_token and the organizations they may open instead. Errors: 401 invalid_credentials, 403 password_setup_required or no_workspace (with an onboarding_token), 429 after 10 attempts per 15 minutes.

Credential: None (public)

Parameter In Type Description
identifier* body string Email, or a Tanzanian phone in any format.
password* body string Password.
device_label body string Labels the session in the sessions list, e.g. "Pixel 8" (up to 80 characters).
device_platform body string ios, android or web.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/sign-in" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "asha@example.com", "password": "correct horse battery", "device_label": "Pixel 8", "device_platform": "android"}'

Example response

{
  "data": {
    "token": "sid_ust_Zx8Kq2LmN4pR7tV1wY5bC9dF",
    "actor": "staff",
    "user": {
      "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "name": "Asha Mwakyusa",
      "email": "asha@example.com",
      "phone": "+255712000001",
      "role": "viewer",
      "orgRole": "member"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Central branch",
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
POST /staff/auth/digid-session Open an organization as a digid person

A digid support person opens an organization after sign-in, using the choice_token as the credential. Answers 201 with a staff session body (actor digid, role digid_admin) valid for 12 hours. Errors: 401 invalid_grant, 403 workspace_not_found, 422 missing_field.

Credential: None (public)

Parameter In Type Description
choice_token* body string From the sign-in response; valid 15 minutes.
organization_id* body string An organization from the sign-in response's workspaces.
branch_id body string A branch id. Default: the head office, else the first branch.
device_label body string Labels the session in the sessions list, e.g. "Pixel 8" (up to 80 characters).
device_platform body string ios, android or web.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/digid-session" \
  -H "Content-Type: application/json" \
  -d '{"choice_token": "SFMyNTY.g2gDbQAAACQ", "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c", "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d"}'

Example response

{
  "data": {
    "token": "sid_gst_Hq3Lm8Np2Rt6Vx0Zb4Df",
    "actor": "digid",
    "user": {
      "id": "7c2d1e0f-9a8b-4c7d-8e6f-5a4b3c2d1e0f",
      "name": "Peter Kamau",
      "email": "peter@example.com",
      "phone": null,
      "role": "digid_admin",
      "orgRole": "admin"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Head Office",
    "setup": {"state": "ready"},
    "permissions": ["manage:organization", "read:branches"],
    "raises_approvals": false
  }
}
POST /staff/auth/code Send a sign-in code

Sends a one-time 6-digit sign-in code by SMS or email. Always answers 202 for valid input, whether or not an account exists. Errors: 422 invalid_identifier, invalid_channel or missing_field, 429 rate_limited.

Credential: None (public)

Parameter In Type Description
identifier* body string Email or phone.
channel body string sms or email. Defaults to the identifier's kind.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/code" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "0712000001", "channel": "sms"}'

Example response

{"data": {"status": "sent"}}
POST /staff/auth/code/verify Verify a sign-in code

Exchanges a sign-in code (valid 5 minutes) for a staff session, answering 201 with the staff session body or 403 no_workspace. Errors: 401 invalid_code or code_expired, 429 too_many_attempts, 422 missing_field.

Credential: None (public)

Parameter In Type Description
identifier* body string The email or phone the code was sent to.
code* body string The 6-digit code.
device_label body string Labels the session in the sessions list, e.g. "Pixel 8" (up to 80 characters).
device_platform body string ios, android or web.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/code/verify" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "0712000001", "code": "482913"}'

Example response

{
  "data": {
    "token": "sid_ust_Zx8Kq2LmN4pR7tV1wY5bC9dF",
    "actor": "staff",
    "user": {
      "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "name": "Asha Mwakyusa",
      "email": "asha@example.com",
      "phone": "+255712000001",
      "role": "viewer",
      "orgRole": "member"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Central branch",
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
POST /staff/auth/phone-code Send a phone sign-in code

The phone-only form of the sign-in code request. Answers 202 whether or not an account uses the phone. Errors: 422 invalid_phone, 429 rate_limited.

Credential: None (public)

Parameter In Type Description
phone* body string Tanzanian phone in any format.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/phone-code" \
  -H "Content-Type: application/json" \
  -d '{"phone": "0712000001"}'

Example response

{"data": {"status": "sent"}}
POST /staff/auth/phone-code/verify Verify a phone sign-in code

Exchanges a phone code for a staff session, answering 201 with the staff session body or 403 no_workspace. Errors: 401 invalid_code or code_expired, 429 too_many_attempts, 422 missing_field.

Credential: None (public)

Parameter In Type Description
phone* body string The phone.
code* body string The 6-digit code.
purpose body string sign_in (default) or sign_up.
device_label body string Labels the session in the sessions list, e.g. "Pixel 8" (up to 80 characters).
device_platform body string ios, android or web.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/phone-code/verify" \
  -H "Content-Type: application/json" \
  -d '{"phone": "0712000001", "code": "482913", "purpose": "sign_in"}'

Example response

{
  "data": {
    "token": "sid_ust_Zx8Kq2LmN4pR7tV1wY5bC9dF",
    "actor": "staff",
    "user": {
      "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "name": "Asha Mwakyusa",
      "email": "asha@example.com",
      "phone": "+255712000001",
      "role": "viewer",
      "orgRole": "member"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Central branch",
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
POST /staff/session Switch workspace

Issues a new staff session token bound to another organization and branch and revokes the token sent; the old session's device label carries over. Staff session only (an API key gets 403 forbidden). Errors: 403 workspace_not_found, 422 missing_field.

Credential: Staff token (sid_ust_)

Parameter In Type Description
organization_id* body string From GET /me/workspaces.
branch_id body string A branch id. Default: the first branch the person can open.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/session" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c", "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d"}'

Example response

{
  "data": {
    "token": "sid_ust_Zx8Kq2LmN4pR7tV1wY5bC9dF",
    "actor": "staff",
    "user": {
      "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "name": "Asha Mwakyusa",
      "email": "asha@example.com",
      "phone": "+255712000001",
      "role": "viewer",
      "orgRole": "member"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Central branch",
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
POST /staff/auth/sign-out Sign out

Revokes the staff session token sent. With an API key it answers the same and revokes nothing; revoke a key in Settings instead.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/auth/sign-out" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{"data": {"status": "signed_out"}}
GET /staff/onboarding/invitations List pending invitations

The signed-in person's pending invitations, for someone with no workspace yet. Public route that takes the sid_onb_ grant from a 403 no_workspace, or a live staff session token; anything else gets 401 invalid_onboarding_token.

Credential: None (public)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/staff/onboarding/invitations"

Example response

{
  "data": [
    {
      "object": "invitation",
      "id": "f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "organization_name": "Acme Fintech",
      "organization_type": "business",
      "role": "member",
      "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
      "branch_name": "Central branch",
      "branch_role": "viewer",
      "expires_at": "2026-10-31T07:00:00Z"
    }
  ]
}
POST /staff/onboarding/invitations/:id/accept Accept an invitation

Joins the organization and answers 201 with a staff session body bound to the invitation's branch; a staff session token sent is revoked. Takes the sid_onb_ grant or a staff session token. An invitation with no branch answers 403 no_workspace with a fresh onboarding_token; other errors are 404 invitation_not_found and 422 invitation_expired.

Credential: None (public)

Parameter In Type Description
id* path string Invitation id.
device_label body string Labels the session in the sessions list, e.g. "Pixel 8" (up to 80 characters).
device_platform body string ios, android or web.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/onboarding/invitations/{id}/accept"

Example response

{
  "data": {
    "token": "sid_ust_Zx8Kq2LmN4pR7tV1wY5bC9dF",
    "actor": "staff",
    "user": {
      "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "name": "Asha Mwakyusa",
      "email": "asha@example.com",
      "phone": "+255712000001",
      "role": "viewer",
      "orgRole": "member"
    },
    "organizationId": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "organizationName": "Acme Fintech",
    "organizationType": "business",
    "branchId": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branchName": "Central branch",
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
POST /staff/onboarding/invitations/:id/decline Decline an invitation

Declines one of the person's pending invitations. Takes the sid_onb_ grant or a staff session token. Errors: 404 invitation_not_found.

Credential: None (public)

Parameter In Type Description
id* path string Invitation id.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/staff/onboarding/invitations/{id}/decline"

Example response

{"data": {"status": "declined"}}
GET /me Get the current credential

Who the credential is. A staff session gets a staff_session object with its organization, branch, setup state and permissions; an API key gets an api_client object with its role and key_prefix.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/me" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{
  "data": {
    "object": "staff_session",
    "actor": "staff",
    "id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
    "name": "Asha Mwakyusa",
    "role": "viewer",
    "orgRole": "member",
    "organization": {
      "id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "name": "Acme Fintech",
      "slug": "acme-fintech",
      "currency": "TZS",
      "type": "business",
      "registration_number": null,
      "tin": null,
      "phone": "+255700000000",
      "email": "info@example.com",
      "branch_roles": ["branch_manager", "viewer"]
    },
    "branch": {"id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d", "name": "Central branch", "code": "CEN"},
    "setup": {"state": "ready"},
    "permissions": ["read:branches", "read:approval_requests", "read:audit_log"],
    "raises_approvals": true
  }
}
GET /me/workspaces List workspaces

Every organization the person can work in, with its branches; organizations where they can open no branch are left out. For a digid person it lists every organization. Staff session only.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/me/workspaces" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "object": "workspace",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "organization_name": "Acme Fintech",
      "organization_type": "business",
      "role": "member",
      "branch_role": "viewer",
      "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
      "branch_name": "Central branch",
      "branches": [{"id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d", "name": "Central branch"}],
      "current": true
    }
  ]
}

Team & approvals

Members, invitations, branches, and the maker-checker approval queue.

Governs API keys: digid enables it for the organization, then each key is given it or not.

GET /org/members List members

The organization's memberships with their users, oldest first. Owners and admins only, so no API key can call it (403 forbidden).

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/org/members" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "id": "71b38e9f-0a1b-4c2d-9e3f-4a5b6c7d8e9f",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "user_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "role": "member",
      "branch_assignment": null,
      "inserted_at": "2026-06-01T08:00:00Z",
      "updated_at": "2026-06-01T08:00:00Z",
      "user": {"id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha Mwakyusa", "email": "asha@example.com", "phone": "+255712000001"}
    }
  ]
}
PATCH /org/members/:id Change a member's role

Changes a membership's organization role through the maker-checker policy: 200 when it took effect, 202 while it waits for a checker. Only owners may make or change owners and the last owner cannot be demoted. Errors: 403 forbidden, 404 not_found, 422 last_owner.

Credential: Staff token (sid_ust_)

Parameter In Type Description
id* path string Membership id.
role* body string owner, admin or member.

Example request

curl -X PATCH "https://digid-production.up.datahuru.com/api/v1/org/members/{id}" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Content-Type: application/json" \
  -d '{"role": "admin"}'

Example response

{
  "data": {
    "status": "pending",
    "approval_request_id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
    "action_code": "organization.member.update_role"
  }
}
DELETE /org/members/:id Remove a member

Removes a member and their branch access through the maker-checker policy: 200 when done, 202 while it waits for a checker. Owners and admins only. Errors: 403 forbidden, 404 not_found, 422 last_owner.

Credential: Staff token (sid_ust_)

Parameter In Type Description
id* path string Membership id.

Example request

curl -X DELETE "https://digid-production.up.datahuru.com/api/v1/org/members/{id}" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": {
    "status": "executed",
    "approval_request_id": null,
    "action_code": null
  }
}
GET /org/invitations List invitations

All of the organization's invitations, newest first, without their tokens. Owners and admins only.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/org/invitations" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "id": "f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "email": "grace@example.com",
      "phone": null,
      "role": "member",
      "status": "pending",
      "expires_at": "2026-10-31T07:00:00Z",
      "invited_by_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
      "branch_role": "viewer",
      "branch": null,
      "inserted_at": "2026-10-24T07:00:00Z",
      "updated_at": "2026-10-24T07:00:00Z"
    }
  ]
}
POST /org/invitations Invite a staff member

Invites a person by email or phone through the organization's approval rules: 201 with the invitation when it goes out at once, or 202 with a pending approval request. Owners and admins only. Errors: 422 invalid_recipient, invalid_branch_assignment, branch_inactive or validation_failed, 404 branch_not_found.

Credential: Staff token (sid_ust_)

Parameter In Type Description
recipient* body string An email address or a Tanzanian phone number.
role* body string owner, admin or member.
branch_id body string Starting branch for a member; send with branch_role or not at all.
branch_role body string Starting branch role for a member, e.g. cashier.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/org/invitations" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"recipient": "0712000002", "role": "member", "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d", "branch_role": "viewer"}'

Example response

{
  "data": {
    "id": "f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
    "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "email": null,
    "phone": "+255712000002",
    "role": "member",
    "status": "pending",
    "expires_at": "2026-10-31T07:00:00Z",
    "invited_by_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
    "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branch_role": "viewer",
    "branch": null,
    "inserted_at": "2026-10-24T07:00:00Z",
    "updated_at": "2026-10-24T07:00:00Z"
  }
}
POST /org/invitations/:id/resend Resend an invitation

Sends a pending invitation again with a fresh expiry. Owners and admins only. Errors: 404 not_found, 422 invitation_not_pending or rate_limited (3 resends per invitation per hour).

Credential: Staff token (sid_ust_)

Parameter In Type Description
id* path string Invitation id.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/org/invitations/{id}/resend" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{
  "data": {
    "id": "f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
    "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "email": null,
    "phone": "+255712000002",
    "role": "member",
    "status": "pending",
    "expires_at": "2026-10-31T07:00:00Z",
    "invited_by_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
    "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branch_role": "viewer",
    "branch": null,
    "inserted_at": "2026-10-24T07:00:00Z",
    "updated_at": "2026-10-24T07:00:00Z"
  }
}
POST /org/invitations/:id/revoke Revoke an invitation

Cancels a pending invitation so its link stops working. Owners and admins only. Errors: 404 not_found, 422 invitation_not_pending.

Credential: Staff token (sid_ust_)

Parameter In Type Description
id* path string Invitation id.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/org/invitations/{id}/revoke" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{
  "data": {
    "id": "f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
    "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
    "email": null,
    "phone": "+255712000002",
    "role": "member",
    "status": "canceled",
    "expires_at": "2026-10-31T07:00:00Z",
    "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "branch_role": "viewer",
    "inserted_at": "2026-10-24T07:00:00Z",
    "updated_at": "2026-10-24T09:00:00Z"
  }
}
GET /org/branches List branches

The organization's branches as stored records. Any role may read branches.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/org/branches" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{
  "data": [
    {
      "id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "name": "Central branch",
      "code": "CEN",
      "is_head_office": true,
      "status": "active",
      "address": "Station Road",
      "town": "Arusha",
      "phone": "+255700000000",
      "email": "central@example.com",
      "manager_id": null,
      "inserted_at": "2026-06-01T08:00:00Z",
      "updated_at": "2026-06-01T08:00:00Z"
    }
  ]
}
GET /org/branches/:id Get a branch

One branch with its profile and staff.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Branch id.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/org/branches/{id}" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{
  "data": {
    "object": "branch",
    "id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "name": "Central branch",
    "code": "CEN",
    "status": "active",
    "is_head_office": true,
    "town": "Arusha",
    "address": null,
    "phone": "+255700000000",
    "email": "central@example.com",
    "staff": [
      {"user_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha Mwakyusa", "email": "asha@example.com", "phone": "+255712000001", "role": "viewer"}
    ]
  }
}
GET /approval-requests List pending approval requests

Pending maker-checker requests in the caller's scope, newest first, not paged; can_check says whether the caller may decide each one. Branch managers (and owners and admins) may read the queue; branch_manager API keys too.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/approval-requests" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{"data": [{    "object": "approval_request",
    "id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
    "action_code": "branch.member.add",
    "entity_type": "branch",
    "entity_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "entity_label": "Central branch",
    "amount": null,
    "status": "pending",
    "approval_mode": "standard",
    "required_checkers": 1,
    "approved_count": 0,
    "maker": {"id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha Mwakyusa"},
    "payload": {"user_id": "d3f45b6c-7d8e-4f9a-8b0c-1d2e3f4a5b6c", "role": "viewer"},
    "created_at": "2026-10-24T07:42:10Z",
    "previous_request_id": null,
    "resubmitted_request_id": null,
    "changes_requested": null,
    "decisions": [],
    "branch": {"id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d", "name": "Central branch"},
    "can_check": true
}]}
GET /approval-requests/:id Get an approval request

One request plus history, the earlier requests in its resubmission chain. Those who read the queue see any request; anyone else only the requests they raised. Errors: 403 forbidden, 404 not_found.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Approval request id.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/approval-requests/{id}" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{"data": {    "object": "approval_request",
    "id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
    "action_code": "branch.member.add",
    "entity_type": "branch",
    "entity_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
    "entity_label": "Central branch",
    "amount": null,
    "status": "pending",
    "approval_mode": "standard",
    "required_checkers": 1,
    "approved_count": 0,
    "maker": {"id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha Mwakyusa"},
    "payload": {"user_id": "d3f45b6c-7d8e-4f9a-8b0c-1d2e3f4a5b6c", "role": "viewer"},
    "created_at": "2026-10-24T07:42:10Z",
    "previous_request_id": null,
    "resubmitted_request_id": null,
    "changes_requested": null,
    "decisions": [],
    "branch": {"id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d", "name": "Central branch"},
    "can_check": true
, "history": []}}
POST /approval-requests/:id/approve Approve a request

Records an approval; when quorum is met the action runs and the status is executed, otherwise pending with the approved count. The caller must be a checker for the action under the Approval Rules and not its maker. Errors: 403 forbidden, 404 not_found, 422 not_pending, already_decided, maker_cannot_check or not_a_checker.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Approval request id.
reason body string Why.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/approval-requests/{id}/approve" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Arrears confirmed"}'

Example response

{"data": {"status": "executed", "id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a"}}
POST /approval-requests/:id/reject Reject a request

One rejection ends the request and unwinds anything the maker staged. Same checker rules and errors as approve, plus 422 reason_required where the action needs a reason.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Approval request id.
reason body string Why.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/approval-requests/{id}/reject" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Staff member left the branch"}'

Example response

{"data": {"status": "rejected", "id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a"}}
POST /approval-requests/:id/request-changes Send a request back for changes

Sends the request back to its maker with a required reason; only some actions can be sent back. Errors: 422 reason_required or changes_not_supported, plus the approve errors.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Approval request id.
reason* body string What to change.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/approval-requests/{id}/request-changes" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Attach the seal number"}'

Example response

{"data": {"status": "changes_requested", "id": "55c49f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a"}}
POST /approval-requests/:id/resubmit Resubmit a request

Always refused: a returned request is revised and raised again from its record. Answers 422 not_returned or resubmit_not_supported.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Approval request id.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/approval-requests/{id}/resubmit" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>"

Example response

No body
GET /approval-policies List approval policies

The organization's stored maker-checker policies, by action code. Owners and admins only, so no API key can call it.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/approval-policies" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "id": "3b4c7d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8f",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "action_code": "branch.member.add",
      "amount_min": null,
      "amount_max": null,
      "required_checkers": 1,
      "is_active": true,
      "inserted_at": "2026-06-01T08:00:00Z",
      "updated_at": "2026-06-01T08:00:00Z"
    }
  ]
}
GET /approval-rules Get the approval rules

The Approval Rules page, read-only: for each action, which roles may make and check it at a branch or organization-wide, plus people named one by one. Owners and admins only.

Credential: Staff token (sid_ust_)

Parameter In Type Description
branch_id query string A branch id; leave out for the organization-wide rules.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/approval-rules" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": {
    "object": "approval_rules",
    "branch_id": null,
    "roles": [{"role": "owner", "label": "Owner"}, {"role": "branch_manager", "label": "Branch manager"}],
    "actions": [
      {"action_code": "branch.member.add", "label": "Branch staff added", "makers": ["branch_manager"], "checkers": ["admin"]}
    ],
    "assignments": [
      {
        "action_code": "branch.member.add",
        "label": "Branch staff added",
        "branch_id": null,
        "user": {"id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha Mwakyusa"},
        "can_make": true,
        "can_check": false
      }
    ]
  }
}

Notifications & audit

In-app notifications and the audit trail.

Governs API keys: digid enables it for the organization, then each key is given it or not.

GET /notifications List notifications

The staff notification bell, generated from the caller's work queues (pending invitations, for owners and admins), with read state per person. Errors: 422 forbidden for a branch_id other than the caller's branch.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
limit query integer 1 to 30, default 10.
branch_id query string Must be the caller's branch if given.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/notifications" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{
  "data": {
    "items": [
      {
        "id": "invite-f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e",
        "kind": "team_invitation_pending",
        "severity": "info",
        "title": "Pending team invitation",
        "message": "asha@example.com has not accepted the invitation yet.",
        "created_at": "2026-10-24T07:42:10Z",
        "branch_id": null,
        "path": "/customer/dashboard/acme-fintech/9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d/settings/team",
        "is_read": false
      }
    ],
    "unread_count": 1,
    "generated_at": "2026-10-24T07:42:10Z"
  }
}
POST /notifications/read-all Mark all notifications read

Marks the current items as read, taking the same limit and branch_id as the list. An API key's read state belongs to its service user.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
limit body integer 1 to 30, default 10.
branch_id body string Must be the caller's branch if given.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/notifications/read-all" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{"data": {"marked_count": 1, "read_at": "2026-10-24T07:45:00Z"}}
POST /notifications/:id/read Mark a notification read

Marks one notification item as read for the caller. The item comes back unread when its count changes.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Notification item id, e.g. invite-f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/notifications/{id}/read" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{"data": {"notification_id": "invite-f1a27d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e", "read_at": "2026-10-24T07:45:00Z"}}
GET /audit/events List audit events

The organization's activity log for the caller's branch, newest first; organization-level events with no branch are not listed. Branch managers and accountants (and owners and admins) may read it. Bad paging answers 422 invalid_pagination; from and to are accepted but have no effect yet.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
user_id query string Actor id.
action query string e.g. api_client.created, membership.removed, invitation.created.
entity_type query string e.g. service_account.
entity_id query string An entity id.
request_id query string An approval request id.
category query string A timeline category.
result query string success, failure, denied or pending.
source query string api, ui, system or worker.
search query string Free text.
page query integer Page number, from 1. A page past the end returns the last page.
page_size query integer 10, 25, 50 or 100. Default 25.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/audit/events" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{
  "data": [
    {
      "id": "6d7e6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "branch_id": "9d2a6b1c-3e4f-4a5b-9c8d-7e6f5a4b3c2d",
      "user_id": "c41d1b2c-3d4e-4f5a-8b6c-7d8e9f0a1b2c",
      "request_id": null,
      "actor_type": "customer",
      "action": "api_client.created",
      "entity_type": "api_client",
      "entity_id": "e5c23a4b-5c6d-4e7f-8a9b-0c1d2e3f4a5b",
      "result": "success",
      "source": "api",
      "changes": {},
      "metadata": {},
      "ip_address": null,
      "user_agent": null,
      "created_at": "2026-10-24T07:42:10Z",
      "user": {"id": "c41d1b2c-3d4e-4f5a-8b6c-7d8e9f0a1b2c", "name": "API · Back office"}
    }
  ],
  "meta": {"page": 1, "page_size": 25, "total": 1, "page_count": 1}
}

Licences

The organization's SDK licences, and fresh signed tokens for them so a backend can rotate the token its apps use.

Governs API keys: digid enables it for the organization, then each key is given it or not.

GET /licences List licences

The organization's SDK licences, active first: environment (sandbox or production), status (draft, active, revoked, expired), features, app bindings and term. Licences are per app and per term, not metered. Any member or key may read them.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/licences" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{"data": [{    "object": "licence",
    "id": "lic_0b8f2c3e-1d4a-4b5c-9e6f-7a8b9c0d1e2f",
    "organization_id": "org_5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
    "name": "KYC app, production",
    "env": "production",
    "status": "active",
    "features": ["card_ocr", "face_match", "liveness"],
    "apps": {
      "android": [{"package": "tz.co.example.app", "cert_sha256": ["AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89"]}],
      "ios": [{"bundle_id": "tz.co.example.app", "team_id": "ABCDE12345"}],
      "web": [{"origin": "https://kyc.example.co.tz"}]
    },
    "valid_from": "2026-10-31T21:00:00Z",
    "valid_until": "2027-01-30T20:59:59Z",
    "activated_at": "2026-10-29T07:00:00Z",
    "revoked_at": null,
    "last_minted_at": "2026-10-29T07:05:00Z",
    "created_at": "2026-10-29T06:50:00Z",
    "updated_at": "2026-10-29T07:05:00Z"
}]}
GET /licences/:id Get a licence

One licence. Errors: 404 not_found.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Licence id, with or without its lic_ prefix.

Example request

curl "https://digid-production.up.datahuru.com/api/v1/licences/{id}" \
  -H "Authorization: Bearer sid_sk_…"

Example response

{"data": {    "object": "licence",
    "id": "lic_0b8f2c3e-1d4a-4b5c-9e6f-7a8b9c0d1e2f",
    "organization_id": "org_5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
    "name": "KYC app, production",
    "env": "production",
    "status": "active",
    "features": ["card_ocr", "face_match", "liveness"],
    "apps": {
      "android": [{"package": "tz.co.example.app", "cert_sha256": ["AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89"]}],
      "ios": [{"bundle_id": "tz.co.example.app", "team_id": "ABCDE12345"}],
      "web": [{"origin": "https://kyc.example.co.tz"}]
    },
    "valid_from": "2026-10-31T21:00:00Z",
    "valid_until": "2027-01-30T20:59:59Z",
    "activated_at": "2026-10-29T07:00:00Z",
    "revoked_at": null,
    "last_minted_at": "2026-10-29T07:05:00Z",
    "created_at": "2026-10-29T06:50:00Z",
    "updated_at": "2026-10-29T07:05:00Z"
}}
POST /licences/:id/tokens Mint a licence token

Signs a fresh offline licence token (digidlic1.…) for an active licence; pass it to the SDK (Engine::new / Digid.init). Its exp is the licence's valid_until and nbf its valid_from, so a backend can mint after every renewal and serve the token to its apps; its plan claim says monthly, payg or enterprise. A pay-as-you-go product's token lives 7 days (with a grace claim of 3 days offline) and is minted only while the product has credit; here it is a bootstrap token, at most once every 30 days per licence, which new phones start from: phones then renew theirs with their usage reports (POST /licences/renew). Tokens are not stored and minting is audited. Owners, admins, branch managers and branch-manager keys only. Errors: 402 insufficient_credit (pay as you go, no credit left: top up), 403 forbidden, 404 not_found, 409 bootstrap_limit, 422 licence_not_active, licence_expired or no_signing_key.

Credential: API key (sid_sk_) or staff token (sid_ust_)

Parameter In Type Description
id* path string Licence id, with or without its lic_ prefix.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/licences/{id}/tokens" \
  -H "Authorization: Bearer sid_sk_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{
  "data": {
    "object": "licence_token",
    "licence_id": "lic_0b8f2c3e-1d4a-4b5c-9e6f-7a8b9c0d1e2f",
    "kid": "2026-10",
    "token": "digidlic1.eyJ2IjoxLCJraWQiOiIyMDI2LTEwIiwi….Cgm58rk8NVk6kEOfrojOd4jX77csfYG_RFE1WsQoA6o7NwUy5tUMyNW7J-buXbPOu51Cbro3E6CJ-czi8Y4ECQ",
    "issued_at": "2026-10-29T07:05:00Z",
    "expires_at": "2027-01-30T20:59:59Z"
  }
}

Usage reports

The SDK's signed daily usage counts (licence, app, day, count; no personal data), posted by the app or relayed by your backend. Authenticated by the licence token inside each report. Always available.

Always available.

POST /usage Report daily usage

Takes one of the SDK's signed daily usage reports (digidusage1.…, from usage_reports in every SDK) and records its count: completed verifications under a licence, in one app, on one business day (Africa/Dar_es_Salaam), for one anonymous counter. Counts only; no personal data. No API key: the licence token inside the report authenticates it, and the report must name the token's licence and an app the token binds. Re-posting the same licence, app, day and counter replaces the count (it never goes down); it does not add. Pay-as-you-go products' credits go down by the increase; monthly products are measured against the fair-use cap, which never blocks. Errors: 422 malformed, bad_signature, invalid_token, invalid_report, app_not_licensed, invalid_day (in the future, over 35 days old or outside the token's validity), invalid_count (0–10,000 per counter and day), invalid_batch, missing_field.

Credential: None (public)

Parameter In Type Description
report* body string The SDK's report: digidusage1.<base64url body>.<base64url MAC>.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/usage" \
  -H "Content-Type: application/json" \
  -d '{"report": "digidusage1.eyJ2IjoxLCJsaWMiOiJsaWNfMGI4ZjJjM2UiLCJhcHAiOiJ0ei5jby5leGFtcGxlLmFwcCIsImRheSI6IjIwMjYtMTAtMzAiLCJiYXRjaCI6IjNmOWExYzA0ZDJlNzQ4YjUiLCJjb3VudCI6MTIsInRva2VuIjoiZGlnaWRsaWMxLuKApiJ9.q5k2H1sV0Jc8oQyXl7pN4mZ2tR9wE3uA6bD0fG1hI2Y"}'

Example response

{
  "data": {
    "object": "usage_report",
    "licence_id": "lic_0b8f2c3e-1d4a-4b5c-9e6f-7a8b9c0d1e2f",
    "app": "tz.co.example.app",
    "day": "2026-10-30",
    "batch": "3f9a1c04d2e748b5",
    "count": 12
  }
}
POST /licences/renew Renew a licence token

Takes the SDK's renewal request (digidrenew1.…, from renewLicence / renewal_request in every SDK) and answers with the phone's next licence token. The app treats request and response as opaque; a backend can forward both server-to-server. No API key: the licence token inside authenticates it. The request carries the phone's signed usage reports (counts only), which are applied first. Pay as you go: no report, no renewal. Each phone has a random counter id; a phone that renewed before must have a report (zero counts included) for every business day since its last renewal, a new phone for every day since the token it holds was issued (at most 7 days), and never more than the last 35 days. Monthly and Enterprise licences renew without that check. Errors: 409 usage_report_missing (details.missing_days, ISO dates), 402 insufficient_credit, 422 malformed, bad_signature, invalid_token, invalid_report, app_not_licensed, invalid_counter, invalid_day, invalid_count, licence_not_active, licence_expired, missing_field.

Credential: None (public)

Parameter In Type Description
request* body string The SDK's renewal request: digidrenew1.<base64url body>.<base64url MAC>.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/licences/renew" \
  -H "Content-Type: application/json" \
  -d '{"request": "digidrenew1.eyJ2IjoxLCJsaWMiOiJsaWNfMGI4ZjJjM2UiLCJhcHAiOiJ0ei5jby5leGFtcGxlLmFwcCIsImN0ciI6IjNmOWExYzA0ZDJlNzQ4YjUiLCJkYXkiOiIyMDI2LTEwLTMwIiwicmVwb3J0cyI6W10sInRva2VuIjoiZGlnaWRsaWMxLuKApiJ9.q5k2H1sV0Jc8oQyXl7pN4mZ2tR9wE3uA6bD0fG1hI2Y"}'

Example response

{
  "data": {
    "object": "licence_token",
    "licence_id": "lic_0b8f2c3e-1d4a-4b5c-9e6f-7a8b9c0d1e2f",
    "plan": "payg",
    "token": "digidlic1.eyJ2IjoxLCJraWQiOiIyMDI2LTEwIiwi….Cgm58rk8NVk6kEOfrojOd4jX77csfYG_RFE1WsQoA6o7NwUy5tUMyNW7J-buXbPOu51Cbro3E6CJ-czi8Y4ECQ",
    "issued_at": "2026-10-30T07:05:00Z",
    "expires_at": "2026-11-06T07:05:00Z"
  }
}

Staff sessions

Staff sign in with their own account (sid_ust_ tokens) and reach what their role allows. Includes the staff account endpoints (profile, password, sessions).

Governs staff session sign-ins for the organization, not API keys.

PATCH /me Change my display name

Changes the signed-in person's display name. Staff session only (an API key gets 403). Errors: 422 invalid_name, validation_failed.

Credential: Staff token (sid_ust_)

Parameter In Type Description
name* body string 2 to 120 characters.

Example request

curl -X PATCH "https://digid-production.up.datahuru.com/api/v1/me" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Content-Type: application/json" \
  -d '{"name": "Asha M. Mwakyusa"}'

Example response

{"data": {"id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c", "name": "Asha M. Mwakyusa"}}
POST /me/password Change my password

Changes the password after checking the current one; web sessions and every other app session are signed out and an email confirms the change. Staff session only. Errors: 422 invalid_current_password, password_too_short or missing_field.

Credential: Staff token (sid_ust_)

Parameter In Type Description
current_password* body string The current password.
password* body string The new password, at least 12 characters.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/me/password" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"current_password": "old horse battery", "password": "correct horse battery staple"}'

Example response

{"data": {"status": "changed"}}
POST /me/revoke-sessions Sign out everywhere else

Signs the person out of every browser and every other app session; the calling token stays. Staff session only.

Credential: Staff token (sid_ust_)

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/me/revoke-sessions" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{"data": {"status": "revoked"}}
GET /me/security-events List my security events

The person's last 25 sign-in and account-security events, newest first. Staff session only.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/me/security-events" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "id": "8a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d",
      "surface": "customer",
      "user_id": "6f1c2a3b-4d5e-4f6a-8b7c-9d0e1f2a3b4c",
      "event": "password_changed",
      "metadata": {},
      "inserted_at": "2026-10-24T07:42:10Z"
    }
  ]
}
POST /me/phone Start a phone number change

Texts a code to the new number and answers 202; confirm with POST /me/phone/verify. Staff session only. Errors (all 422): invalid_phone, phone_taken, rate_limited, delivery_failed, missing_field.

Credential: Staff token (sid_ust_)

Parameter In Type Description
phone* body string The new Tanzanian phone number.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/me/phone" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"phone": "0712000009"}'

Example response

{"data": {"status": "code_sent"}}
POST /me/phone/verify Confirm a phone number change

Checks the code sent by POST /me/phone and swaps the phone on the account. Staff session only. Errors (all 422): invalid, expired, too_many_attempts, phone_taken, verification_failed, missing_field.

Credential: Staff token (sid_ust_)

Parameter In Type Description
code* body string The code texted to the new number.

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/me/phone/verify" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>" \
  -H "Content-Type: application/json" \
  -d '{"code": "482913"}'

Example response

{"data": {"status": "verified"}}
GET /me/notification-preferences Get my push preferences

The person's push notification categories, all on until turned off. Staff session only.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/me/notification-preferences" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": {
    "object": "notification_preferences",
    "channel": "email",
    "approvals": false
  }
}
PUT /me/notification-preferences Update my push preferences

Turns push categories on or off; categories left out keep their value. Staff session only. Errors: 422 validation_failed for a non-boolean value.

Credential: Staff token (sid_ust_)

Parameter In Type Description
approvals body boolean Approval request and decision emails.

Example request

curl -X PUT "https://digid-production.up.datahuru.com/api/v1/me/notification-preferences" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Content-Type: application/json" \
  -d '{"approvals": false}'

Example response

{
  "data": {
    "object": "notification_preferences",
    "channel": "email",
    "approvals": false
  }
}
GET /me/sessions List my sessions

The person's live app sessions, most recently used first; current marks the calling one. Staff session only.

Credential: Staff token (sid_ust_)

Example request

curl "https://digid-production.up.datahuru.com/api/v1/me/sessions" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{
  "data": [
    {
      "object": "session",
      "id": "2b8e0a1b-2c3d-4e4f-9a5b-6c7d8e9f0a1b",
      "device_label": "Pixel 8",
      "platform": "android",
      "organization_id": "0b7e4c1a-2d3f-4e5a-8b9c-1d2e3f4a5b6c",
      "organization_name": "Acme Fintech",
      "created_at": "2026-10-01T06:00:00Z",
      "last_used_at": "2026-10-24T07:42:10Z",
      "expires_at": "2026-10-31T06:00:00Z",
      "current": true
    }
  ]
}
DELETE /me/sessions/:id Sign one session out

Revokes one of the person's app sessions. Staff session only. Errors: 404 not_found.

Credential: Staff token (sid_ust_)

Parameter In Type Description
id* path string Session id from GET /me/sessions.

Example request

curl -X DELETE "https://digid-production.up.datahuru.com/api/v1/me/sessions/{id}" \
  -H "Authorization: Bearer sid_ust_…"

Example response

{"data": {"status": "revoked"}}
POST /me/deletion-code Request an account deletion code

Texts a deletion code to the person's verified phone and answers 202; confirm with DELETE /me. Staff session only. Errors: 422 no_phone, 429 rate_limited, 503 delivery_failed.

Credential: Staff token (sid_ust_)

Example request

curl -X POST "https://digid-production.up.datahuru.com/api/v1/me/deletion-code" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Idempotency-Key: <uuid>"

Example response

{"data": {"status": "code_sent"}}
DELETE /me Delete my account

Deletes the person's staff account once the texted code checks out. Staff session only. Errors: 422 last_owner (details.organizations lists them), invalid_code or code_expired, 429 too_many_attempts.

Credential: Staff token (sid_ust_)

Parameter In Type Description
code* body string The code from POST /me/deletion-code.

Example request

curl -X DELETE "https://digid-production.up.datahuru.com/api/v1/me" \
  -H "Authorization: Bearer sid_ust_…" \
  -H "Content-Type: application/json" \
  -d '{"code": "482913"}'

Example response

{"data": {"status": "deleted"}}

Webhooks

Events digid pushes to your HTTPS endpoints, set up under Settings → Webhooks. Outbound only; documented here for reference.

Outbound only: nothing to call.

Owners and admins add HTTPS endpoints under Settings → Webhooks and choose the event types (or *). Each event is a signed JSON POST; verify the signature with the endpoint's signing secret, shown once when the endpoint is saved or its secret rotated.

Delivered today:

  • Approvals: approval.submitted , approval.approved , approval.rejected , approval.overridden .
  • Licences: licence.activated , licence.renewed , licence.revoked , licence.expiring (licence.expiring 30, 14 and 3 days before the end of term; the body is the licence plus days_remaining).
  • Subscriptions: subscription.created , subscription.activated , subscription.renewed , subscription.updated , subscription.past_due , subscription.cancelled , subscription.expired (the body is the subscription).
  • Invoices: invoice.issued , invoice.paid , invoice.voided (the body is the invoice, with its lines, totals and amount due).
  • Payments: payment.succeeded , payment.failed (the body is the payment; no payer details are sent).
  • Pay-as-you-go credits: credits.granted , credits.adjusted , credits.low , credits.exhausted (the body is the product's credit balance; granted and adjusted add the ledger entry).
  • Fair use: usage.cap_warning , usage.cap_reached (a monthly product at 80% or 100% of its monthly cap; the body is the month's count and the cap).

Failed deliveries are retried.