I. Overview
This document provides guidelines for integrating with the External API using a secure service-to-service mechanism.
The API is designed for partners to retrieve job information and resume application data in a controlled, authenticated, and monitored manner.
Important: All API requests must be authenticated using a Client Key and Client Secret, and access is restricted by IP whitelisting.
II. Environment & Base URL
The API is available in two environments:
| Environment | Purpose | Base URL |
|---|---|---|
| Sandbox | Testing, integration verification | https://openapi.vl24hv2.staging.sieuviet-team.com/integration |
| Production | Live production traffic | https://openapi.vieclam24h.vn/integration |
III. API Versioning
The API supports versioning via URL path.
Current supported version: v1
Future versions may introduce changes without breaking backward compatibility.
IV. Authentication Mechanism
1. Client Credentials
Each partner is issued a unique pair of credentials:
- client-key
- client-secret
These credentials must be included in every API request via request headers.
Required Headers
| Header Name | Type | Description |
|---|---|---|
| client-key | string | Partner identifier |
| client-secret | string | Secret key for authentication |
2. Purpose of Client Credentials
The Client Key and Client Secret are used to:
- Authenticate the request source
- Identify the partner system
- Control API access permissions
- Apply rate limiting
- Enable request logging and monitoring
- Prevent unauthorized or invalid requests
V. IP Whitelisting (Service-to-Service Security)
To ensure secure communication, this API uses IP whitelisting.
1. Whitelisted IP Requirement
Only requests originating from registered IP addresses are allowed to access the API. If a request comes from a non-whitelisted IP, the server will reject it even if credentials are valid.
2. IP Whitelisting Process
Partners must provide the following information:
- Static public IP address(es) of the calling service
- Environment (Sandbox / Production)
- Partner system name
Note: Dynamic IPs are not recommended for service-to-service integration.
VI. How to Obtain client-key & client-secret
1. Requesting API Access
To obtain API credentials, partners must send an email request to the Vieclam24h team.
Email information required:
- Company name
- Contact person
- Email & phone number
- Target environment (Sandbox / Production)
- Public IP address(es) for whitelisting
2. Credential Issuance
After verification, the Vieclam24h team will provide:
- Client key
- Client Secret
- Partner code
- Confirmed environment access
- Whitelisted IP confirmation
Security: Credentials are sent privately via email and must be kept confidential.
3. Request Flow (Service-to-Service)
|
| (client-key + client-secret + Whitelisted IP + Partner code)
↓
External API Gateway
|
| Authentication & Authorization
| Rate limit & Logging
↓
Business Services
VII. API Endpoints Detail
1. Get Job
Summary: Retrieve basic information about a job.
Description: Returns basic details of a job based on the provided job identifier.
Request
GET /ex/api/v1/partners/{partner-code}/jobs
| Type | Params | Values |
|---|---|---|
| HEAD | client-secret | string |
| HEAD | client-key | string |
| QUERY | page | integer |
| QUERY | per_page | integer |
Response
| Status | Response |
|---|---|
| 200 | { "items": [Job], "pagination": Pagination } |
| 403 | {"error":"Permission denied."} |
| 401 | {"error":"Incorrect Client-key or client-secret."} |
| 429 | {"error":"Too Many Requests."} |
| 500 | {"error":"Something went wrong. Please try again later."} |
Job Object
| Field | Type | Description |
|---|---|---|
| id | integer | Unique job identifier |
| channelCode | string | Job posting channel code |
| title | string | Job title |
| titleSlug | string | URL-friendly slug of the job title |
| levelRequirement | string | Required job level or qualification |
| provinces | array[string] | List of provinces/cities where the job is located |
| districts | array[string] | List of districts where the job is located |
| occupations | array[string] | List of job categories/occupations |
| vacancyQuantity | integer | Number of positions to be filled |
| workingMethod | string | Working method (e.g., On-site, Remote, Hybrid) |
| experienceRange | string | Required experience range |
| salaryMin | integer | Minimum salary |
| salaryMax | integer | Maximum salary |
| salaryRange | string | Display salary range |
| status | string | Job status |
| createdAt | string | Creation date |
| updatedAt | string | Last updated |
| totalViews | integer | Total number of views |
| totalResumeApplied | integer | Total number of submitted applications |
| jobRequirement | string | Job requirements |
| otherRequirement | string | Additional requirements |
Pagination Object
| Field | Type | Description |
|---|---|---|
| current | integer | Current page |
| before | integer | Previous page |
| next | integer | Next page |
| last | integer | Last page |
| totalPages | integer | Total number of pages |
| totalItems | integer | Total number of records |
2. Get Job Detail
Summary: Retrieve basic information for a specific job.
Description: Returns the essential details of a job identified by the provided job ID. This endpoint is intended for displaying job summaries and basic job information without extended or sensitive data.
Request
GET /ex/api/v1/partners/{partner-code}/jobs/{job-id}
| Type | Params | Values |
|---|---|---|
| HEAD | client-secret | string |
| HEAD | client-key | string |
| PATH | job-id | integer |
| PATH | partner-code | string |
Response
| Status | Response |
|---|---|
| 200 | {job object} |
| 403 | {"error":"Permission denied."} |
| 401 | {"error":"Incorrect Client-key or client-secret."} |
| 429 | {"error":"Too Many Requests."} |
| 500 | {"error":"Something went wrong. Please try again later."} |
3. Get Job Resume Applied by Job ID
Summary: Get resumes applied to a job.
Description: Returns a list of candidate resumes associated with the specified job ID. This endpoint allows employers or authorized systems to review applications submitted for a particular job, including basic resume and application information.
Request
GET /ex/api/v1/partners/{partner-code}/jobs/{job-id}/resume-applied
| Type | Params | Values |
|---|---|---|
| HEAD | client-secret | string |
| HEAD | client-key | string |
| PATH | job-id | integer |
| PATH | partner-code | string |
| QUERY | page | integer |
| QUERY | per_page | integer |
Response
| Status | Response |
|---|---|
| 200 | { "items": [Resume applied], "pagination": Pagination } |
| 403 | {"error":"Permission denied."} |
| 401 | {"error":"Incorrect Client-key or client-secret."} |
| 429 | {"error":"Too Many Requests."} |
| 500 | {"error":"Something went wrong. Please try again later."} |
Resume Applied Object
| Field | Type | Description |
|---|---|---|
| id | integer | Unique identifier of the job application |
| channelCode | string | Channel code where the application was submitted |
| jobId | integer | Identifier of the job |
| employerId | integer | Identifier of the employer |
| resumeId | integer | Identifier of the resume |
| seekerId | integer | Identifier of the candidate (job seeker) |
| fileName | string | Resume file name |
| fileNameUrl | string | Public URL to download resume file |
| appliedAt | string | Application submission time (ISO 8601) |
| isNew | integer | Indicates whether the application is new (1 = new, 0 = viewed) |
| appliedStatus | integer | Application status code |
| createdAt | string | Record creation time |
| updatedAt | string | Last update time |
| seekerInfo | object | Candidate basic information |
| resumeInfo | object | Resume detail information |
Seeker Info Object
| Field | Type | Description |
|---|---|---|
| id | integer | Candidate identifier |
| name | string | Full name of the candidate |
| channelCode | string | Candidate channel code |
| mobile | integer | Candidate phone number |
| string | Candidate email address | |
| gender | integer | Gender code |
| maritalStatus | integer | Marital status code |
| address | string | Candidate address |
| birthday | integer | Birthday (timestamp) |
| resumeStatus | integer | Resume status |
| avatar | string | Avatar image URL |
Resume Info Object
| Field | Type | Description |
|---|---|---|
| id | integer | Resume identifier |
| seekerId | integer | Candidate identifier |
| title | string | Resume title |
| channelCode | string | Resume channel |
| slug | string | Resume slug |
| minExpectedSalary | integer | Minimum expected salary |
| experience | integer | Years of experience |
| level | integer | Career level |
| currentPosition | integer | Current position code |
| point | integer | Resume score |
| fieldIds | array[string] | Industry/field identifiers |
| provinceIds | array[string] | Preferred working locations |
| resumeType | integer | Resume type |
| lastRevisionStatus | integer | Last revision status |
| statusCombine | integer | Combined status |
| diploma | string | Education level |
| language | string | Languages |
| experienceInfo | array[string] | Experience summary |
4. Get List Resume Applied
Summary: Retrieve a list of applied resumes.
Description: Fetches a list of resumes that have been applied to jobs.
Request
GET /ex/api/v1/partners/{partner-code}/resume-applied
| Type | Params | Values |
|---|---|---|
| HEAD | client-secret | string |
| HEAD | client-key | string |
| PATH | partner-code | string |
| QUERY | page | integer |
| QUERY | per_page | integer |
Response
| Status | Response |
|---|---|
| 200 | { "items": [Resume applied], "pagination": Pagination } |
| 403 | {"error":"Permission denied."} |
| 401 | {"error":"Incorrect Client-key or client-secret."} |
| 429 | {"error":"Too Many Requests."} |
| 500 | {"error":"Something went wrong. Please try again later."} |
Note: This endpoint returns the same Resume Applied Object, Seeker Info Object, Resume Info Object, and Pagination Object structures as described in endpoint #3 above.