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

# Store Metadata

> API for storing policy metadata

# Store Metadata

Store the mapping between policy ID and IPFS CID after creating an on-chain policy.

## Endpoint

```http theme={null}
POST /api/storeMetadata
Content-Type: application/json
Authorization: Bearer {token}
```

## Request Body

```json theme={null}
{
  "policyId": "abc123...",
  "cid": "QmXyz...",
  "sender": "0x742d...",
  "recipient": "0x1234...",
  "expiry": 1708608000,
  "maxAttempts": 3,
  "contentType": "file",
  "fileName": "document.pdf",
  "fileSize": 1048576
}
```

### Parameters

| Field         | Type    | Required | Description                     |
| ------------- | ------- | -------- | ------------------------------- |
| `policyId`    | string  | ✅        | Unique policy identifier (hash) |
| `cid`         | string  | ✅        | IPFS Content Identifier         |
| `sender`      | address | ✅        | Creator's wallet address        |
| `recipient`   | address | ✅        | Authorized recipient address    |
| `expiry`      | number  | ✅        | Unix timestamp of expiration    |
| `maxAttempts` | number  | ✅        | Maximum access attempts         |
| `contentType` | enum    | ✅        | `"file"` or `"message"`         |
| `fileName`    | string  |          | Original filename (files only)  |
| `fileSize`    | number  |          | Size in bytes (files only)      |

## Response

### Success (201)

```json theme={null}
{
  "success": true,
  "policyId": "abc123..."
}
```

### Error (400)

```json theme={null}
{
  "error": "Invalid policyId format"
}
```

### Error (409)

```json theme={null}
{
  "error": "Policy already exists"
}
```

### Error (401)

```json theme={null}
{
  "error": "Unauthorized"
}
```

## Example Usage

### JavaScript

```typescript theme={null}
const response = await fetch('/api/storeMetadata', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    policyId: '0xabc123...',
    cid: 'QmXyz789...',
    sender: '0x742d35...',
    recipient: '0x123456...',
    expiry: Date.now() / 1000 + 86400, // 24 hours
    maxAttempts: 3,
    contentType: 'file',
    fileName: 'report.pdf',
    fileSize: 2.5 * 1024 * 1024, // 2.5MB
  }),
});

const data = await response.json();
```

### cURL

```bash theme={null}
curl -X POST https://app.shieldhq.xyz/api/storeMetadata \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "policyId": "0xabc123...",
    "cid": "QmXyz...",
    "sender": "0x742d...",
    "recipient": "0x1234...",
    "expiry": 1708608000,
    "maxAttempts": 3,
    "contentType": "file"
  }'
```

## Flow Integration

This endpoint is called after:

1. Content encrypted client-side
2. Encrypted content uploaded to IPFS
3. Policy created on-chain

```typescript theme={null}
// Full flow
async function createSecureLink(file, recipient, expiry) {
  // 1. Encrypt
  const { encrypted, secretKey } = await encryptFile(file);

  // 2. Upload to IPFS
  const cid = await uploadToIPFS(encrypted);

  // 3. Create on-chain policy
  const policyId = await createPolicy(recipient, expiry, 3);

  // 4. Store metadata
  await fetch('/api/storeMetadata', {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${token}` },
    body: JSON.stringify({
      policyId,
      cid,
      sender: address,
      recipient,
      expiry,
      maxAttempts: 3,
      contentType: 'file',
      fileName: file.name,
      fileSize: file.size,
    }),
  });

  // 5. Return secure link
  return `${APP_URL}/access/${policyId}#${secretKey}`;
}
```

## Validation

The API validates:

* ✅ Authenticated session
* ✅ Valid policyId format (0x + 64 hex chars)
* ✅ Valid IPFS CID (Qm... or bafy...)
* ✅ Valid Ethereum addresses
* ✅ Future expiry timestamp
* ✅ maxAttempts > 0

## Rate Limits

| Limit       | Value         |
| ----------- | ------------- |
| Requests    | 10 per minute |
| Per address | 5 per minute  |

## Database Schema

Stored in PostgreSQL:

```sql theme={null}
CREATE TABLE policies (
  policy_id VARCHAR(66) PRIMARY KEY,
  cid VARCHAR(64) NOT NULL,
  sender VARCHAR(42) NOT NULL,
  recipient VARCHAR(42) NOT NULL,
  expiry INTEGER NOT NULL,
  max_attempts INTEGER NOT NULL,
  attempts INTEGER DEFAULT 0,
  content_type VARCHAR(10) NOT NULL,
  file_name VARCHAR(255),
  file_size INTEGER,
  created_at TIMESTAMP DEFAULT NOW(),
  valid BOOLEAN DEFAULT TRUE
);
```
