Quickstart

Add phone and desktop uploads to a form in minutes: create a project, add a session endpoint, attach the widget.

How the pieces fit

  • Your backend holds a secret API key (sk_…) and exposes a session endpoint. It authenticates your own user, decides the file policy and calls CrossUpload.
  • The widget calls your session endpoint when the picker opens, receives short-lived session credentials, and uploads directly to private storage.
  • Your form receives accepted file IDs in a hidden field. Your backend validates them before attaching them to a record.
Never put a secret API key in HTML, JavaScript, a QR code or logs. Public project identifiers (pk_…) cannot create sessions.

1. Create a project and key

  1. Create an account. A first project is created for you.
  2. In Dashboard → Projects, add your website’s origins (for example https://www.example.com), allowed file types, size limit and default files per session.
  3. In Dashboard → API keys, create a key for that project. It is shown once; store it in your server’s secret manager.

2. Add a session endpoint

Your endpoint calls POST /v1/sessions and returns the JSON response to the browser. Minimal example with curl:

curl -X POST https://app.crossupload.com/v1/sessions \
  -H "Authorization: Bearer $CROSSUPLOAD_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: application-42-attempt-1" \
  -d '{"externalReference":"user:17:application:42","maxFiles":3,"origin":"https://www.example.com","locale":"en"}'

See Session endpoint (Rust/Axum) for a complete server example that authenticates users and applies server-owned limits.

3. Attach the widget

<form method="post" action="/applications">
  <button type="button" id="upload">Upload a file</button>
  <input type="hidden" id="attachments" name="attachment_ids" value="[]">
  <button type="submit">Submit application</button>
</form>
<script src="https://app.crossupload.com/v1/widget.js"></script>
<script>
  const uploader = CrossUpload.attach({
    target: '#upload',
    mode: 'picker',
    sessionEndpoint: '/api/crossupload/session',
    resultInput: '#attachments',
    locale: 'en',
    maxFiles: 3,
    onComplete({ files }) { console.log('accepted', files); },
    onError(error) { console.error(error.code, error.message); }
  });
</script>

4. Validate on submit

When the form posts, attachment_ids contains a JSON array like [{"id":"file_…","sessionId":"ses_…", …}]. Do not trust it. For each ID call GET /v1/files/{id} with your secret key and check that status is ready, sessionId is a session you created for this user, and externalReference matches the record. Then store the file ID.

Need the file later? Call POST /v1/files/{id}/url for a fresh temporary URL. See Files, URLs & retention.

Try it

The live demo runs this exact flow against a server-owned demo project.


Something unclear or wrong? Email [email protected].