API Documentation
The seospark.io API allows you to access data available in seospark.io through a programmable HTTP interface. Access to the API is not included by default in the subscription plans. If you're interested in using the API, please submit a request to info@seospark.io.
Authorization
All API requests should include your API key in an Authorization
HTTP header as follows:
Authorization: Bearer SEOSPARK_API_KEY
If you are subscribed to a version of seospark.io that includes API access, you can find your API key in the account page of your dashboard.
Rate limits
Access to the API is rate limited. Rate limits are calculated on an account basis, meaning all requests made with your API keys are counted towards the limit regardless of client IP. Different endpoints of the API have individual rate limits based on their intended usage.
API responses include the X-Ratelimit-Limit
, X-Ratelimit-Remaining
and X-Ratelimit-Reset
headers which you can use to make sure you are not triggering rate limits by accident.
The respective rate limits for each endpoint are included in the documentation below.
Credits
Your account is charged a certain amount of credits for using different endpoints. Credits are included in your subscription. For larger projects, you can purchase on-demand credits. Please note that an active subscription is needed to access the API.
The respective cost for each endpoint is included in the documentation below.
You can use the GET /account endpoint to retrieve the current number of credits available on your account.
API model
Data formats
The API communicates via HTTP and uses JSON payloads.
number
fields are represented as actual numbers in request / response JSON payloads. Numbers are never encoded as strings ("4.6"
).boolean
fields are represented as actual booleans in request / response JSON payloads. Booleans are never encoded as strings ("true"
,"false"
) or number values (0
,1
).Date
fields are represented as simplified extended ISO 8601 formatted strings, in terms of UTC+0. Example:"2022-02-25T10:30:15.000Z"
.
Request format
GET
requests accept parameters as URL parameters.POST
requests accept parameters in a JSON-encoded request body (Content-Type:application/json
).
Response format
Response payloads have a content type of
application/json; charset=utf-8
. TheContent-Type
HTTP header is set accordingly.Response payloads are in
JSON
format with keys following thesnake_case
naming convention.Response payloads have one of the following two base structures, depending on whether the request failed or succeeded:
Success
// HTTP StatusCode: 200 { "status": "success" /** * The response data for the given endpoint. * If the endpoint does not return data and simply acknowledges * the successful processing of the request, this field is set to `null`. */ "data": {...} | [...] | null }
Error
{ "status": "error" /** * A distinct error code indicating the type of error that occurred. */ "error_code": string /** * If applicable, a human readable, detailed explanation of why the error occurred. */ "message"?: string | string[] }
The HTTP StatusCode is also set to represent the error (see
error_code
details in the endpoint documentation). However, sinceerror_code
values generally describe the issue that occurred more accurately, we advise you to rely on them to handle error responses.
Payload compression
The API requires gzip
compression of response payloads. After profiling the API extensively, we have decided to make adoption of gzip
compression mandatory for all API users. Since we're potentially querying data for thousands of keyword combinations, data for some queries can get quite big (multiple MBs uncompressed). In oder to ensure the service is running smoothly in the future, we need to keep data throughput at a sane level.
To enable gzip
compression, add the Accept-Encoding: gzip
header to your requests and use a gzip
compatible client to run the query. Here is a list of tools and open source HTTP clients that support gzip
by default:
- Postman
- axios, got, node-fetch (node.js)
- urllib3 (python)
If you're using one of these to access the API, you shouldn't have to worry about enabling compression at all.
Common error codes
bad_request :400
The request payload or one of the payload fields was either badly formatted or is missing.If request payload fields were missing or badly formatted, the
message
response field will contain detailed information for each payload field. Additionally,invalid_fields
will contain a list of invalid payload field names causing the error to occur.Example
// HTTP StatusCode: 400 { "status": "error", "error_code": "bad_request", "message": ["country_code must be one of the following values: us, de"], "invalid_fields": ["country_code"] }
unauthorized :401
TheAuthorization
header is missing or the API Key you have provided is invalid.forbidden :403
The api key provided is not entitled to access the requested resource.insufficient_credits :403
Your account credit balance is too low for that operation. Either upgrade your plan or purchase on-demand credits to continue.not_found :404
The requested resource does not exist.gzip_required :406
TheAccept-Encoding
HTTP header is missing thegzip
option. More info.rate_limit_exceeded :429
You have made too many requests to this endpoint and the rate limit is in effect. TheRetry-After
HTTP header indicates how many seconds to wait before making a follow-up request.internal_server_error :500
The request could not be processed for an unknown reason. It is probably best to indicate to your users to retry the request after a few minutes.
Quick start
- If you are subscribed to a version of seospark.io that includes API access, find your API key in the account page of the dashboard.
- Try the request below to fetch information about your account's access status.
curl -X GET \
-H "Authorization: Bearer YOUR_API_KEY" \
--compressed \
https://api.seospark.io/v1/account
- You should see a response describing your account's current access and credit status similar to the example here.
Endpoints
GET /account
This endpoint is used to fetch information about your account's current access and credit status.
Rate limit
This endpoint is rate limited to 100 requests / minute.
Cost
Usage of this endpoint is free of charge.
Request parameters
This endpoint has no parameters.
Response data
{
/**
* The amount of credits on your account.
*
* Subscription credits are replenished on the 1st of every month while you have an active subscription.
*/
"credits": number
},
Example
// HTTP StatusCode: 200
{
"status": "success",
"data": {
"credits": 14500
}
}
POST /keywords/metrics
This endpoint is used to fetch metrics for your list of keywords. You can fetch metrics for up to 500 keywords with one request.
Rate limit
This endpoint is rate limited to 100 requests / minute.
Cost
10 credits
+ 1 credit
for every 5 keywords.
You are only charged for keywords that we find metrics for.
Examples
You send a list of 3 keywords to this endpoint:
10 credits + (roundup(3 / 5) * 1 credit) = 11 credits
You send a list of 300 keywords to this endpoint:
10 credits + (roundup(300 / 5) * 1 credit) = 70 credits
If we only find metrics for 50 of the 300 keywords:
10 credits + (roundup(50 / 5) * 1 credit) = 20 credits
Request parameters
{
/**
* The country for which to fetch metrics.
*/
"country_code": string
/**
* The language for which to fetch metrics.
*/
"language_code": string
/**
* The keywords for which to fetch metrics.
*
* - Max array size: 500.
* - Each keyword must be less than 80 characters.
* - Keywords will be lowercased, duplicates will be removed.
*/
"keywords": string[]
}
Refer to the locations endpoint for a list of valid values for
country_code
andlanguage_code
.
Response data
{
"keywords": {
/**
* The keyword you supplied.
*/
"keyword": string
/**
* Metrics for the keyword.
*
* - May be null if no metrics could be found.
*/
"metrics": null | {
/**
* When the metrics for this keyword where last updated in our database.
*/
"updated_at": Date
/**
* The average search volume over the last 12 months.
*/
"average_search_volume": number | null
/**
* The historical search volume for the last 12 months.
*/
"search_volume_history": {
"period_start": Date
"value": number
}[]
/**
* The relative amount of competition associated with the given keyword.
* The value is based on Google Ads data and can be between 0 and 1 (inclusive).
*/
"competition": number | null
/**
* The average cost per click (in USD) historically paid for the keyword.
*/
"cpc": number | null
/**
* The average number of daily impressions of the advertisement
* if a bid is set to 999.
*/
"daily_impressions_average": number | null
/**
* Keyword difficulty.
*
* - Indicates how hard it is to rank for this keyword organically.
* - 0-100, higher values mean harder to rank.
*/
"keyword_difficulty": number | null
/**
* Types of search results (items) found in SERP.
*
* As the Google SERP evolves, more types might be added.
*
* Example values:
* - organic
* - paid
* - featured_snippet
* - local_pack
* - people_also_ask
* - video
* - related_searches
* - knowledge_graph
*/
"serp_item_types": string[]
/**
* Number of search results for the keyword.
*/
"serp_results_count": number | null
}
}[]
}
Example
// HTTP StatusCode: 200
{
"status": "success",
"data": {
"keywords": [
{
"keyword": "baum",
"metrics": {
"updated_at": "2024-09-28T10:05:33.137Z",
"competition": 0.02,
"cpc": 0.34,
"daily_impressions_average": 14,
"keyword_difficulty": 24,
"serp_results_count": 368000000,
"serp_item_types": ["organic", "people_also_ask", "video", "related_searches", "knowledge_graph"],
"average_search_volume": 110000,
"search_volume_history": [
{
"period_start": "2024-08-01T00:00:00.000Z",
"value": 201000
},
{
"period_start": "2024-07-01T00:00:00.000Z",
"value": 90500
},
{
"period_start": "2024-06-01T00:00:00.000Z",
"value": 90500
},
{
"period_start": "2024-05-01T00:00:00.000Z",
"value": 110000
},
{
"period_start": "2024-04-01T00:00:00.000Z",
"value": 135000
},
{
"period_start": "2024-03-01T00:00:00.000Z",
"value": 90500
},
{
"period_start": "2024-02-01T00:00:00.000Z",
"value": 60500
},
{
"period_start": "2024-01-01T00:00:00.000Z",
"value": 74000
},
{
"period_start": "2023-12-01T00:00:00.000Z",
"value": 60500
},
{
"period_start": "2023-11-01T00:00:00.000Z",
"value": 135000
},
{
"period_start": "2023-10-01T00:00:00.000Z",
"value": 110000
},
{
"period_start": "2023-09-01T00:00:00.000Z",
"value": 110000
}
]
}
}
]
}
}
GET /keywords/locations
This endpoint serves as a lookup for valid values for the country_code
and associated language_code
parameters for keyword endpoints.
Rate limit
This endpoint is rate limited to 100 requests / minute.
Cost
Usage of this endpoint is free of charge.
Request parameters
This endpoint has no parameters.
Response data
[
{
"label": "Algeria",
"country_code": "dz",
"language_codes": [
{
"label": "French",
"language_code": "fr"
},
{
"label": "Arabic",
"language_code": "ar"
}
]
},
{
"label": "Angola",
"country_code": "ao",
"language_codes": [
{
"label": "Portuguese",
"language_code": "pt"
}
]
},
{
"label": "Azerbaijan",
"country_code": "az",
"language_codes": [
{
"label": "Azeri",
"language_code": "az"
}
]
},
{
"label": "Argentina",
"country_code": "ar",
"language_codes": [
{
"label": "Spanish",
"language_code": "es"
}
]
},
{
"label": "Australia",
"country_code": "au",
"language_codes": [
{
"label": "English",
"language_code": "en"
}
]
},
...
]