> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.taktoria.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.taktoria.com/_mcp/server.

# Import Objectives

POST https://api.taktoria.com/api/v1/objectives/import
Content-Type: application/json

Bulk entry: a period's objectives and their key results from pasted
text, as the dashboard's Bulk entry page makes them. Lines it cannot
read are skipped and listed in `problems`. A person or team the
workspace does not have, or an objective naming more than one owner
(an objective has one: a person or a team), stops the whole import
with a 422, and `details.problem` names the line, its `reason`
(`notMember`, `notTeam` or `oneOwner`) and the addresses or
`#team-slug`s at fault in `emails`. Needs `objectives:write` and
`keyResults:write`. Anybody with a seat may but a Viewer of OKR Hub,
as with `createObjective`; the activity feed says the objectives were
imported, for a key under the name of whoever made the key.

Expensive: besides the caller's own limits, it counts against
`okr-bulk` (see "Rate limits").

Reference: https://docs.taktoria.com/api-reference/okr/import-objectives

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://api.taktoria.com/api/v1` (Production, default)
- `http://localhost:3000/api/v1` (Local)

## Request

### Body (application/json)

This endpoint expects an ImportObjectivesRequest.

- `text` (string, required) — The pasted text, at most 100,000 characters.
- `year` (integer, required) — The fiscal year, 2000 to 2100.
- `period` (enum, optional) — Defaults to QUARTERLY.
  - Allowed values: `QUARTERLY`, `ANNUAL`
- `quarter` (integer, optional) — 1 to 4; needed for a QUARTERLY period.
- `visibility` (enum, optional) — Public objectives are browsable by everyone in the workspace. Private ones are visible to their owner, the members of the owning team, and whoever created them, whoever they belong to. The owners of its key results see it too.
  - Allowed values: `PUBLIC`, `PRIVATE`
- `draft` (boolean, optional) — Every objective a draft. Defaults to false; `[draft]` on a line marks just that one.
- `teamId` (string, optional) — The team that owns the lines naming nobody. Never with `ownerUserId`.
- `ownerUserId` (string, optional) — The person who owns the lines naming nobody. Never with `teamId`.

## Response

### 200

- `created` (integer, required) — How many objectives were made.
- `objectiveIds` (list of string, required) — Their ids, in the order they were pasted.
- `skipped` (integer, required) — How many lines could not be read.
- `problems` (list of ImportProblem, required) — Those lines, and why.

## Errors

### 403 Forbidden Error

Refused, and `error.code` says why. On an app's write endpoints, a signed-in session is refused `viewer_only` when the person is a Viewer of the app (they read it, and change nothing in it), and `seat_required` without a seat on it; a key is never either. Beyond those: `admin_required` when the change is an admin's (an app admin's for an app's admin powers, a workspace admin's for the workspace's settings), `forbidden` when the person may not change this one thing, `read_only_session` for a change only a key makes, `person_required` for what only a signed-in person does through their own account elsewhere (exporting a LaunchCal artifact to their docs tool), which a key cannot, `insufficient_scope` for a key without the scope, and `google_sign_in_required` for a session the workspace's Google rule turns away. Nothing was done.

- `error` (ErrorDetail, required)

### 402 Subscription Required Error

The organization has no subscription for the app that lets it in: active, trialing or past due. One that is unpaid (Stripe stopped retrying a failed payment), paused, incomplete or cancelled answers this too, and the message says which: an unpaid app is locked until a workspace admin updates the payment details. `details.status` is the app's subscription status (null with none), and `details.paymentIssue` is `unpaid`, or `payment_failed` for an incomplete one whose first payment failed, as `paymentIssue` on `GET /subscription` reckons it; null when a payment is not why.

- `error` (ErrorDetail, required)

### 422 Validation Error

- `error` (ErrorDetail, required)

### 429 Too Many Requests Error

