or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-configuration.mdcomments-annotations.mdcommon-types.mddatasets.mdexceptions.mdhealth.mdindex.mdingestion.mdmedia.mdmetrics.mdmodels.mdpagination.mdprojects-organizations.mdprompts.mdscim.mdscores.mdsessions.mdtraces-observations.md

ingestion.mddocs/

0

# Ingestion API

1

2

The Ingestion API provides batched ingestion of tracing data for Langfuse. This is the primary API for tracing operations, supporting event deduplication and multiple event types in a single batch. The API handles traces, observations (spans, events, generations), and scores.

3

4

Note: The recommended approach for tracing is via OpenTelemetry instrumentation rather than direct Ingestion API usage, as it provides more detailed and standardized tracing without requiring manual batching and update handling.

5

6

## Capabilities

7

8

### IngestionClient

9

10

Client for batched ingestion of tracing events.

11

12

```java { .api }

13

/**

14

* Batched ingestion for Langfuse Tracing

15

*

16

* Features:

17

* - Event deduplication using event IDs

18

* - Multiple event types in a single batch

19

* - Batch size limit: 3.5 MB

20

* - Returns 207 Multi-Status with individual error details

21

* instead of 4xx for input errors

22

*

23

* @param request Batch of ingestion events

24

* @param requestOptions Optional request configuration

25

* @return Response with success/error details for each event

26

*/

27

IngestionResponse batch(IngestionRequest request);

28

IngestionResponse batch(IngestionRequest request, RequestOptions requestOptions);

29

```

30

31

**Usage Example:**

32

33

```java

34

import com.langfuse.client.LangfuseClient;

35

import com.langfuse.client.resources.ingestion.requests.IngestionRequest;

36

import com.langfuse.client.resources.ingestion.types.*;

37

import com.langfuse.client.resources.commons.types.CreateScoreValue;

38

import java.time.OffsetDateTime;

39

import java.util.List;

40

import java.util.Map;

41

42

LangfuseClient client = LangfuseClient.builder()

43

.url("https://cloud.langfuse.com")

44

.credentials("pk-lf-...", "sk-lf-...")

45

.build();

46

47

// Create a batch of events

48

// Note: All event types use staged builders requiring id(), timestamp(), body() in that order

49

IngestionRequest request = IngestionRequest.builder()

50

.batch(List.of(

51

// Trace event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()

52

IngestionEvent.traceCreate(TraceEvent.builder()

53

.id("event-trace-123") // Event ID for deduplication (required first)

54

.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String ISO 8601 (required second)

55

.body(TraceBody.builder() // Event body (required third)

56

.id("trace-123")

57

.name("User Query")

58

.userId("user-456")

59

.input(Map.of("query", "What is AI?"))

60

.timestamp(OffsetDateTime.now())

61

.build())

62

.metadata(Map.of("source", "api")) // Optional event metadata

63

.build()),

64

65

// Span event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()

66

IngestionEvent.spanCreate(CreateSpanEvent.builder()

67

.id("event-span-123") // Event ID for deduplication (required first)

68

.timestamp(OffsetDateTime.now().plusSeconds(1).toString()) // Event timestamp as String ISO 8601 (required second)

69

.body(CreateSpanBody.builder() // Event body (required third)

70

.id("span-123")

71

.traceId("trace-123")

72

.name("LLM Call")

73

.startTime(OffsetDateTime.now().plusSeconds(1))

74

.endTime(OffsetDateTime.now().plusSeconds(3))

75

.input(Map.of("prompt", "What is AI?"))

76

.output(Map.of("response", "AI is..."))

77

.build())

78

.build()),

79

80

// Score event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()

81

IngestionEvent.scoreCreate(ScoreEvent.builder()

82

.id("event-score-123") // Event ID for deduplication (required first)

83

.timestamp(OffsetDateTime.now().plusSeconds(2).toString()) // Event timestamp as String ISO 8601 (required second)

84

.body(ScoreBody.builder() // Score body uses staged builder: name() -> value() -> other fields -> build()

85

.name("quality") // Required first: score name

86

.value(CreateScoreValue.of(0.95)) // Required second: score value as CreateScoreValue union

87

.id("score-123") // Optional: score ID (available in _FinalStage)

88

.traceId("trace-123") // Optional: trace ID

89

.build())

90

.build())

91

))

92

.build();

93

94

// Send batch

95

IngestionResponse response = client.ingestion().batch(request);

96

97

// Check results

98

for (IngestionSuccess success : response.getSuccesses()) {

99

System.out.println("Success: " + success.getId());

100

}

101

for (IngestionError error : response.getErrors()) {

102

System.err.println("Error: " + error.getId() + " - " + error.getMessage());

103

}

104

```

