# INFRA API Documentation

> INFRA is a digital identity infrastructure platform currently in sandbox/beta mode. Users verify once via KYC, receive cryptographic zero-knowledge credentials, and share them with any integrated app — without re-verification or raw document exposure. All data is for testing purposes only.

This is the machine-readable version of the INFRA developer documentation, intended for AI agents, crawlers, and offline reading. The interactive version lives at `/documentation`. This file is generated from the same source, so it mirrors that content 1:1.

- **API base URL:** `https://api.infra.philtechs.org/api/v1`
- **OAuth authorization server:** `https://auth.infra.philtechs.org`
- **Integration support:** engineering@infra.philtechs.org

## Table of contents

1. [Overview](#overview)
2. [Quick Start](#quick-start)
3. [Authentication (OAuth 2.0 + PKCE)](#authentication-oauth-20--pkce)
4. [API Reference](#api-reference)
5. [Webhooks](#webhooks)
6. [INFRA Connect](#infra-connect)
7. [ZK Claims](#zk-claims)
8. [Scopes & Trust Levels](#scopes--trust-levels)
9. [Developer Policy](#developer-policy)

---

## Overview

**What is INFRA?** INFRA is a digital identity infrastructure platform currently in sandbox/beta mode for testing. Users verify once via KYC, receive cryptographic zero-knowledge credentials, and share them with any integrated app — without re-verification or raw document exposure. All data is for development and testing purposes only.

Key properties:

- **Verify Once, Use Everywhere** — One KYC verification on the INFRA mobile app unlocks access to all integrated applications.
- **Zero-Knowledge Claims** — Apps receive cryptographic proofs (age, residency, KYC status) — never raw documents.
- **Standard OAuth 2.0** — Full OAuth 2.0 + PKCE authorization flow. Works with any standard OAuth client library.
- **User-Controlled Consent** — Users approve and revoke app access at any time from the INFRA mobile app.

**Base URL:** `https://api.infra.philtechs.org/api/v1`

---

## Quick Start

Follow these steps to integrate INFRA into your application. You'll need a registered developer account and an OAuth app.

1. **Register on the Developer Portal** — Visit the INFRA developer portal and create your account. Verify your email to activate access.
2. **Create an OAuth App** — In the portal, create a new application. You'll receive a client_id and client_secret. Set your redirect_uri(s).
3. **Implement the OAuth Flow** — Redirect users to the INFRA authorization endpoint with PKCE. Handle the callback and exchange the code for tokens.
4. **Call the User Data API** — Use the access token to call INFRA API endpoints and retrieve verified user data and ZK claims.

### Step 1: Redirect user to INFRA authorization

```javascript
// Generate PKCE code verifier and challenge first
const authUrl = new URL('https://auth.infra.philtechs.org/oauth2/auth');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', 'YOUR_CLIENT_ID');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('scope', 'kyc:read profile:read claims:read');
authUrl.searchParams.set('state', generateState());
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authUrl.toString();
```

### Step 2: Exchange code for tokens (backend)

```javascript
const response = await fetch('https://auth.infra.philtechs.org/oauth2/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authorizationCode,
    redirect_uri: 'https://yourapp.com/callback',
    code_verifier: codeVerifier,
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
  }),
});
const { access_token, refresh_token, expires_in } = await response.json();
```

### Step 3: Fetch verified user data

```javascript
// Get user profile
const profile = await fetch(
  'https://api.infra.philtechs.org/api/v1/users/{userId}/profile',
  { headers: { 'Authorization': `Bearer ${accessToken}` } }
);
const data = await profile.json();
// { success: true, data: { id, email, first_name, kyc_level, ... } }
```

---

## Authentication (OAuth 2.0 + PKCE)

INFRA uses standard OAuth 2.0 with PKCE (Proof Key for Code Exchange) for all authorization flows. No proprietary SDK required.

### PKCE Flow

1. **Generate PKCE Pair** — Create a cryptographically random code_verifier (43-128 chars). Derive code_challenge = BASE64URL(SHA256(code_verifier)).
2. **Authorization Request** — Redirect user to https://auth.infra.philtechs.org/oauth2/auth with response_type=code, scopes, state, and code_challenge.
3. **User Consent** — INFRA shows the user a consent screen listing the requested scopes. User approves or denies.
4. **Authorization Code** — INFRA redirects to your redirect_uri with ?code=AUTH_CODE&state=YOUR_STATE.
5. **Token Exchange** — Your backend POSTs to /oauth2/token with the code, code_verifier, client credentials. Receives access_token + refresh_token.
6. **API Calls** — Use the access_token as a Bearer token in the Authorization header for all INFRA API requests.

### Scopes

| Scope | Description | Trust Level |
|---|---|---|
| `profile:read` | Name, email, country, profile photo | Standard |
| `kyc:read` | KYC level, status, verification date | Standard |
| `claims:read` | Zero-knowledge claims (age, residency, etc.) | Standard |
| `documents:metadata` | Document type and verification status (no content) | Standard |
| `documents:read` | JWE-encrypted sensitive documents | Trusted |

### Token Lifetimes

| Token | Lifetime | Notes |
|---|---|---|
| Access Token | 1 hour | Use for API calls. Refresh when expired. |
| Refresh Token | 30 days | Exchange for new access token. Rotates on use. |

---

## API Reference

All endpoints require a valid Bearer access token obtained via the OAuth 2.0 flow.

**Base URL:** `https://api.infra.philtechs.org/api/v1`

### GET /users/:userId/profile

Returns the verified profile for a user. Requires `profile:read` scope.

```javascript
const response = await fetch(
  `https://api.infra.philtechs.org/api/v1/users/${userId}/profile`,
  { headers: { 'Authorization': `Bearer ${accessToken}` } }
);

// Response
{
  "success": true,
  "data": {
    "id": "uuid",
    "email": "user@example.com",
    "first_name": "John",
    "last_name": "Doe",
    "country": "NG",
    "kyc_level": "level_1",
    "risk_score": 75
  }
}
```

### GET /users/:userId/kyc

Returns KYC verification status. Requires `kyc:read` scope.

```javascript
// Response
{
  "success": true,
  "data": {
    "kyc_level": "level_1",
    "status": "verified",
    "verified_at": "2026-01-15T10:30:00Z",
    "provider": "sumsub"
  }
}
```

### GET /users/:userId/claims

Returns zero-knowledge claims for a user. Requires `claims:read` scope.

```javascript
// Response
{
  "success": true,
  "data": {
    "claims": [
      {
        "claim_type": "kyc_verified",
        "provider": "sumsub",
        "revoked": false
      },
      {
        "claim_type": "age_over_18",
        "provider": "infra",
        "revoked": false
      },
      {
        "claim_type": "country_resident",
        "provider": "infra",
        "revoked": false
      },
      {
        "claim_type": "unique_human",
        "provider": "sumsub",
        "revoked": false
      }
    ]
  }
}
```

---

## Webhooks

INFRA sends webhook events to your registered endpoint when key actions occur. Configure your webhook URL in the developer portal.

### Event Types

| Event | Description |
|---|---|
| `kyc.verified` | User completed KYC successfully |
| `kyc.rejected` | KYC verification was rejected |
| `consent.granted` | User approved your app's access request |
| `consent.revoked` | User revoked your app's access |
| `claim.issued` | A new ZK claim was issued to a user |
| `claim.revoked` | A ZK claim was revoked |
| `data.deletion_requested` | User requested data deletion (GDPR) |

### Webhook Payload

```javascript
// Example: kyc.verified event
{
  "event_type": "kyc.verified",
  "event_id": "evt_01HXYZ...",
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "user_id": "usr_01HXYZ...",
    "kyc_level": "level_1",
    "status": "verified",
    "provider": "sumsub"
  }
}
```

### Verifying Signatures

Every webhook request includes an `x-webhook-signature` header. Always verify this before processing the event.

```javascript
const crypto = require('crypto');

function verifyWebhook(req, webhookSecret) {
  const signature = req.headers['x-webhook-signature'];
  const expectedSig = crypto
    .createHmac('sha256', webhookSecret)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (signature !== expectedSig) {
    throw new Error('Invalid webhook signature');
  }
  return true;
}

// In your Express route:
app.post('/webhooks/infra', (req, res) => {
  verifyWebhook(req, process.env.INFRA_WEBHOOK_SECRET);
  const { event_type, data } = req.body;

  switch (event_type) {
    case 'kyc.verified':
      // Update user KYC status in your DB
      break;
    case 'consent.revoked':
      // Remove user access tokens
      break;
  }
  res.json({ received: true });
});
```

---

## INFRA Connect

INFRA Connect lets you request user consent directly via API — no OAuth redirect required. The user receives an in-app notification to approve or deny.

### How It Works

1. **Request Consent** — POST to /connect/request with the user's INFRA ID and the scopes you need.
2. **User Gets Notified** — The user receives a push notification in the INFRA mobile app with your request details.
3. **User Approves or Denies** — User reviews and approves or denies the request in-app.
4. **Poll for Result** — Poll GET /connect/result/:requestId or receive a consent.granted webhook.

### Request Consent

```javascript
const response = await fetch(
  'https://api.infra.philtechs.org/api/v1/connect/request',
  {
    method: 'POST',
    headers: {
      'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      infra_user_id: 'usr_01HXYZ...',
      scopes: ['profile:basic', 'kyc:status'],
      callback_url: 'https://yourapp.com/webhooks/infra',
    }),
  }
);

// Response
{
  "request_id": "req_01HXYZ...",
  "status": "pending",
  "expires_in": 300
}
```

### Poll for Result

```javascript
const result = await fetch(
  `https://api.infra.philtechs.org/api/v1/connect/result/${requestId}`,
  {
    headers: {
      'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
    },
  }
);

// Response when approved
{
  "request_id": "req_01HXYZ...",
  "status": "approved",
  "user_id": "usr_01HXYZ...",
  "granted_scopes": ["profile:basic", "kyc:status"],
  "access_token": "eyJ..."
}
```

---

## ZK Claims

INFRA issues cryptographic claims derived from verified identity data. Apps receive proof of a fact — never the underlying data.

### Available Claims

**`kyc_verified` — KYC Verified**
- What it means: User has passed KYC verification via an accredited KYC vendor.
- What it proves: Identity has been verified by an accredited KYC provider.
- Not shared: No personal data, documents, or scores are shared.

**`age_over_18` — Age Over 18**
- What it means: User is 18 years of age or older.
- What it proves: Age threshold met — derived from verified date of birth.
- Not shared: Actual date of birth is never shared with the app.

**`country_resident` — Country Resident**
- What it means: User's verified country of residence.
- What it proves: Residency in a specific country, confirmed during KYC.
- Not shared: Full address and document details are not shared.

**`unique_human` — Unique Human**
- What it means: User has passed duplicate identity detection.
- What it proves: This is a real, unique person — not a duplicate account.
- Not shared: Biometric data is processed by the KYC vendor and never stored by INFRA.

### Claim Revocation

Claims can be revoked by the user at any time from the INFRA mobile app, or automatically if the underlying KYC verification is invalidated. Your app will receive a `claim.revoked` webhook event.

---

## Scopes & Trust Levels

INFRA uses two trust tiers. Standard apps can access public profile data and ZK claims. Trusted apps can additionally request encrypted sensitive documents.

### Standard Apps

Default tier for all registered developer apps. Access to public identity data and ZK claims.

- User profile (name, email, country)
- KYC level and verification status
- Zero-knowledge claims
- Document metadata (type only)
- Consent management
- Webhook events

### Trusted Apps

Elevated tier for regulated platforms (fintech, healthcare, etc.). Requires approval. Includes everything in Standard plus:

- JWE-encrypted passport data
- National ID number (NIN)
- Bank Verification Number (BVN)
- Full document images (encrypted)
- Enhanced KYC data

### Full Scope Reference

| Scope | Returns | Tier |
|---|---|---|
| `profile:read` | id, email, first_name, last_name, country, photo_url | Standard |
| `kyc:read` | kyc_level, status, verified_at, provider | Standard |
| `claims:read` | Array of ZK claims with type, provider, revoked status | Standard |
| `documents:metadata` | Document type, country, verification status (no content) | Standard |
| `documents:read` | JWE-encrypted document content (passport, NIN, BVN) | Trusted |

### JWE Encryption

Sensitive documents returned by Trusted apps are encrypted using JSON Web Encryption (JWE). Your app must hold the corresponding private key to decrypt the payload. Key exchange is handled during the Trusted app approval process.

---

## Developer Policy

All developers integrating with the INFRA API must read and comply with this policy. Violations may result in immediate suspension of access.

> **Important Notice:** By integrating with this API, you agree to comply with all data access, consent, and security requirements defined below. Failure to comply may result in immediate suspension of access, revocation of credentials, and removal from the platform.

### 1. Consent Enforcement Rules

Consent is mandatory for all data access. Applications must not access user data without active consent, attempt to bypass consent flows, or cache and reuse expired consent tokens.

On consent revocation:
- All access must stop immediately
- Tokens must be treated as invalid
- No further API requests should be made on behalf of the user

### 2. Data Usage Restrictions

Applications must only use data for the purpose explicitly approved by the user.

Applications must not:
- Resell user data
- Share data with third parties without consent
- Use data for profiling beyond approved scope
- Store data longer than necessary

### 3. Data Storage Policy

Storage of raw identity documents is strongly restricted. Applications should prefer verification status over raw documents and minimize stored personal data.

For sensitive data:
- Access requires explicit approval and trusted developer status
- Storage must follow secure handling practices

### 4. Revocation Handling (CRITICAL)

Upon receiving a `consent_revoked` event, applications must:

- Immediately stop processing user data
- Disable user-specific features relying on that data
- Treat previously obtained data as non-current

Applications may retain data only if required for legal or operational purposes and it is no longer actively processed.

### 5. Account Deletion Enforcement

Upon receiving a `user_deleted` event, applications must:

- Permanently delete all user-related data
- Remove all stored identity information
- Confirm deletion where applicable

**This action is mandatory and non-optional.**

### 6. Token and Security Rules

Applications must:
- Securely store API keys and tokens
- Never expose credentials client-side
- Implement server-side verification

Applications must not:
- Hardcode secrets in public code
- Transmit tokens over insecure channels
- Reuse expired tokens

### 7. Webhook Compliance

Applications must:
- Verify webhook signatures
- Process webhook events reliably
- Handle retries and idempotency

Ignoring these events is non-compliance:
- `consent_revoked`
- `user_deleted`

### 8. Abuse and Misuse

The following behaviors are strictly prohibited:

- Excessive or automated consent requests
- Scraping or bulk data extraction
- Attempting to infer data beyond granted scope
- Simulating user actions

### 9. Trusted Developer Requirements

Access to sensitive claims is restricted. Applications must undergo review before accessing sensitive data, justify data usage, and maintain compliance standards. Approval may be revoked at any time.

### 10. Rate Limiting and Access Control

Applications must respect rate limits. Excessive requests may result in:

- Temporary throttling
- API suspension
- Permanent access removal

### 11. Compliance and Enforcement

We reserve the right to audit application behavior, monitor usage patterns, and suspend or revoke access without prior notice.

### 12. Data Validity Disclaimer (IMPORTANT)

Access to data does not imply permanent validity. Applications must:

- Revalidate data where required
- Respect expiration timestamps
- Not rely on stale or outdated information

---

*To register as a developer, visit the INFRA developer access page or contact engineering@infra.philtechs.org.*
