Skip to content

Create a note

POST/api/v1/pastes

Access
API key
Permission
content:write

Create a text note with explicit access or account defaults

Example request

curl -X POST "https://lac.pics/api/v1/pastes" \
  -H "Authorization: Bearer lac_api_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "console.log(\"hello\");",
  "format": "code",
  "language": "javascript",
  "visibility": "unlisted"
}'

Request body

application/jsonrequired

  • textstringrequired

    The note text, 1–200,000 characters.

    length 1–200,000

  • formatstring

    plain: text, markdown: Markdown, code: highlighted code.

    values: "plain" "markdown" "code"

    default "plain"

  • languagestring

    Syntax language for code format. Ignored for plain text and Markdown.

    values: "text" "javascript" "typescript" "json" "python" "bash" "css" "xml" "sql" "rust" "go" "c" "cpp" "csharp" "yaml"

    default "text"

  • tagsarray of string

    NFKC, trim, collapse spaces and lowercase; deduplicated after normalization. Raw controls are invalid. Omission preserves tags on update; an empty array clears them.

    up to 10 items · unique

  • titlestring

    Title, up to 180 characters.

    up to 180 characters

  • visibilitystring

    private is owner-only. unlisted is accessible by link. public also appears in the authenticated feed and profile. public cannot be combined with oneTime (400 ONE_TIME_NOT_PUBLIC). Omitted on creation: use the account default (private or unlisted). Omitted on update: retain current access.

    values: "private" "unlisted" "public"

  • ttlstring

    Relative to this request; forever clears expiry. Access stops at expiry; encrypted objects are removed asynchronously through a persistent retry queue.

    values: "forever" "day" "week" "month"

  • passwordstringrequest only

    8–128 characters. Empty string removes the password; omission retains it on update. Stored as Argon2id, never returned. Changing it revokes previous viewer access. Other accounts see protected content in the feed, favorites, profiles and albums only as a locked card (id, type, author, lock flags): title, tags, file name, size, dimensions, dates and previews stay hidden.

    up to 128 characters · pattern ^(?:[\s\S]{8,128})?$

  • oneTimeboolean

    Only the first guest browser to explicitly open the share page receives access, for at most 10 minutes (including video Range requests). Owner previews and GET/HEAD do not consume the link. Omission retains the setting on update. Cannot be combined with visibility public: the resulting state is checked on creation and update (400 ONE_TIME_NOT_PUBLIC). Other accounts never see one-time content in the feed, profiles or albums.

    default false