105

106

## Request Types

107

108

### IngestionRequest

109

110

```java { .api }

111

/**

112

* Batch ingestion request containing multiple events

113

*/

114

public final class IngestionRequest {

115

List<IngestionEvent> getBatch();

116

Optional<Object> getMetadata();

117

118

static Builder builder();

119

}

120

```

121

122

### IngestionEvent

123

124

Union type representing all possible event types.

125

126

```java { .api }

127

/**

128

* Union type for ingestion events

129

* Supports all event types for tracing

130

*/

131

public final class IngestionEvent {

132

// Factory methods for creating typed events

133

static IngestionEvent traceCreate(TraceEvent value);

134

static IngestionEvent scoreCreate(ScoreEvent value);

135

static IngestionEvent observationCreate(CreateObservationEvent value);

136

static IngestionEvent observationUpdate(UpdateObservationEvent value);

137

static IngestionEvent eventCreate(CreateEventEvent value);

138

static IngestionEvent spanCreate(CreateSpanEvent value);

139

static IngestionEvent spanUpdate(UpdateSpanEvent value);

140

static IngestionEvent generationCreate(CreateGenerationEvent value);

141

static IngestionEvent generationUpdate(UpdateGenerationEvent value);

142

static IngestionEvent sdkLog(SdkLogEvent value);

143

144

// Visitor pattern for type-safe access

145

<T> T visit(Visitor<T> visitor);

146

}

147

```

148

149

## Event Types

150

151

### TraceEvent

152

153

Create or update a trace.

154

155

```java { .api }

156

/**

157

* Event for creating/updating a trace

158

* Type: "trace-create"

159

*

160

* Staged Builder Pattern (required order):

161

* 1. id(String) - Event ID for deduplication

162

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

163

* 3. body(TraceBody) - Trace data

164

* 4. metadata(Object) - Optional SDK metadata

165

* 5. build() - Build the event

166

*/

167

public final class TraceEvent {

168

String getId(); // Event ID for deduplication

169

String getTimestamp(); // Event timestamp as String (ISO 8601)

170

Optional<Object> getMetadata(); // Optional SDK metadata

171

TraceBody getBody();

172

173

static IdStage builder(); // Returns staged builder starting with id()

174

}

175

```

176

177

### ScoreEvent

178

179

Create a score for a trace or observation.

180

181

```java { .api }

182

/**

183

* Event for creating a score

184

* Type: "score-create"

185

*

186

* Staged Builder Pattern (required order):

187

* 1. id(String) - Event ID for deduplication

188

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

189

* 3. body(ScoreBody) - Score data

190

* 4. metadata(Object) - Optional SDK metadata

191

* 5. build() - Build the event

192

*/

193

public final class ScoreEvent {

194

String getId(); // Event ID for deduplication

195

String getTimestamp(); // Event timestamp as String (ISO 8601)

196

Optional<Object> getMetadata(); // Optional SDK metadata

197

ScoreBody getBody();

198

199

static IdStage builder(); // Returns staged builder starting with id()

200

}

201

```

202

203

### Observation Events

204

205

Observations represent spans, events, and generations in traces.

206

207

