# .sparku Files and Import

> .sparku format, what it doesn't include, POST /v1/imports and sparku import, user consent, risks.

## .sparku format

An integration export is its schema without secrets: name, address, fields, island and card
styling, control elements. The file is plain JSON:

```json
{
  "format": "sparku.integration",
  "version": 1,
  "integration": {
    "slug": "deploy",
    "name": "Deploy",
    "icon": "shippingbox.fill",
    "accent": "blue",
    "fields": [
      {"key": "progress", "type": "progress", "label": "Progress"},
      {"key": "stage", "type": "state", "label": "Stage", "states": [
        {"id": "running", "label": "Running", "icon": "arrow.triangle.2.circlepath", "color": "blue"},
        {"id": "done", "label": "Done", "icon": "checkmark.circle.fill", "color": "success"},
        {"id": "failed", "label": "Failed", "icon": "xmark.octagon.fill", "color": "error"}
      ]},
      {"key": "title", "type": "text", "label": "Service", "maxLength": 60}
    ],
    "valueLifetime": null,
    "island": {"...": "indicator and text settings"},
    "card": {"...": "template, slots, control elements"}
  }
}
```

**Not included in the file:** `id`, `createdAt`, `isEnabled`, and of course the token — an
imported integration always gets a new one. Only the user creates the schema: the file carries
what they've already configured, not a script's right to build the interface itself (see
[Concepts](/docs/api/concepts.md)).

File size limit is 512 KB: an integration is dozens of fields and templates, not megabytes.
A file saved by a newer SparkU version (`version` higher than supported) is rejected with a
request to update the app.

## Export

A button in the integration editor's header (Settings → Custom Integrations → `slug`) saves
the file `<address>.sparku` (name is the integration name, transliterated to address).

## Import in Settings

"+" → "Import from file…" opens a `.sparku` from disk. SparkU shows a consent screen: who is
offering the integration, what will appear on the island and in the card, and separately — which
control elements open URLs, run commands, or launch Shortcuts. A taken address (`slug`) is renamed to an available one —
`deploy` → `deploy-2`.

Double-clicking a `.sparku` file in Finder opens the same screen — SparkU is registered as
the owner of the file type. If Custom Integrations are turned off, SparkU opens the
Integrations section and asks you to turn them on first.

## `POST /v1/imports`

Same endpoint, but initiated by a script or installer: the request body is the contents of
the `.sparku` file as-is (not a JSON wrapper, the file itself). No token needed — the
integration doesn't exist yet.

```bash
curl --unix-socket ~/.sparku/run/api.sock \
  --data-binary @deploy.sparku \
  http://sparku/v1/imports
```

The request **blocks** until the user opens Settings and answers the offer — SparkU opens that
section itself. Consent:

```json
{"slug": "deploy", "name": "Deploy", "token": "spk_9f2c...a31b"}
```

Status `201 Created`. Refusal — `403 import_declined`. While another offer is already waiting
for an answer (from settings or another request), a new `POST /v1/imports` gets `409 import_pending` immediately, without waiting.

If SparkU closes or the API is disabled while a request is waiting — `503 withdrawn`.
A file that fails schema validation (as in the editor) — `422 invalid_package`.

## `sparku import`

```bash
sparku import deploy.sparku
```

Waits for consent just like a direct `POST /v1/imports`, and prints to stdout the token export line:

```
export SPARKU_TOKEN_DEPLOY=spk_9f2c...a31b
```

So an installer script does:

```bash
eval "$(sparku import deploy.sparku)"
sparku push deploy progress=0
```

User refusal — exit code `77` (permission denied, like invalid token); in all other cases
codes are regular `sparku`, see [sparku CLI](/docs/api/cli.md#exit-codes).

## Risks

Importing `.sparku` is trust in someone else's configuration, not their code: the file itself
is not executed, but control elements in it can be set to **run commands** on this Mac when
tapped in the card (action "Run command" or "Launch Shortcut"). The import screen shows such
elements explicitly — with the command text or Shortcuts name — before the user agrees.
Read them as carefully as you would a command line from an email.

Control elements with "send event to listener" action are safe in themselves: they only
report a tap to whoever ran `sparku listen` — they can't execute anything without a separate
listener.

> [!WARNING]
> Don't run `sparku import` and don't open `.sparku` files from sources you don't trust,
> even if the import screen showed no risks: URLs in "Open" elements are also worth checking
> before you tap the button on the island.

## Response codes

| Code | HTTP | When |
|---|---|---|
| — | 201 | user agreed, integration added |
| `import_declined` | 403 | user refused the offer |
| `import_pending` | 409 | SparkU is already waiting for an answer to another offer |
| `invalid_package` | 422 | file is not in `.sparku` format or fails schema validation |
| `withdrawn` | 503 | SparkU closed or API was disabled while waiting |
