# Payload


## Endpoint

`POST https://ingress.flareapp.io/v1/traces`

### Headers

| Header         | Value              | Description |
  |----------------|--------------------|-------------|
| `Content-Type` | `application/json` | Required    |
| `Accept`       | `application/json` | Required    |
| `x-api-token`  | `{apiToken}`       | API token   |

## Authentication

Authenticate using your project's **private API key** in the `x-api-token` header. The public API key cannot be used for this endpoint.

## Payload

The trace payload follows the OpenTelemetry protocol structure.

| Field           | Type  | Validation          | Description                    |
  |-----------------|-------|---------------------|--------------------------------|
| `resourceSpans` | array | required, non-empty | Array of resource span objects |

### Resource Spans

| Field        | Type   | Validation          | Description                    |
|---|---|---|---|
| `resource`   | object | required, non-empty | The resource producing these spans |
| `scopeSpans` | array  | required, non-empty | Array of scope span objects    |

#### Resource

A resource represents the entity producing telemetry data (your application/service). For a list of common resource attributes, see [Resources](/docs/protocol/general/resources).

| Field | Type | Validation | Description |
|---|---|---|---|
| `attributes` | array | required | OTEL-format key-value pairs |
| `droppedAttributesCount` | int | required | Number of dropped attributes |

### Scope Spans

| Field   | Type   | Validation          | Description                    |
|---|---|---|---|
| `scope` | object | required, non-empty | The instrumentation scope |
| `spans` | array  | required, non-empty | Array of span objects     |

#### Scope

A scope represents the instrumentation library that produced the spans. Different libraries (e.g. your Flare client, a database recorder, a cache recorder) can each be their own scope within the same resource.

| Field | Type | Validation | Description |
|---|---|---|---|
| `name` | string | required, non-empty | Instrumentation scope name |
| `version` | string/number | required, non-empty | Instrumentation scope version |
| `attributes` | array | optional | OTEL-format key-value pairs |
| `droppedAttributesCount` | int | optional | Number of dropped attributes |

### Spans

A span represents a single unit of work within a trace, such as an HTTP request, a database query, or a cache operation. Each span has a start time, end time, and optional attributes that describe the work being done. Spans can be nested using `parentSpanId` to form a tree structure that represents the full execution flow of a request.

| Field                    | Type        | Validation          | Description                                  |
  |--------------------------|-------------|---------------------|----------------------------------------------|
| `traceId`                | string      | required, non-empty | Trace identifier (32 lowercase hex characters) |
| `spanId`                 | string      | required, non-empty | Span identifier (16 lowercase hex characters)  |
| `parentSpanId`           | string/null | required            | Parent span identifier (null for root spans) |
| `name`                   | string      | required, non-empty | Human-readable span name                     |
| `startTimeUnixNano`      | int         | required            | Start time in nanoseconds                    |
| `endTimeUnixNano`        | int         | required            | End time in nanoseconds                      |
| `status`                 | object      | required, non-empty | Span status                                  |
| `attributes`             | array       | optional            | OTEL-format attributes                       |
| `droppedAttributesCount` | int         | optional            | Number of dropped attributes                 |
| `events`                 | array       | required            | Array of span event objects                  |
| `droppedEventsCount`     | int         | required            | Number of dropped events                     |

A non-null `parentSpanId` on a non-container span must reference a span sent in the same payload. Flare resolves such a span's container by walking up the parent chain, so a `parentSpanId` pointing at a span Flare never received leaves that span out of the trace, and depending on processing order other spans in the same payload with it. The report is still accepted, so nothing signals the loss.

[Container spans](/docs/protocol/traces/lifecycle) are the exception. A container may name a parent that lives in a different payload, which is how a queued job links back to the request that dispatched it, or how a `browser_web_vital` span links back to the pageload it belongs to.

### Span Status

| Field     | Type        | Validation | Description    |
  |-----------|-------------|------------|----------------|
| `code`    | int         | required   | Status code    |
| `message` | string/null | optional   | Status message |

#### Status Codes

| Code | Name  | Description                                   |
  |------|-------|-----------------------------------------------|
| `0`  | Unset | Default, no explicit status set               |
| `1`  | Ok    | Manually set by developer to indicate success |
| `2`  | Error | An error occurred during the span             |

### Span Events

Span events are nested inside their parent span. For the full list of span types and span event types with their attributes, see [Events](/docs/protocol/general/events).

| Field                    | Type   | Validation          | Description                    |
  |--------------------------|--------|---------------------|--------------------------------|
| `name`                   | string | required, non-empty | Event name                     |
| `timeUnixNano`           | int    | required            | Event timestamp in nanoseconds |
| `attributes`             | array  | optional            | OTEL-format attributes         |
| `droppedAttributesCount` | int    | optional            | Number of dropped attributes   |