```java { .api }

208

/**

209

* Event for creating an observation

210

* Type: "observation-create"

211

*

212

* Staged Builder Pattern (required order):

213

* 1. id(String) - Event ID for deduplication

214

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

215

* 3. body(ObservationBody) - Observation data

216

* 4. metadata(Object) - Optional SDK metadata

217

* 5. build() - Build the event

218

*/

219

public final class CreateObservationEvent {

220

String getId();

221

String getTimestamp();

222

Optional<Object> getMetadata();

223

ObservationBody getBody();

224

225

static IdStage builder();

226

}

227

228

/**

229

* Event for updating an observation

230

* Type: "observation-update"

231

*

232

* Staged Builder Pattern (required order):

233

* 1. id(String) - Event ID for deduplication

234

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

235

* 3. body(OptionalObservationBody) - Observation data

236

* 4. metadata(Object) - Optional SDK metadata

237

* 5. build() - Build the event

238

*/

239

public final class UpdateObservationEvent {

240

String getId();

241

String getTimestamp();

242

Optional<Object> getMetadata();

243

OptionalObservationBody getBody();

244

245

static IdStage builder();

246

}

247

```

248

249

### Span Events

250

251

Spans represent operations or sub-processes within a trace.

252

253

```java { .api }

254

/**

255

* Event for creating a span

256

* Type: "span-create"

257

*

258

* Staged Builder Pattern (required order):

259

* 1. id(String) - Event ID for deduplication

260

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

261

* 3. body(CreateSpanBody) - Span data

262

* 4. metadata(Object) - Optional SDK metadata

263

* 5. build() - Build the event

264

*/

265

public final class CreateSpanEvent {

266

String getId();

267

String getTimestamp();

268

Optional<Object> getMetadata();

269

CreateSpanBody getBody();

270

271

static IdStage builder();

272

}

273

274

/**

275

* Event for updating a span

276

* Type: "span-update"

277

*

278

* Staged Builder Pattern (required order):

279

* 1. id(String) - Event ID for deduplication

280

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

281

* 3. body(UpdateSpanBody) - Span data

282

* 4. metadata(Object) - Optional SDK metadata

283

* 5. build() - Build the event

284

*/

285

public final class UpdateSpanEvent {

286

String getId();

287

String getTimestamp();

288

Optional<Object> getMetadata();

289

UpdateSpanBody getBody();

290

291

static IdStage builder();

292

}

293

```

294

295

### Event Events

296

297

Events represent point-in-time occurrences within a trace.

298

299

```java { .api }

300

/**

301

* Event for creating an event

302

* Type: "event-create"

303

*

304

* Staged Builder Pattern (required order):

305

* 1. id(String) - Event ID for deduplication

306

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

307

* 3. body(CreateEventBody) - Event data

308

* 4. metadata(Object) - Optional SDK metadata

309

* 5. build() - Build the event

310

*/

311

public final class CreateEventEvent {

312

String getId();

313

String getTimestamp();

314

Optional<Object> getMetadata();

315

CreateEventBody getBody();

316

317

static IdStage builder();

318

}

319

```

320

321

### Generation Events

322

323

Generations represent LLM generation calls within a trace.

324

325

```java { .api }

326

/**

327

* Event for creating a generation

328

* Type: "generation-create"

329

*

330

* Staged Builder Pattern (required order):

331

* 1. id(String) - Event ID for deduplication

332

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

333

* 3. body(CreateGenerationBody) - Generation data

334

* 4. metadata(Object) - Optional SDK metadata

335

* 5. build() - Build the event

336

*/

337

public final class CreateGenerationEvent {

338

String getId();

339

String getTimestamp();

340

Optional<Object> getMetadata();

341

CreateGenerationBody getBody();

342

343

static IdStage builder();

344

}

345

346

/**

347

* Event for updating a generation

348

* Type: "generation-update"

349

*

350

* Staged Builder Pattern (required order):

351

* 1. id(String) - Event ID for deduplication

352

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

353

* 3. body(UpdateGenerationBody) - Generation data

354

* 4. metadata(Object) - Optional SDK metadata

355

* 5. build() - Build the event

356

*/

357

public final class UpdateGenerationEvent {

358

String getId();

359

String getTimestamp();

360

Optional<Object> getMetadata();

361

UpdateGenerationBody getBody();

362

363

static IdStage builder();

364

}

365

```

