ichiba.tech
Search listings Get started

Build on Ichiba

Extend the Ichiba marketplace as a seller. This guide covers the two main integration points: market seeders that populate your listings automatically, and seller gateways that provision cloud resources when buyers make purchases.

Market Seeders

One-shot programs that pull infrastructure data from a cloud provider's API and create or update listings in the marketplace. Run them as cron jobs to keep your catalog fresh.

Seller Gateways

Persistent HTTP services you operate. When a buyer purchases a listing, Ichiba calls your gateway to provision the underlying resource and return credentials.

Overview

Sellers on Ichiba operate two systems that work in tandem. The market seeder is responsible for the supply side: it reads your available infrastructure from a cloud provider API and publishes listings to Ichiba so buyers can discover and price-compare them. The seller gateway is responsible for fulfillment: it receives provisioning requests from Ichiba when a buyer completes a purchase, creates the actual cloud resource, and returns access credentials.

Both systems authenticate to Ichiba using a Bearer token issued to your organization. The gateway additionally uses a shared secret so Ichiba can authenticate inbound calls to it.

Market Seeders

What is a seeder?

A market seeder is a one-shot CLI program that syncs your cloud provider's catalog into the Ichiba marketplace. It runs to completion — fetching, mapping, and upserting listings — then exits. You schedule it as a cron job (hourly, daily, etc.) to keep pricing and availability current.

When to build a seeder

Build a seeder when you want to bulk-publish many listings from a structured data source (a cloud provider API, a pricing sheet, a database) rather than creating listings one by one through the API or UI.

Prerequisites

  • An Ichiba API token — generate one from your organization's API Tokens section in the web app
  • Cloud provider credentials appropriate for reading instance type or pricing data (e.g. AWS credentials via the standard SDK credential chain, a DigitalOcean personal access token, a Hetzner API token)
  • Network access to both the provider's API and https://api.ichiba.tech

How it works

A seeder follows this sequence on every run:

  1. Read configuration — load ICHIBA_API_TOKEN, ICHIBA_API_URL, and provider credentials from environment variables.
  2. Fetch existing listings — call GET /api/listings with your Bearer token and build a name → listing ID map so you can update existing entries instead of creating duplicates.
  3. Query the provider — call the cloud provider's API to get the current set of available instance types, storage classes, and their prices.
  4. Map to Ichiba payload — transform each provider offering into an Ichiba listing payload (see the schema below).
  5. Upsert — if the listing name already exists in your name → ID map, call PUT /api/listings/{id} to update it. Otherwise call POST /api/listings to create it.
  6. Print summary — report the count of created, updated, skipped, and failed listings.

The listing payload

The API reference documents the full schema. Below are representative payloads for the two asset types.

Compute listing

{
  "listing": {
    "name": "m6i.xlarge",
    "description": "General-purpose — 4 vCPU, 16 GB RAM",
    "asset_type": "compute",
    "price": "0.192",
    "status": "active"
  },
  "instance_type_spec": {
    "family": "general",
    "vcpus": 4,
    "memory_gb": "16",
    "cpu_architecture": "x86_64",
    "network_gbps": "12.5",
    "region": "us-east-1"
  },
  "network_spec": {
    "ipv4_included": true,
    "ipv6_supported": true,
    "byoip_supported": false,
    "private_networking": true,
    "egress_price_per_gb": "0.09"
  }
}

Block storage listing

{
  "listing": {
    "name": "Standard Block Storage — nyc3",
    "description": "SSD-backed block storage, multi-region replicated",
    "asset_type": "block_storage",
    "price": "0.10",
    "status": "active"
  },
  "block_storage_spec": {
    "capacity_gb": "500",
    "storage_class": "standard",
    "redundancy": "multi_region",
    "max_iops": 10000,
    "max_throughput_mbps": "500",
    "region": "nyc3"
  }
}

Set status to draft if you want to review listings before making them visible to buyers. Change to active to publish.

Code walkthrough — fetch → map → upsert

The following pseudocode illustrates the core seeder loop. Adapt it to your language and cloud provider SDK of choice.

Step 1 — fetch existing listings

