> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opencharge.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate KYC

> Check a user's KYC status and granted permissions

<Info>
  Use this endpoint to check if a user has completed KYC and what permissions they've granted to your OCID.
</Info>

## Use Cases

* Check if a user has verified their identity before processing a transaction
* Determine which KYC data you can request via `/kyc/data`
* Verify the user has granted your OCID access to specific data

## Verification Statuses

Each KYC item returns one of these statuses:

| Status       | Meaning                                            |
| ------------ | -------------------------------------------------- |
| `verified`   | User provided this and KYC provider verified it    |
| `pending`    | User provided this but verification is in progress |
| `missing`    | User has not provided this information             |
| `restricted` | User explicitly denied permission for this item    |

## Implementation

```javascript theme={null}
app.post('/kyc/validate', verifyAuth, async (req, res) => {
  const requestingOcid = req.headers['x-oc-id'];
  const { user_ocid, grants } = req.body;

  // Get user's KYC record
  const userKyc = await db.getUserKyc(user_ocid);
  if (!userKyc) {
    return res.status(404).json({
      error: { code: 'USER_NOT_FOUND', message: 'User not found' }
    });
  }

  // Get grants for this requesting OCID
  const userGrants = await db.getKycGrants(user_ocid, requestingOcid);

  // Build status for each requested grant
  const grantStatus = {};
  const checkGrants = grants || Object.keys(userKyc.items);

  for (const grant of checkGrants) {
    if (userGrants.denied?.includes(grant)) {
      grantStatus[grant] = 'restricted';
    } else if (!userKyc.items[grant]) {
      grantStatus[grant] = 'missing';
    } else if (userKyc.items[grant].status === 'pending') {
      grantStatus[grant] = 'pending';
    } else if (userGrants.granted?.includes(grant)) {
      grantStatus[grant] = 'verified';
    } else {
      grantStatus[grant] = 'missing'; // Not granted to this OCID
    }
  }

  res.json({
    user_ocid,
    kyc_complete: userKyc.basic_verified,
    grants: grantStatus,
    verified_at: userKyc.verified_at,
    expires_at: userKyc.expires_at
  });
});
```

## Example: Check Before Transaction

```javascript theme={null}
async function checkUserKyc(kycProviderOcid, userOcid, requiredGrants) {
  const response = await fetch(`${kycProviderEndpoint}/kyc/validate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-OC-ID': MY_OCID,
      'X-OC-Timestamp': timestamp,
      'X-OC-Nonce': nonce,
      'X-OC-Signature': signature
    },
    body: JSON.stringify({
      user_ocid: userOcid,
      grants: requiredGrants
    })
  });

  const result = await response.json();

  // Check if all required grants are verified
  const allVerified = requiredGrants.every(
    grant => result.grants[grant] === 'verified'
  );

  if (!allVerified) {
    // Redirect user to grant page for missing/restricted items
    const missingGrants = requiredGrants.filter(
      grant => result.grants[grant] !== 'verified'
    );
    return { verified: false, missing: missingGrants };
  }

  return { verified: true };
}
```


## OpenAPI

````yaml kyc-provider-api/endpoint/kyc-provider-api/openapi.json post /kyc/validate
openapi: 3.1.0
info:
  title: Opencharge KYC Provider API
  description: >-
    API specification for KYC providers integrating with the Opencharge
    protocol. KYC providers collect and verify user identity information, then
    share it with authorized OCN entities.
  version: 0.1.0
  license:
    name: MIT
servers:
  - url: https://kyc.provider.example/opencharge
    description: Example KYC provider Opencharge endpoint
security: []
paths:
  /kyc/validate:
    post:
      summary: Validate KYC status
      description: >-
        Check if a user has completed KYC, what permissions they've granted to
        the requesting OCID, and the verification status of each item.
      operationId: validateKyc
      parameters:
        - $ref: '#/components/parameters/X-OC-ID'
        - $ref: '#/components/parameters/X-OC-Timestamp'
        - $ref: '#/components/parameters/X-OC-Nonce'
        - $ref: '#/components/parameters/X-OC-Signature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/KycValidateRequest'
            example:
              user_ocid: 12345
              grants:
                - name
                - email
                - phone
                - id_card
                - liveness
      responses:
        '200':
          description: KYC validation result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KycValidateResponse'
              example:
                user_ocid: 12345
                kyc_complete: true
                grants:
                  name: verified
                  email: verified
                  phone: verified
                  id_card: verified
                  liveness: verified
                  passport: missing
                  address: restricted
                verified_at: 1706500000
                expires_at: 1738036000
        '401':
          description: Authentication failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: User not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  parameters:
    X-OC-ID:
      name: X-OC-ID
      in: header
      required: true
      description: Caller's OCID
      schema:
        type: string
      example: '300'
    X-OC-Timestamp:
      name: X-OC-Timestamp
      in: header
      required: true
      description: Unix timestamp in seconds
      schema:
        type: string
      example: '1706500000'
    X-OC-Nonce:
      name: X-OC-Nonce
      in: header
      required: true
      description: Unique request identifier
      schema:
        type: string
      example: req_abc123
    X-OC-Signature:
      name: X-OC-Signature
      in: header
      required: true
      description: secp256k1 ECDSA signature
      schema:
        type: string
      example: a1b2c3d4...7f1b
  schemas:
    KycValidateRequest:
      type: object
      required:
        - user_ocid
      properties:
        user_ocid:
          type: integer
          description: The end user's OCID
        grants:
          type: array
          items:
            type: string
          description: Specific grants to check (optional, returns all if omitted)
    KycValidateResponse:
      type: object
      required:
        - user_ocid
        - kyc_complete
        - grants
      properties:
        user_ocid:
          type: integer
        kyc_complete:
          type: boolean
          description: Whether user has completed basic KYC verification
        grants:
          type: object
          additionalProperties:
            type: string
            enum:
              - verified
              - pending
              - missing
              - restricted
          description: Status of each KYC item
        verified_at:
          type: integer
          description: Unix timestamp of last verification
        expires_at:
          type: integer
          description: Unix timestamp when verification expires
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - INVALID_SIGNATURE
                - TIMESTAMP_EXPIRED
                - NONCE_REUSED
                - UNKNOWN_OCID
                - USER_NOT_FOUND
                - KYC_NOT_COMPLETE
                - GRANT_NOT_AUTHORIZED
                - GRANT_EXPIRED
                - INVALID_GRANT
                - INVALID_CALLBACK_URL
            message:
              type: string
            details:
              type: object

````