366

367

### SdkLogEvent

368

369

SDK log messages for debugging.

370

371

```java { .api }

372

/**

373

* Event for SDK log messages

374

* Type: "sdk-log"

375

*

376

* Staged Builder Pattern (required order):

377

* 1. id(String) - Event ID for deduplication

378

* 2. timestamp(String) - Event timestamp (ISO 8601 format)

379

* 3. body(SdkLogBody) - Log message data

380

* 4. metadata(Object) - Optional SDK metadata

381

* 5. build() - Build the event

382

*/

383

public final class SdkLogEvent {

384

String getId();

385

String getTimestamp();

386

Optional<Object> getMetadata();

387

SdkLogBody getBody();

388

389

static IdStage builder();

390

}

391

```

392

393

## Event Body Types

394

395

### TraceBody

396

397

```java { .api }

398

/**

399

* Trace data for trace events

400

*/

401

public final class TraceBody {

402

Optional<String> getId(); // Unique trace ID

403

Optional<OffsetDateTime> getTimestamp(); // Timestamp as OffsetDateTime

404

Optional<String> getName();

405

Optional<String> getUserId();

406

Optional<Object> getMetadata();

407

Optional<String> getRelease();

408

Optional<String> getVersion();

409

Optional<String> getSessionId();

410

Optional<Object> getInput();

411

Optional<Object> getOutput();

412

Optional<List<String>> getTags();

413

Optional<String> getEnvironment();

414

Optional<Boolean> getPublic(); // Make trace publicly accessible

415

416

static Builder builder();

417

}

418

```

419

420

### ScoreBody

421

422

```java { .api }

423

/**

424

* Score data for score events

425

* Uses staged builder: name() -> value() -> optional fields -> build()

426

*/

427

public final class ScoreBody {

428

Optional<String> getId(); // Unique score ID

429

Optional<String> getTraceId();

430

String getName(); // Required: score name

431

CreateScoreValue getValue(); // Required: Union type (String, Integer, or Double)

432

Optional<String> getSessionId();

433

Optional<String> getObservationId();

434

Optional<String> getDatasetRunId();

435

Optional<String> getComment();

436

Optional<Object> getMetadata();

437

Optional<ScoreDataType> getDataType(); // NUMERIC, CATEGORICAL, BOOLEAN

438

Optional<String> getConfigId();

439

Optional<String> getEnvironment();

440

441

static NameStage builder(); // Returns staged builder starting with name()

442

}

443

```

444

445

### ObservationBody

446

447

```java { .api }

448

/**

449

* Observation data (for spans, events, generations)

450

*/

451

public final class ObservationBody {

452

Optional<String> getId(); // Unique observation ID

453

Optional<String> getTraceId();

454

ObservationType getType(); // SPAN, EVENT, GENERATION (required)

455

Optional<String> getName();

456

Optional<OffsetDateTime> getStartTime(); // Start time as OffsetDateTime

457

Optional<OffsetDateTime> getEndTime(); // End time as OffsetDateTime

458

Optional<OffsetDateTime> getCompletionStartTime(); // Completion start time as OffsetDateTime

459

Optional<String> getModel();

460

Optional<Map<String, MapValue>> getModelParameters();

461

Optional<Object> getInput();

462

Optional<Object> getOutput();

463

Optional<Usage> getUsage(); // Token/cost usage (from commons.types)

464

Optional<Object> getMetadata();

465

Optional<ObservationLevel> getLevel(); // DEBUG, DEFAULT, WARNING, ERROR

466

Optional<String> getStatusMessage();

467

Optional<String> getParentObservationId();

468

Optional<String> getVersion();

469

Optional<String> getEnvironment();

470

471

static Builder builder();

472

}

473

```

474

475

### OptionalObservationBody

476

477