curl https://api.ichiba.tech/api/listings \
  -H "Authorization: Bearer $ICHIBA_API_TOKEN"

Build a map of name → id from the response. You'll use this to decide whether to POST or PUT each offering.

Step 2 — upsert loop

for each offering from provider API:
    payload = map_to_ichiba_payload(offering)

    if existing_id = name_to_id[payload.listing.name]:
        PUT /api/listings/{existing_id}  body=payload
    else:
        POST /api/listings               body=payload

Step 3 — handle errors per listing

if response.status == 201 or 200:
    created_or_updated += 1
elif response.status == 422:
    log("validation error", response.body)
    failed += 1
else:
    log("unexpected status", response.status)
    failed += 1

Error handling tip

Process each listing independently — don't abort the entire run on a single failure. Log validation errors (422) with the listing name and response body so you can inspect and fix mapping issues without rerunning the full import.

Running as a cron job

Seeders are designed to be run repeatedly. Because each run is idempotent (it upserts by name), you can schedule it as often as needed without creating duplicate listings.

Build and run (Go example)

go build -o seeder . && ./seeder

Crontab entry — run daily at midnight

0 0 * * * /opt/seeder/seeder >> /var/log/seeder.log 2>&1

Docker

docker build -t my-seeder .
docker run --env-file .env my-seeder

Pass ICHIBA_API_TOKEN, ICHIBA_API_URL, and provider credentials via environment variables or an env file. Never bake secrets into the image.

Seller Gateways

What is a gateway?

A seller gateway is a persistent HTTP service that you operate. It implements a small, well-defined API that Ichiba calls to provision and deprovision cloud resources on behalf of buyers. Your gateway handles the cloud-provider-specific logic; Ichiba handles billing, discovery, and the buyer experience.

Ichiba calls your gateway — not the other way around

Your gateway is passive. It waits for Ichiba to call it. When a buyer purchases a listing, Ichiba sends a POST /tenants request to your gateway URL. When the buyer cancels, Ichiba sends DELETE /tenants/{id}. You do not need to poll Ichiba — just implement the four endpoints below.

Prerequisites

  • A publicly routable HTTPS endpoint for your gateway service
  • A shared secret you choose — set as ICHIBA_GATEWAY_SECRET and registered in your Ichiba seller profile
  • A PostgreSQL database to persist tenant state and credentials
  • Cloud provider credentials with permission to create, describe, and delete the resources you are selling
  • An encryption key for storing access credentials at rest — set as GATEWAY_ENCRYPTION_KEY

The HTTP API contract

All gateways must implement these four endpoints. Ichiba will not call any others.

GET /health Liveness check

No authentication required. Return 200 OK when the service is healthy. Ichiba checks this before routing traffic to your gateway.

{ "status": "ok" }
POST /tenants Provision a resource

Ichiba calls this when a buyer purchases a listing. Provision the cloud resource and return a tenant object with access credentials. Auth: Bearer shared secret.

Request body

{
  "idempotency_key": "purchase_550e8400-e29b-41d4-a716-446655440000",
  "listing_id": 42,
  "buyer_org_id": 7,
  "asset_type": "compute",
  "spec": {
    "vcpus": 4,
    "memory_gb": "16",
    "region": "us-east-1"
  }
}

Response — compute (201 Created)

{
  "id": "tenant_abc123",
  "status": "active",
  "access_details": {
    "host": "ec2-203-0-113-42.compute-1.amazonaws.com",
    "username": "ubuntu",
    "ssh_private_key": "-----BEGIN RSA PRIVATE KEY-----\n..."
  }
}

Response — block storage (201 Created)

{
  "id": "tenant_def456",
  "status": "active",
  "access_details": {
    "volume_id": "vol-0abcdef1234567890",
    "region": "us-east-1",
    "device": "/dev/xvdf"
  }
}

Async response (202 Accepted)

{
  "id": "tenant_ghi789",
  "status": "provisioning",
  "access_details": null
}

Return 202 if provisioning takes more than a few seconds. Ichiba will poll GET /tenants/{id} until status becomes active or failed.

GET /tenants/{id} Retrieve tenant status