Rate limited (`rate_limited`): the key, the signed-in person, the workspace or an expensive endpoint's own budget is used up for now. `Retry-After` says how many seconds to wait, and `details` names the `policy`, its `limit`, `windowSeconds` and `retryAfter`. Every answer to an authenticated request carries the IETF `RateLimit-Policy` and `RateLimit` headers, so a client can slow down before it gets this. Nothing was done; wait and send it again. See "Rate limits".

- `error` (ErrorDetail, required)

## Types

### ImportProblem

A line bulk entry skipped.

- `line` (integer, required) — The line's number, from 1; 0 for an objective, named by its `text`.
- `text` (string, required)
- `reason` (enum, required)
  - Allowed values: `noText`, `orphanKeyResult`, `noKeyResults`

### ErrorDetail

- `code` (string, required) — A stable machine-readable code such as `not_found`.
- `message` (string, required)
- `details` (any, optional)

## Examples

**Request**

```json
{
  "text": "Make onboarding effortless (x2) #growth\n  - Median time to first launch under 10 minutes [P1]\n  - 90% of new workspaces invite a second person sam@example.com\nClose the books faster\n",
  "year": 2026,
  "quarter": 3
}
```

**Response**

```json
{
  "created": 1,
  "objectiveIds": [
    "obj_7f3a"
  ],
  "skipped": 1,
  "problems": [
    {
      "line": 0,
      "text": "Close the books faster",
      "reason": "noKeyResults"
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.taktoria.com/api/v1/objectives/import"

payload = {
    "text": "Make onboarding effortless (x2) #growth
  - Median time to first launch under 10 minutes [P1]
  - 90% of new workspaces invite a second person sam@example.com
Close the books faster
",
    "year": 2026,
    "quarter": 3
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.taktoria.com/api/v1/objectives/import';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"text":"Make onboarding effortless (x2) #growth\n  - Median time to first launch under 10 minutes [P1]\n  - 90% of new workspaces invite a second person sam@example.com\nClose the books faster\n","year":2026,"quarter":3}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.taktoria.com/api/v1/objectives/import"

	payload := strings.NewReader("{\n  \"text\": \"Make onboarding effortless (x2) #growth\\n  - Median time to first launch under 10 minutes [P1]\\n  - 90% of new workspaces invite a second person sam@example.com\\nClose the books faster\\n\",\n  \"year\": 2026,\n  \"quarter\": 3\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.taktoria.com/api/v1/objectives/import")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"text\": \"Make onboarding effortless (x2) #growth\\n  - Median time to first launch under 10 minutes [P1]\\n  - 90% of new workspaces invite a second person sam@example.com\\nClose the books faster\\n\",\n  \"year\": 2026,\n  \"quarter\": 3\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.taktoria.com/api/v1/objectives/import")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"text\": \"Make onboarding effortless (x2) #growth\\n  - Median time to first launch under 10 minutes [P1]\\n  - 90% of new workspaces invite a second person sam@example.com\\nClose the books faster\\n\",\n  \"year\": 2026,\n  \"quarter\": 3\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.taktoria.com/api/v1/objectives/import', [
  'body' => '{
  "text": "Make onboarding effortless (x2) #growth\\n  - Median time to first launch under 10 minutes [P1]\\n  - 90% of new workspaces invite a second person sam@example.com\\nClose the books faster\\n",
  "year": 2026,
  "quarter": 3
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.taktoria.com/api/v1/objectives/import");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"text\": \"Make onboarding effortless (x2) #growth\\n  - Median time to first launch under 10 minutes [P1]\\n  - 90% of new workspaces invite a second person sam@example.com\\nClose the books faster\\n\",\n  \"year\": 2026,\n  \"quarter\": 3\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "text": "Make onboarding effortless (x2) #growth
  - Median time to first launch under 10 minutes [P1]
  - 90% of new workspaces invite a second person sam@example.com
Close the books faster
",
  "year": 2026,
  "quarter": 3
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.taktoria.com/api/v1/objectives/import")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```