{"components":{"schemas":{"Error":{"properties":{"error":{"properties":{"code":{"description":"Stable machine-readable error code.","type":"string"},"fields":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Per-field messages. Present on validation_error only.","type":"object"},"message":{"description":"Human-readable explanation.","type":"string"},"request_id":{"description":"Quote this when contacting support.","type":"string"}},"type":"object"}},"type":"object"},"Uploader":{"properties":{"allowed_file_extensions":{"description":"File types a visitor may upload, e.g. [\"pdf\", \"docx\"]. Case and a leading dot are ignored. Null allows every type. New uploaders: null.","items":{"maxLength":20,"pattern":"^(?:\\.?[A-Za-z0-9]+(?:\\.[A-Za-z0-9]+)*)$","type":"string"},"maxItems":50,"minItems":1,"nullable":true,"type":"array"},"created":{"format":"date-time","readOnly":true,"type":"string"},"description":{"description":"Optional text under the uploader title. Plain text: HTML is shown literally, not rendered. Line breaks are kept.","maxLength":4000,"type":"string"},"email_notifications":{"description":"Send an e-mail to notification_emails after every upload. New uploaders: true.","type":"boolean"},"expires_at":{"description":"When the uploader stops accepting uploads (ISO 8601, UTC). Null never expires. A past time closes the uploader immediately.","format":"date-time","nullable":true,"type":"string"},"formkey":{"description":"Short public key used in the upload URL.","readOnly":true,"type":"string"},"google_drive_folder_id":{"description":"Id of the Google Drive folder files are collected into.","readOnly":true,"type":"string"},"google_drive_folder_name":{"description":"Name of the Google Drive folder to collect files into. Created in the root of your Drive if it is not there already; an existing folder of the same name is reused. Write-only: responses carry the resulting google_drive_folder_id instead.","maxLength":200,"minLength":1,"type":"string","writeOnly":true},"is_active":{"description":"False once the uploader has expired.","readOnly":true,"type":"boolean"},"key":{"description":"Uploader id. Use it to delete the uploader.","readOnly":true,"type":"string"},"max_file_size_mb":{"description":"Largest file a visitor may upload, in megabytes (1 MB = 1,000,000 bytes). Null allows any size. New uploaders: null.","maximum":1000000,"minimum":1,"nullable":true,"type":"integer"},"name":{"description":"Shown to visitors on the upload page.","maxLength":200,"minLength":1,"type":"string"},"notification_emails":{"description":"Who receives the upload notifications, at most 3 addresses. An empty list means your account's own address. New uploaders: your address.","items":{"maxLength":254,"pattern":"^(?:[A-Za-z0-9.+_-]+@[A-Za-z0-9._-]+\\.[A-Za-z]{2,})$","type":"string"},"maxItems":3,"type":"array"},"num_files":{"description":"Files received so far.","readOnly":true,"type":"integer"},"type":{"description":"Which kind of uploader this is. Always check it before assuming.","readOnly":true,"type":"string"},"upload_url":{"description":"The page you send visitors to.","readOnly":true,"type":"string"},"webhook_per_file":{"description":"true: one webhook call per file. false: one call per upload, listing all its files. New uploaders: false.","type":"boolean"},"webhook_url":{"description":"Public https:// URL that receives a JSON POST describing each upload (files with Drive links, folder, form answers). Null turns the webhook off. New uploaders: null.","maxLength":2000,"minLength":1,"nullable":true,"type":"string"}},"required":["google_drive_folder_name","name"],"type":"object"},"UploaderCreate":{"properties":{"allowed_file_extensions":{"description":"File types a visitor may upload, e.g. [\"pdf\", \"docx\"]. Case and a leading dot are ignored. Null allows every type. New uploaders: null.","items":{"maxLength":20,"pattern":"^(?:\\.?[A-Za-z0-9]+(?:\\.[A-Za-z0-9]+)*)$","type":"string"},"maxItems":50,"minItems":1,"nullable":true,"type":"array"},"description":{"description":"Optional text under the uploader title. Plain text: HTML is shown literally, not rendered. Line breaks are kept.","maxLength":4000,"type":"string"},"email_notifications":{"description":"Send an e-mail to notification_emails after every upload. New uploaders: true.","type":"boolean"},"expires_at":{"description":"When the uploader stops accepting uploads (ISO 8601, UTC). Null never expires. A past time closes the uploader immediately.","format":"date-time","nullable":true,"type":"string"},"google_drive_folder_name":{"description":"Name of the Google Drive folder to collect files into. Created in the root of your Drive if it is not there already; an existing folder of the same name is reused. Write-only: responses carry the resulting google_drive_folder_id instead.","maxLength":200,"minLength":1,"type":"string","writeOnly":true},"max_file_size_mb":{"description":"Largest file a visitor may upload, in megabytes (1 MB = 1,000,000 bytes). Null allows any size. New uploaders: null.","maximum":1000000,"minimum":1,"nullable":true,"type":"integer"},"name":{"description":"Shown to visitors on the upload page.","maxLength":200,"minLength":1,"type":"string"},"notification_emails":{"description":"Who receives the upload notifications, at most 3 addresses. An empty list means your account's own address. New uploaders: your address.","items":{"maxLength":254,"pattern":"^(?:[A-Za-z0-9.+_-]+@[A-Za-z0-9._-]+\\.[A-Za-z]{2,})$","type":"string"},"maxItems":3,"type":"array"},"type":{"description":"Which kind of uploader to create. Only online_uploader exists today; e-mail uploaders are managed in the admin for now.","enum":["online_uploader"],"type":"string"},"webhook_per_file":{"description":"true: one webhook call per file. false: one call per upload, listing all its files. New uploaders: false.","type":"boolean"},"webhook_url":{"description":"Public https:// URL that receives a JSON POST describing each upload (files with Drive links, folder, form answers). Null turns the webhook off. New uploaders: null.","maxLength":2000,"minLength":1,"nullable":true,"type":"string"}},"required":["google_drive_folder_name","name"],"type":"object"},"UploaderDuplicate":{"properties":{"google_drive_folder_name":{"description":"Collect the copy's files into this Google Drive folder instead of the original's. Created in the root of your Drive if needed.","maxLength":200,"minLength":1,"type":"string"},"name":{"description":"Name of the copy. Defaults to \"Copy of <original name>\".","maxLength":200,"minLength":1,"type":"string"}},"type":"object"},"UploaderList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Uploader"},"type":"array"},"next_cursor":{"description":"Pass as ?cursor= for the next page. Null on the last page.","nullable":true,"type":"string"}},"type":"object"},"UploaderUpdate":{"properties":{"allowed_file_extensions":{"description":"File types a visitor may upload, e.g. [\"pdf\", \"docx\"]. Case and a leading dot are ignored. Null allows every type. New uploaders: null.","items":{"maxLength":20,"pattern":"^(?:\\.?[A-Za-z0-9]+(?:\\.[A-Za-z0-9]+)*)$","type":"string"},"maxItems":50,"minItems":1,"nullable":true,"type":"array"},"description":{"description":"Optional text under the uploader title. Plain text: HTML is shown literally, not rendered. Line breaks are kept.","maxLength":4000,"type":"string"},"email_notifications":{"description":"Send an e-mail to notification_emails after every upload. New uploaders: true.","type":"boolean"},"expires_at":{"description":"When the uploader stops accepting uploads (ISO 8601, UTC). Null never expires. A past time closes the uploader immediately.","format":"date-time","nullable":true,"type":"string"},"google_drive_folder_name":{"description":"Name of the Google Drive folder to collect files into. Created in the root of your Drive if it is not there already; an existing folder of the same name is reused. Write-only: responses carry the resulting google_drive_folder_id instead.","maxLength":200,"minLength":1,"type":"string","writeOnly":true},"max_file_size_mb":{"description":"Largest file a visitor may upload, in megabytes (1 MB = 1,000,000 bytes). Null allows any size. New uploaders: null.","maximum":1000000,"minimum":1,"nullable":true,"type":"integer"},"name":{"description":"Shown to visitors on the upload page.","maxLength":200,"minLength":1,"type":"string"},"notification_emails":{"description":"Who receives the upload notifications, at most 3 addresses. An empty list means your account's own address. New uploaders: your address.","items":{"maxLength":254,"pattern":"^(?:[A-Za-z0-9.+_-]+@[A-Za-z0-9._-]+\\.[A-Za-z]{2,})$","type":"string"},"maxItems":3,"type":"array"},"webhook_per_file":{"description":"true: one webhook call per file. false: one call per upload, listing all its files. New uploaders: false.","type":"boolean"},"webhook_url":{"description":"Public https:// URL that receives a JSON POST describing each upload (files with Drive links, folder, form answers). Null turns the webhook off. New uploaders: null.","maxLength":2000,"minLength":1,"nullable":true,"type":"string"}},"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"du_live_...","scheme":"bearer","type":"http"}}},"info":{"description":"Manage your DriveUploader uploaders programmatically.\n\n## Authentication\n\nSend your key as a bearer token on every request:\n\n    Authorization: Bearer du_live_xxxxxxxx\n\nCreate and revoke keys in the admin under **API keys**. The key is shown once,\nat creation - store it somewhere safe, because it cannot be retrieved again.\nA key acts as the account that created it.\n\nAvailable on the **Pro** plan. A key stops working as soon as the account is no\nlonger on Pro, and starts working again after an upgrade.\n\n## Rate limits\n\n60 requests per minute per key, of which 10 may be writes (POST, PATCH,\nDELETE), and 5000 requests per day.\n\nEvery response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and\n`X-RateLimit-Reset`, describing the budget that applies to *that* request - so\na write reports your write budget, not the overall one. A 429 also carries\n`Retry-After`.\n\n## Errors\n\nEvery non-2xx response has the same body shape, with a stable `code` and a\n`request_id`. Quote the `request_id` in support requests - it is how we find\nthe exact server-side log line for your call.\n\n## Scope\n\nList, create, edit, duplicate and delete uploaders, including their expiry,\nfile limits (size and types), e-mail notifications and webhook. Everything\nelse - embedding, passwords, styling, custom form fields, linked spreadsheets\nand Document AI - is configured in the admin UI.\n\nWebhook URLs must be public `https://` addresses.\n\n**Tip:** design an uploader once in the admin - look, form fields, emails,\nlimits - and use `POST /api/v1/uploaders/{key}/duplicate` to stamp out copies.\nA copy carries everything the admin's own Duplicate button copies.\n\nDriveUploader has two kinds of uploader: the **Online file uploader**, a page\nvisitors drop files onto, and the **E-mail uploader**, which saves attachments\nsent to a generated address. Only the first is available here, as\n`type: \"online_uploader\"`. E-mail uploaders are created in the admin for now,\nand they do not appear in the list - but they will, so read each entry's\n`type` rather than assuming.","title":"DriveUploader API","version":"1.0.0"},"openapi":"3.0.3","paths":{"/api/v1/uploaders":{"get":{"description":"Newest first. Returns **every kind** of uploader you own - check each entry's `type` rather than assuming, because new kinds are added over time. An uploader shared with you through a team is not included. Deleted uploaders are filtered out after the page is read, so a page can contain fewer than `limit` items while more pages remain - keep paging until `next_cursor` is null.","parameters":[{"in":"query","name":"limit","required":false,"schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}},{"description":"The next_cursor from a previous page.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploaderList"}}},"description":"One page of uploaders."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body failed validation."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid or revoked API key."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account is not on the Pro plan."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error."}},"summary":"List your uploaders","tags":["Uploaders"]},"post":{"description":"`google_drive_folder_name` says where the files go. The folder is created in the root of your Drive if it is not there already, and an existing folder of that name is reused rather than duplicated.\n\nNote that only folders DriveUploader created are visible to it, so a folder you made by hand in Drive will not be reused - a second one of the same name is created alongside it. Move it afterwards in Drive if you like; the uploader follows the folder by id.\n\nThe new uploader gets the same defaults as one created in the admin; adjust anything else there.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploaderCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Uploader"}}},"description":"The created uploader."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body failed validation."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid or revoked API key."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account is not on the Pro plan."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Your Google account needs reconnecting."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error."}},"summary":"Create an uploader","tags":["Uploaders"]}},"/api/v1/uploaders/{key}":{"delete":{"description":"The uploader stops accepting uploads immediately. Files already collected stay in your Google Drive - nothing is removed from Drive.","responses":{"204":{"description":"Deleted."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body failed validation."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid or revoked API key."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account is not on the Pro plan."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such uploader, or not yours."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error."}},"summary":"Delete an uploader","tags":["Uploaders"]},"parameters":[{"description":"The uploader `key`, as returned by list or create.","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"patch":{"description":"Only the fields you send are changed; an empty object changes nothing. Changing `google_drive_folder_name` sends **new** uploads to that folder - files already collected stay where they are.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploaderUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Uploader"}}},"description":"The updated uploader."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body failed validation."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid or revoked API key."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account is not on the Pro plan."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such uploader, or not yours."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Your Google account needs reconnecting."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error."}},"summary":"Edit an uploader","tags":["Uploaders"]}},"/api/v1/uploaders/{key}/duplicate":{"parameters":[{"description":"The uploader to copy.","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"post":{"description":"Creates a copy with the original's settings, design, form fields, limits and notifications - the same as the Duplicate button in the admin. The copy gets a new `key` and upload URL, starts with no files and no expiry, and notifies you rather than the original's recipients.\n\nThe body is optional. Without `google_drive_folder_name` the copy collects into the same Drive folder as the original.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploaderDuplicate"}}},"required":false},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Uploader"}}},"description":"The copy."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body failed validation."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing, invalid or revoked API key."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account is not on the Pro plan."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such uploader, or not yours."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Your Google account needs reconnecting."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error."}},"summary":"Duplicate an uploader","tags":["Uploaders"]}}},"security":[{"bearerAuth":[]}],"servers":[{"url":"https://v7-dot-driveuploadercom.appspot.com"}],"tags":[{"description":"Create and manage Google Drive uploaders.","name":"Uploaders"}]}
