# Payments API

Inspection credits and Business access via Stripe

Stripe billing for inspection-credit packs and optional Business workspace access. Purchase credits, manage Business access, open the billing portal, and retrieve balances and billing history.

## Available Endpoints

| Method  | Endpoint                                                                                                                                     | Description                                        |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `POST`  | [`/api/user/organizations/{organizationId}/payments/checkout`](#post-apiuserorganizations{organizationId}paymentscheckout)                   | Create a credit-pack or Business checkout          |
| `GET`   | [`/api/user/organizations/{organizationId}/payments/purchases`](#get-apiuserorganizations{organizationId}paymentspurchases)                  | Get organization purchase history                  |
| `GET`   | [`/api/user/organizations/{organizationId}/payments/credits`](#get-apiuserorganizations{organizationId}paymentscredits)                      | Get available inspection credits and expiring lots |
| `POST`  | [`/api/user/organizations/{organizationId}/payments/verify`](#post-apiuserorganizations{organizationId}paymentsverify)                       | Verify checkout completion                         |
| `GET`   | [`/api/user/organizations/{organizationId}/payments/subscription`](#get-apiuserorganizations{organizationId}paymentssubscription)            | Get the Business subscription                      |
| `PATCH` | [`/api/user/organizations/{organizationId}/payments/subscription`](#patch-apiuserorganizations{organizationId}paymentssubscription)          | Update Business member capacity or interval        |
| `GET`   | [`/api/user/organizations/{organizationId}/payments/subscription/usage`](#get-apiuserorganizations{organizationId}paymentssubscriptionusage) | Get active member usage                            |
| `GET`   | [`/api/user/organizations/{organizationId}/payments/portal`](#get-apiuserorganizations{organizationId}paymentsportal)                        | Create a Stripe Billing Portal session             |

## Endpoints

### POST /api/user/organizations/{organizationId}/payments/checkout

Create a credit-pack or Business checkout

**Auth:** bearer · **Scopes:** `subscription:write`, `organization:manage-billing`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Request example

**curl**

```bash
curl -X POST "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/checkout" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"kind":"credits","operationId":"string","packs":1,"successUrl":"https://indexhog.com/billing/success","cancelUrl":"https://indexhog.com/billing/cancel"}'
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/checkout", {
method: "POST",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
body: JSON.stringify({
  "kind": "credits",
  "operationId": "string",
  "packs": 1,
  "successUrl": "https://indexhog.com/billing/success",
  "cancelUrl": "https://indexhog.com/billing/cancel"
}),
});

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

#### Response `200` — Checkout session created

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "sessionId": "string",
  "url": "https://example.com"
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### GET /api/user/organizations/{organizationId}/payments/purchases

Get organization purchase history

**Auth:** bearer · **Scopes:** `subscription:read`, `organization:read`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Query parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `offset` | number \| null | no | Number of items to skip | `0` |
| `limit` | number | no | Number of items to return (max 100) | `20` |

#### Request example

**curl**

```bash
curl -X GET "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/purchases" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json"
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/purchases", {
method: "GET",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
});

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

#### Response `200` — Purchase history fetched

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Items fetched successfully",
"data": [
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "purchasedByUserId": "550e8400-e29b-41d4-a716-446655440000",
    "provider": "stripe",
    "items": [
      {
        "productId": "retired_product_id",
        "quantity": 1,
        "grants": [
          {
            "type": "seats",
            "amount": 1
          }
        ],
        "kind": "business",
        "billing": "recurring"
      }
    ],
    "acquiredAt": "2024-01-15T10:30:00.000Z",
    "availableAt": "2024-01-15T10:30:00.000Z",
    "kind": "subscription",
    "subscriptionInterval": "monthly",
    "expiresAt": "2024-01-15T10:30:00.000Z",
    "status": "paid",
    "reversedAt": null,
    "reversalReason": null,
    "restoredAt": null
  }
],
"meta": {
  "total": 100,
  "offset": 0,
  "limit": 10,
  "hasMore": true
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### GET /api/user/organizations/{organizationId}/payments/credits

Get available inspection credits and expiring lots

**Auth:** bearer · **Scopes:** `subscription:read`, `organization:read`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Request example

**curl**

```bash
curl -X GET "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/credits" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json"
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/credits", {
method: "GET",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
});

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

#### Response `200` — Credit balance retrieved

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "balance": 0,
  "lots": [
    {
      "grantId": "string",
      "source": "credit_pack_purchase",
      "remaining": 0,
      "expiresAt": "2024-01-15T10:30:00.000Z"
    }
  ]
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### POST /api/user/organizations/{organizationId}/payments/verify

Verify checkout completion

**Auth:** bearer · **Scopes:** `subscription:write`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Body parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `sessionId` | string | yes |  |  |

#### Request example

**curl**

```bash
curl -X POST "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/verify" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"sessionId":"string"}'
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/verify", {
method: "POST",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
body: JSON.stringify({
  "sessionId": "string"
}),
});

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

#### Response `200` — Checkout verification result

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "status": "complete",
  "customerId": "string"
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### GET /api/user/organizations/{organizationId}/payments/subscription

Get the Business subscription

**Auth:** bearer · **Scopes:** `subscription:read`, `organization:read`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Request example

**curl**

```bash
curl -X GET "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json"
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription", {
method: "GET",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
});

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

#### Response `200` — Business subscription retrieved

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "status": "active",
  "interval": "monthly",
  "currentPeriodEnd": "2024-01-15T10:30:00.000Z",
  "cancelAt": "2024-01-15T10:30:00.000Z",
  "memberCap": 1
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### PATCH /api/user/organizations/{organizationId}/payments/subscription

Update Business member capacity or interval

**Auth:** bearer · **Scopes:** `subscription:write`, `organization:manage-billing`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Body parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `operationId` | string | yes |  |  |
| `memberCap` | number | no |  |  |
| `interval` | BillingInterval | no |  |  |

#### Request example

**curl**

```bash
curl -X PATCH "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"operationId":"string","memberCap":1,"interval":"monthly"}'
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription", {
method: "PATCH",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
body: JSON.stringify({
  "operationId": "string",
  "memberCap": 1,
  "interval": "monthly"
}),
});

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

#### Response `200` — Business subscription updated

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "status": "active",
  "interval": "monthly",
  "currentPeriodEnd": "2024-01-15T10:30:00.000Z",
  "cancelAt": "2024-01-15T10:30:00.000Z",
  "memberCap": 1
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### GET /api/user/organizations/{organizationId}/payments/subscription/usage

Get active member usage

**Auth:** bearer · **Scopes:** `subscription:read`, `organization:read`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Request example

**curl**

```bash
curl -X GET "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription/usage" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json"
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/subscription/usage", {
method: "GET",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
});

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

#### Response `200` — Member usage retrieved

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "activeMembers": 0,
  "projectCount": 0
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```

### GET /api/user/organizations/{organizationId}/payments/portal

Create a Stripe Billing Portal session

**Auth:** bearer · **Scopes:** `subscription:write`, `organization:manage-billing`

#### Path parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `organizationId` | string | yes | Organization ID | `550e8400-e29b-41d4-a716-446655440000` |

#### Query parameters

| Name | Type | Required | Description | Example |
| --- | --- | --- | --- | --- |
| `returnUrl` | string | yes |  |  |

#### Request example

**curl**

```bash
curl -X GET "https://api.indexhog.com/api/user/organizations/{organizationId}/payments/portal" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -H "Content-Type: application/json"
```

**JavaScript**

```javascript
const response = await fetch("https://api.indexhog.com/api/user/organizations/{organizationId}/payments/portal", {
method: "GET",
headers: {
  "Authorization": "Bearer YOUR_ACCESS_TOKEN",
  "Content-Type": "application/json",
},
});

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

#### Response `200` — Portal session created

```json
{
"success": true,
"status": 200,
"code": "OK",
"message": "Operation completed successfully",
"data": {
  "url": "https://example.com"
}
}
```

#### Response `401` — Unauthorized - Invalid or missing authentication

```json
{
"success": false,
"status": 401,
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
```

#### Response `403` — Forbidden - Insufficient permissions

```json
{
"success": false,
"status": 403,
"code": "FORBIDDEN",
"message": "You do not have permission to perform this action"
}
```