Skip to main content
Participant
November 5, 2025
Question

PDF services API - No AWSAccessKey was presented

  • November 5, 2025
  • 1 reply
  • 91 views

I am doing some testing with Adobe PDF services APIs and everything seems to be working, but I get an error that says "Job completed but no downloadUri found" and when I look into .\last-status.json I see an error that says "AccessDenied" "No AWSAccessKey was presented". 

 

I am using the code on the Adobe site with the tokens and keys provided on the Adobe Developer Console. 

 

I'm not sure what I am doing wrong. If anyone could help me out that would be great. 

    1 reply

    Adobe Employee
    November 5, 2025

    Please provide the code you are using. Your decription is too vague.

    Participant
    November 6, 2025

    I am using a powershell script

    <#
    .SYNOPSIS
    Convert a single local HTML file to PDF using Adobe PDF Services REST API (end-to-end).

    .DESCRIPTION
    Steps:
    1) Obtain (or use) an access token
    2) POST /assets (mediaType=text/html) to get uploadUri + assetID
    3) PUT your HTML to the pre-signed uploadUri (S3) — no auth header
    4) POST /operation/htmltopdf with assetID and options
    5) Poll Location until 'done', then GET downloadUri and save the PDF

    .REFERENCES
    - Getting Started (token, assets, upload, submit, poll, download)
    https://developer.adobe.com/document-services/docs/overview/pdf-services-api/gettingstarted/
    - Html-to-PDF operation (request body fields)
    https://developer.adobe.com/document-services/apis/pdf-services/html-to-pdf/
    - Presigned URL expiry + null download links (SDK utilities and notes)
    https://developer.adobe.com/document-services/docs/overview/pdf-services-api/howtos/sdk-utilities/
    #>

    [CmdletBinding()]
    param(
    # Use EITHER ClientId+ClientSecret (recommended) OR AccessToken
    [string]$ClientId = '75ffed95fa9a4eb182551f2b18c0a862',
    [string]$ClientSecret = 'p8e-CYFQ5Wrn2xHUEYImOsfj6L8Ile4GhXOb',
    [string]$AccessToken = 'eyJhbGciOiJSUzI1NiIsIng1dSI6Imltc19uYTEta2V5LWF0LTEuY2VyIiwia2lkIjoiaW1zX25hMS1rZXktYXQtMSIsIml0dCI6ImF0In0.eyJpZCI6IjE3NjIzNTI4NDYzMTVfMzVmNDAyYjgtNTMzMS00MjQ1LWJmZWQtMDM3MjM3ZTQzMzM5X3VlMSIsIm9yZyI6IjIxNzgyMkQyNjkwQTE3MzkwQTQ5NUMxQkBBZG9iZU9yZyIsInR5cGUiOiJhY2Nlc3NfdG9rZW4iLCJjbGllbnRfaWQiOiI3NWZmZWQ5NWZhOWE0ZWIxODI1NTFmMmIxOGMwYTg2MiIsInVzZXJfaWQiOiI1N0Y2MjJDRDY5MEI1RTgyMEE0OTVDMDRAdGVjaGFjY3QuYWRvYmUuY29tIiwiYXMiOiJpbXMtbmExIiwiYWFfaWQiOiI1N0Y2MjJDRDY5MEI1RTgyMEE0OTVDMDRAdGVjaGFjY3QuYWRvYmUuY29tIiwiY3RwIjozLCJtb2kiOiIzNjU1N2IxYSIsImV4cGlyZXNfaW4iOiI4NjQwMDAwMCIsInNjb3BlIjoiRENBUEksb3BlbmlkLEFkb2JlSUQiLCJjcmVhdGVkX2F0IjoiMTc2MjM1Mjg0NjMxNSJ9.QCXuNvETk4WqooiUpboL7uDsXtLUlLNGZIbpe8Yc8V3-LJw1CcglFmoCxyRdzaqDeZKtDfqMw_QeY0Xatsw_boFiL_15Kl3YgzNSIlafT0LPaXnb_I-FY1qt3792Lo7Q3QgzMQ7h0kMqIcawafi8yzj-ZIiEBOQVS2My203sTrGJxYabfw0dZEaM1j69-obsWgA1z1ouk2LXXwcvdUeb2l9y6ZgrvIvm-ed9Jd3VuFuF7xbVQwb5_cZCPsVwOaHB2Cxtwu-qZqWk9ogsgDG3db3kpAs2k-LcQZlwfMt0gKBvWAPpU7QkbDDW1lsntn4V8f75R5WVRlOIHvjv-ISBVQ',

    # Required: path to your local .html/.htm file
    [Parameter(Mandatory=$true)]
    [ValidateScript({ Test-Path -LiteralPath $_ })]
    [string]$HtmlPath,

    # Required: where to save the PDF (e.g., .\out\file.pdf)
    [Parameter(Mandatory=$true)]
    [string]$OutputPdf,

    # Optional Html-to-Pdf settings
    [switch]$IncludeHeaderFooter,
    [double]$PageWidthInches = 11,
    [double]$PageHeightInches = 8.5,
    [int]$WaitTimeToLoadMs = 100,

    # If your HTML expects a JSON string for dynamic data, pass it here
    [string]$JsonData = '{}',

    # Advanced / overrides
    [string]$ApiBase = 'https://pdf-services.adobe.io',
    [int]$PollSeconds = 2,
    [int]$GlobalTimeoutSec = 300
    )

    # ---------------- Helpers ----------------
    function Info($m){ Write-Host $m -ForegroundColor Cyan }
    function Ok($m){ Write-Host $m -ForegroundColor Green }
    function Warn($m){ Write-Host $m -ForegroundColor Yellow }
    function Err($m){ Write-Host $m -ForegroundColor Red }

    try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {}

    # Validate inputs
    $ext = [IO.Path]::GetExtension($HtmlPath).ToLower()
    if ($ext -notin @('.html','.htm')) { throw "HtmlPath must be a .html or .htm file." }
    $mediaType = 'text/html'

    # 1) Get/verify access token
    if (-not $AccessToken) {
    if (-not $ClientId -or -not $ClientSecret) {
    throw "Provide -ClientId and -ClientSecret (or set ADOBE_API_KEY/ADOBE_CLIENT_SECRET), or pass -AccessToken."
    }
    Info "Requesting access token…"
    # POST /token (x-www-form-urlencoded) with client_id & client_secret (Adobe docs)
    $tokenResp = Invoke-RestMethod `
    -Uri "$ApiBase/token" -Method Post `
    -Headers @{ 'Content-Type' = 'application/x-www-form-urlencoded' } `
    -Body "client_id=$ClientId&client_secret=$ClientSecret"
    $AccessToken = $tokenResp.access_token
    if (-not $AccessToken) { throw "Failed to obtain access token." }
    Ok "Access token acquired."
    } else {
    Info "Using provided access token."
    }

    if (-not $ClientId) {
    throw "ClientId is required for the 'x-api-key' header on Adobe API calls."
    }

    $commonHeaders = @{
    'x-api-key' = $ClientId
    'Authorization' = "Bearer $AccessToken"
    }

    # 2) Create asset (POST /assets) → uploadUri + assetID
    Info "Creating asset (mediaType: $mediaType)…"
    $assetBody = @{ mediaType = $mediaType } | ConvertTo-Json
    $assetResp = Invoke-RestMethod `
    -Uri "$ApiBase/assets" -Method Post `
    -Headers ($commonHeaders + @{ 'Content-Type' = 'application/json' }) `
    -Body $assetBody

    $uploadUri = $assetResp.uploadUri
    $assetId = $assetResp.assetID
    if (-not $uploadUri -or -not $assetId) { throw "Asset creation failed (no uploadUri/assetID returned)." }
    Ok "Asset created. assetID: $assetId"

    # 3) Upload HTML via pre-signed S3 URL (PUT uploadUri)
    # IMPORTANT:
    # * Use uploadUri exactly as returned; do not decode/alter the query string.
    # * Do NOT send Authorization here; S3 auth is baked into the URL's X-Amz-* params.
    # * Set only Content-Type to the same mediaType passed to /assets.
    Info "Uploading HTML to pre-signed URL…"
    $null = Invoke-WebRequest `
    -Uri $uploadUri `
    -Method Put `
    -InFile $HtmlPath `
    -ContentType $mediaType `
    -Headers @{} # keep empty to avoid accidental auth or extra headers
    Ok "Upload complete."

    # 4) Submit Html-to-PDF job (POST /operation/htmltopdf)
    Info "Submitting Html-to-PDF job…"
    $jobPayload = [ordered]@{
    assetID = $assetId
    json = $JsonData
    includeHeaderFooter = [bool]$IncludeHeaderFooter
    pageLayout = @{
    pageWidth = $PageWidthInches
    pageHeight = $PageHeightInches
    }
    waitTimeToLoad = $WaitTimeToLoadMs
    } | ConvertTo-Json -Depth 6

    $submit = Invoke-WebRequest `
    -Uri "$ApiBase/operation/htmltopdf" -Method Post `
    -Headers ($commonHeaders + @{ 'Content-Type' = 'application/json' }) `
    -Body $jobPayload

    if ($submit.StatusCode -notin @(201,202)) {
    Err "Unexpected submit status: $($submit.StatusCode)"
    if ($submit.Content) { Write-Host $submit.Content }
    throw "Job submission failed."
    }
    $location = $submit.Headers['Location']
    if (-not $location) { throw "No Location header returned from job submit." }
    Ok "Job submitted. Polling: $location"

    # 5) Poll for completion, then locate and download the PDF
    $deadline = (Get-Date).AddSeconds($GlobalTimeoutSec)
    $statusUrl = $location

    function Get-DownloadUriFromStatus($s) {
    # Persist status for diagnostics
    $s | ConvertTo-Json -Depth 20 | Out-File -FilePath ".\last-status.json" -Encoding utf8

    $du = $null
    if ($s.PSObject.Properties.Name -contains 'downloadUri') { $du = $s.downloadUri }
    if (-not $du -and $s.result) { $du = $s.result.downloadUri }
    if (-not $du -and $s.result -and $s.result.asset) { $du = $s.result.asset.downloadUri }
    if (-not $du -and $s.result -and $s.result.assets -and $s.result.assets.Count -gt 0) {
    $du = $s.result.assets[0].downloadUri
    }
    return $du
    }

    function Get-ResultAssetId($s) {
    $aid = $null
    if ($s.asset -and $s.asset.assetID) { $aid = $s.asset.assetID }
    if (-not $aid -and $s.result -and $s.result.asset -and $s.result.asset.assetID) {
    $aid = $s.result.asset.assetID
    }
    if (-not $aid -and $s.result -and $s.result.assets -and $s.result.assets.Count -gt 0 -and $s.result.assets[0].assetID) {
    $aid = $s.result.assets[0].assetID
    }
    return $aid
    }

    do {
    Start-Sleep -Seconds $PollSeconds
    $status = Invoke-RestMethod -Uri $statusUrl -Method Get -Headers $commonHeaders
    Write-Host (" status: {0}" -f $status.status)
    if ($status.status -eq 'failed') {
    Err "Job failed."
    if ($status.error) { $status.error | ConvertTo-Json -Depth 10 | Write-Host }
    throw "Conversion failed."
    }
    if ((Get-Date) -gt $deadline) { throw "Timed out after ${GlobalTimeoutSec}s waiting for job completion." }
    } while ($status.status -ne 'done')

    # Try to locate the downloadUri in multiple shapes
    $downloadUri = Get-DownloadUriFromStatus $status

    # If missing, retry once (presigned URLs may be null or need a refreshed status)
    if (-not $downloadUri) {
    Warn "downloadUri not present. Retrying status once to refresh…"
    Start-Sleep -Seconds 1
    $status = Invoke-RestMethod -Uri $statusUrl -Method Get -Headers $commonHeaders
    $downloadUri = Get-DownloadUriFromStatus $status
    }

    if (-not $downloadUri) {
    $resultAssetId = Get-ResultAssetId $status
    if ($resultAssetId) {
    Warn "Job returned result AssetID = $resultAssetId but no downloadUri. Presigned URLs can expire or be null; retry or new status may be required."
    }
    throw "Job completed but no downloadUri found. See .\last-status.json for full response."
    }

    # Ensure output folder exists, then download
    $folder = Split-Path -Parent $OutputPdf
    if ($folder -and -not (Test-Path -LiteralPath $folder)) { New-Item -ItemType Directory -Path $folder | Out-Null }

    Info "Downloading PDF…"
    Invoke-WebRequest -Uri $downloadUri -OutFile $OutputPdf
    Ok "Saved PDF to: $OutputPdf"

    Inspiring
    November 19, 2025