Contents
Credentials
As part of the setup process we need to exchange credentials and URLs. These need to be communicated with your Adway contact over a trusted channel.
Supplied by you
Endpoint URL | Where we POST deliveries. Must be HTTPS on a public hostname. |
Signing secret | At least 16 characters. We use it to sign every delivery so you can verify that it came from us. |
Bearer token | At least 64 characters. We send it back to you as an |
Supplied by Adway
|
|
API access token | A signed token you present to read applications and download files. |
Environment | Test |
At least one of the secret or the token is required.
Receiving webhooks
A delivery fires when an application reaches an event that is broadcasted.
Webhook payload
The delivery tells you which application changed and what happened to it.
POST /your/endpoint HTTP/1.1
Content-Type: application/json
Authorization: Bearer <your 64+ char token>
X-Adway-Timestamp: 1789012345678
X-Adway-Delivery: 9f2c1e7b4d8a…
X-Hub-Signature-256: sha256=4a7d9c…
{
"version": 2,
"event": "APPLICATION_QUALIFIED",
"applicationId": "6712aaaaaaaaaaaaaaaaaaaa",
"customerId": "6100aaaaaaaaaaaaaaaaaaaa"
}Field | Meaning |
| Payload version. Currently |
| Trigger event. See below. |
| Affected application's ID. |
Events
Event | Sent when |
| The first time an application qualifies. |
Delivery headers
Header | Sent when | Meaning |
| Always | Milliseconds since the Unix epoch, taken at the moment of this attempt. Part of the signed material. |
| Always | Identifies one delivery across its retries. Retries of the same delivery repeat this value. |
| You gave a secret |
|
| You gave a token |
|
Verifying a delivery
When you supply a secret, every delivery carries X-Hub-Signature-256. The signature is an HMAC-SHA256 over the timestamp and the raw body joined by a single period, hex encoded and prefixed with sha256=.
# signed material
"<X-Adway-Timestamp>" + "." + "<exact raw request body>"
# expected header value
"sha256=" + hex(hmac_sha256(secret, signed_material))
In order to verify the payload, sign the raw bytes you received. Parsing the JSON and re-serializing it will change key order or whitespace and the signature will not match.
const crypto = require("node:crypto");
function isGenuine(rawBody, headers, secret) {
const timestamp = headers["x-adway-timestamp"];
const received = headers["x-hub-signature-256"];
if (!timestamp || !received) return false;
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const a = Buffer.from(received);
const b = Buffer.from(expected);
// Constant-time compare; lengths must match first.
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Responses & retries
We expect status 200 on a successful delivery.
A failed delivery is retried a limited number of times with exponential backoff. We retry 5xx, 408, 429 and connection failures. Any other 4xx is treated as a permanent rejection and is not retried.
Idempotency
X-Adway-Delivery identifies an individual webhook event across retries/deliveries.
Application API
The API is provided to allow fetching additional data, such as the sensitive information supplied by the applicant, including the attached/generated files.
Authorization: Bearer <your Adway access token>
Get an application
GET https://connect.adway.ai/api/external-api/v2/applications/{id}{id} is the applicationId from the delivery. The response is the application data with file metadata.
{
"id": "6712aaaaaaaaaaaaaaaaaaaa",
"customerId": "6100aaaaaaaaaaaaaaaaaaaa",
"jobPostId": "6650aaaaaaaaaaaaaaaaaaaa",
"atsJobId": "REQ-4711",
"state": "created",
"isQualified": true,
"rating": 0.82,
"score": 4,
"age": 34,
"utmSource": "linkedin",
"registrationForm": {
"fullName": "Ada Lovelace",
"email": "[email protected]",
"phone": "+46700000000",
"completedAt": "2026-09-01T08:00:00.000Z",
"upsertedToAtsAt": "2026-09-01T08:05:00.000Z"
},
"files": [
{
"id": "kK3rW1vQ0nS7bT2xY9pL",
"name": "cv.pdf",
"size": 182734,
"extension": "pdf",
"type": "cv"
},
{
"id": "aB8mN2cV5xZ1qW4eR7tY",
"name": "cover letter.docx",
"size": 20481,
"extension": "docx",
"type": "coverLetter"
},
{
"id": "pQ6yU3iO9aS2dF5gH8jK",
"name": "nursing-licence.pdf",
"size": 90112,
"extension": "pdf",
"type": "attachment"
},
{
"id": "zX4cV7bN1mQ8wE2rT5yU",
"name": "Adway Smart CV - Ada Lovelace.pdf",
"size": 241664,
"extension": "pdf",
"type": "smartCV"
}
],
"screeningQuestions": [
{
"id": "6700aaaaaaaaaaaaaaaaaaaa",
"title": "Do you hold a valid nursing licence?",
"answer": true,
"formattedAnswer": "Yes",
"upsertedToAtsAt": "2026-09-01T08:05:00.000Z"
}
],
"questions": [
{
"question": "Do you hold a valid nursing licence?",
"type": "Boolean",
"answer": true,
"source": "ScreeningQuestion"
},
{
"question": "Years of experience?",
"type": "Number",
"answer": "7",
"source": "LeadAd"
}
],
"enrichmentData": {
"cvParser": {
"name": "Ada Lovelace",
"title": "Registered Nurse",
"email": "[email protected]",
"phone": "+46700000000",
"linkedinProfile": "https://www.linkedin.com/in/ada",
"dateOfBirth": { "year": 1992, "month": 4, "day": 17 },
"location": {
"city": "Umeå",
"region": "Västerbotten",
"country": "Sweden",
"postalCode": "90325"
},
"skills": ["Triage", "Paediatrics"],
"otherQualifications": ["Driving licence B"],
"spokenLanguages": [
{ "language": "Swedish", "proficiency": "Native" }
],
"workHistory": [
{
"position": "Registered Nurse",
"company": "Norrlands universitetssjukhus",
"companyLogo": null,
"location": { "city": "Umeå", "country": "Sweden" },
"startDate": { "year": 2019, "month": 8, "day": 1 },
"endDate": null,
"responsibilities": ["Triage", "Ward rounds"]
}
],
"internships": [],
"educationHistory": [
{
"institution": "Umeå universitet",
"institutionLogoUrl": null,
"degree": "BSc Nursing",
"description": null,
"fields": ["Nursing"],
"location": { "city": "Umeå", "country": "Sweden" },
"startDate": { "year": 2015, "month": 9, "day": 1 },
"endDate": { "year": 2018, "month": 6, "day": 5 }
}
],
"references": [
{
"name": "Charles Babbage",
"position": "Ward Manager",
"company": "Norrlands universitetssjukhus",
"email": "[email protected]",
"phone": "+46700000001"
}
]
},
"linkedinProfile": {
"name": "Ada Lovelace",
"title": "Registered Nurse",
"username": "ada",
"profileUrl": "https://www.linkedin.com/in/ada",
"profileImageUrl": "https://media.example.com/ada.jpg",
"description": "Nurse with seven years in acute care.",
"location": { "city": "Umeå", "country": "Sweden" },
"skills": ["Triage"],
"spokenLanguages": [],
"workHistory": [],
"internships": []
}
}
}This response contains sensitive personal data.
Rate limits
Responses carry the standard RateLimit-* headers.
Downloading files
The application response lists file metadata. Fetch the actual file(s) through the endpoint below:
GET https://connect.adway.ai/api/external-api/v2/applications/{id}/files/{fileId}{fileId} is the id of an entry in the application's files array. The response is the document itself as application/octet-stream, with Content-Disposition and Content-Length set.
curl -fL \
-H "Authorization: Bearer $ADWAY_TOKEN" \
-o cv.pdf \
"https://connect.adway.ai/api/external-api/v2/applications/$ID/files/$FILE_ID"
File field | Meaning |
| File ID that you want to download. |
| Original file name, as uploaded or generated. |
| Size in bytes. |
|
|
| File source. See below. |
Type | Origin | What it is |
| Candidate | The CV as uploaded. |
| Candidate | The cover letter as uploaded. |
| Candidate | Any further document they attached. There can be several. |
| Adway | A generated, standardised CV. |
| Adway | A plain-text rendering, useful for parsing. |
| Adway | The candidate's documents merged into one PDF. |
Generated files are replaced, not versioned. When a smart, plain or consolidated CV is regenerated it gets a new id and the old one stops resolving. If a download returns 404, please fetch the application again and use the current list rather than retrying the stale ID.
Errors
Failures come back as JSON with a single error field.
Status | Means | What to do |
400 | The application or file ID is not a well-formed identifier. | Send the IDs exactly as they appear in the delivery and the application response. |
401 | Token missing, expired, revoked, or lacking the required permission. | Check the header is present and unaltered, then ask us to confirm the token's permissions. |
403 | The access token is not fully configured. | Misconfiguration on our side. Contact us. |
404 | No such application or file. | Confirm the ID is one we sent you, and that a generated CV has not since been replaced. |
429 | Hourly rate limit reached. | Back off and retry using the |
502 | An Adway service behind the API is unavailable. | Transient issue. Please retry with a backoff and tell us if it persists. |
Going live
Setup up an HTTPS endpoint that answers
2xxon properly validated deliveries.Generate a signing secret and a bearer token, at least 16 and 64 characters respectively. Send them and the URL to your Adway contact via a trusted channel.
We register the webhook and issue your API access token for a test.
Ask us for a test delivery and confirm that your receiver verifies the signature, rejects a tampered body, and records the
applicationIdas needed.Fetch that application from
/v2/applications/{id}, then fetch one of its files, to prove your access token and both paths work end to end.
Regarding questions, a new secret, or a token that needs revoking: contact your Adway representative. The interactive API reference is at https://connect.adway.ai/api/external-api/v2/swagger/, and on test at https://connect-test.adway.ai/api/external-api/v2/swagger/.