```java { .api }

478

/**

479

* Observation data with all optional fields (for updates)

480

* Contains a subset of ObservationBody fields, all optional

481

*/

482

public final class OptionalObservationBody {

483

Optional<String> getTraceId();

484

Optional<String> getName();

485

Optional<OffsetDateTime> getStartTime(); // Start time as OffsetDateTime

486

Optional<Object> getMetadata();

487

Optional<Object> getInput();

488

Optional<Object> getOutput();

489

Optional<ObservationLevel> getLevel();

490

Optional<String> getStatusMessage();

491

Optional<String> getParentObservationId();

492

Optional<String> getVersion();

493

Optional<String> getEnvironment();

494

495

static Builder builder();

496

}

497

```

498

499

### Typed Observation Bodies

500

501

```java { .api }

502

/**

503

* Span-specific body

504

* Shares fields with ObservationBody through interface implementation

505

*/

506

public final class CreateSpanBody {

507

// Has all ObservationBody fields

508

static Builder builder();

509

}

510

511

/**

512

* Update span body

513

* Shares fields with OptionalObservationBody through interface implementation

514

*/

515

public final class UpdateSpanBody {

516

static Builder builder();

517

}

518

519

/**

520

* Event-specific body

521

* Shares fields with ObservationBody through interface implementation

522

*/

523

public final class CreateEventBody {

524

static Builder builder();

525

}

526

527

/**

528

* Update event body

529

* Shares fields with OptionalObservationBody through interface implementation

530

*/

531

public final class UpdateEventBody {

532

static Builder builder();

533

}

534

535

/**

536

* Generation-specific body

537

* Shares fields with ObservationBody through interface implementation

538

*/

539

public final class CreateGenerationBody {

540

static Builder builder();

541

}

542

543

/**

544

* Update generation body

545

* Shares fields with OptionalObservationBody through interface implementation

546

*/

547

public final class UpdateGenerationBody {

548

static Builder builder();

549

}

550

```

551

552

### SdkLogBody

553

554

```java { .api }

555

/**

556

* SDK log message data

557

*/

558

public final class SdkLogBody {

559

String getLog(); // Log message content

560

561

static Builder builder();

562

}

563

```

564

565

## Usage Types

566

567

### IngestionUsage

568

569

Union type for different usage formats.

570

571

```java { .api }

572

/**

573

* Union type for usage information

574

* Supports OpenAI usage formats and custom usage details

575

*/

576

public final class IngestionUsage {

577

static IngestionUsage openAiUsage(OpenAiUsage value);

578

static IngestionUsage usageDetails(UsageDetails value);

579

580

<T> T visit(Visitor<T> visitor);

581

}

582

```

583

584

### OpenAiUsage

585

586

OpenAI-style usage with token counts.

587

588

```java { .api }

589

/**

590

* OpenAI usage with token counts

591

*/

592

public final class OpenAiUsage {

593

Optional<Integer> getPromptTokens();

594

Optional<Integer> getCompletionTokens();

595

Optional<Integer> getTotalTokens();

596

597

static Builder builder();

598

}

599

```

600

601

### OpenAiCompletionUsageSchema

602

603

```java { .api }

604

/**

605

* OpenAI completion usage schema

606

*/

607

public final class OpenAiCompletionUsageSchema {

608

Optional<Integer> getPromptTokens();

609

Optional<Integer> getCompletionTokens();

610

Optional<Integer> getTotalTokens();

611

612

static Builder builder();

613

}

614

```

615

616

### OpenAiResponseUsageSchema

617

618

```java { .api }

619

/**

620

* Extended OpenAI response usage schema

621

*/

622

public final class OpenAiResponseUsageSchema {

623

Optional<Integer> getPromptTokens();

624

Optional<Integer> getCompletionTokens();

625

Optional<Integer> getTotalTokens();

626

// Extended fields for detailed token breakdown

627

628

static Builder builder();

629

}

630

```

631

632

### UsageDetails

633

634

