Skip to content

Partner API

Partner API integration guide

The Freespoke Partner API lets publishers submit content for indexing and monitor indexing status. This guide is for external developers building a direct integration.

If you would like to integrate the Freespoke Partner API, contact us at [email protected].

Base URL

All endpoints are served over HTTPS:

https://api.partners.freespoke.com

Authentication

All requests require a bearer token sent via the Authorization header:

Authorization: Bearer <token>

There are two ways to obtain a token:

API key

If you have been issued an API key, use it directly as the bearer token. No additional exchange is required.

Terminal window
curl -H "Authorization: Bearer $PARTNERS_API_TOKEN" \
https://api.partners.freespoke.com/v1/content/epoch

OAuth2 client credentials grant

If you have been issued a client ID and client secret, exchange them for a short-lived access token using the OAuth 2.0 Client Credentials Grant. The token endpoint is a standard OpenID Connect token endpoint, so any RFC 6749-compliant OAuth2 library can handle the token exchange and refresh automatically.

Token endpoint:

https://accounts.freespoke.com/realms/freespoke/protocol/openid-connect/token

Token request:

Terminal window
curl -X POST https://accounts.freespoke.com/realms/freespoke/protocol/openid-connect/token \
-d grant_type=client_credentials \
-d client_id=$PARTNER_CLIENT_ID \
-d client_secret=$PARTNER_CLIENT_SECRET

Token response:

{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 300
}

Use the access_token value as the bearer token for subsequent API requests. Tokens expire after a short period (indicated by expires_in in seconds) and should be refreshed when they expire.

Security notes

Treat API keys and client secrets like passwords. Do not embed them in client-side apps or commit them to version control.

Data model

Article (index request)

Required fields:

  • url (string, absolute URL)
  • title (string)
  • content (string)
  • publish_time (RFC3339 timestamp)
  • authors (array with at least one author)

Optional fields:

  • description (string)
  • keywords (array of strings, max 32)
  • image_url (string, absolute URL)
  • content_medium (string enum; use MEDIUM_WEBPAGE)
  • test_mode (boolean; defaults to false)

Notes:

  • Your url must belong to a domain approved for your organization.
  • HTML content is accepted; the API will normalize it for indexing.
  • Use UTC timestamps (for example 2024-01-01T00:00:00Z).
  • When test_mode is true, the request is validated and processed end-to-end, but the resulting content is not persisted and no ingest event is emitted. Use it to verify your integration without publishing real content.

Author (person)

Required fields:

  • name (string)

Optional fields:

  • id (string)
  • url (string)
  • bias (float)
  • twitter_id (string)
  • facebook_id (string)

Indexing flow

Indexing is asynchronous. You submit an article, receive a job ID, then poll job status.

1) Submit content

POST /v1/content

Example:

Terminal window
curl -X POST https://api.partners.freespoke.com/v1/content \
-H "Authorization: Bearer $PARTNERS_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/article",
"title": "Example Title",
"description": "Short summary",
"content": "<p>Hello world</p>",
"authors": [
{ "id": "author-1", "name": "Jane Doe" }
],
"keywords": ["news", "example"],
"publish_time": "2024-01-01T00:00:00Z",
"image_url": "https://example.com/image.jpg",
"content_medium": "MEDIUM_WEBPAGE"
}'

Response:

{
"jobId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"workflowId": "partner-ingest/123456"
}

If the request fails validation or is rejected, the response may include errorMessage.

2) Poll job status

GET /v1/job/{job_id}

Example:

Terminal window
curl -H "Authorization: Bearer $PARTNERS_API_TOKEN" \
https://api.partners.freespoke.com/v1/job/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

Response:

{
"job": {
"jobId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "JOB_STATUS_COMPLETE",
"createTime": "2024-01-01T00:00:00Z",
"updateTime": "2024-01-01T00:00:10Z",
"error": { "code": 0, "message": "", "details": [] },
"metadata": { "@type": "type.googleapis.com/...", "value": "..." },
"result": { "@type": "type.googleapis.com/...", "value": "..." }
}
}

Status values:

  • JOB_STATUS_PENDING
  • JOB_STATUS_COMPLETE
  • JOB_STATUS_FAILED

When a job reaches JOB_STATUS_COMPLETE, its result is a google.protobuf.StringValue whose value is the document’s IndexItem id. Record this id — you can pass it to DELETE /v1/content to target removal precisely.

Removing content

If a piece of content is taken down on your site, request its removal from the Freespoke index.

DELETE /v1/content

Pass the URL as a query parameter. Optionally include the id previously returned by an indexing job — when present it is sanity-checked against the URL.

Terminal window
curl -X DELETE -H "Authorization: Bearer $PARTNERS_API_TOKEN" \
"https://api.partners.freespoke.com/v1/content?url=https%3A%2F%2Fexample.com%2Farticle"

Response:

{ "id": "9b1deb4d3b7d4bad9bdd2b0d7b3dcb6d12345678" }

The id echoed back is the document’s IndexItem id. The request must come from an organization that owns the URL’s host; otherwise 412 Failed Precondition is returned. Removal is best-effort and propagates asynchronously.

Epoch (re-indexing)

The API exposes an epoch to help you detect when re-indexing is required.

GET /v1/content/epoch

Terminal window
curl -H "Authorization: Bearer $PARTNERS_API_TOKEN" \
https://api.partners.freespoke.com/v1/content/epoch

Response:

{ "epoch": 1704067200 }

Recommended usage:

  1. Record the epoch value when you submit content.
  2. Periodically fetch the latest epoch.
  3. If the latest epoch is greater than your recorded value, re-submit the content.

Error handling

Expect standard HTTP status codes:

  • 400 for invalid requests
  • 401/403 for authentication and authorization failures
  • 404 for unknown endpoints or jobs
  • 500 for server errors

Use retries for transient errors (5xx or network timeouts). Avoid retrying 4xx errors without correcting the request.

Not yet implemented

The following endpoints exist in the spec but are not currently supported:

  • POST /v1/status

If you need these, contact Freespoke support.

Client libraries

Support and onboarding

To integrate, you will need:

  • An API key or OAuth2 client credentials (client ID and secret)
  • Your publishing domains allow-listed

If you are ready to start or need help, contact support at [email protected].