<!--
{
  "availability" : [

  ],
  "documentType" : "symbol",
  "framework" : "Tor",
  "identifier" : "/documentation/Tor/TorControlClient/addOnion(key:ports:detach:)",
  "metadataVersion" : "0.1.0",
  "role" : "Instance Method",
  "symbol" : {
    "kind" : "Instance Method",
    "modules" : [
      "Tor"
    ],
    "preciseIdentifier" : "s:3Tor0A13ControlClientC8addOnion3key5ports6detachAA0E7ServiceVAA0E7KeySpecO_SayAA0E11PortMappingVGSbtYaKF"
  },
  "title" : "addOnion(key:ports:detach:)"
}
-->

# addOnion(key:ports:detach:)

Register an ephemeral v3 onion service via `ADD_ONION`
(control-spec.txt §3.27).

```
func addOnion(key: OnionKeySpec, ports: [OnionPortMapping], detach: Bool = false) async throws -> OnionService
```

## Parameters

`key`

Key policy. See [`OnionKeySpec.newV3(discardPrivateKey:)`](/documentation/Tor/OnionKeySpec/newV3(discardPrivateKey:))
for Tor-generated keys or [`OnionKeySpec.providedV3(_:)`](/documentation/Tor/OnionKeySpec/providedV3(_:))
to re-adopt a persisted key.

`ports`

One or more virtual-port → target mappings. Use
[`toLocalPort(_:localPort:)`](/documentation/Tor/OnionPortMapping/toLocalPort(_:localPort:)) for the
common loopback case.

`detach`

Whether to detach the service from this
connection. Defaults to `false`.

## Return Value

A fresh [`OnionService`](/documentation/Tor/OnionService) record. Its
[`privateKey`](/documentation/Tor/OnionService/privateKey) is populated iff `key` was
[`OnionKeySpec.newV3(discardPrivateKey:)`](/documentation/Tor/OnionKeySpec/newV3(discardPrivateKey:)) with
`discardPrivateKey: false` or
[`OnionKeySpec.providedV3(_:)`](/documentation/Tor/OnionKeySpec/providedV3(_:)) (in which case it echoes the
supplied key).

## Discussion

Serialises `ADD_ONION <keyType> [Flags=…] Port=… Port=…` from
the provided [`OnionKeySpec`](/documentation/Tor/OnionKeySpec) and [`OnionPortMapping`](/documentation/Tor/OnionPortMapping) array,
sends it, parses the reply with
[`parseAddOnionResponse(_:)`](/documentation/Tor/ControlProtocolParser/parseAddOnionResponse(_:)-rg89),
and wraps the result in an [`OnionService`](/documentation/Tor/OnionService) with a fresh
`createdAt` timestamp.

### Lifecycle

- `detach: false` (default) — service is tied to **this**
  control connection and removed when the socket closes.
  Ideal for request-scoped services (e.g. a one-shot file
  transfer).
- `detach: true` — `Detach` flag is added; service persists
  until explicit ``doc://Tor/documentation/Tor/TorControlClient/delOnion(_:)-7ei4o`` or Tor exit. Ideal
  for long-lived services that outlive the launching process.

> Throws: ``doc://Tor/documentation/Tor/TorError/controlProtocolError(code:message:)`` on
> rejection, ``doc://Tor/documentation/Tor/TorError/invalidResponse(_:)`` on malformed
> reply, or ``doc://Tor/documentation/Tor/TorError/serviceAlreadyExists(_:)`` when a
> duplicate key is submitted (Tor reply 550/554).

> Important: ``doc://Tor/documentation/Tor/OnionService/privateKey`` is secret material.
> Persist only via Keychain (Apple) or an equivalent
> credential store.