Returns the current status and access credentials for a tenant. Auth: Bearer shared secret. Ichiba polls this endpoint while a purchase is in pending status.

{
  "id": "tenant_abc123",
  "status": "active",
  "access_details": { ... }
}
DELETE /tenants/{id} Deprovision a resource

Ichiba calls this when a buyer cancels a purchase. Destroy the cloud resource and mark the tenant as cancelled. Auth: Bearer shared secret. Must be idempotent — calling DELETE on an already-cancelled tenant must return 200, not an error.

{ "id": "tenant_abc123", "status": "cancelled" }

The tenant lifecycle

Each tenant moves through a well-defined set of states:

Status Description
provisioning Resource creation in progress (async path only)
active Resource ready — access_details populated
failed Provisioning failed — set an error_message
cancelled Resource destroyed, tenant record retained for audit

The normal path is provisioning → active → cancelled. If creation fails, transition to failed with an error message. Retain the tenant row in your database after cancellation — delete only the cloud resource.

Step-by-step implementation

1. Validate the Bearer token on every request

Every inbound request (except GET /health) must carry Authorization: Bearer {ICHIBA_GATEWAY_SECRET}. Reject requests with a wrong or missing token with 401 Unauthorized.

curl https://your-gateway.example.com/tenants \
  -X POST \
  -H "Authorization: Bearer $ICHIBA_GATEWAY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"idempotency_key":"k1","listing_id":42,...}'

2. Implement idempotency on POST /tenants

Before creating a resource, check your database for an existing tenant with the same idempotency_key. If found, return it immediately without creating a new resource. Ichiba may retry the request on network failure.

existing = db.find_tenant_by_idempotency_key(params.idempotency_key)
if existing:
    return 200, existing

tenant = db.create_tenant(idempotency_key=params.idempotency_key, status="provisioning")
resource = cloud.create_resource(params.spec)
tenant.update(status="active", access_details=encrypt(resource.credentials))
return 201, tenant

3. Tag all provisioned resources

Apply these tags to every cloud resource you create so you can identify and audit Ichiba-managed infrastructure:

{
  "ManagedBy":          "ichiba",
  "IchibaListingId":    "42",
  "IchibaBuyerOrgId":   "7",
  "IchibaTenantId":     "tenant_abc123"
}

4. Isolate credentials per tenant

Create a dedicated IAM user, SSH key pair, or access credential for each tenant. Do not share credentials across tenants. This ensures that cancelling one purchase does not affect another buyer's access.

5. Encrypt credentials at rest

Store all access credentials encrypted in your database using GATEWAY_ENCRYPTION_KEY. Decrypt only when returning them in a tenant response.

6. Make DELETE idempotent

If the tenant is already cancelled (or the cloud resource is already gone), return 200 with the current tenant state. Never return an error for a resource that no longer exists.

Configuration & env vars

Variable Required Description
ICHIBA_GATEWAY_SECRET Yes Shared secret — Ichiba sends this as the Bearer token on every inbound call
DATABASE_URL Yes PostgreSQL connection string for persisting tenant state
GATEWAY_ENCRYPTION_KEY Yes AES-256 key (base64-encoded) used to encrypt access credentials at rest
PORT No HTTP port to listen on (default: 8080)
Provider credentials Yes AWS, DigitalOcean, Hetzner, or other provider credentials needed to create resources

Registering with Ichiba

Once your gateway is deployed and passes the local lifecycle test, register it in Ichiba so the platform can route purchases to it.

  1. Open the web app and navigate to your organization's seller settings.
  2. Enter your gateway's public HTTPS URL (e.g. https://gateway.yourcompany.com).
  3. Enter the shared secret you configured as ICHIBA_GATEWAY_SECRET.
  4. Save. Ichiba will immediately call GET /health to verify connectivity.
  5. Activate any listings you want buyers to be able to purchase — they are now backed by your gateway.

Keep your gateway reachable

Ichiba will reject purchase attempts if your GET /health endpoint is unreachable or returns a non-200 status. Monitor your gateway's uptime and ensure TLS is valid — Ichiba does not follow redirects or accept self-signed certificates.