```java { .api }

635

/**

636

* Union type for detailed usage information

637

* Use static factory methods to create instances

638

*/

639

public final class UsageDetails {

640

// Factory methods for creating UsageDetails

641

static UsageDetails of(Map<String, Integer> value); // Custom usage map

642

static UsageDetails of(OpenAiCompletionUsageSchema value); // OpenAI completion usage

643

static UsageDetails of(OpenAiResponseUsageSchema value); // OpenAI response usage

644

645

// Visitor pattern for type-safe access

646

<T> T visit(Visitor<T> visitor);

647

}

648

```

649

650

## Response Types

651

652

### IngestionResponse

653

654

```java { .api }

655

/**

656

* Response from batch ingestion

657

* HTTP 207 Multi-Status with individual event results

658

*/

659

public final class IngestionResponse {

660

List<IngestionSuccess> getSuccesses();

661

List<IngestionError> getErrors();

662

663

static Builder builder();

664

}

665

```

666

667

### IngestionSuccess

668

669

```java { .api }

670

/**

671

* Successful ingestion of an event

672

*/

673

public final class IngestionSuccess {

674

String getId(); // Event ID

675

int getStatus(); // HTTP status (200, 201, etc.)

676

677

static Builder builder();

678

}

679

```

680

681

### IngestionError

682

683

```java { .api }

684

/**

685

* Failed ingestion of an event

686

*/

687

public final class IngestionError {

688

String getId(); // Event ID

689

int getStatus(); // HTTP status (400, 422, etc.)

690

String getMessage(); // Error message

691

Optional<String> getError(); // Additional error details

692

693

static Builder builder();

694

}

695

```

696

697

## Enums

698

699

### ObservationType

700

701

```java { .api }

702

/**

703

* Type of observation

704

*/

705

public enum ObservationType {

706

SPAN,

707

EVENT,

708

GENERATION

709

}

710

```

711

712

### ObservationLevel

713

714

```java { .api }

715

/**

716

* Log level for observations

717

*/

718

public enum ObservationLevel {

719

DEBUG,

720

DEFAULT,

721

WARNING,

722

ERROR

723

}

724

```

725

726

### ModelUsageUnit

727

728

```java { .api }

729

/**

730

* Unit for usage measurement

731

*/

732

public enum ModelUsageUnit {

733

CHARACTERS,

734

TOKENS,

735

REQUESTS,

736

IMAGES,

737

SECONDS

738

}

739

```

740

741

### ScoreDataType

742

743

```java { .api }

744

/**

745

* Data type for scores

746

*/

747

public enum ScoreDataType {

748

NUMERIC,

749

CATEGORICAL,

750

BOOLEAN

751

}

752

```

753

754

## Complete Tracing Example

755

756

