Download a user data export
GET /v1/jobs/user-exports/{job_id}/download · permission users:export
Gives a single-use link to the package of a completed user data export. Every call writes a user_export.downloaded record to the management audit log before the link is issued.
Request
| Parameter | In | Required | Description |
|---|---|---|---|
job_id |
path | yes | Job id, prefixed job_. |
A job created with include_ip: true also requires audit-events:read_ip on the downloading credential.
Response
302 Found with an empty body. Location is a relative link on the same host, /downloads/user-exports/{environment_id}/{job_id}/{token}. The response carries Cache-Control: no-store and Referrer-Policy: no-referrer.
- The link is valid for 15 minutes and works once: the token is spent on the first request, even if the transfer is interrupted. Call this operation again for a new link.
- The link needs no credentials; the token is the only credential. Keep
Locationsecret and do not log it. - The file is encrypted at rest with the environment's key, so no storage presigned URL is used; KeenAuth decrypts and streams it.
Following the link with GET returns 200 OK with Content-Type: application/zip, Content-Length and Content-Disposition: attachment; filename="user-export-job_….zip". HEAD is refused with 405 so that link previews do not spend the token. Compare the SHA-256 of the file with file.sha256 of the job. If the connection ends before Content-Length bytes arrive, the package is incomplete; discard it and request a new link. An invalid, used or expired link returns 404 not_found.
Errors
Every error is an application/problem+json body with a stable code.
| HTTP | code |
When |
|---|---|---|
| 401 | unauthenticated |
The API key is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The key lacks users:export, or the job was created with include_ip and the key lacks audit-events:read_ip (required_permissions lists both). |
| 404 | not_found |
The job does not exist, belongs to another environment, or the id is malformed. On the link: the token is invalid, used or expired. |
| 409 | conflict |
The job is not completed yet, or its file has expired. |
| 429 | rate_limited |
The rate limit was exceeded; honor Retry-After. The link itself allows 10 requests per minute per IP address. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry later. |
Example
curl -L -o user-export.zip \
https://api.eu.keenauth.com/v1/jobs/user-exports/job_01j9xk3m7q8r2s4t6v8w0y2z4e/download \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
The CLI follows the link itself, writes the package to a file (never to standard output), refuses to overwrite an existing file and prints the size and SHA-256 of what it wrote:
keenauth jobs user-exports download job_01j9xk3m7q8r2s4t6v8w0y2z4e --file user-export.zip
Personal data
This endpoint carries personal data: end-user profile. Personal data in the KeenAuth APIs describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.