InfraRabbit provider feed, version 1
An open format for a hosting provider to publish its own prices as one JSON file. Anyone can read it, InfraRabbit included, without scraping your site.
Spec licence: CC BY 4.0. Current version: 1.0. Shaped with EDIS Global's feed (schema 2.0) as a starting point; this is an acknowledgement, not an endorsement by or of anyone.
Why publish a feed
- One fetch a day instead of scraping: your servers see one small request, not a crawler walking your pages.
- Exact prices: we show what you publish, to the cent, with the currency, the VAT basis and the billing period.
- You control accuracy: a number is right because you wrote it, and a price change you announce shows up with its date.
How to publish
- Write one JSON file per location (or one file per provider with a plan list per location file; v1 keeps it to one location per file). Follow the schema; see the example.
- Serve it at a stable public URL of your own, over HTTPS, as
application/json. Regenerate it whenever a price changes, and at least daily. - Tell us the URL (next section). Publishing the URL and telling us is your permission to read it; nothing else is needed, and we read it no more than once a day.
- Check the file with the validator below before you tell us.
Rules of the format: state, never estimate. Leave out what you do not know; never write 0 for an unknown (0 means free). Prices are the ones you publish, in your own currency. Unknown fields are allowed and ignored, so you can add your own.
How to tell us
Write to inbox@infrarabbit.com with the feed URL, or use the corrections page if a number of ours differs from your feed. We read the feed, show the prices and date them from your generated_at.
Fields
Required fields are marked. Types follow JSON Schema; dates are ISO 8601; a TB is 1000 GB unless gb_per_tb says otherwise.
| Field | Required | Type | Meaning |
|---|---|---|---|
schema_version | yes | string | Version of this spec the file follows: 1.0 for this version. |
provider | yes | object | Who publishes the feed. |
provider.name | yes | string | Company or brand name. |
provider.url | yes | string | The provider's website. |
provider.contact | string | Where we can reach you about the feed: an email address or a URL. | |
generated_at | yes | string | When the file was generated, RFC 3339 date-time. |
location | yes | object | The location the plans below are sold in. |
location.id | yes | string | Your stable identifier of the location, for example nl-ams. |
location.country | yes | string | ISO 3166-1 alpha-2 country code, uppercase, for example NL. |
location.city | string | City name. | |
location.display_name | string | Location name as shown on your site. | |
location.datacenter | string | Datacenter or facility name, as you state it. | |
plans | yes | array | The plans sold in this location, with the prices as published. |
plans[].id | yes | string | Your stable identifier for the plan (a product id or slug). Must not change when the price changes. |
plans[].name | yes | string | The plan name as shown on your site. |
plans[].url | yes | string | Public page of the plan on your site. |
plans[].order_url | string | Link that starts the order for this plan. | |
plans[].vcpu | yes | integer | Number of virtual CPU cores included. |
plans[].vcpu_type | shared | dedicated | shared if cores are shared with other customers, dedicated if reserved for this plan. | |
plans[].cpu_model | string | CPU model or family, as you state it. | |
plans[].ram_gb | yes | number | RAM in GB. |
plans[].disk_gb | yes | number | Disk size in GB. |
plans[].disk_type | string | Disk technology as you state it, for example NVMe, SSD, HDD. | |
plans[].traffic_tb | number | Monthly traffic included, in TB (1 TB = 1000 GB unless gb_per_tb says otherwise). Omit if unmetered or unknown; use traffic_unmetered for unmetered. | |
plans[].gb_per_tb | 1000 | 1024 | GB in one TB for traffic_tb. 1000 if omitted. | |
plans[].traffic_unmetered | boolean | true if traffic is not metered (fair use still goes in the plan page). | |
plans[].traffic_counted | in | out | in+out | Which direction counts against the allowance. | |
plans[].bandwidth_mbps_guaranteed | number | Bandwidth in Mbit/s that is guaranteed per VPS. Omit if only best effort. | |
plans[].port_speed_mbps | number | Port speed in Mbit/s (a port speed is not a guarantee). | |
plans[].ipv4_included | integer | Number of IPv4 addresses included. | |
plans[].ipv6_prefix | string | Size of the IPv6 prefix included, for example /64. Omit if none or unknown. | |
plans[].price | yes | object | The base price of the plan as published, for one billing period. |
plans[].price.amount | yes | number | The price as published, in the currency below. 0 only when the plan or option is really free. |
plans[].price.currency | yes | string | ISO 4217 currency code of the amount, for example EUR. |
plans[].price.vat_included | yes | boolean | true if the amount includes VAT, false if VAT is added at checkout. |
plans[].price.billing_period | yes | hour | month | year | The period the amount is charged for. |
plans[].terms | array | Longer commitments with their own monthly price. | |
plans[].terms[].months | yes | integer | Length of the commitment in months. |
plans[].terms[].price_per_month | yes | number | Price per month on this term, in the currency and VAT basis of price. |
plans[].terms[].setup_fee | number | One-time setup fee on this term, same currency as price. | |
plans[].setup_fee | number | One-time setup fee in the currency of price. Omit if unknown; 0 only if stated as free. | |
plans[].availability | object | Stock state of the plan. | |
plans[].availability.status | yes | in_stock | out_of_stock | unknown | Whether the plan can be ordered now. |
plans[].availability.checked_at | string | When the status was last checked, RFC 3339 date-time. | |
plans[].end_of_sale_date | string | Date (YYYY-MM-DD) after which the plan can no longer be ordered, if announced. | |
addons | array | Priced options besides the plans. | |
addons[].type | yes | extra_ipv4 | backups | snapshots | windows_licence | ddos | traffic_overage_per_tb | What the add-on is. |
addons[].name | string | The add-on name as shown on your site. | |
addons[].url | string | Public page of the add-on. | |
addons[].price | yes | object | Price as published. billing_period is once for one-time fees; traffic_overage_per_tb is the price per TB. |
addons[].price.amount | yes | number | The price as published, in the currency below. 0 only when the plan or option is really free. |
addons[].price.currency | yes | string | ISO 4217 currency code of the amount, for example EUR. |
addons[].price.vat_included | yes | boolean | true if the amount includes VAT, false if VAT is added at checkout. |
addons[].price.billing_period | yes | hour | month | year | once | The period the amount is charged for. |
policies | object | Rules that apply to the plans in this feed. | |
policies.port_25 | open | blocked | on_request | Outbound SMTP on port 25. | |
policies.sla_percent | number | Uptime promised in the SLA, in percent, for example 99.9. | |
policies.money_back_days | integer | Days in which an order can be refunded. | |
policies.aup_url | string | Link to the acceptable use policy. | |
changes | array | Announced future price changes. The most valuable optional field: it lets readers show a change before it takes effect. | |
changes[].effective_date | yes | string | Date (YYYY-MM-DD) from which the new price applies. |
changes[].plan_id | yes | string | The id of the plan in plans[] that changes. |
changes[].old_price | number | The price before the change, same currency, period and VAT basis as the plan price. | |
changes[].new_price | yes | number | The price from effective_date, same currency, period and VAT basis as the plan price. |
changes[].note | string | Short reason or remark, for example the announcement. |
Example
The same file as example.json:
{
"schema_version": "1.0",
"provider": {
"name": "Example Hosting B.V.",
"url": "https://www.example-hosting.test",
"contact": "feeds@example-hosting.test"
},
"generated_at": "2026-11-13T06:00:00Z",
"location": {
"id": "nl-ams",
"country": "NL",
"city": "Amsterdam",
"display_name": "Netherlands - Amsterdam",
"datacenter": "Example DC1"
},
"plans": [
{
"id": "vps-s",
"name": "VPS S",
"url": "https://www.example-hosting.test/vps/s",
"order_url": "https://my.example-hosting.test/order?plan=vps-s",
"vcpu": 1,
"vcpu_type": "shared",
"cpu_model": "AMD EPYC 7543",
"ram_gb": 2,
"disk_gb": 40,
"disk_type": "NVMe",
"traffic_tb": 2,
"traffic_counted": "in+out",
"port_speed_mbps": 1000,
"ipv4_included": 1,
"ipv6_prefix": "/64",
"price": {
"amount": 4.5,
"currency": "EUR",
"vat_included": false,
"billing_period": "month"
},
"terms": [
{
"months": 12,
"price_per_month": 4.0,
"setup_fee": 0
}
],
"setup_fee": 0,
"availability": {
"status": "in_stock",
"checked_at": "2026-11-13T05:55:00Z"
}
},
{
"id": "vps-m",
"name": "VPS M",
"url": "https://www.example-hosting.test/vps/m",
"vcpu": 4,
"vcpu_type": "dedicated",
"ram_gb": 8,
"disk_gb": 160,
"disk_type": "NVMe",
"traffic_tb": 10,
"gb_per_tb": 1000,
"traffic_counted": "out",
"bandwidth_mbps_guaranteed": 250,
"port_speed_mbps": 1000,
"ipv4_included": 1,
"price": {
"amount": 16,
"currency": "EUR",
"vat_included": false,
"billing_period": "month"
},
"availability": {
"status": "unknown"
},
"end_of_sale_date": "2027-06-30"
}
],
"addons": [
{
"type": "extra_ipv4",
"price": {
"amount": 2,
"currency": "EUR",
"vat_included": false,
"billing_period": "month"
}
},
{
"type": "backups",
"price": {
"amount": 1.2,
"currency": "EUR",
"vat_included": false,
"billing_period": "month"
}
},
{
"type": "traffic_overage_per_tb",
"price": {
"amount": 1,
"currency": "EUR",
"vat_included": false,
"billing_period": "once"
}
}
],
"policies": {
"port_25": "on_request",
"sla_percent": 99.9,
"money_back_days": 14,
"aup_url": "https://www.example-hosting.test/aup"
},
"changes": [
{
"effective_date": "2027-01-01",
"plan_id": "vps-s",
"old_price": 4.5,
"new_price": 5.0,
"note": "Announced 2026-11-01 on our blog."
}
]
}
Validation
Post your file to the validator. It reads only what you send; it never fetches a URL, so there is no GET form with ?url=. Answers are JSON: valid and a list of errors, each with a path (a JSON pointer) and a message. At most 512 KB per file, rate limited like our other public requests.
curl -sS -X POST --data-binary @feed.json \
-H "Content-Type: application/json" \
https://infrarabbit.com/spec/provider-feed/validate
Status 200 means the file was read (see valid); 400 means it is not JSON; 413 means it is too large; 429 means slow down.
Badge
If you publish the feed, you can say so. Paste this text link on your site:
<a href="https://infrarabbit.com/spec/provider-feed">Prices published in InfraRabbit feed format v1</a>
Versioning and changelog
The version is in schema_version. Within version 1 we only add optional fields and values; a file that is valid today stays valid. A change that could break a valid file becomes version 2 at a new address (v2.schema.json); version 1 stays online.
- 1.0 (13 November 2026): first version.