Agents like Codex and Deep Research show that reasoning models can take several minutes to solve complex problems. Background mode enables you to execute long-running tasks on models like GPT-5.2 and GPT-5.2 Pro reliably, without having to worry about timeouts or other connectivity issues.
Background mode kicks off these tasks asynchronously, and developers can poll response objects to check status over time. To start response generation in the background, make an API request with background set to true:
Background requests from Zero Data Retention (ZDR) projects run with
store=false. Response data is temporarily stored to disk for roughly 10
minutes to enable asynchronous execution and polling.
1
2
3
4
5
6
7
8curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-5.6",
"input": "Write a very long novel about otters in space.",
"background": true
}'
1
2
3
4
5
6
7
8
9
10import OpenAI from "openai";
const client = new OpenAI();
const resp = await client.responses.create({
model: "gpt-5.6",
input: "Write a very long novel about otters in space.",
background: true,
});
console.log(resp.status);
1
2
3
4
5
6
7
8
9
10
11from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5.6",
input="Write a very long novel about otters in space.",
background=True,
)
print(resp.status)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Background: openai.Bool(true),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Write a very long novel about otters in space."),
},
})
if err != nil {
panic(err)
}
fmt.Println(response.Status)
}
To check the status of background requests, use the GET endpoint for Responses. Keep polling while the request is in the queued or in_progress state. When it leaves these states, it has reached a final (terminal) state.
1
2
3curl https://api.openai.com/v1/responses/resp_123 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import OpenAI from "openai";
const client = new OpenAI();
let resp = await client.responses.create({
model: "gpt-5.6",
input: "Write a very long novel about otters in space.",
background: true,
});
while (resp.status === "queued" || resp.status === "in_progress") {
console.log("Current status: " + resp.status);
await new Promise((resolve) => setTimeout(resolve, 2000)); // wait 2 seconds
resp = await client.responses.retrieve(resp.id);
}
console.log("Final status: " + resp.status + "\nOutput:\n" + resp.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from openai import OpenAI
from time import sleep
client = OpenAI()
resp = client.responses.create(
model="gpt-5.6",
input="Write a very long novel about otters in space.",
background=True,
)
while resp.status in {"queued", "in_progress"}:
print(f"Current status: {resp.status}")
sleep(2)
resp = client.responses.retrieve(resp.id)
print(f"Final status: {resp.status}\nOutput:\n{resp.output_text}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36package main
import (
"context"
"fmt"
"time"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Background: openai.Bool(true),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Write a very long novel about otters in space."),
},
})
if err != nil {
panic(err)
}
for response.Status == "queued" || response.Status == "in_progress" {
fmt.Println("Current status:", response.Status)
time.Sleep(2 * time.Second)
response, err = client.Responses.Get(context.Background(), response.ID, responses.ResponseGetParams{})
if err != nil {
panic(err)
}
}
fmt.Printf("Final status: %s\nOutput:\n%s\n", response.Status, response.OutputText())
}
You can also cancel an in-flight response like this:
1
2
3curl -X POST https://api.openai.com/v1/responses/resp_123/cancel \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY"
1
2
3
4
5
6import OpenAI from "openai";
const client = new OpenAI();
const resp = await client.responses.cancel("resp_123");
console.log(resp.status);
1
2
3
4
5
6
7
8
9
10import os
from openai import OpenAI
response_id = os.environ["OPENAI_RESPONSE_ID"]
client = OpenAI()
resp = client.responses.cancel(response_id)
print(resp.status)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
canceled, err := client.Responses.Cancel(context.Background(), "resp_123")
if err != nil {
panic(err)
}
fmt.Println(canceled.Status)
}
Cancelling twice is idempotent - subsequent calls simply return the final Response object.
You can create a background Response and start streaming events from it right away. This may be helpful if you expect the client to drop the stream and want the option of picking it back up later. To do this, create a Response with both background and stream set to true. You will want to keep track of a “cursor” corresponding to the sequence_number you receive in each streaming event.
Currently, the time to first token you receive from a background response is
higher than what you receive from a synchronous one. We are working to reduce
this latency gap in the coming weeks.
1
2
3
4
5
6
7
8
9
10
11
12
13
14curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-5.6",
"input": "Write a very long novel about otters in space.",
"background": true,
"stream": true
}'
// To resume:
curl "https://api.openai.com/v1/responses/resp_123?stream=true&starting_after=42" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import OpenAI from "openai";
const client = new OpenAI();
const stream = await client.responses.create({
model: "gpt-5.6",
input: "Write a very long novel about otters in space.",
background: true,
stream: true,
});
let cursor = null;
for await (const event of stream) {
console.log(event);
cursor = event.sequence_number;
}
// If the connection drops, you can resume streaming from the last cursor (SDK support coming soon):
// const resumedStream = await client.responses.stream(resp.id, { starting_after: cursor });
// for await (const event of resumedStream) { ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from openai import OpenAI
client = OpenAI()
# Fire off an async response but also start streaming immediately
stream = client.responses.create(
model="gpt-5.6",
input="Write a very long novel about otters in space.",
background=True,
stream=True,
)
cursor = None
for event in stream:
print(event)
cursor = event.sequence_number
# If your connection drops, the response continues running and you can reconnect:
# SDK support for resuming the stream is coming soon.
# for event in client.responses.stream(resp.id, starting_after=cursor):
# print(event)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
stream := client.Responses.NewStreaming(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Background: openai.Bool(true),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Write a very long novel about otters in space."),
},
})
var cursor int64
var responseID string
for stream.Next() {
event := stream.Current()
fmt.Println(event.Type)
cursor = event.SequenceNumber
if event.Response.ID != "" {
responseID = event.Response.ID
}
}
if err := stream.Err(); err != nil {
panic(err)
}
fmt.Printf("response %s last cursor %d\n", responseID, cursor)
// If the connection drops, resume streaming from the last cursor:
// resumed := client.Responses.GetStreaming(
// context.Background(),
// responseID,
// responses.ResponseGetParams{StartingAfter: openai.Int(cursor)},
// )
// for resumed.Next() {
// fmt.Println(resumed.Current().Type)
// }
}
- Background requests can use
store=false, but response data is temporarily
stored to support asynchronous execution and polling.
- To cancel a synchronous response, terminate the connection
- You can only start a new stream from a background response if you created it with
stream=true.