# Money sites

Hosting on Zinn Digital's platform: plans, orders, sites, usage, and the free WooCommerce tick on a PBN-line WordPress site.

## Money-site plans and prices

`GET /money-sites/plans` · scope `moneysites:read`

Every money-site hosting tier on sale, with the price for 1, 3, 6 and 12 months, what the plan includes, and whether it can be ordered straight away. Money sites run on Zinn Digital's platform - separate infrastructure from the PBN network - and Zinn Digital LTD bills them.

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/money-sites/plans" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/money-sites/plans", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/plans", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "currency": "USD",
    "terms": [
      1,
      3,
      6,
      12
    ],
    "can_order": false,
    "plans": [
      {
        "code": "mainstream_starter",
        "name": "Starter",
        "monthly": "$7.99",
        "currency": "USD",
        "on_sale": true,
        "woocommerce": false,
        "terms": [
          {
            "months": 1,
            "total": "$7.99",
            "per_month": "$7.99",
            "saving": "$0.00"
          },
          {
            "months": 12,
            "total": "$76.70",
            "per_month": "$6.39",
            "saving": "$19.18"
          }
        ],
        "includes": [
          {
            "label": "Websites",
            "value": "1"
          },
          {
            "label": "Disk",
            "value": "10 GB"
          }
        ]
      }
    ],
    "applications": [
      {
        "key": "wordpress",
        "name": "WordPress"
      }
    ]
  }
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## My money sites

`GET /money-sites` · scope `moneysites:read`

Every money site on this account, with its state, plan, application and last known usage.

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/money-sites" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/money-sites", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": [
    {
      "id": 7,
      "domain": "example.com",
      "state": "live",
      "state_label": "Live",
      "application": "WordPress",
      "woocommerce": false,
      "hosted_by": "Zinn Digital LTD",
      "plan": {
        "code": "mainstream_plus",
        "name": "Plus",
        "monthly": "$15.00"
      },
      "usage": [
        {
          "label": "Disk",
          "used": "2,100",
          "allowed": "30,720",
          "percent": 7
        }
      ],
      "panel_url": "https://app.zinndigital.com/sites/abc123"
    }
  ]
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## One money site

`GET /money-sites/{site_id}` · scope `moneysites:read`

One money site in full: state, plan, hostnames, PHP version, region, usage against the plan's allowances, recent jobs and errors, and the links for the few jobs that are finished in the Zinn Digital panel.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `site_id` | path | integer | yes | The money site id. |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/money-sites/123" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/money-sites/123", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/123", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "id": 7,
    "domain": "example.com",
    "state": "live",
    "state_label": "Live",
    "application": "WordPress",
    "woocommerce": false,
    "hosted_by": "Zinn Digital LTD",
    "plan": {
      "code": "mainstream_plus",
      "name": "Plus",
      "monthly": "$15.00"
    },
    "usage": [
      {
        "label": "Disk",
        "used": "2,100",
        "allowed": "30,720",
        "percent": 7
      }
    ],
    "panel_url": "https://app.zinndigital.com/sites/abc123"
  }
}
```

Errors: `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## Re-read everything from Zinn Digital

`POST /money-sites/refresh` · scope `moneysites:read`

Ask Zinn Digital for this account's sites and orders again. Use it after paying, or if a site was set up for you by our team and is not listed yet.

### Example

```bash
curl -s -X POST "https://app.pbn.ltd/api/v1/money-sites/refresh" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/money-sites/refresh", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/refresh", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "found": 1,
    "sites": 2
  }
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## My money-site orders

`GET /money-sites/orders` · scope `moneysites:read`

Every money-site order on this account, newest first, with its state and what it cost.

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/money-sites/orders" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/money-sites/orders", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/orders", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": [
    {
      "id": 12,
      "state": "paying",
      "status": "Awaiting payment",
      "plan": {
        "code": "mainstream_plus",
        "name": "Plus",
        "line": "money-site hosting"
      },
      "term_months": 12,
      "domain": "example.com",
      "application": "WordPress",
      "total": "$153.00",
      "reference": "ZD-10023",
      "billed_by": "Zinn Digital LTD"
    }
  ]
}
```

Errors: `rate_limited`, `scope_missing`, `unauthorized`

## One money-site order

`GET /money-sites/orders/{order_id}` · scope `moneysites:read`

One order, re-read from Zinn Digital if it is still open.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `order_id` | path | integer | yes | The order id. |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/money-sites/orders/order_id" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/money-sites/orders/order_id", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/orders/order_id", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "id": 12,
    "state": "paying",
    "status": "Awaiting payment",
    "plan": {
      "code": "mainstream_plus",
      "name": "Plus",
      "line": "money-site hosting"
    },
    "term_months": 12,
    "domain": "example.com",
    "application": "WordPress",
    "total": "$153.00",
    "reference": "ZD-10023",
    "billed_by": "Zinn Digital LTD"
  }
}
```

Errors: `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## Order a money-site plan

