PHP SDK for the APITube News API — access global news articles, headlines, stories, sentiment analysis, and more.
- PHP 8.1+
- A PSR-18 HTTP client (e.g. Guzzle)
- A PSR-17 HTTP factory
composer require apitube/news-apiuse APITube\Client;
$client = new Client(apiKey: 'your-api-key');
// Search news articles
$response = $client->news('everything', [
'title' => 'artificial intelligence',
'language.code' => 'en',
'per_page' => 5,
]);
foreach ($response->articles as $article) {
echo $article->title . "\n";
echo $article->url . "\n\n";
}use APITube\Client;
$client = new Client(
apiKey: 'your-api-key',
baseUrl: 'https://api.apitube.io', // optional, default value
);You can pass any PSR-18 HTTP client:
$client = new Client(
apiKey: 'your-api-key',
httpClient: new \GuzzleHttp\Client(['timeout' => 30]),
);$response = $client->news('everything', [
'title' => 'climate change',
'language.code' => 'en',
'per_page' => 10,
]);
echo "Page: {$response->page}\n";
echo "Has next page: " . ($response->hasNextPages ? 'yes' : 'no') . "\n";
foreach ($response->articles as $article) {
echo "{$article->title}\n";
echo "Source: {$article->source?->domain}\n";
echo "Sentiment: {$article->sentiment?->overall?->polarity}\n";
// English translation of the headline for non-English articles
// (null for English articles — fall back to the original title)
echo "English title: " . ($article->translations?->en?->title ?? $article->title) . "\n\n";
}Instead of assembling filters by hand, describe what you want in the prompt parameter. The API
translates the sentence into the regular filters before searching and returns what it used in
meta.prompt:
$response = $client->news('everything', [
'prompt' => 'Tesla and Elon Musk news in English for the last 10 days',
'per_page' => 5,
]);
// ['person.name' => 'Elon Musk', 'organization.name' => 'Tesla', 'language.code' => 'en', 'published_at.start' => 'NOW-10DAY']
print_r($response->meta['prompt']['applied']);
print_r($response->meta['prompt']['ignored']); // values understood but not used, each with a reason
var_dump($response->meta['prompt']['cached']); // true = served from cache, no extra chargeThe prompt must be 3–500 characters. Filters you pass yourself always win over the prompt.
Translating a prompt costs 2 extra points, but only the first time a given wording is used —
interpretations are cached for 24 hours. See the
prompt reference.
$response = $client->news('everything', [
'title' => 'artificial intelligence',
'per_page' => 5,
], version: 'v1');By default, the SDK uses v1.
$response = $client->news('top-headlines', [
'language.code' => 'en',
'per_page' => 10,
]);
foreach ($response->articles as $article) {
echo "{$article->title} — {$article->source?->domain}\n";
}$response = $client->news('article', [
'id' => 'article-id',
]);
$article = $response->articles[0];
echo $article->title . "\n";
echo $article->body . "\n";$response = $client->news('story', [
'id' => 'story-id',
]);
foreach ($response->articles as $article) {
echo "{$article->title}\n";
}Fetch recently discovered articles before parsing and enrichment:
$response = $client->news('raw', [
'per_page' => 50,
'sort.by' => 'published_at',
'sort.order' => 'desc',
]);
foreach ($response->articles as $article) {
echo "{$article->title}\n";
}Count articles matching the same filters as everything:
$count = $client->count([
'title' => 'artificial intelligence',
'language.code' => 'en',
]);
echo "Matching articles: {$count}\n";Supported types: categories, topics, industries, entities.
$items = $client->suggest('categories', 'spo');
foreach ($items as $item) {
echo "{$item['name']} (id: {$item['id']})\n";
}Each entity exposes a paginated list method and a profile method by ID:
// List
$people = $client->people(['name' => 'Elon', 'per_page' => 5]);
foreach ($people->results as $person) {
echo "{$person['name']} (id: {$person['id']})\n";
}
// Profile with coverage statistics
$profile = $client->person($people->results[0]['id']);
echo "Articles: {$profile['coverage']['article_count']}\n";
// Same shape for the other entities:
$client->companies(['name' => 'Tesla']);
$client->company($id);
$client->sources(['country' => 1]);
$client->source($id);
$client->journalists(['name' => 'Smith']);
$client->journalist($id);$balance = $client->balance();
echo "Plan: {$balance->plan}\n";
echo "Points: {$balance->points}\n";$isAvailable = $client->ping();
echo $isAvailable ? 'API is available' : 'API is unavailable';The SDK throws typed exceptions:
use APITube\Exceptions\ApiException;
use APITube\Exceptions\AuthenticationException;
use APITube\Exceptions\RateLimitException;
try {
$response = $client->news('everything', ['title' => 'php']);
} catch (AuthenticationException $e) {
// Invalid or missing API key (HTTP 401)
echo "Auth error: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
// Rate limit exceeded (HTTP 429)
echo "Rate limited. Retry after: {$e->retryAfter} seconds\n";
} catch (ApiException $e) {
// Other API errors
echo "API error ({$e->getCode()}): {$e->getMessage()}\n";
echo "Request ID: {$e->requestId}\n";
}composer install
vendor/bin/phpunitMIT