README.md

# Idverse

An Elixir client library for the IDVerse / IDKit identity verification API.

## ⚠️ AI Generated! ⚠️
Full disclosure, this repo was largely generated by Claude Code. Use at your own risk.

## Installation

Add `idverse` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:idverse, "~> 0.1.0"}
  ]
end
```

## Configuration

Configure environments in your `config/runtime.exs`:

```elixir
# Optional mock server for development
config :idverse, :mock_server,
  enabled: true,
  port: 4500,
  repo: Ubre.Repo

config :idverse,
  environments: [
    prod: [
      base_url: System.get_env("IDVERSE_BASE_URL"),
      oauth2_url: System.get_env("IDVERSE_OAUTH2_URL"),
      api_key: System.get_env("IDVERSE_API_KEY")
    ],
    mock: [
      base_url: "http://localhost:4500/v1",
      oauth2_url: "http://localhost:4500",
      api_key: "mock_api_key"
    ]
  ]
```

Each environment gets its own supervised `TokenManager` process that handles OAuth2 token acquisition and automatic refresh.

## Usage

### Creating a Client

```elixir
# Create a client for an environment
client = Idverse.Client.new(environment: :prod)
```

### Transaction Operations

```elixir
# Create a new verification transaction
{:ok, transaction} = Idverse.Client.Transactions.create(client, %{
  name: "John Doe",
  reference: "order-123",
  flow_type: "NORMAL2",
  phone_region_code: "61",
  phone_number: "400000000",
  redirect_url_success: "https://example.com/success",
  redirect_url_exit: "https://example.com/exit"
})

# Get transaction details
{:ok, details} = Idverse.Client.Transactions.get(client, transaction["transaction_id"])

# Get PDF report
{:ok, pdf_binary} = Idverse.Client.Transactions.get(client, transaction_id, "pdf")

# Resend SMS notification
{:ok, response} = Idverse.Client.Transactions.resend(client, transaction_id)

# Cancel a transaction
{:ok, response} = Idverse.Client.Transactions.cancel(client, transaction_id)

# Redact transaction data
{:ok, response} = Idverse.Client.Transactions.redact(client, transaction_id, ["records", "assets", "face", "data"])
```

### Webhook Notifications

You can configure webhook notifications when creating a transaction:

```elixir
{:ok, transaction} = Idverse.Client.Transactions.create(client, %{
  name: "John Doe",
  flow_type: "NORMAL2",
  phone_region_code: "61",
  phone_number: "400000000",
  notifications: %{
    complete: [
      %{
        type: "https",
        url: "https://example.com/webhook",
        auth_header_name: "Authorization",
        auth_header_value: "Bearer token123"
      }
    ]
  }
})
```

## Architecture

The library uses a supervised `TokenManager` GenServer for each configured environment. This provides:

- Automatic OAuth2 token acquisition using client credentials flow
- Token caching and automatic refresh before expiry
- Thread-safe token access across multiple processes

## Mock Server

The library includes a built-in mock server for local development and testing. This allows you to:

- Develop without API credentials
- Run integration tests without hitting the real API
- Avoid per-transaction billing during development

### Enabling the Mock Server

Add to your config files:

```elixir
# config/dev.exs
config :idverse, :mock_server,
  enabled: true,
  port: 4500

# config/test.exs
config :idverse, :mock_server,
  enabled: true,
  port: 4501
```

### Using the Mock Server

Configure your client to use the mock server URLs:

```elixir
# Configure a dev environment pointing to the mock server
config :idverse,
  environments: [
    mock: [
      base_url: "http://localhost:4500/v1",
      oauth2_url: "http://localhost:4500",
      api_key: "any_key_works"
    ]
  ]

# Then create a client
client = Idverse.Client.new(environment: :mock)
```

### Verification Flow UI

When you create a transaction, the returned `url` points to a mock verification flow. Open this URL in a browser to walk through the verification screens:

1. **Privacy Consent** - User confirms they accept the privacy terms
2. **Capture Photo ID** - Simulates capturing an ID document
3. **Reviewing ID Data** - Brief loading screen
4. **Check ID Details** - Displays mock extracted data for confirmation
5. **Face Verification** - Simulates the liveness check
6. **Verification Complete** - Success screen

Completing this flow automatically marks the transaction as "completed" with realistic verification data.

### Programmatic Completion

For automated testing, you can skip the UI and complete transactions programmatically:

```elixir
# Via helper function
Idverse.MockServer.complete_transaction(transaction_id)

# Via HTTP endpoint
POST http://localhost:4500/mock/simulate/complete/:transaction_id
```

Completed transactions include realistic mock verification data (documents, liveness checks, facematch scores, etc.).

### Mock Server API Endpoints

The mock server implements all IDVerse API endpoints:

| Endpoint | Description |
|----------|-------------|
| `POST /oauth2/token` | OAuth2 token endpoint |
| `POST /v1/transactions` | Create transaction |
| `GET /v1/transactions/:id/json` | Get transaction JSON |
| `GET /v1/transactions/:id/pdf` | Get transaction PDF |
| `POST /v1/transactions/resend` | Resend SMS |
| `POST /v1/transactions/cancel` | Cancel transaction |
| `POST /v1/transactions/redact` | Redact transaction data |
| `GET /verify/:id` | Start verification flow (HTML) |
| `POST /mock/simulate/complete/:id` | Simulate completion |
| `GET /health` | Health check |

### Test Helpers

```elixir
# Clear all mock state between tests
Idverse.MockServer.clear_all()

# Get configured URLs
Idverse.MockServer.base_url()    # => "http://localhost:4500/v1"
Idverse.MockServer.oauth2_url()  # => "http://localhost:4500"
```

### PostgreSQL Persistence (Optional)

By default, the mock server stores transactions in ETS (in-memory), meaning data is lost when the application restarts. For development scenarios where you need persistent transactions, you can configure the mock server to use your application's PostgreSQL database.

#### Setup

1. **Add the optional dependencies** to your `mix.exs`:

```elixir
def deps do
  [
    {:idverse, "~> 0.1.0"},
    {:ecto_sql, "~> 3.10"},
    {:postgrex, "~> 0.17"}
  ]
end
```

2. **Configure the mock server** with your Ecto repo:

```elixir
# config/dev.exs
config :idverse, :mock_server,
  enabled: true,
  port: 4500,
  repo: MyApp.Repo
```

3. **Create a migration** in your application:

```bash
mix ecto.gen.migration add_idverse_mock_server
```

4. **Call the library's migration functions**:

```elixir
# priv/repo/migrations/YYYYMMDDHHMMSS_add_idverse_mock_server.exs
defmodule MyApp.Repo.Migrations.AddIdverseMockServer do
  use Ecto.Migration

  def up, do: Idverse.MockServer.Migrations.up(version: 1)
  def down, do: Idverse.MockServer.Migrations.down(version: 1)
end
```

5. **Run the migration**:

```bash
mix ecto.migrate
```

#### Database Tables

The migration creates two tables:

- `idverse_mock_transactions` - Stores transaction records with all verification data
- `idverse_mock_tokens` - Stores OAuth tokens

#### Schema Prefix (Multi-tenant)

For multi-tenant setups, you can specify a database schema prefix:

```elixir
def up, do: Idverse.MockServer.Migrations.up(version: 1, prefix: "tenant_schema")
def down, do: Idverse.MockServer.Migrations.down(version: 1, prefix: "tenant_schema")
```

#### Backward Compatibility

- Without a `repo` configured, the mock server uses ETS storage (default behavior)
- With a `repo` configured, transactions persist to PostgreSQL
- All API endpoints work identically regardless of storage backend

## License

MIT