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. The Content-Type HTTP header is set accordingly.

  • Response payloads are in JSON format with keys following the snake_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, since error_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:

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
    The Authorization 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
    The Accept-Encoding HTTP header is missing the gzip option. More info.

  • rate_limit_exceeded :429
    You have made too many requests to this endpoint and the rate limit is in effect. The Retry-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

  1. 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.
  2. 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
  1. You should see a response describing your account's current access and credit status similar to the example here.

Endpoints

GET /account

https://api.seospark.io/v1/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

https://api.seospark.io/v1/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 and language_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

https://api.seospark.io/v1/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"
            }
        ]
    },
    ...
]
Table of contents