15-minute quickstart

From pip install to a cryptographic receipt your auditor can verify offline. No clever tricks, no skipping ahead, no half-built examples. Follow the five steps and you'll be looking at a verified receipt in your terminal before your coffee gets cold.

What you'll need. Python 3.9+, a terminal, and 15 minutes. We'll create a Marturia account, send your first OpenTelemetry span, generate a signed receipt, and verify it offline.
1

Sign up and grab your API key (2 min)

Open marturia.dev/app/signup and create an account. We'll auto-create your first project and mint a development API key.

From the dashboard, navigate to Keys and copy the plaintext secret once — we hash and forget it after that.

# Stash it somewhere your shell can read
export MARTURIA_API_KEY="mar_live_xxxxxxxxxxxxxxxxxx"
One shot at the secret. The Keys page shows the plaintext only on the modal where you mint it. After that, only the SHA-256 hash is stored. If you lose it, mint a new one.
2

Install the OpenTelemetry SDK (3 min)

Marturia speaks standard OTLP/HTTP. Any OTel SDK works; we'll use Python here.

pip install opentelemetry-api opentelemetry-sdk \
            opentelemetry-exporter-otlp-proto-http

If you already use OpenTelemetry, you only need the opentelemetry-exporter-otlp-proto-http piece — point an existing tracer-provider at our endpoint with the X-Marturia-Key header.

3

Emit your first span (3 min)

Save this as hello_marturia.py and run it.

import os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
    OTLPSpanExporter,
)

# 1. Tell OTel who's emitting (shows up in the Marturia dashboard).
resource = Resource.create({"service.name": "hello-marturia"})

# 2. Wire the exporter to marturia.dev with your API key.
exporter = OTLPSpanExporter(
    endpoint="https://marturia.dev/api/marturia/v1/traces",
    headers={"X-Marturia-Key": os.environ["MARTURIA_API_KEY"]},
)
provider = TracerProvider(resource=resource)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

# 3. Emit a span.
tracer = trace.get_tracer("hello")
with tracer.start_as_current_span("my_first_span") as span:
    span.set_attribute("llm.model", "gpt-4")
    span.set_attribute("llm.cost_usd", 0.012)
    print("hello, marturia")

# 4. Flush before exit so the BatchSpanProcessor ships.
provider.shutdown()
python hello_marturia.py

Open the dashboard and you'll see the span land within a second or two. Click it to inspect attributes, events, and the resource. Congrats — you're producing observability data.

4

Generate a cryptographic receipt (3 min)

Now the part that makes Marturia different. POST to /api/marturia/v1/receipts with the same API key:

curl -X POST https://marturia.dev/api/marturia/v1/receipts \
  -H "X-Marturia-Key: $MARTURIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "purchase_approver",
    "payload": {
      "order_id": 12345,
      "decision": "approve",
      "confidence": 0.97
    },
    "agent_run_id": "run_demo_001"
  }'

You'll get back something like:

{
  "id": 98,
  "tenant_id": 2,
  "receipt_seq": 54,
  "signing_kid": "t2-v1",
  "receipt_hash": "803e993d40faef9071dd0d458d6b5382...",
  "verify_url": "https://marturia.dev/v1/verify/2/98"
}

The verify_url is the headline. Copy it. That URL is what your customer or auditor would receive.

Pasting it in any browser returns the full receipt JSON — no auth required. The cryptographic chain is the auth.

5

Verify it offline (4 min)

Install the verifier and confirm the receipt is real:

pip install marturia-verify

# Pull the receipt + the public key from the verify URL
curl -s https://marturia.dev/v1/verify/2/98 > receipt.json
jq -r .public_key receipt.json > pubkey.hex

# Verify — runs offline, no network call
marturia-verify --receipt receipt.json --pubkey pubkey.hex

You should see:

VALID: signature valid; receipt_hash matches; sequence 54 of tenant 2

That's the whole pitch. The verifier is a few hundred lines of Python — auditable. If anyone tampers with the payload, the hash stops matching. If anyone forges a receipt, the signature stops verifying. The chain is the trust.

You're done

You just completed the loop:

  1. Real OTel spans flowing into Marturia.
  2. A signed receipt anchored in your tenant's hash chain.
  3. An auditor-shareable URL.
  4. Offline verification proving the receipt is authentic.

What to do next

Stuck?

Most first-run problems are listed at Troubleshooting — bad header, expired key, payload too large, or the OTel SDK silently buffering on exit.