`POST /money-sites/orders` · scope `moneysites:write`

Place a money-site order. Zinn Digital LTD bills it, so the answer carries a one-time `pay_url` on Zinn Digital's own secure page - open it to pay. Nothing is charged by this call. If Zinn Digital cannot take a partner order for that tier, the order is recorded as a request, a support ticket is opened, and the answer says so plainly instead of pretending.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `plan` | body | string | yes | A plan code from /money-sites/plans. |
| `months` | body | integer (one of: 1, 3, 6, 12) | no | How many months to pay for. Default: `1`. |
| `domain` | body | string | no | The domain for the site. Leave it out to start on a temporary address. |
| `application` | body | string | no | A one-click application key from /money-sites/plans. Default: `wordpress`. |
| `notes` | body | string | no | Anything our team should know. |
| `accept_terms` | body | boolean | no | Must be true: it records that this account accepts the Terms and Conditions for this purchase, exactly as the tick box on the website does. Default: `False`. |

### Example

```bash
curl -s -X POST "https://app.pbn.ltd/api/v1/money-sites/orders" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/money-sites/orders", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/orders", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`201`

```json
{
  "data": {
    "order": {
      "id": 12,
      "state": "paying",
      "status": "Awaiting payment",
      "plan": {
        "code": "mainstream_plus",
        "name": "Plus",
        "line": "money-site hosting"
      },
      "term_months": 12,
      "domain": "example.com",
      "application": "WordPress",
      "total": "$153.00",
      "reference": "ZD-10023",
      "billed_by": "Zinn Digital LTD"
    },
    "pay_url": "https://zinndigital.com/pay/...",
    "requested": false,
    "ticket_id": null
  }
}
```

Errors: `conflict`, `rate_limited`, `scope_missing`, `unauthorized`, `unavailable`

## Cancel an unpaid money-site order

`POST /money-sites/orders/{order_id}/cancel` · scope `moneysites:write` · **destructive**

Cancel an order that has not been paid. Nothing was charged, so nothing is refunded.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `order_id` | path | integer | yes | The order id. |

### Example

```bash
curl -s -X POST "https://app.pbn.ltd/api/v1/money-sites/orders/order_id/cancel" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/money-sites/orders/order_id/cancel", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/money-sites/orders/order_id/cancel", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "id": 12,
    "state": "paying",
    "status": "Awaiting payment",
    "plan": {
      "code": "mainstream_plus",
      "name": "Plus",
      "line": "money-site hosting"
    },
    "term_months": 12,
    "domain": "example.com",
    "application": "WordPress",
    "total": "$153.00",
    "reference": "ZD-10023",
    "billed_by": "Zinn Digital LTD"
  }
}
```

Errors: `conflict`, `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## WooCommerce on a PBN-line site

`GET /sites/{site_id}/woocommerce` · scope `moneysites:read`

Whether WooCommerce is installed on one of your PBN-line WordPress sites, which version, and the health checks: plugin active, shop/cart/checkout pages, a currency, pretty permalinks, HTTPS, and cart and checkout kept out of any page cache.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `site_id` | path | integer | yes | A PBN-line site id (the same id the /sites endpoints use). |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/sites/123/woocommerce" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/sites/123/woocommerce", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/woocommerce", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "site_id": 12345,
    "eligible": true,
    "on": true,
    "busy": false,
    "version": "9.3.3",
    "free": true,
    "health": [
      {
        "key": "plugin_active",
        "label": "WooCommerce is active",
        "ok": true
      }
    ]
  }
}
```

Errors: `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## Add or remove WooCommerce (free)

`POST /sites/{site_id}/woocommerce` · scope `moneysites:write` · returns a job

Adds WooCommerce to a PBN-line WordPress site, free of charge, or switches it off again. The install runs in the background and usually takes a minute or two; poll GET /sites/{site_id}/woocommerce for the result. WooCommerce is a WordPress plugin, so a site of another type is refused with the reason - use the WooCommerce money-site plan instead.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `site_id` | path | integer | yes | A PBN-line site id (the same id the /sites endpoints use). |
| `on` | body | boolean | no | true installs and activates WooCommerce; false deactivates it (products and orders stay in the database). Default: `True`. |

### Example

```bash
curl -s -X POST "https://app.pbn.ltd/api/v1/sites/123/woocommerce" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/sites/123/woocommerce", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/woocommerce", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "site_id": 12345,
    "state": "queued",
    "free": true
  },
  "job": {
    "id": "job_4f1c0a9e2b7d6c5a3e10",
    "kind": "...",
    "status": "running",
    "url": "https://app.pbn.ltd/api/v1/jobs/job_4f1c0a9e2b7d6c5a3e10"
  }
}
```

Errors: `conflict`, `not_found`, `rate_limited`, `scope_missing`, `unauthorized`
