Package Releases API
The Package Releases API allows you to request the release of one or more packages from eVault, download the approved exports, and acknowledge receipt.
Overview
A Package Release is the integration-facing way to paper out a package: you request a release, the Concord operations team reviews the request, and approval produces a downloadable export of the authoritative copy. Custody of the authoritative copy transfers out of eVault on the first download.
Key concepts: A Release Request is your request to release a package, reviewed by the operations team. An Export is the ZIP artifact produced when a request is approved, identified by a certificate number in format PO-{date}-{hex} (for example, PO-20260115-A7B3C9D1). Custody Transfer means the first download of the export permanently transfers custody; the package remains in eVault as a receipt copy only. Acknowledgement is your confirmation that the export was downloaded and verified, after which the export file is destroyed.
Release lifecycle
The release request (status) and its export (export.status) have separate lifecycles, and both use the value Pending at different times: a request that is Pending is awaiting review, while an approved request briefly carries an export that is Pending generation (status: "Approved", export.status: "Pending").
- Request Pending: The release request is awaiting review by the operations team.
- Request Approved: The request was approved and export generation begins; request Declined: the request was rejected with a documented reason.
- Export Pending → Processing → Ready: The export ZIP is generated and becomes downloadable.
- Export Ready → Downloaded: The first download transfers custody of the authoritative copy.
- Export Acknowledged: You confirm verified receipt; the export file is destroyed.
The export can be re-downloaded between the first download and acknowledgement. Exports expire 7 days after they become ready; expired exports are destroyed whether or not they were downloaded.
Required scopes
| Scope | Description |
|---|---|
package-releases:read | View release requests and export status |
package-releases:write | Request, export, and acknowledge releases |
package-releases | Full access (read + write) |
Request Package Releases
Submit release requests for one or more packages. Each package must be an active authoritative copy with no paper out in progress, no pending transfers, and no pending transfer batch. Eligibility is evaluated per package: ineligible packages are skipped with a documented reason and do not fail the batch.
POST /api/package-releases
Required scope: package-releases:write.
{
"vaultPackageIds": [
"3fa85f64-5717-4562-b3fc-2c963f66afa6",
"4fa85f64-5717-4562-b3fc-2c963f66afa7"
]
}
Request body
| Field | Type | Required | Description |
|---|---|---|---|
vaultPackageIds | guid[] | Yes | Package IDs to request release for. Max 25. Duplicates are ignored. |
Response (202 Accepted)
{
"createdCount": 1,
"skippedCount": 1,
"results": [
{
"vaultPackageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"releaseRequest": {
"id": "8fa85f64-5717-4562-b3fc-2c963f66afa6",
"vaultPackageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"packageName": "Loan 100234",
"status": "Pending",
"requestedByName": "My Integration Key",
"declineReason": null,
"reviewedAt": null,
"createdAt": "2026-01-15T10:30:00Z",
"export": null
},
"skipReason": null
},
{
"vaultPackageId": "4fa85f64-5717-4562-b3fc-2c963f66afa7",
"releaseRequest": null,
"skipReason": "A release request is already pending for this package."
}
]
}
releaseRequest is set for each created request — use its id to poll for approval. skipReason documents why a package was skipped (not found, not an active authoritative copy, paper out in progress, pending transfers, or a release request already pending).
Error responses: 400 — No package IDs provided, more than 25 package IDs provided, or the vault is archived; 404 — Vault not found.
Get Package Release
Retrieve a release request, including the export status once approved. Poll this endpoint after approval to learn when the export is ready.
GET /api/package-releases/{releaseRequestId}
Required scope: package-releases:read. Path parameter releaseRequestId (guid, required).
Response (200 OK)
{
"id": "8fa85f64-5717-4562-b3fc-2c963f66afa6",
"vaultPackageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"packageName": "Loan 100234",
"status": "Approved",
"requestedByName": "My Integration Key",
"declineReason": null,
"reviewedAt": "2026-01-16T09:00:00Z",
"createdAt": "2026-01-15T10:30:00Z",
"export": {
"status": "Ready",
"certificateNumber": "PO-20260116-A7B3C9D1",
"fileSizeBytes": 1048576,
"checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"expiresAt": "2026-01-23T09:05:00Z",
"downloadedAt": null,
"acknowledgedAt": null,
"canExport": true
}
}
The export object is null until the request is approved. canExport is true when the export can currently be downloaded. If the request was declined, status is Declined and declineReason documents the decision.
Error responses: 404 — Release request not found.
List Package Releases
List release requests for the vault, optionally filtered by status.
GET /api/package-releases
Required scope: package-releases:read.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | int | No | Page number (default 1) |
pageSize | int | No | Items per page (default 20) |
status | string | No | Filter: Pending, Approved, or Declined (case-insensitive) |
Response (200 OK)
{
"data": [
{
"id": "8fa85f64-5717-4562-b3fc-2c963f66afa6",
"vaultPackageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"packageName": "Loan 100234",
"status": "Pending",
"requestedByName": "My Integration Key",
"declineReason": null,
"reviewedAt": null,
"createdAt": "2026-01-15T10:30:00Z",
"export": null
}
],
"metadata": { "page": 1, "pageSize": 20, "totalCount": 1 }
}
Export Package Release
Download the approved release export as a ZIP file.
POST /api/package-releases/{releaseRequestId}/export
Required scope: package-releases:write.
This is a POST (not GET) because the first download permanently transfers custody of the authoritative copy — an irreversible state change. The response body is the ZIP file. Keys with only package-releases:read receive a 403.
Warning: The first download permanently transfers custody of the authoritative copy out of eVault. The package remains visible in eVault as a receipt copy only. The export stays downloadable until you acknowledge receipt or the download window expires.
Path parameters: releaseRequestId (guid, required).
Request body: None.
Response (200 OK): Returns the ZIP file with the following headers:
| Header | Description |
|---|---|
Content-Disposition | Attachment with generated filename |
X-Paper-Out-Certificate | The export certificate number |
X-Paper-Out-Checksum | SHA-256 checksum for integrity verification |
Best practice: Verify the downloaded file against X-Paper-Out-Checksum before acknowledging.
Error responses: 400 — Request not approved, request declined, export still generating, export expired, or export already acknowledged and destroyed; 404 — Release request not found.
Acknowledge Package Release
Confirm that the exported package was downloaded and its contents verified. The export file is destroyed in eVault; the receipt copy of the package remains for records.
POST /api/package-releases/{releaseRequestId}/acknowledge
Required scope: package-releases:write. Path parameter releaseRequestId (guid, required). Request body: none.
Response (200 OK): Returns the updated release request. export.acknowledgedAt is set and export.canExport becomes false.
Error responses: 400 — Export not yet downloaded, or already acknowledged; 404 — Release request not found.
Typical integration flow
POST /api/package-releases— request releases for one or more packages.- For each created request, poll
GET /api/package-releases/{id}untilstatusisApprovedandexport.statusisReady(or handle aDeclinedstatus usingdeclineReason). POST /api/package-releases/{id}/export— download the ZIP (custody transfers on first download).- Verify the ZIP contents against
X-Paper-Out-Checksum. POST /api/package-releases/{id}/acknowledge— confirm receipt so the export is destroyed.
Note: Exports expire 7 days after becoming ready. Download and acknowledge promptly; an expired export requires a new release request.
Next: Appendix.
