openonce

API

Бесплатный, без ключей, с ограничением частоты запросов по IP. Шифруйте на своей стороне, а мы сохраним байты.

Базовый URL

https://api.openonce.link/api/v1
POST/secrets

Создать секрет

Возвращает идентификатор и время истечения.

Запрос

{
  "content": "ciphertext-or-plaintext",
  "ttl": "1d",
  "ttlSeconds": 3600,
  "views": 1,
  "password": null,
  "notifyChannel": "webhook",
  "notifyTo": "https://hooks.slack.com/services/...",
  "label": "prod db password",
  "kind": "text",
  "fileMeta": "{\"name\":\"config.env\",\"size\":2048,\"type\":\"text/plain\"}"
}

Ответ

{
  "id": "8f3kQ2mVxL",
  "expiresAt": "2026-08-08T12:04:11.000Z",
  "views": 1,
  "hasPassword": false,
  "notifyOnRead": true
}
GET/secrets/:id/meta

Проверить секрет

Сообщает, жив ли ещё секрет и сколько просмотров осталось. Просмотр при этом не расходуется.

Ответ

{
  "id": "8f3kQ2mVxL",
  "alive": true,
  "viewsLeft": 1,
  "viewsTotal": 2,
  "expiresAt": "2026-08-08T12:04:11.000Z",
  "hasPassword": false,
  "kind": "text"
}
POST/secrets/:id/reveal

Показать секрет

Расходует один просмотр и возвращает сохранённое содержимое. Это необратимо.

Запрос

{
  "password": null
}

Ответ

{
  "content": "ciphertext-or-plaintext",
  "viewsLeft": 0,
  "kind": "file",
  "fileMeta": "{\"name\":\"config.env\",\"size\":2048,\"type\":\"text/plain\"}"
}
DELETE/secrets/:id

Уничтожить секрет

Удаляет секрет до того, как его кто-либо прочитает.

Ответ

{
  "destroyed": true
}

Отправка файлов

Укажите kind: "file" и передайте fileMeta как JSON-строку с name, size и type. Байты идут в content, как и любые другие данные — шифруйте их сами. Учтите: fileMeta хранится как есть, поэтому не помещайте секреты в имя файла.

Уведомления о сгорании

Передайте notifyChannel и notifyTo при создании секрета, и мы вызовем ваш эндпоинт в момент прочтения. Полезная нагрузка никогда не содержит сам секрет.

POST https://your-app.com/hook
X-Openonce-Event: secret.revealed
X-Openonce-Timestamp: 1786412651
X-Openonce-Signature: sha256=9f86d081884c7d65...

{
  "event": "secret.revealed",
  "secretId": "8f3kQ2mVxL",
  "occurredAt": "2026-08-07T17:45:47.797Z",
  "viewsLeft": 0,
  "label": "prod db password"
}
Проверка подписи

Каждый запрос несёт подпись HMAC-SHA256 по timestamp.rawBody. Сравнивайте её за постоянное время, прежде чем доверять полезной нагрузке.

const expected = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(`${timestamp}.${rawBody}`)
  .digest('hex');

const isValid = crypto.timingSafeEqual(
  Buffer.from(signature.replace('sha256=', '')),
  Buffer.from(expected),
);

Командная строка

Отправьте что угодно в ссылку, не покидая терминал.

npx openonce "my api key" --ttl 1h --views 2

Ограничения частоты

Лимиты действуют на каждый IP-адрес. При превышении возвращается 429, пока окно не сбросится.

Создание секретов10 за 60 с
Все остальные эндпоинты30 за 60 с

Ошибки

Ошибки используют стандартные коды статуса с телом JSON, содержащим код ошибки и понятное человеку сообщение.

{
  "statusCode": 404,
  "error": "Not Found",
  "code": "SECRET_NOT_FOUND",
  "message": "This secret does not exist or has already been destroyed."
}
400CONTENT_TOO_LARGE
400INVALID_NOTIFICATION_TARGET
401PASSWORD_REQUIRED
401WRONG_PASSWORD
404SECRET_NOT_FOUND
429ThrottlerException