- Chủ yếu
- Tài liệu API
API Documentation
API endpoint: https://2index.ninja/api/v1/
To make an API request, pass a Bearer access token in the Authorization header.
curl https://2index.ninja/api/v1/account -H "Authorization: Bearer API_TOKEN"
You can obtain the access token in the corresponding section of your account.
Every API response contains a success field that indicates whether the request succeeded.
The errors field contains error messages.
In some cases, if a 403 error is returned, you may need to set a user-agent header, for example:
curl https://2index.ninja/api/v1/account -H "Authorization: Bearer API_TOKEN" -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
Requests may also be throttled by your hosting provider — in that case we recommend using a proxy.
Account methods
Register a user
Send a POST request to register:
POST https://2index.ninja/api/v1/register
Request parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | User email in [email protected] format. |
|
| source | string | no | Registration source, defaults to api. May be, for example, wordpress_plugin. |
Example responses:
Successful registration:
{
"success": true,
"message": "User registered successfully!",
"account": {
"email": "[email protected]",
"tariff": "White Ninja",
"available_projects": 1,
"balance": 100.0,
"available_links": 100,
"available_indexation_check_links": 500,
"link_sending_speed": 100,
"available_link_sending_speed": 100,
"tariff_available": true,
"tariff_expiring_date": "2025-01-16T14:26:11.700740Z",
"email_verified": false,
"link_cost": "$0.00056",
"api_key": "API_KEY"
}
}
Possible errors:
Validation error:
{
"errors": {
"email": ["The email field is required."]
}
}
Email already registered:
{
"message": "The email has already been taken."
}
After a successful registration, an activation email will be sent to the specified address.
Get account data
Send a GET request to account:
GET https://2index.ninja/api/v1/account
The response is a JSON object:
{
"success": true,
"account": {
"email": "[email protected]",
"tariff": "White Ninja",
"balance": 100.0,
"available_projects": 1,
"available_links": 100,
"available_indexation_check_links": 500,
"link_sending_speed": 100,
"available_link_sending_speed": 45,
"tariff_available": true,
"tariff_expiring_date": "2025-01-16T14:26:11.000000Z",
"email_verified": false,
"link_cost": "$0.00056"
}
}
Where:
| Field | Description |
|---|---|
link_sending_speed |
Tariff link-sending speed limit (total per account per day). |
available_link_sending_speed |
Remaining speed — link_sending_speed minus the sum of indexing_speed across all projects. That is, how much speed is still available to assign to new or existing projects without exceeding the limit. |
Project methods
Get the list of projects
Send a GET request to project:
GET https://2index.ninja/api/v1/project
Pagination (optional)
By default (no parameters) all non-archived projects of the user are returned — this preserves backward compatibility.
If the page parameter is passed, the response switches to paginated mode and additionally contains a pagination block.
| Parameter | Type | Required | Description |
|---|---|---|---|
page |
integer | no | Page number. If not passed — all projects are returned. |
per_page |
integer | no | Page size. Accepted only together with page. Defaults to 20, allowed range 1…100 (values outside the range are clamped). |
Example paginated request:
GET https://2index.ninja/api/v1/project?page=2&per_page=10
The response is a JSON object:
{
"success": true,
"projects": [
{
"id": 1,
"name": "Project name",
"type": "indexing",
"website": "https://domain.com/",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_type": "internal",
"google_account_access_granted": 0,
"links_total": 500,
"links_sending_speed": 400,
"links_sent_google": 100,
"links_sent_yandex": 40,
"links_sent_bing": 100,
"in_queue": 360,
"sent_links": 100,
"indexed": 30,
"not_indexed": 0,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_sent_url": "DOWNLOAD_SENT_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL"
},
{
"id": "2",
"name": "Project 2 name",
"type": "indexing_check",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_total": 200,
"links_checking_speed": 100,
"in_queue": 100,
"checked": 100,
"indexed": 70,
"not_indexed": 30,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL",
"download_all_url": "DOWNLOAD_ALL_URL",
"download_checked_url": "DOWNLOAD_CHECKED_URL",
}
...
]
}
In paginated mode (when page is passed) the response contains an additional pagination block:
{
"success": true,
"projects": [ ... ],
"pagination": {
"current_page": 2,
"last_page": 5,
"per_page": 10,
"total": 47
}
}
Get project data
Send a GET request to project/{project_id}:
GET https://2index.ninja/api/v1/project/1
The response is a JSON object:
- For an indexing project:
{
"success": true,
"project": {
"id": 1,
"name": "Project name",
"type": "indexing",
"website": "https://domain.com/",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_type": "internal",
"google_account_access_granted": 0,
"links_total": 500,
"links_sending_speed": 400,
"links_sent_google": 100,
"links_sent_yandex": 40,
"links_sent_bing": 100,
"in_queue": 360,
"sent_links": 100,
"indexed": 30,
"not_indexed": 0,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_sent_url": "DOWNLOAD_SENT_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL"
}
}
- For an indexing-check project:
{
"success": true,
"project": {
"id": "2",
"name": "Project 2 name",
"type": "indexing_check",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_total": 200,
"links_checking_speed": 100,
"in_queue": 100,
"checked": 100,
"indexed": 70,
"not_indexed": 30,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL",
"download_all_url": "DOWNLOAD_ALL_URL",
"download_checked_url": "DOWNLOAD_CHECKED_URL"
}
}
Create a project
Send a POST request to project:
POST https://2index.ninja/api/v1/project
Request parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Project name. |
| website | string | yes* | Website URL in https://site.domain/ format. *Required when project type is indexing. |
| for_external_links | boolean | no | Project for external links. If not specified, will be for internal links only. |
| indexing_speed | integer | no** | Project indexing speed. If not specified, the entire available account speed is used. Used for projects with type indexing. For projects with type indexing_check, checking_speed is used instead. |
| checking_speed | integer | no** | Project link-checking speed. If not specified, the entire available account speed is used. Used for projects with type indexing_check. For projects with type indexing, indexing_speed is used instead. |
| type | string | no | Project type. Possible values: indexing — link indexing, indexing_check — link indexing check. If not specified, an indexing link-indexing project is created. |
** For any project type you can use either of the indexing_speed and checking_speed parameters — they are aliases of each other; if both are passed, indexing_speed is used.
The response is a JSON object:
{
"success": true,
"message": "The project has been successfully created"
}
Example of creating a link-indexing project:
POST https://2index.ninja/api/v1/project
name: Project 1
website: https://website.com
for_external_links: 1
indexing_speed: 100
Example of creating an indexing-check project:
POST https://2index.ninja/api/v1/project
name: Project 2
checking_speed: 100
Create (or get) a project for the WordPress plugin
Finds a project linked to a WordPress site. If no such project exists, creates a new one.
Send a POST request to account/get_wordpress_project:
POST https://2index.ninja/api/v1/account/get_wordpress_project
Request parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| website | string | yes | Website URL in https://site.domain/ format. |
As a result of the request, either an existing user project matching the website URL is found, or a new project is created for that site. A new project will be configured for internal-link indexing with the maximum sending speed.
For an existing project the response is a JSON object:
{
"success": true,
"message": "Found existing project domain.com",
"project": {
"id": 1,
"name": "Project name",
"website": "https://domain.com/",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_type": "internal",
"google_account_access_granted": 0,
"links_total": 500,
"links_sending_speed": 400,
"links_sent_google": 100,
"links_sent_yandex": 40,
"links_sent_bing": 100,
"in_queue": 360,
"sent_links": 100,
"indexed": 30,
"not_indexed": 0,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_sent_url": "DOWNLOAD_SENT_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL"
}
}
For a newly created project the response is a JSON object:
{
"success": true,
"message": "The project has been successfully created",
"project": {
"id": 1,
"name": "Project name",
"website": "https://domain.com/",
"status": "in progress",
"created_at": "2024-03-01 14:34:56",
"links_type": "internal",
"google_account_access_granted": 0,
"links_total": 500,
"links_sending_speed": 400,
"links_sent_google": 100,
"links_sent_yandex": 40,
"links_sent_bing": 100,
"in_queue": 360,
"sent_links": 100,
"indexed": 30,
"not_indexed": 0,
"download_queue_url": "DOWNLOAD_QUEUE_URL",
"download_sent_url": "DOWNLOAD_SENT_URL",
"download_indexed_url": "DOWNLOAD_INDEXED_URL",
"download_unindexed_url": "DOWNLOAD_UNINDEXED_URL"
}
}
Clear the indexing queue
Send a POST request to project/{project_id}/clear_queue:
POST https://2index.ninja/api/v1/project/1/clear_queue
The response is a JSON object:
{
"success": true,
"message": "The indexing queue has been cleared successfully. X links have been removed"
}
Or the corresponding error message will be returned:
{
"success": false,
"errors": ["Project not found"]
}
Reset speed of completed projects
A bulk operation — sets indexing_speed = 0 for all completed projects of the user. Useful when, after bulk-completing projects, you want to free up the occupied speed without archiving them.
Send a POST request to project/reset_speed_completed:
POST https://2index.ninja/api/v1/project/reset_speed_completed
With no parameters it affects all the user's completed projects with indexing_speed > 0. All filter parameters are optional; dates are passed in Y-m-d format.
| Field | Type | Required | Description |
|---|---|---|---|
created_at_from |
string | no | Project creation date, lower bound (Y-m-d). |
created_at_to |
string | no | Project creation date, upper bound (Y-m-d). |
completed_at_from |
string | no | Date of transition to completed, lower bound. |
completed_at_to |
string | no | Date of transition to completed, upper bound. |
The response is a JSON object:
{
"success": true,
"message": "Speed reset for 5 projects",
"affected_projects": 5
}
For an invalid date format:
{
"success": false,
"errors": {
"completed_at_from": ["The completed at from field must match the format Y-m-d."]
}
}
Archive completed projects
A bulk operation — moves all completed projects of the user to archived, zeroing their speed. Useful for batch-closing completed projects without per-item requests.
Send a POST request to project/archive_completed:
POST https://2index.ninja/api/v1/project/archive_completed
Accepts the same optional date-range filters as reset_speed_completed:
| Field | Type | Required | Description |
|---|---|---|---|
created_at_from |
string | no | Project creation date, lower bound (Y-m-d). |
created_at_to |
string | no | Project creation date, upper bound (Y-m-d). |
completed_at_from |
string | no | Date of transition to completed, lower bound. |
completed_at_to |
string | no | Date of transition to completed, upper bound. |
The response is a JSON object:
{
"success": true,
"message": "5 projects have been archived",
"archived_count": 5
}
Link methods
Add links
Send a POST request to link/add:
POST https://2index.ninja/api/v1/link/add
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_id | yes | Project ID. |
| links | yes | List of links. Can be passed either as an array of links or as text (one link per line). |
| no, if yandex or bing is specified | Send links to Google. | |
| yandex | no, if google or bing is specified | Send links to Yandex. |
| bing | no, if google or yandex is specified | Send links to Bing. |
| google_access_granted | no | Google account access granted. |
The response is a JSON object:
{
"success": true,
"message": "Links have been successfully added to the project"
}
If the list contains invalid links, no links will be added and the corresponding error message will be returned:
{
"success": false,
"errors": ["You sent invalid links"],
"invalid_links": ["http://wrong.link"]
}
For indexing-check projects, links are added exactly the same way as for indexing — google_access_granted is not required and will be ignored. Search engines must be specified, but currently only Google is supported for indexing checks.
Add links by project name
Send a POST request to link/add_simple. If no project with the specified name exists, it will be created automatically with the maximum sending speed.
POST https://2index.ninja/api/v1/link/add_simple
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_name | no | Project name. If not specified, a project named "default" will be created. |
| links | yes | List of links. Can be passed as an array or as text (one link per line). |
| no, if yandex or bing is specified | Send links to Google. | |
| yandex | no, if google or bing is specified | Send links to Yandex. |
| bing | no, if google or yandex is specified | Send links to Bing. |
| google_access_granted | no | Google account access granted. |
For indexing-check projects, links are added exactly the same way as for indexing — google_access_granted is not required and will be ignored. Search engines must be specified, but currently only Google is supported for indexing checks.
Request example:
{
"project_name": "My Website",
"links": ["https://example.com/page1", "https://example.com/page2"],
"google": true,
"yandex": false,
"bing": true,
"google_access_granted": false
}
Successful response:
{
"success": true,
"message": "Links have been successfully added to the project",
"project_name": "My Website",
"project_id": 12345
}
Possible errors:
- If the list contains invalid links:
{
"success": false,
"errors": ["You sent invalid links"],
"invalid_links": ["http://wrong.link"]
}
- If project creation failed:
{
"success": false,
"errors": ["Failed to create the project"]
}
Check link status
Send a POST request to /api/v1/link/status:
POST https://2index.ninja/api/v1/link/status
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_id | yes | Project ID |
| link | yes | Link to check |
- On success the response is a JSON object:
{
"success": true,
"link": {
"id": 34368960,
"url": "https://2index.ninja/",
"google": "Sent",
"yandex": "Sent",
"bing": "Sent",
"is_external": 1,
"google_sent": "2025-08-24 20:10:02",
"yandex_sent": "2025-08-24 20:45:02",
"bing_sent": "2025-08-24 20:05:05",
"google_sent_attempts": 1,
"yandex_sent_attempts": 1,
"bing_sent_attempts": 1,
"google_indexed": 1,
"google_indexing_check_date": "2025-08-29"
}
}
Where:
| Field | Description |
|---|---|
id |
Link ID |
url |
Link |
google |
* Send status in Google |
yandex |
* Send status in Yandex |
bing |
* Send status in Bing |
is_external |
External link |
google_sent |
Date sent to Google |
yandex_sent |
Date sent to Yandex |
bing_sent |
Date sent to Bing |
google_sent_attempts |
Number of send attempts to Google |
yandex_sent_attempts |
Number of send attempts to Yandex |
bing_sent_attempts |
Number of send attempts to Bing |
google_indexed |
Indexed in Google |
google_indexing_check_date |
Date of indexing check in Google |
* Possible statuses:
| Status | Meaning |
|---|---|
New |
New |
Sent |
Sent |
In the queue |
In the sending queue |
In the process |
In the process of sending |
Error sending |
An error occurred while sending |
Don\'t index |
Do not index |
Sent to reindexing |
Sent for reindexing |
- If an error occurs, a JSON object with the error message is returned. Examples:
{
"success": false,
"errors":{
"link": [
"The link field is required."
]
}
}
{
"success": false,
"errors":[
"Project not found"
]
}
{
"success": false,
"errors":[
"URL not found"
]
}
You can also fetch the link status by link ID
Send a GET request to /api/v1/link/status/ID:
GET https://2index.ninja/api/v1/link/status/ID
The response is the same as in the previous variant.
Resend links for reindexing
Sends not-indexed links for reindexing. Accepts a max_attempts parameter that limits the maximum number of resend attempts (between 1 and 10). Accepts an array of links to resend for indexing; if no links are passed, all not-indexed links from the project are picked up. The method then checks the number of send attempts and tries to add the links to the project, taking account limits into account. If you pass links that were never sent before, they will also be added to the queue.
Send a POST request to /api/v1/link/resent_notindexed_links/{project_id}:
POST https://2index.ninja/api/v1/link/resent_notindexed_links/{project_id}
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_id | yes | Project ID |
| max_attempts | yes (from 1 to 10) | Indexing send attempts limit |
| links | no — if omitted, ALL not-indexed links of the project will be used | Links to resend |
- On success the response is a JSON object:
{
"success": true,
"message": "Links have been successfully added to the project. Invalid links was ignored.",
"invalid_links": [],
"project_id": 1,
"ignored_links": [
{
"url": "https://domain.com/url1",
"attempts": 2
},
{
"url": "https://domain.com/url2",
"attempts": 2
}
]
}
Where:
| Field | Description |
|---|---|
success |
Request success status |
message |
Success message |
invalid_links |
List of invalid links that were not added |
project_id |
Project ID |
ignored_links |
Ignored links — links that have already been sent max_attempts times or more |
On error, a JSON object with error messages is returned. For example:
{
"success": false,
"errors": {
"max_attempts": [
"The max attempts field must not be greater than 10."
],
"links": [
"The links field must be an array."
]
}
}
Or:
{
"success": false,
"errors": [
"You do not have enough tokens to add any links. You need at least 1 tokens."
],
"ignored_links": []
}
Delete links from a project
Deletes a link or an array of links from the project. If a link is still in the sending queue, the tokens spent on it are refunded to the balance. Already-sent links are deleted without a token refund.
Send a POST request to /api/v1/link/delete/{project_id}:
POST https://2index.ninja/api/v1/link/delete/{project_id}
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_id | yes | Project ID (passed in the URL). |
| link | yes | Link to delete. Can be a single string or an array of links. |
- On success the response is a JSON object:
{
"success": true,
"deleted": 3,
"message": "The URLs have been deleted."
}
If the project contained several identical URLs (for example, the link was added multiple times), the response will additionally include a duplicates field:
{
"success": true,
"deleted": 5,
"duplicates": 2,
"message": "The URLs have been deleted, including duplicate (re-submitted) entries."
}
If none of the submitted links were found in the project:
{
"success": true,
"deleted": 0,
"message": "No URLs were found to delete."
}
Possible errors:
{
"success": false,
"errors": ["You cannot work with links. The project is deeply archived"]
}
{
"success": false,
"errors": "Project not found"
}
Working with link sources
Link sources are available for any project type and are processed identically. For indexing-check projects only Google can be selected.
Adding a sitemap
Send a POST request to /api/v1/sitemap/add:
POST https://2index.ninja/api/v1/sitemap/add
Request parameters:
| Field | Required | Description |
|---|---|---|
| project_id | yes | Project ID |
| sitemap | yes | Sitemap URL |
| no, if yandex or bing is specified | Send links to Google | |
| yandex | no, if google or bing is specified | Send links to Yandex |
| bing | no, if google or yandex is specified | Send links to Bing |
| google_access_granted | no | Google account access granted |
| watch | no | Watch for sitemap changes |
Possible errors:
| Error |
|---|
| Data validation error. One of the required fields is missing or has an invalid value. |
| Tariff unavailable. The user's tariff plan has expired. |
| Project not found. The user does not own the specified project or the project does not exist. |
| Internal server error. |
Example responses:
Sitemap added successfully:
{
"success": true,
"message": "The sitemap has been successfully added; we will download it as soon as possible and send a notification by email once finished."
}
Validation error:
{
"errors": ["sitemap":["The sitemap field is required."]]
}
Project not found:
{
"errors": ["Project not found"]
}
Updating sitemap watch status
Send a POST request to /api/v1/sitemap/update_watch:
POST https://2index.ninja/api/v1/sitemap/update_watch
Request parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| project_id | integer | yes | Project ID |
| sitemap_id | integer | yes | Sitemap ID |
| watch | boolean | yes | Whether to watch for sitemap changes |
Possible errors:
| Error |
|---|
| Data validation error. One of the required fields is missing or has an invalid value. |
| Project or link source not found. The user does not own the specified project or the project/source does not exist. |
| Internal server error. |
Example responses:
Watch status updated successfully:
{
"success": true
}
Link source not found:
{
"errors": ["Link source not found"]
}
Deleting a link source
Send a POST request to /api/v1/sitemap/delete:
POST https://2index.ninja/api/v1/sitemap/delete
Request parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| project_id | integer | yes | Project ID |
| sitemap_id | integer | yes | Sitemap ID |
Possible errors:
| Error |
|---|
| Data validation error. One of the required fields is missing or has an invalid value. |
| Project or link source not found. The user does not own the specified project or the project/source does not exist. |
| Internal server error. |
Example responses:
Link source deleted successfully:
{
"success": true,
"message": "The link source has been successfully deleted"
}
Project not found:
{
"errors": ["Project not found"]
}
List of link sources
To get the list of added link sources, send a POST request to https://2index.ninja/api/v1/link_sources.
Pass project_id in the request.
The result is a data set like this:
[
{
"id": 1247,
"project_id": 3540,
"name": "urls.txt",
"type": "text file",
"created_at": "2025-01-17T15:51:43.000000Z",
"processing_date": "2025-01-17T15:51:48.000000Z",
"has_error": false,
"error_message": "",
"status": "success",
"is_pending": false,
"is_success": true,
"total_links": 29585,
"added_links": 29582,
"invalid_links": 3,
"watch": 0,
"google_access_granted": 0,
"is_external_links": 1,
"search_engines": {
"google": "1"
}
},
{
"id": 1246,
"project_id": 3540,
"name": "urls.txt",
"type": "text file",
"created_at": "2025-01-17T15:50:59.000000Z",
"processing_date": "2025-01-17T15:51:02.000000Z",
"has_error": false,
"error_message": "",
"status": "success",
"is_pending": false,
"is_success": true,
"total_links": 29585,
"added_links": 10440,
"invalid_links": 1,
"watch": 0,
"google_access_granted": 0,
"is_external_links": 1,
"search_engines": {
"google": "1"
}
},
{
"id": 1245,
"project_id": 3540,
"name": "urls.txt",
"type": "text file",
"created_at": "2025-01-17T15:46:17.000000Z",
"processing_date": null,
"has_error": false,
"error_message": null,
"status": "pending",
"is_pending": true,
"is_success": false,
"total_links": 0,
"added_links": 0,
"invalid_links": 0,
"watch": 0,
"google_access_granted": 0,
"is_external_links": 1,
"search_engines": {
"google": "1"
}
},
{
"id": 1244,
"project_id": 3540,
"name": "urls.txt",
"type": "text file",
"created_at": "2025-01-17T14:52:07.000000Z",
"processing_date": "2025-01-17T14:53:06.000000Z",
"has_error": true,
"error_message": "Unable to encode attribute [invalid_links_list] for model [App\\Models\\LinkSource\\LinkSource] to JSON: Malformed UTF-8 characters, possibly incorrectly encoded.",
"status": "error",
"is_pending": false,
"is_success": false,
"total_links": 29585,
"added_links": 0,
"invalid_links": 3,
"watch": 0,
"google_access_granted": 0,
"is_external_links": 1,
"search_engines": {
"google": "1"
}
}
]
Where
id — link source ID
project_id — project ID
name — name of the attached file or sitemap URL
type — link source type (text file or sitemap) — can be: sitemap, text file
created_at — creation date
processing_date — processing date
has_error — whether a processing error occurred
error_message — error message
status — status — can be: pending (waiting to be processed), error (processing error), success
is_pending — currently being processed
is_success — successful processing
total_links — total links found
added_links — links added
invalid_links — invalid links
watch — sitemap watch status
google_access_granted — whether Google account access has been granted
is_external_links — external links
search_engines — connected search engines
PHP implementation example
<?php
/**
* A class for working with the 2Index.Ninja service API.
*/
class API_2IndexNinja
{
/**
* API endpoint URL
* @var string
*/
private $url = 'https://2index.ninja/api/v1/';
/**
* API access token
* @var string
*/
private $access_token;
/**
* Class constructor.
*
* @param string $access_token API authorization access token.
*/
public function __construct($access_token)
{
$this->access_token = $access_token;
}
/*
|--------------------------------------------------------------------------
| Account methods
|--------------------------------------------------------------------------
*/
/**
* Gets information about the current account.
*
* @return array|null Decoded API response with account data.
*/
public function account()
{
return $this->make_request('account');
}
/**
* Registers a new user.
*
* @param string $email New user email.
* @param string $source Registration source.
* @return array|null Decoded API response.
*/
public function register_user($email, $source)
{
return $this->make_request('register', [
'email' => $email,
'source' => $source,
]);
}
/*
|--------------------------------------------------------------------------
| Project methods
|--------------------------------------------------------------------------
*/
/**
* Gets the list of the user's projects.
*
* Without parameters returns all non-archived projects. If $page is passed,
* pagination is enabled and the response includes a 'pagination' block.
*
* @param int|null $page Page number (when set — pagination is enabled).
* @param int|null $per_page Page size (1..100, defaults to 20). Only used together with $page.
* @return array|null Decoded API response with the list of projects.
*/
public function projects_list($page = null, $per_page = null)
{
$url_data = [];
if ($page) {
$url_data['page'] = $page;
if ($per_page) {
$url_data['per_page'] = $per_page;
}
}
$url_data = $url_data ? ('?' . http_build_query($url_data)) : '';
return $this->make_request('project' . $url_data);
}
/**
* Gets data of a specific project by its ID.
*
* @param int $id Project ID.
* @return array|null Decoded API response with project data.
*/
public function project($id)
{
return $this->make_request('project/' . $id);
}
/**
* Adds a new project for link indexing.
*
* @param string $name Project name.
* @param string $website Project website.
* @param bool $for_external_links Whether it is for external links (0 or 1).
* @param int|null $indexing_speed Indexing speed.
* @return array|null Decoded API response with the created project data.
*/
public function add_project($name, $website, $for_external_links = 0, $indexing_speed = null)
{
return $this->make_request('project', [
'name' => $name,
'website' => $website,
'for_external_links' => $for_external_links,
'indexing_speed' => $indexing_speed,
'type' => 'indexing',
]);
}
/**
* Adds a new project for indexing check.
*
* @param string $name Project name.
* @param int|null $checking_speed Checking speed.
* @return array|null Decoded API response with the created project data.
*/
public function add_indexing_check_project($name, $checking_speed = null)
{
return $this->make_request('project', [
'name' => $name,
'checking_speed' => $checking_speed,
'type' => 'indexing_check',
]);
}
/**
* Finds a project linked to a WordPress site.
* If no such project exists, creates a new one.
*
* @param string $website Website URL to look up the project by.
* @return array|null Decoded API response with project data.
*/
public function get_wordpress_project($website)
{
return $this->make_request('account/get_wordpress_project', ['website' => $website]);
}
/**
* Clears the link queue for a project.
*
* @param int $project_id Project ID.
* @return array|null Decoded API response.
*/
public function clear_queue($project_id)
{
return $this->make_request('project/' . $project_id . '/clear_queue', true);
}
/**
* Resets the indexing speed of all the user's completed projects.
* All filter parameters are optional; dates are in Y-m-d format.
*
* @param string|null $created_at_from
* @param string|null $created_at_to
* @param string|null $completed_at_from
* @param string|null $completed_at_to
* @return array|null Decoded response: success, message, affected_projects.
*/
public function reset_speed_completed(
$created_at_from = null,
$created_at_to = null,
$completed_at_from = null,
$completed_at_to = null
) {
$payload = array_filter([
'created_at_from' => $created_at_from,
'created_at_to' => $created_at_to,
'completed_at_from' => $completed_at_from,
'completed_at_to' => $completed_at_to,
]);
// Without parameters: an empty array is treated by make_request() as
// "no POST data" and a GET is sent instead, which gets matched by the
// project/{id} route. So when filters are empty we force POST via true.
return $this->make_request('project/reset_speed_completed', $payload ?: true);
}
/**
* Archives all the user's completed projects.
* Accepts the same optional date-range filters as reset_speed_completed.
*
* @param string|null $created_at_from
* @param string|null $created_at_to
* @param string|null $completed_at_from
* @param string|null $completed_at_to
* @return array|null Decoded response: success, message, archived_count.
*/
public function archive_completed(
$created_at_from = null,
$created_at_to = null,
$completed_at_from = null,
$completed_at_to = null
) {
$payload = array_filter([
'created_at_from' => $created_at_from,
'created_at_to' => $created_at_to,
'completed_at_from' => $completed_at_from,
'completed_at_to' => $completed_at_to,
]);
return $this->make_request('project/archive_completed', $payload ?: true);
}
/*
|--------------------------------------------------------------------------
| Link methods
|--------------------------------------------------------------------------
*/
/**
* Adds links to the specified project.
*
* @param int $project_id Project ID.
* @param array|string $links Array of links or a single link as a string.
* @param bool $google Whether to send to Google.
* @param bool $yandex Whether to send to Yandex.
* @param bool $bing Whether to send to Bing.
* @param bool $google_access_granted Flag confirming Google access.
* @return array|null Decoded API response.
*/
public function add_links($project_id, $links, $google, $yandex, $bing, $google_access_granted = false)
{
return $this->make_request('link/add', [
'project_id' => $project_id,
'links' => $links,
'google' => $google,
'yandex' => $yandex,
'bing' => $bing,
'google_access_granted' => $google_access_granted,
]);
}
/**
* Adds links to a project by name. If the project doesn't exist, it will be created.
*
* @param array|string $links Array of links or a single link as a string.
* @param bool $google Whether to send to Google.
* @param bool $yandex Whether to send to Yandex.
* @param bool $bing Whether to send to Bing.
* @param string $project_name Project name (defaults to 'default').
* @param bool $google_access_granted Flag confirming Google access.
* @return array|null Decoded API response.
*/
public function add_links_simple($links, $google, $yandex, $bing, $project_name = 'default', $google_access_granted = false)
{
return $this->make_request('link/add_simple', [
'project_name' => $project_name,
'links' => $links,
'google' => $google,
'yandex' => $yandex,
'bing' => $bing,
'google_access_granted' => $google_access_granted,
]);
}
/**
* Gets the link sources for a project.
*
* @param int $project_id Project ID.
* @return array|null Decoded API response.
*/
public function link_sources($project_id)
{
return $this->make_request('link_sources', [
'project_id' => $project_id
]);
}
/**
* Gets the status of the specified link.
* If the same link was sent several times, returns the status of the latest one.
*
* @param int $project_id Project ID
* @param string $link Link to check
* @return array Link status
*/
public function checkLink($project_id, $link)
{
return $this->make_request('link/status', [
'project_id' => $project_id,
'link' => $link,
]);
}
/**
* Gets the status of the specified link.
*
* @param int $link_id Link ID
* @return array Link status
*/
public function checkLinkById($link_id)
{
return $this->make_request('link/status/' . $link_id);
}
/**
* Resends a project's not-indexed links for indexing.
* If $links is not passed, all not-indexed links of the project are used,
* those whose attempt count is less than $max_attempts.
*
* @param int $project_id Project ID.
* @param int $max_attempts Maximum send attempts (1..10).
* @param array|null $links Specific list of links to resend.
* @return array|null
*/
public function resent_notindexed_links($project_id, $max_attempts, $links = null)
{
return $this->make_request('link/resent_notindexed_links/' . $project_id, [
'max_attempts' => $max_attempts,
'links' => $links,
]);
}
/**
* Deletes a link or an array of links from a project.
*
* @param int $project_id Project ID.
* @param string|array $link Link to delete (or an array).
* @return array|null
*/
public function deleteUrls($project_id, $link)
{
return $this->make_request('link/delete/' . $project_id, [
'link' => $link,
]);
}
/*
|--------------------------------------------------------------------------
| Link source methods
|--------------------------------------------------------------------------
*/
/**
* Adds a Sitemap to a project.
*
* @param int $project_id Project ID.
* @param string $sitemap_url Sitemap file URL.
* @param bool $google Whether to send to Google.
* @param bool $yandex Whether to send to Yandex.
* @param bool $bing Whether to send to Bing.
* @param bool $google_access_granted Flag confirming Google access.
* @param bool $watch Whether to enable watching for Sitemap changes.
* @return array|null Decoded API response.
*/
public function add_sitemap($project_id, $sitemap_url, $google, $yandex, $bing, $google_access_granted = false, $watch = false)
{
return $this->make_request('sitemap/add', [
'project_id' => $project_id,
'sitemap' => $sitemap_url,
'google' => $google,
'yandex' => $yandex,
'bing' => $bing,
'google_access_granted' => $google_access_granted,
'watch' => $watch,
]);
}
/**
* Enables or disables watching for changes for a Sitemap.
*
* @param int $project_id Project ID.
* @param int $sitemap_id Sitemap file ID.
* @param bool $watch New watch status (true — enable, false — disable).
* @return array|null Decoded API response.
*/
public function update_sitemap_watch($project_id, $sitemap_id, $watch)
{
return $this->make_request('sitemap/update_watch', [
'project_id' => $project_id,
'sitemap_id' => $sitemap_id,
'watch' => $watch,
]);
}
/**
* Removes a Sitemap from a project.
*
* @param int $project_id Project ID.
* @param int $sitemap_id Sitemap file ID to remove.
* @return array|null Decoded API response.
*/
public function sitemap_delete($project_id, $sitemap_id)
{
return $this->make_request('sitemap/delete', [
'project_id' => $project_id,
'sitemap_id' => $sitemap_id,
]);
}
/**
* Performs an API request.
*
* @param string $endpoint API endpoint to call.
* @param array|true $post_data POST data. If true, an empty POST is sent.
* @return array|null Decoded JSON API response or null on failure.
*/
private function make_request($endpoint, $post_data = [])
{
$ch = curl_init($this->url . $endpoint);
if ($post_data === true) {
curl_setopt($ch, CURLOPT_POST, 1);
} elseif ($post_data) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
}
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer " . $this->access_token]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
// Sets the user-agent — required if you start getting 403 errors.
// curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36');
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, 1);
}
}