Responses

  • 201SuccessCreated
    • idstringrequired

      The file id.

    • titlestringrequired

      Title, up to 180 characters.

    • tagsarray of stringrequired

      NFKC, trim, collapse spaces and lowercase; deduplicated after normalization. Raw controls are invalid. Omission preserves tags on update; an empty array clears them.

      up to 10 items · unique

    • originalNamestring

      The original file name.

    • typestringrequired

      IMAGE, VIDEO, PASTE or FOLDER (a folder of code).

      values: "IMAGE" "VIDEO" "PASTE" "FOLDER"

    • mimestringrequired

      The MIME type of the stored file.

    • pasteFormatstringor null

      values: "plain" "markdown" "code"

    • pasteLanguagestringor null
    • folderFilesintegeror null

      A code folder (type FOLDER): files in its archive. Null for other kinds. The archive itself is the media: GET /api/media/{id} serves it (Range requests read one file by the ZIP central directory), ?download=1 as an attachment.

      at least 1

    • revisionintegerrequired

      Optimistic revision for editing saved paste text; distinct from share access version.

      at least 1

    • accessVersionintegerrequired

      Share access version: 1 for a new file, raised by every change of visibility, password or one-time. From 2 on, url carries it as ?v= so messengers build a fresh link card instead of the one they kept for the previous access.

      at least 1

    • sizeinteger · int64required

      Size in bytes.

    • visibilitystringrequired

      private is owner-only. unlisted is accessible by link. public also appears in the authenticated feed and profile. public cannot be combined with oneTime (400 ONE_TIME_NOT_PUBLIC). Omitted on creation: use the account default (private or unlisted). Omitted on update: retain current access.

      values: "private" "unlisted" "public"

    • allowDownloadbooleanrequired
    • passwordProtectedbooleanrequired
    • oneTimebooleanrequired
    • consumedAtstring · date-timeor null
    • readExpiresAtstring · date-timeor null
    • readMaxExpiresAtstring · date-timeor null
    • hasVideoTextboolean
    • videoTextRevisioninteger

      0–2,147,483,647

    • viewsintegerrequired

      Explicit guest opens, deduplicated during the viewer grant (normally 24 hours). Owner previews are excluded.

      at least 0

    • viewLimitintegeror null

      Link control (Pro, plan feature view_limit): after this many counted views the link answers like an expired one (404 SHARE_UNAVAILABLE) to everyone but the owner and viewers still holding the grant of their counted open. Media of a limited file is served only after an explicit open (POST /api/share/{id}/open), so direct media links and link cards cannot bypass the count. Null: no limit.

      1–1,000,000

    • viewLimitReachedAtstring · date-timeor null

      When the view limit was used up; null while views remain or without a limit.

    • mediaStatusstring

      New videos are processed asynchronously. Playback and previews require READY. The owner may explicitly download the original with ?download=1 while PROCESSING or FAILED; it is returned as an application/octet-stream attachment.

      values: "PROCESSING" "READY" "FAILED"

    • mediaErrorstringor null

      The reason when processing failed.

    • widthintegeror null

      Width in pixels.

    • heightintegeror null

      Height in pixels.

    • durationMsintegeror null

      Video duration in milliseconds.

    • videoCodecstringor null
    • hasAudioboolean
    • previewUrlstringor null

      Encrypted derived preview served with the same access checks as the source.

    • expiresAtstring · date-timeor null
    • createdAtstring · date-timerequired

      When it was created.

    • urlstring · urirequired

      The file page to share: {WEB_ORIGIN}/s/{id}, with ?v={accessVersion} once access changed (the page ignores the parameter; older links keep working).

    • mediaUrlstringrequired

      The address of the file itself.

    • moderationHoldstringor null

      Automatic check: review — hidden from everyone but the owner until a moderator decides; blocked — kept hidden by a moderator. Others get such a file exactly like a private one, so only the owner ever sees a non-null value.

      values: "review" "blocked"

    • favoriteboolean

      Present in list responses

    • ownedboolean

      Present in list responses

    • authorobject
      3 fields
      • idstring

        The author’s id.

      • usernamestring
      • namestring
    • contentContent

      same as Content above

  • 400Invalid inputONE_TIME_NOT_PUBLIC
  • 401Authentication required
  • 403Insufficient scope
  • 404Content unavailable
  • 409Media processing, upload idempotency or paste revision conflict
  • 410Previously uploaded content was deleted or expired
  • 413Size or quota limit
  • 429Rate limit, or the account already uses all its upload slots
  • 503Upload or password verification capacity reached

Example response

201 · application/json
{
  "id": "Xq3u9RkT0bLmA7cV2pWz1eFy",
  "title": "capture",
  "tags": [
    "release"
  ],
  "originalName": "capture.png",
  "type": "IMAGE",
  "mime": "image/png",
  "pasteFormat": null,
  "pasteLanguage": null,
  "folderFiles": 1,
  "revision": 1,
  "accessVersion": 1,
  "size": 482133,
  "visibility": "unlisted",
  "allowDownload": true,
  "passwordProtected": false,
  "oneTime": false,
  "consumedAt": null,
  "readExpiresAt": null,
  "readMaxExpiresAt": null,
  "hasVideoText": false,
  "videoTextRevision": 0,
  "views": 3,
  "viewLimit": null,
  "viewLimitReachedAt": null,
  "mediaStatus": "READY",
  "mediaError": null,
  "width": 1920,
  "height": 1080,
  "durationMs": null,
  "videoCodec": null,
  "hasAudio": false,
  "previewUrl": null,
  "expiresAt": null,
  "createdAt": "2026-09-27T09:30:00.000Z",
  "url": "https://lac.pics/s/Xq3u9RkT0bLmA7cV2pWz1eFy",
  "mediaUrl": "/api/media/Xq3u9RkT0bLmA7cV2pWz1eFy",
  "moderationHold": null,
  "favorite": false,
  "owned": true,
  "author": {
    "id": "cmf8a1x2k0000q7lh3v9w2e4d",
    "username": "alex",
    "name": "Alex"
  }
}

Error codes

CodeStatusMessage
ONE_TIME_NOT_PUBLIC400A one-time file cannot be published in the feed and profile. Choose link access or turn off the one-time link.

Answers of any method with a key (an invalid or expired key, a missing permission, too many requests) are in Errors.

Create a note: POST /api/v1/pastes · lacuna API