Shell City API
Web data extraction built for AI agents. One API key, pay-per-request pricing, no subscriptions. Scrape URLs, extract structured data, and monitor your usage with a simple REST API.
Authentication
All authenticated endpoints require a Bearer token in the Authorization header. API keys start with the prefix sc_live_.
Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
You can create an API key programmatically using the Create API Key endpoint (no authentication required), or from the Dashboard.
Endpoints
POST Create API Key
Create a new API key. Every new key receives 100 free credits ($0.10) to start. You can optionally provide a name to identify the key.
| Parameter | Type | Description |
|---|---|---|
| nameoptional | string | A human-readable name for the key (e.g., "My App", "Production Agent") |
curl -X POST https://shellcity.polsia.app/v1/keys \ -H "Content-Type: application/json" \ -d '{"name": "My App"}'
const response = await fetch('https://shellcity.polsia.app/v1/keys', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'My App' }) }); const data = await response.json(); console.log(data.api_key.key); // sc_live_xxxxxxxx...
{
"success": true,
"api_key": {
"key": "sc_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"id": "key_8f3a9b2c",
"prefix": "sc_live_a1b2",
"name": "My App",
"balance_credits": 100
},
"message": "API key created. You have 100 free credits ($0.10)."
}
GET Get Key Info
Retrieve information about the currently authenticated API key, including credit balance, usage statistics, and account details.
curl https://shellcity.polsia.app/v1/keys/me \ -H "Authorization: Bearer sc_live_your_key_here"
const response = await fetch('https://shellcity.polsia.app/v1/keys/me', { headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}` } }); const data = await response.json(); console.log(data);
{
"success": true,
"api_key": {
"id": "key_8f3a9b2c",
"prefix": "sc_live_a1b2",
"name": "My App",
"balance_credits": 95,
"balance_usd": 0.095,
"total_requests": 5,
"created_at": "2026-03-15T10:30:00Z",
"last_used_at": "2026-03-17T08:22:14Z",
"status": "active"
}
}
POST Scrape URL 1 credit ($0.001)
Scrape a URL and return the page content as clean markdown. Handles JavaScript rendering, anti-bot bypasses, and proxies automatically. The response includes metadata about credits used and remaining balance.
| Parameter | Type | Description |
|---|---|---|
| urlrequired | string | The URL to scrape. Must be a valid HTTP or HTTPS URL. |
| formatsoptional | string[] | Output formats. Supported: "markdown", "html", "text". Default: ["markdown"] |
curl -X POST https://shellcity.polsia.app/v1/scrape \ -H "Authorization: Bearer sc_live_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "formats": ["markdown"] }'
const response = await fetch('https://shellcity.polsia.app/v1/scrape', { method: 'POST', headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://example.com', formats: ['markdown'] }) }); const data = await response.json(); console.log(data.data.markdown);
{
"success": true,
"data": {
"markdown": "# Example Domain\n\nThis domain is for use in illustrative examples..."
},
"metadata": {
"credits_used": 1,
"credits_remaining": 94,
"provider": "firecrawl",
"response_time_ms": 1240
}
}
POST Extract Structured Data 5 credits ($0.005)
Extract structured data from a URL using AI. Provide a natural language prompt describing what to extract, and optionally a JSON schema for the output. The LLM reads the page content and returns clean, structured data matching your requirements.
| Parameter | Type | Description |
|---|---|---|
| urlrequired | string | The URL to extract data from. |
| promptrequired | string | Natural language description of what to extract (e.g., "Extract all product names and prices"). |
| schemaoptional | object | A JSON schema defining the expected output structure. Helps the LLM return consistently formatted data. |
curl -X POST https://shellcity.polsia.app/v1/extract \ -H "Authorization: Bearer sc_live_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/products", "prompt": "Extract all product names and prices", "schema": { "type": "object", "properties": { "products": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "price": { "type": "number" }, "currency": { "type": "string" } } } } } } }'
const response = await fetch('https://shellcity.polsia.app/v1/extract', { method: 'POST', headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://example.com/products', prompt: 'Extract all product names and prices', schema: { type: 'object', properties: { products: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, price: { type: 'number' }, currency: { type: 'string' } } } } } } }) }); const data = await response.json(); console.log(data.data);
{
"success": true,
"data": {
"products": [
{
"name": "Wireless Keyboard Pro",
"price": 79.99,
"currency": "USD"
},
{
"name": "Ergonomic Mouse X1",
"price": 49.99,
"currency": "USD"
}
]
},
"metadata": {
"credits_used": 5,
"credits_remaining": 89,
"provider": "firecrawl",
"response_time_ms": 3420
}
}
GET Usage Statistics
Retrieve usage statistics for your API key, including total requests, credits used, daily breakdown, and breakdown by provider.
curl https://shellcity.polsia.app/v1/usage \ -H "Authorization: Bearer sc_live_your_key_here"
const response = await fetch('https://shellcity.polsia.app/v1/usage', { headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}` } }); const data = await response.json(); console.log(data);
{
"success": true,
"usage": {
"total_requests": 142,
"credits_used": 312,
"daily": [
{
"date": "2026-03-17",
"requests": 23,
"credits": 48
},
{
"date": "2026-03-16",
"requests": 45,
"credits": 110
}
],
"by_provider": {
"firecrawl": { "requests": 120, "credits": 250 },
"scrapingbee": { "requests": 22, "credits": 62 }
}
}
}
GET Request History
Retrieve a paginated list of individual API requests made with your key. Useful for debugging, auditing, and understanding usage patterns.
| Parameter | Type | Description |
|---|---|---|
| limitoptional | integer | Number of records to return. Default: 50. Max: 200. |
| offsetoptional | integer | Number of records to skip for pagination. Default: 0. |
curl "https://shellcity.polsia.app/v1/usage/history?limit=10&offset=0" \ -H "Authorization: Bearer sc_live_your_key_here"
const params = new URLSearchParams({ limit: 10, offset: 0 }); const response = await fetch( `https://shellcity.polsia.app/v1/usage/history?${params}`, { headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}` } } ); const data = await response.json(); console.log(data.requests);
{
"success": true,
"requests": [
{
"id": "req_9f8e7d6c",
"endpoint": "/v1/scrape",
"method": "POST",
"url": "https://example.com",
"status": 200,
"credits_used": 1,
"provider": "firecrawl",
"response_time_ms": 1180,
"created_at": "2026-03-17T08:22:14Z"
},
{
"id": "req_5a4b3c2d",
"endpoint": "/v1/extract",
"method": "POST",
"url": "https://example.com/products",
"status": 200,
"credits_used": 5,
"provider": "firecrawl",
"response_time_ms": 3210,
"created_at": "2026-03-17T08:15:03Z"
}
],
"pagination": {
"limit": 10,
"offset": 0,
"total": 142,
"has_more": true
}
}
GET Credits
Retrieve your current credit balance and recent transaction history. Use this endpoint to monitor your spending and track credit purchases.
curl https://shellcity.polsia.app/v1/credits \ -H "Authorization: Bearer sc_live_your_key_here"
const response = await fetch('https://shellcity.polsia.app/v1/credits', { headers: { 'Authorization': `Bearer ${SHELL_CITY_KEY}` } }); const data = await response.json(); console.log(`Balance: ${data.balance.credits} credits ($${data.balance.usd})`);
{
"success": true,
"balance": {
"credits": 4850,
"usd": 4.85
},
"transactions": [
{
"id": "txn_a1b2c3d4",
"type": "purchase",
"credits": 5000,
"amount_usd": 5.00,
"description": "Credit purchase via Stripe",
"created_at": "2026-03-15T10:30:00Z"
},
{
"id": "txn_e5f6g7h8",
"type": "usage",
"credits": -150,
"amount_usd": -0.15,
"description": "API usage (150 requests)",
"created_at": "2026-03-16T23:59:59Z"
},
{
"id": "txn_i9j0k1l2",
"type": "bonus",
"credits": 100,
"amount_usd": 0.10,
"description": "Welcome bonus - 100 free credits",
"created_at": "2026-03-15T10:30:00Z"
}
]
}
Pricing
Shell City uses a simple credit-based pricing model. Buy credits, spend them on API calls. No subscriptions, no monthly minimums, no surprise bills.
Error Codes
All error responses follow a consistent format with a success: false flag and a human-readable message field. Your integration should handle these status codes gracefully.
| Status | Code | Description |
|---|---|---|
| 401 | Unauthorized | Invalid or missing API key. Verify your Authorization header contains a valid Bearer token. |
| 402 | Insufficient Credits | Your credit balance is too low for this request. Purchase additional credits to continue. |
| 403 | Forbidden | API key has been revoked or lacks permission for the requested operation. |
| 422 | Provider Error | The upstream scraping provider returned an error. This may be a temporary issue with the target URL or provider. Retry after a brief delay. |
| 502 | Provider Unavailable | The upstream provider is temporarily unavailable. Shell City will attempt automatic failover. If the error persists, retry after 30 seconds. |
{
"success": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits. Required: 5, available: 2. Purchase more credits to continue.",
"credits_required": 5,
"credits_available": 2
}
}
Rate Limits
Shell City applies rate limits per API key to ensure fair usage and platform stability. Rate limit information is included in response headers.
| Tier | Limit | Window |
|---|---|---|
| Default | 60 requests | Per minute |
| Burst | 10 requests | Per second |
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 X-RateLimit-Reset: 1710662400
When rate limited, you will receive a 429 Too Many Requests response. Wait for the time indicated in the X-RateLimit-Reset header before retrying.