> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Encrypted KYC Submission

> Send KYC data as a hybrid RSA-AES encrypted payload, on the same user application endpoint you already call.

Rain supports secure KYC data submission through encrypted payloads sent to the standard Create User Application endpoint. Any tenant can submit customer KYC data directly to Rain by including an encryption header and an encrypted payload structure, using industry-standard hybrid RSA-AES encryption to keep sensitive data protected in transit.

<Info>
  The flow on this page uses the consumer application and consumer document endpoints.
</Info>

## Key features

Encrypted KYC submission provides:

* **Hybrid encryption:** combines RSA-OAEP and AES-256-GCM for optimal security and performance
* **Existing endpoint integration:** uses the standard `/issuing/applications/user` endpoint with encryption support
* **Header-based activation:** encryption enabled via the `encrypted: true` request header
* **Universal access:** all tenants can use the encrypted endpoint with a Rain-provided public key
* **Secure processing:** all data is decrypted and validated server-side before processing
* **Standard response:** returns the standard Rain user object upon successful processing

## Technical requirements

Encrypted KYC submission uses the following endpoints, encryption scheme, and payload structure.

### API endpoints

* **Endpoint:** [`/issuing/applications/user`](/reference/applications/create-a-consumer-application-for-a-user)
  * **Method:** POST
  * **Content-Type:** application/json
  * **Required header:** `encrypted: "true"` (when submitting an encrypted payload)
* **Endpoint:** [`/issuing/applications/user/<userId>/document`](/reference/applications/upload-a-document-to-support-a-users-consumer-application)
  * **Method:** PUT
  * **Content-Type:** application/json
  * **Required header:** `encrypted: "true"` (when submitting an encrypted payload)

### Encryption specifications

The encrypted KYC submission requires a specific encrypted payload structure using hybrid encryption:

1. **RSA-OAEP encryption:** used to encrypt a randomly generated AES-256 key
2. **AES-256-GCM encryption:** used to encrypt the actual KYC payload data
3. **Base64 encoding:** all encrypted components are base64-encoded for transmission

### Request structure

When submitting encrypted data, include the `encrypted: "true"` header and structure the payload with these four components:

```typescript theme={null}
{
  key: string; // base64-encoded RSA-encrypted AES key
  iv: string; // base64-encoded initialization vector
  ciphertext: string; // base64-encoded encrypted payload data
  tag: string; // base64-encoded authentication tag
}
```

### Payload data format

The decrypted payload data must match Rain's standard user application schema, including:

* Personal information (name, date of birth, address)
* Identity verification documents
* Compliance information (occupation, income, etc.)
* Blockchain wallet addresses (if applicable)
* Terms of service acceptance

## Encryption process

Rain manages all server-side configuration for you, including decryption keys, validation parameters, and endpoint encryption support. On your side, encrypting and submitting a payload takes seven steps, plus a sandbox pass before you go live:

<Steps>
  <Step title="Get your public key">
    Obtain the sandbox and production public keys for encrypted KYC submissions from [KYC encryption public keys](/docs/kyc-encryption-public-keys).

    Rain generates and manages the keys for you: it creates the RSA key pairs, provides the public key for encryption, securely stores the private key for decryption, and maintains separate keys for sandbox and production.
  </Step>

  <Step title="Generate an AES key">
    Create a random 256-bit AES key.
  </Step>

  <Step title="Encrypt the payload">
    Use AES-256-GCM to encrypt your KYC JSON data.
  </Step>

  <Step title="Encrypt the AES key">
    Use the Rain-provided RSA public key with OAEP padding.
  </Step>

  <Step title="Encode the components">
    Base64-encode all encrypted components.
  </Step>

  <Step title="Set the header">
    Include the `encrypted: "true"` header in your request.
  </Step>

  <Step title="Submit the request">
    Send the structured encrypted payload to the `/issuing/applications/user` endpoint.
  </Step>

  <Step title="Test in the sandbox">
    Before you go live, test your integration in Rain's sandbox environment:

    * Verify your encryption implementation using the Rain-provided public key
    * Test various payload scenarios, including the encrypted header requirement
    * Validate error handling for both encrypted and plaintext scenarios
    * Confirm response processing
  </Step>
</Steps>

## Implementation guide

This section shows example code and covers error and response handling.

### Example encryption method

```javascript theme={null}
const encrypt = (data) => {
  const aesKey = crypto.randomBytes(32);
  const iv = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv("aes-256-gcm", aesKey, iv);
  const ciphertext = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
  const tag = cipher.getAuthTag();

  const publicKey = fs.readFileSync("./public.pem", "utf8");
  const key = crypto.publicEncrypt(
    {
      key: publicKey,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: "sha256",
    },
    aesKey
  );

  return {
    key: key.toString("base64"),
    iv: iv.toString("base64"),
    ciphertext: ciphertext.toString("base64"),
    tag: tag.toString("base64"),
  };
};
```

### Example request

```bash theme={null}
curl -X POST https://api.rain.xyz/v1/issuing/applications/user \
  -H "Content-Type: application/json" \
  -H "encrypted: true" \
  -H "api-key: YOUR_API_KEY" \
  -d '{
    "key": "base64-encoded-encrypted-aes-key",
    "iv": "base64-encoded-initialization-vector",
    "ciphertext": "base64-encoded-encrypted-payload",
    "tag": "base64-encoded-authentication-tag"
  }'
```

### Error handling

The endpoint returns specific error codes for encrypted submissions:

* **400:** malformed encrypted payload, decryption failure, or schema validation error
* **401:** authentication failure (invalid or missing API key)
* **500:** internal processing error

### Response processing

Successful encrypted submissions return the same standard Rain user object as plaintext submissions:

* Unique user identifier
* Application status
* User profile information
* Associated account details

## Security considerations

* Rain manages all encryption keys. Use only the public key Rain provides, never generate or modify keys yourself, and contact Rain for key rotation or environment-specific updates.
* Rain maintains separate keys for sandbox and production, so encrypt with the key for the environment you are calling.
* Validate payload integrity using the authentication tag.

## Support and troubleshooting

### Common issues

* **Missing header:** verify the `encrypted: "true"` header is included with encrypted payloads
* **Decryption failures:** verify key format and encryption parameters
* **Authorization errors:** confirm API key validity for encrypted submissions
* **Schema validation:** ensure the decrypted payload matches the required data structure
* **Network issues:** implement appropriate retry logic and error handling

### Getting help

For technical support with external encrypted KYC integrations:

* Contact Rain support through your designated integration channel
* Describe your integration and the environment you are calling
* Provide detailed error logs, with credentials redacted
* Reference specific API requests and response codes

<Warning>
  Redact your `api-key` before sharing anything. The headers this endpoint documents carry it, so raw request logs and header dumps expose it. Never send an API key to support.
</Warning>

## What's next

<Columns cols={3}>
  <Card title="KYC encryption public keys" icon="key" href="/docs/kyc-encryption-public-keys">
    Get the sandbox and production keys you encrypt with.
  </Card>

  <Card title="Create a consumer application" icon="code" href="/reference/applications/create-a-consumer-application-for-a-user">
    API reference for the endpoint you submit to.
  </Card>

  <Card title="Reuse an existing verification" icon="arrows-rotate" href="/docs/reuse-existing-verification">
    Share a Sumsub or Persona verification instead of submitting raw KYC.
  </Card>

  <Card title="Verification requirements" icon="shield-check" href="/docs/verification-requirements">
    See what Rain verifies and screens for each applicant.
  </Card>
</Columns>