### Span & Span Event Types

The span type is determined by the `flare.span_type` attribute on the span. The span event type is determined by the `flare.span_event_type` attribute on the span event. These attributes are stripped from the attributes before display.

### Entry Point

The root [container span](/docs/protocol/traces/lifecycle) of a trace (a `php_request`, `php_command`, `laravel_job`, `browser_pageload`, or `browser_navigation`) should carry `flare.entry_point.*` attributes describing the request, command, job, or browser page that the trace represents. The same attributes are used by errors and logs; see [Entry points](/docs/protocol/general/entry-points) for the schema and per-scenario examples.

### Attribute Format

All attributes in the traces endpoint use the OpenTelemetry typed attribute format. See [Attribute Formats](/docs/protocol/general/attribute-formats) for the full format specification and value types.

### Web Vitals

A browser client splits Core Web Vitals over two spans: whatever is final goes on the `browser_pageload` span, and the rest follows later on a `browser_web_vital` span backdated to the page's start. See [Web vitals](/docs/protocol-javascript/traces/web-vitals) in the JavaScript protocol docs.

## Responses

All responses include CORS headers (`Access-Control-Allow-Origin: *`) and return `application/json`.

| Status | Description |
|---|---|
| `201` | Trace accepted |
| `403` | Invalid API key |
| `405` | HTTP method not allowed (only `POST` is accepted) |
| `401` | Missing API key |
| `422` | Validation error (missing `resourceSpans`, missing `traceId` or `spanId`) |
| `429` | Rate limit or trace quota exceeded |

Success response:

```json
{}
```

Validation error responses include the field path and a description of the issue:

```json
{
    "message": "The given data was invalid.",
    "errors": {
        "resourceSpans.0.scopeSpans.0.spans.0.traceId": [
            "The traceId field is required in this resourceSpan."
        ]
    }
}
```

## Example

```json
{
    "resourceSpans": [
        {
            "resource": {
                "attributes": [
                    { "key": "service.name", "value": { "stringValue": "My Application" } },
                    { "key": "service.version", "value": { "stringValue": "1.0.0" } },
                    { "key": "service.stage", "value": { "stringValue": "production" } },
                    { "key": "telemetry.sdk.language", "value": { "stringValue": "PHP" } },
                    { "key": "telemetry.sdk.name", "value": { "stringValue": "spatie/flare-client-php" } },
                    { "key": "telemetry.sdk.version", "value": { "stringValue": "1.0.0" } }
                ],
                "droppedAttributesCount": 0
            },
            "scopeSpans": [
                {
                    "scope": {
                        "name": "spatie/laravel-flare",
                        "version": "1.0.0"
                    },
                    "spans": [
                        {
                            "traceId": "a1b2c3d4e5f67890a1b2c3d4e5f67890",
                            "spanId": "1234567890abcdef",
                            "parentSpanId": null,
                            "name": "GET /users",
                            "startTimeUnixNano": 1710252000000000000,
                            "endTimeUnixNano": 1710252000150000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "php_request" } },
                                { "key": "http.request.method", "value": { "stringValue": "GET" } },
                                { "key": "http.route", "value": { "stringValue": "/users" } },
                                { "key": "http.response.status_code", "value": { "intValue": 200 } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [
                                {
                                    "name": "cache hit",
                                    "timeUnixNano": 1710252000050000000,
                                    "attributes": [
                                        { "key": "flare.span_event_type", "value": { "stringValue": "php_cache" } },
                                        { "key": "cache.operation", "value": { "stringValue": "get" } },
                                        { "key": "cache.result", "value": { "stringValue": "hit" } },
                                        { "key": "cache.key", "value": { "stringValue": "users.list" } }
                                    ]
                                }
                            ],
                            "droppedEventsCount": 0
                        },
                        {
                            "traceId": "a1b2c3d4e5f67890a1b2c3d4e5f67890",
                            "spanId": "abcdef1234567890",
                            "parentSpanId": "1234567890abcdef",
                            "name": "select * from `users`",
                            "startTimeUnixNano": 1710252000060000000,
                            "endTimeUnixNano": 1710252000080000000,
                            "status": { "code": 0 },
                            "attributes": [
                                { "key": "flare.span_type", "value": { "stringValue": "php_query" } },
                                { "key": "db.system", "value": { "stringValue": "mysql" } },
                                { "key": "db.statement", "value": { "stringValue": "select * from `users`" } }
                            ],
                            "droppedAttributesCount": 0,
                            "events": [],
                            "droppedEventsCount": 0
                        }
                    ]
                }
            ]
        }
    ]
}
```
