---
# System prepended metadata

title: Permaweb Payment Protocol

---

# Permaweb Payment Protocol

# Goal

Describe a protocol that enables payment channels to incentivize a variety  services in the Arweave ecosystem.

# Mechanism Design

1. Clients enumerate available service providers.
1. Clients request service prices from providers.
1. Clients make deposits at cheapest and most responsive service providers.
1. Clients make service requests to providers holding deposits.
1. Service providers charge service fees against the clients deposit.
1. Clients score service providers based on reliability and responsiveness.
1. Service providers compete on price, reliability, and responsiveness to serve clients.

![](https://i.imgur.com/oKIGYJk.png)

# Rates

Service providers may publish their services and corresponding rates via the rates endpoint.

:::info
`GET` http://arweave.net/**rates**
:::
The following is an example response body from the `/rates` endpoint.
```json=
{
 "endpoints": [ {
   "endpoint":"/graphql",
   "modSeq": 1,
   "rates": {
     "description": "Price per block queried",
     "arweave": {
       "AR": {
         "price":"10000",
         "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
       },
       "VRT": {
         "price":"1",
         "contractId":"aLemOhg9OGovn-0o4cOCbueiHT9VgdYnpJpq7NgMA1A",
         "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
       }
     },
     "external": {
       "url":"https://example.com/deposit.html"
     },
     "polygon": {
       "MATIC": {
         "price":"11010101",
         "address": "0x0e2Db4C482B9fd5809f5bF48d04A3eE1a9D73D96"
       }
     },
     "solana": {
       "SOL": {
         "price":"111101010",
         "address":"ApFWL3dtpFX8tU15uPzWnvfeQRtompvoAs9DNEnQH6DL"
       }
     }
   }
 }, {
   "endpoint":"/tx/{id}/{field}",
   "modSeq": 3,
   "rates": {
     "description": "Price per request",
     "arweave": {
       "AR": {
         "price":"10000",
         "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
       }
     }
   }
 }, {
   "endpoint":"/tx/{id}",
   "modSeq": 1,
   "rates": {
     "description": "Price per request",
     "arweave": {
       "AR": {
         "price":"10000",
         "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
       }
     }
   }
 },{
   "endpoint":"/chunk/{offset}",
   "modSeq": 5,
   "rates": {
     "description": "Price per byte of data",
     "arweave": {
       "price":"100000",
       "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
     }
   }
 }, {
   "endpoint":"/{txid}",
   "modSeq": 2,
   "rates": {
     "arweave": {
       "price":"100000",
       "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
     }
   }
 }]
}
```

### Schema

The root object contains an array of `Service Endpoint Config`, each one representing the pricing and metadata for a particular service endpoint.

```json=
{
  "endpoints": [ … ]
}
```

### Service Endpoint Config

Each element of the `endpoints` array is an instance of a `Service Endpoint Config`. Each config describes the HTTP API service endpoint along service rates (cost).

```json=
{
   "endpoint":"/graphql",
   "modSeq": 1,
   "rates": { … }
}
```

| Property | Required | Description |
| -------- | -------- | -------- |
| endpoint | required     | The path to the endpoint that is providing service.     |
| modSeq   | required     | The `modification sequence` number for the endpoint config.</br> Enables clients to cache rates for an endpoint and be directed to requery rates only when the underlying rates are updated.
| rates    | required     | A `Rates Config` object describing the prices for service at this endpoint.

### Rates Config

Each `Service Endpoint Config` publishes an array of `Rates Config` to describe service pricing. `Rate Configs` allow for prices to be listed in a variety of network tokens, provided the service operator maintains a wallet native to that network.

```json=
  "rates": {
     "description": "Price per block queried",
     "arweave": { … },
     "polygon": { … },
     "solana": { … }
  }
```

### Network Price Config

Describes the price of service denominated in a token native to the network. Also provides the wallet address to transfer tokens to in order to fun a deposit.

```json=
"arweave": {
   "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
   "AR": {
     "price":"10000",
   },
   "VRT": {
     "price":"1",
     "contractId":"aLemOhg9OGovn-0o4cOCbueiHT9VgdYnpJpq7NgMA1A",
     "address":"89tR0-C1m3_sCWCoVCChg4gFYKdiH5_ZDyZpdJ2DDRw"
   }
 },
```

In this example the arweave Network Price Config supports payment in the native token AR as well as a PST token VRT. VRT is managed by a smartweave contract so that `contractId` is listed as well. For each token the corresponding price for service is listed.

| Property  | Description |
| --------- |------------ |
| price     | The cost of service (described in the Rates Config description property).</br>In the case of arweave, the price is delineated in Winstons (atomic units).
| address   | The wallet address to receive the service payment.
| contractId|In the case of a token managed by a smart contract like a PST or ERC-20, this specifies the contract ID.

:::info
**NOTE:** `price` is always denominated in the smallest divisible unit of the token, otherwise known as **atomic units**
:::

### External Price Config

For “off chain” value transfers (like credit card payments or other incentivized channels) the price config simply provides a URL of a page to make the payment.

```json=
 "external": {
    "url":"https://example.com/deposit.html"
  },
```
# Service Requests

Requesting service from a Permaweb Payments Protocol (P3) endpoint follows a standard HTTP API request format. However, to properly identify which wallet to charge for the service, requests must also include some P3 specific HTTP headers.

### Request Headers


| Header | Required | Description |
| -------- | -------- | -------- |
| anchor     | (optional) | [Nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) that can be optionally provided and optionally implemented by the service endpoint to prevent replay attacks.     |
| modSeq     | (optional) | The caller can specify the `modSeq` of the [Endpoint Config](#Service-Endpoint-Config) they have cached locally and are expecting to be charged.
| price      | (optional) | The `<network>/<token>` of the Price Config to use. Defaults to `arweave/AR`.
| timeout|(optional)| Number of milliseconds the client will wait before timing out the request. This enables clients to indicate a willingness to wait longer for responses when the data is important (and not score the provider poorly as a result)
| endpoint | required | The value of the `endpoint` field in the `ServiceEndpointConfig` e.g. `"/graphql"`
| address    | required | The wallet address of the deposit to charge for service.
| signature  | required | The request headers `endpoint` + `address` + `modSeq` + `price` + `anchor` + `timeout` are concatenated, SHA-256 hashed and the hash is signed by the private key of the wallet indicated by `address`. (if optional parameters are missing they are dropped)


### HTTP Response Codes



| Code     | Description | 
| -------- | ----------- |
| 🟢 200   | OK          |
| 🔴 400   | Bad Request - invalid P3 headers/header values |
| 🔴 402   | Bad Request - Payment Required - Not enough funds on deposit |
| 🟡 428  | Precondition Required - modSeq is out of date |
| 🟡 429  | Too many requests - and/or Rate limited 

### Response Headers
When the service endpoint responds with data, it will include the following HTTP headers in the response.

# Deposits

By default any wallet posting a “deposit” transaction to an address specified by a Price Config will be credited with the deposit and able to sign P3 request headers to bill against it.

Optionally, a deposit transaction may specify an array of wallet entries to be credited with a portion of the deposit. This is accomplished by adding a “addresses” [Custom Tag](https://github.com/ArweaveTeam/arweave-js#add-tags-to-a-transaction) to the transaction with the following entry format, a JSON array of `{<address>:<amount>}` entries.

```
"addresses": “[
   { "79pOFCwHmdgiqcl6blGFY45eS87V-OkiPspLvRCrRq4" : 100 },
   { "NoHbaZ9ZchidleZNdHYHb2TFV4puCBJTiESZ07dPXJg" : 50 },
   { "xo6_3x3pdVnRc6fKPduoUtK3M3ABF2-V7iUilHMCy3I" : 50 }
]”
```
If the total of the `amount` values does not exactly match the number of tokens being deposited, then the `amount`‘s will be averaged and the deposit split amongst the wallets proportionally.

In the case where a `wallets` list is provided, the owner of the transaction must include their own wallet address in the `wallets` list if they wish it to be credited with a portion of the deposit.

# Balances
Enables clients to check their balance with a given service provider to verify pricing and determine when to "top up" their deposit.
:::info
`GET` http://arweave.net/**balance/{address}/{network}/{token}**
:::

**Note:** While [Rate Configs](#Rates-Config) are unique to each service endpoint, the balance on deposit for a given wallet address is shared across all service endpoints. There is no protocol defined means to limit deposits to a single service endpoint. If the provider has a deposit for the client wallet it will bill against that deposit regardless of what service is requested.

# Charging for Service
When a gateway bills a client for service, it deducts that amount from the local deposit ledger it maintains for client addresses. This way the gateway can more efficiently rollup fees to a single transaction at day's end, or whatever interval makes sense for the gateway operator.

As long as the [Balance](#Balances) endpoint is accurate, this should be sufficient for clients.