```java

757

import com.langfuse.client.LangfuseClient;

758

import com.langfuse.client.resources.ingestion.requests.IngestionRequest;

759

import com.langfuse.client.resources.ingestion.types.*;

760

import com.langfuse.client.resources.commons.types.CreateScoreValue;

761

import java.time.OffsetDateTime;

762

import java.util.List;

763

import java.util.Map;

764

765

public class TracingExample {

766

public static void main(String[] args) {

767

LangfuseClient client = LangfuseClient.builder()

768

.url("https://cloud.langfuse.com")

769

.credentials("pk-lf-...", "sk-lf-...")

770

.build();

771

772

String traceId = "trace-" + System.currentTimeMillis();

773

String spanId = "span-" + System.currentTimeMillis();

774

String generationId = "gen-" + System.currentTimeMillis();

775

776

IngestionRequest request = IngestionRequest.builder()

777

.batch(List.of(

778

// 1. Create trace - Note: Staged builder requires id() -> timestamp() -> body()

779

IngestionEvent.traceCreate(TraceEvent.builder()

780

.id("event-" + traceId) // Event ID for deduplication

781

.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String (ISO 8601)

782

.body(TraceBody.builder() // Trace body data

783

.id(traceId)

784

.name("Chat Completion")

785

.userId("user-123")

786

.sessionId("session-456")

787

.input(Map.of("message", "Hello, AI!"))

788

.timestamp(OffsetDateTime.now())

789

.tags(List.of("chat", "production"))

790

.build())

791

.build()),

792

793

// 2. Create span for preprocessing - Staged builder: id() -> timestamp() -> body()

794

IngestionEvent.spanCreate(CreateSpanEvent.builder()

795

.id("event-" + spanId) // Event ID for deduplication

796

.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String (ISO 8601)

797

.body(CreateSpanBody.builder() // Span body data

798

.id(spanId)

799

.traceId(traceId)

800

.name("Preprocess Input")

801

.startTime(OffsetDateTime.now())

802

.endTime(OffsetDateTime.now().plusSeconds(1))

803

.input(Map.of("raw", "Hello, AI!"))

804

.output(Map.of("processed", "hello ai"))

805

.build())

806

.build()),

807

808

// 3. Create generation for LLM call - Staged builder: id() -> timestamp() -> body()

809

IngestionEvent.generationCreate(CreateGenerationEvent.builder()

810

.id("event-" + generationId) // Event ID for deduplication

811

.timestamp(OffsetDateTime.now().plusSeconds(1).toString()) // Event timestamp as String (ISO 8601)

812

.body(CreateGenerationBody.builder() // Generation body data

813

.id(generationId)

814

.traceId(traceId)

815

.parentObservationId(spanId)

816

.name("OpenAI Chat")

817

.model("gpt-4")

818

.startTime(OffsetDateTime.now().plusSeconds(1))

819

.endTime(OffsetDateTime.now().plusSeconds(3))

820

.input(Map.of("messages", List.of(

821

Map.of("role", "user", "content", "Hello, AI!")

822

)))

823

.output(Map.of("content", "Hello! How can I help you?"))

824

.usage(IngestionUsage.openAiUsage(

825

OpenAiUsage.builder()

826

.promptTokens(10)

827

.completionTokens(8)

828

.totalTokens(18)

829

.build()

830

))

831

.build())

832

.build()),

833

834

// 4. Add quality score - Staged builder: id() -> timestamp() -> body()

835

IngestionEvent.scoreCreate(ScoreEvent.builder()

836

.id("event-score-" + System.currentTimeMillis()) // Event ID for deduplication

837

.timestamp(OffsetDateTime.now().plusSeconds(3).toString()) // Event timestamp as String (ISO 8601)

838

.body(ScoreBody.builder() // Score body uses staged builder: name() -> value() -> optional fields

839

.name("quality") // Required first: score name

840

.value(CreateScoreValue.of(0.95)) // Required second: score value

841

.id("score-" + System.currentTimeMillis()) // Optional: available in _FinalStage

842

.traceId(traceId) // Optional: trace ID

843

.dataType(ScoreDataType.NUMERIC) // Optional: data type

844

.build())

845

.build())

846

))

847

.build();

848

849

// Send batch

850

IngestionResponse response = client.ingestion().batch(request);

851

852

// Handle results

853

System.out.println("Successes: " + response.getSuccesses().size());

854

System.out.println("Errors: " + response.getErrors().size());

855

856

for (IngestionError error : response.getErrors()) {

857

System.err.println("Failed event " + error.getId() + ": " + error.getMessage());

858

}

859

}

860

}

861

```

862

863

## Best Practices

864

865

1. **Use Event IDs for Deduplication**: Always provide unique event IDs to enable deduplication on retries

866

2. **Batch Related Events**: Send related events (trace + observations + scores) in a single batch

867

3. **Handle Partial Failures**: Check both successes and errors in the response (207 Multi-Status)

868

4. **Stay Under Size Limit**: Keep batch sizes under 3.5 MB

869

5. **Use Timestamps**: Provide accurate ISO 8601 timestamps for all events

870

6. **Link Observations**: Use `traceId` and `parentObservationId` to build trace hierarchy

871

7. **Prefer OpenTelemetry**: For production use, consider OpenTelemetry instrumentation instead

872

873

## Related Documentation

874

875

- [Traces and Observations](./traces-observations.md) - Retrieving and managing traces

876

- [Scores](./scores.md) - Score management and configuration

877

- [Common Types](./common-types.md) - Shared type definitions

878