# AIOZ Pin — Pinning

Base URL: https://api.aiozpin.network/api
Authentication: pinning_api_key + pinning_secret_key headers

## Setup

```typescript
const BASE = 'https://api.aiozpin.network/api'
const PIN_HEADERS = {
  'pinning_api_key': process.env.AIOZ_PIN_API_KEY!,
  'pinning_secret_key': process.env.AIOZ_PIN_SECRET_KEY!
}
```

---

## Pin File or Directory

POST https://api.aiozpin.network/api/pinning

Upload a file and pin it to IPFS. Use multipart/form-data.

```typescript
import fs from 'fs'
import FormData from 'form-data'

async function pinFile(filePath: string, name?: string) {
  const form = new FormData()
  form.append('file', fs.createReadStream(filePath))
  if (name) {
    form.append('metadata', JSON.stringify({ name }))
  }

  const res = await fetch(`${BASE}/pinning`, {
    method: 'POST',
    headers: { ...PIN_HEADERS, ...form.getHeaders() },
    body: form
  })
  return res.json()
}

const result = await pinFile('./image.png', 'my-image')
// result.data.cid       — IPFS CID
// result.data.id        — pin ID
// result.data.status    — pin status
// result.data.is_dir    — true if directory
```

Response fields:
- id, file_record_id, root_hash, cid, user_id
- date_pinned, date_unpinned, pinned, is_pin_by_hash, is_dir
- metadata: { name, type }
- status

---

## Pin by CID

POST https://api.aiozpin.network/api/pinning/pinByHash

Pin an existing IPFS CID without uploading a file.

```typescript
async function pinByCid(cid: string, name?: string) {
  const res = await fetch(`${BASE}/pinning/pinByHash`, {
    method: 'POST',
    headers: { ...PIN_HEADERS, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      hash_to_pin: cid,
      metadata: name ? { name } : undefined
    })
  })
  return res.json()
}

const result = await pinByCid('Qmc1135ziMvmFG534i75E8HpJoLqzLzgKBxfjBV9cBsMAs', 'my-pin')
// result.data.cid
// result.data.id
```

---

## Get Pin Details

GET https://api.aiozpin.network/api/pinning/{pinId}

```typescript
async function getPinDetails(pinId: string) {
  const res = await fetch(`${BASE}/pinning/${pinId}`, { headers: PIN_HEADERS })
  return res.json()
}

const result = await getPinDetails('3c3fec2a-ca65-4b8e-bcf3-c8e2ceaa23d2')
// result.data.cid
// result.data.size    — bytes
// result.data.pinned  — boolean
// result.data.status
```

---

## List Pins

GET https://api.aiozpin.network/api/pinning/pins/

```typescript
async function listPins(options: {
  offset?: number
  limit?: number
  pinned?: 'all' | 'true' | 'false'
  sortBy?: 'created_at' | 'size' | 'name'
  sortOrder?: 'ASC' | 'DESC'
} = {}) {
  const { offset = 0, limit = 10, pinned = 'all', sortBy = 'created_at', sortOrder = 'DESC' } = options
  const params = new URLSearchParams({
    offset: String(offset),
    limit: String(limit),
    pinned,
    sortBy,
    sortOrder
  })
  const res = await fetch(`${BASE}/pinning/pins/?${params}`, { headers: PIN_HEADERS })
  return res.json()
}

const result = await listPins({ pinned: 'true', sortBy: 'name', sortOrder: 'ASC' })
// result.data.totals.files  — total file count
// result.data.totals.size   — total bytes
// result.data.pins[]        — array of pin objects
```

Query params:
- offset (default 0), limit (default 10)
- pinned: 'all' | 'true' | 'false' (default 'all')
- sortBy: 'created_at' | 'size' | 'name' (default 'created_at')
- sortOrder: 'ASC' | 'DESC' (default 'DESC')

---

## Unpin (Remove File)

DELETE https://api.aiozpin.network/api/pinning/unpin/{pinId}

```typescript
async function unpin(pinId: string) {
  const res = await fetch(`${BASE}/pinning/unpin/${pinId}`, {
    method: 'DELETE',
    headers: PIN_HEADERS
  })
  return res.json()
}

await unpin('e5c4456d-5e5c-465d-a02a-3a536fc6e718')
// result.data.pinned: false after unpin
```
