Skip to content

Example C · Send a File

Send an encrypted file from the gateway — small files via relay, large files via QUIC when both peers support it.


Prerequisites

  • Gateway running with an active peer chat (Example B)
  • Active license
  • File available inside the container at the path you pass to send-file or privitty_send_file

Paths are inside the container

/Users/.../Desktop/file.pdf on your Mac is not visible to the daemon. Use a container path such as /data/file.pdf.


Step 1 — Make the file available inside the container

Choose one of the three options below.

Option A — Bind mount (best for production)

Add a host folder when you start the container. Files dropped on the host appear inside the container automatically — no docker cp needed.

mkdir -p ~/privitty-outbox

docker run -d \
  --name privitty-edged \
  --restart unless-stopped \
  -e PRIVITTY_PROFILE=factory-gw-01 \
  -e PRIVITTY_LICENSE_URL="https://plm.privittytech.com/v1/license/YOUR_TOKEN" \
  -p 127.0.0.1:7200:7200 \
  -v privitty-data:/var/lib/privitty \
  -v ~/privitty-outbox:/data \
  privitty/edge:latest

Copy a file to the host folder — it is immediately at /data/ inside the container:

cp ~/Desktop/env/environmental_monitoring.pdf ~/privitty-outbox/
# Inside container: /data/environmental_monitoring.pdf

Bind mount must be set at container start

You cannot add -v ~/privitty-outbox:/data to a container that is already running. If you started without this mount, use Option B below or recreate the container (your privitty-data volume is preserved).

Mount must be writable

Do not use :ro on /data — encryption writes filename.pdf.prv alongside the original.

Option B — docker cp (quick test, container already running)

Copy a file from your Mac into the running container:

docker cp ~/Desktop/env/environmental_monitoring.pdf privitty-edged:/data/

Use the container path in the next step: /data/environmental_monitoring.pdf.

If /data does not exist yet, copy to the accounts volume instead:

docker run --rm -v privitty-data:/var/lib/privitty alpine:3.19 mkdir -p /var/lib/privitty/staging

docker cp ~/Desktop/env/environmental_monitoring.pdf \
  privitty-edged:/var/lib/privitty/staging/

# Container path: /var/lib/privitty/staging/environmental_monitoring.pdf

Option C — Stage via the named volume (no container recreate)

Copy from your Mac into privitty-data using a temporary Alpine container:

docker run --rm \
  -v privitty-data:/var/lib/privitty \
  -v "$(pwd)":/incoming:ro \
  alpine:3.19 \
  sh -c "mkdir -p /var/lib/privitty/staging && cp /incoming/environmental_monitoring.pdf /var/lib/privitty/staging/"

Container path: /var/lib/privitty/staging/environmental_monitoring.pdf


The privitty-edge send-file command inside the container performs encryption and delivery — the same as running ./privitty-edge send-file on bare metal.

docker exec privitty-edged \
  privitty-edge --accounts /var/lib/privitty send-file \
  --chat 12 \
  --file /data/environmental_monitoring.pdf \
  --message "Sending a CDR file" \
  --allow-forward \
  --duration 40

Expected output:

Sending 'environmental_monitoring.pdf' (0.0 MB) via Privitty …
  allow_download=false  allow_forward=true   duration=40 min
  Encrypted  → /data/environmental_monitoring.pdf.prv
  File ID    : 1
✓ File sent via SMTP  (msg_id=22)
Flag Meaning
--chat Chat ID from privitty-edge chats
--file Path inside the container
--message Caption sent with the attachment
--allow-forward Recipient may forward the file
--allow-download Recipient may save the decrypted file (off by default)
--duration Access window in minutes (0 = unlimited)

List chats to find the chat ID:

docker exec privitty-edged \
  privitty-edge --accounts /var/lib/privitty chats

Step 3 — Send with curl (two RPC calls)

There is no single JSON-RPC method that encrypts and sends together. Use two calls, or the CLI above.

3a — Resolve peer contact ID (chat 12, 1:1):

curl -s -X POST http://127.0.0.1:7200/rpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"get_chat_contacts","params":[1,12],"id":1}' | jq .
{"jsonrpc":"2.0","result":[1,12],"id":1}

Contact 1 is self; the other ID is the peer.

3b — Encrypt:

curl -s -X POST http://127.0.0.1:7200/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "method":"privitty_send_file",
    "params":[1,12,12,"/data/environmental_monitoring.pdf",false,true,40],
    "id":2
  }' | jq .

Params: [account_id, chat_id, peer_contact_id, path, allow_download, allow_forward, duration_minutes]

3c — Deliver (use encrypted_path from step 3b):

curl -s -X POST http://127.0.0.1:7200/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "method":"send_msg",
    "params":[1,12,{
      "text":"Sending a CDR file",
      "file":"/data/environmental_monitoring.pdf.prv",
      "viewtype":"File"
    }],
    "id":3
  }' | jq .

See Curl Cookbook · Send an encrypted file for a one-liner shell script that chains both RPC calls.


Transfer paths

File size Path Notes
Small (< ~20 MiB) Relay (IMAP/SMTP) Encrypted .prv travels as a standard attachment
Large (≥ ~20 MiB) QUIC (iroh P2P) Peer receives a QUIC offer; no send_msg attachment needed

The CLI and daemon handle path selection automatically.

Monitor progress via SSE:

curl -N http://127.0.0.1:7200/events

Look for PrivittyFileEncrypted and MsgDelivered.


Step 4 — Revoke access (optional)

docker exec privitty-edged \
  privitty-edge --accounts /var/lib/privitty revoke --msg-id 22

Or via curl — see Curl Cookbook · Revoke.


Next