Download OpenAPI specification:
This documentation details the API for the Sourceflow platform.
Where endpoints require authentication, it will be marked as OAuth2.0. Authentication uses the client credentials flow of OAuth 2.0. See https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow for more information.
The token endpoint is /_sf/api/oauth/token.json. Authenticated endpoints require an
Authorization header with the value Bearer TOKEN, where TOKEN is a UUID valid for 1 hour.
Obtain a Bearer token using the OAuth 2.0 client credentials flow.
The returned token is valid for 1 hour and must be included in subsequent
authenticated requests as Authorization: Bearer TOKEN.
| grant_type required | string Value: "client_credentials" |
| client_id required | string Your OAuth2 client ID |
| client_secret required | string Your OAuth2 client secret |
{- "grant_type": "client_credentials",
- "client_id": "your-client-id",
- "client_secret": "your-client-secret"
}{- "access_token": "5b83dc8e-b95b-4c68-9e94-368a63e4b4f3",
- "token_type": "bearer",
- "expires_in": 3599
}[- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
]Create a new job posting. external_reference and url_slug must be unique. Set skip_webhook: true in the top-level body to suppress job webhooks.
required | object (JobInput) |
| skip_webhook | boolean Skip firing job webhooks for this request. |
{- "job": {
- "title": "A Fantastic Job Title",
- "description": "<p>A fantastic job description</p>",
- "external_reference": "JOB-12345",
- "url_slug": "1234-fantastic-job"
}, - "skip_webhook": true
}{- "action": "create",
- "status": 0,
- "job": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
}If a job with the given external_reference exists it will be updated;
otherwise a new job will be created. Returns an action field indicating
whether the record was created or updated. Set skip_webhook: true in the top-level body to suppress job webhooks.
required | object (JobInput) |
| skip_webhook | boolean Skip firing job webhooks for this request. |
{- "job": {
- "title": "A Fantastic Job Title",
- "description": "<p>A fantastic job description</p>",
- "external_reference": "JOB-12345",
- "url_slug": "1234-fantastic-job",
- "location": "10 Downing St, London SW1A 2AA",
- "city": "London",
- "country": "United Kingdom",
- "expires_at": "2025-01-01Z12:00:00",
- "displayed_posting_date": "2022-09-30Z12:00:00",
- "external_application_email": "applications@mybestwebsite.com",
- "salary_package": "£20 per hour + free doughnuts",
- "salary_low": 1000,
- "salary_high": 100000,
- "featured": true,
- "consultant_name": "Joe Bloggs",
- "consultant_email": "j.bloggs@rec.rec",
- "origin": "my_ats_system",
- "draft": false,
- "is_scheduled": true,
- "scheduled_at": "2025-06-01T09:00:00Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
]
}, - "skip_webhook": true
}{- "action": "create",
- "status": 0,
- "job": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
}Same upsert behaviour as /jobs/update_or_create.json but accepts
human-readable category names (e.g. sector names) instead of UUIDs.
Use /jobs/simplified_categories.json to retrieve the available names.
Set skip_webhook: true in the top-level body to suppress job webhooks.
required | object (SimplifiedJobInput) Simplified job creation/update using category names instead of UUIDs |
| skip_webhook | boolean Skip firing job webhooks for this request. |
{- "job": {
- "title": "string",
- "description": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "expires_at": "string",
- "displayed_posting_date": "string",
- "external_application_email": "user@example.com",
- "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "featured": true,
- "consultant_name": "string",
- "consultant_email": "user@example.com",
- "origin": "string",
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "string",
- "sectors": [
- "string"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "string"
], - "regions": [
- "string"
]
}, - "skip_webhook": true
}{- "action": "create",
- "status": 0,
- "job": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
}Partially update an existing job. Only fields included in the payload will be changed.
Setting a field to null will clear its value.
The {jobId} can be either the external_reference used when creating the job,
or the Sourceflow UUID returned on creation. Set skip_webhook: true in the top-level body to suppress job webhooks.
| jobId required | string Sourceflow UUID or external_reference of the job |
required | object (JobInput) |
| skip_webhook | boolean Skip firing job webhooks for this request. |
{- "job": {
- "title": "A Fantastic Job Title",
- "description": "<p>A fantastic job description</p>",
- "external_reference": "JOB-12345",
- "url_slug": "1234-fantastic-job",
- "location": "10 Downing St, London SW1A 2AA",
- "city": "London",
- "country": "United Kingdom",
- "expires_at": "2025-01-01Z12:00:00",
- "displayed_posting_date": "2022-09-30Z12:00:00",
- "external_application_email": "applications@mybestwebsite.com",
- "salary_package": "£20 per hour + free doughnuts",
- "salary_low": 1000,
- "salary_high": 100000,
- "featured": true,
- "consultant_name": "Joe Bloggs",
- "consultant_email": "j.bloggs@rec.rec",
- "origin": "my_ats_system",
- "draft": false,
- "is_scheduled": true,
- "scheduled_at": "2025-06-01T09:00:00Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
]
}, - "skip_webhook": true
}{- "action": "create",
- "status": 0,
- "job": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
}Permanently delete a job from the website and search index. This cannot be undone and will remove the job's web page (potentially breaking existing links).
If you only want to hide a job, use PATCH to set expires_at to a date in the past.
The {jobId} can be either the external_reference or the Sourceflow UUID.
| jobId required | string Sourceflow UUID or external_reference of the job |
Check whether a job's page has been published and is publicly accessible. When a job is first created there is a short delay before the page is live. Poll this endpoint to know when the job is available.
| id required | string Example: id=09605 The external_reference or Sourceflow UUID of the job |
{- "published": true
}Returns jobs similar to a specified job, based on category matching.
| job_id required | string The external_reference or Sourceflow UUID of the source job |
{- "jobs": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
]
}Search and filter the job index. Supports text queries, category filters,
and commute-time filtering. Pagination is supported via page_token.
object |
{- "job_search": {
- "query": "finance",
- "filters": {
- "14db7d92-f95c-4d19-bd4f-213db3419dd5": [
- "a53cb5f4-05ad-4a26-91a2-625c97ca95d0"
]
}, - "commute_filter": {
- "commute_method": 1,
- "start_coordinates": {
- "latitude": 53.4791821,
- "longitude": -2.2463738
}, - "travel_duration": {
- "seconds": 2400
}
}, - "page_token": null
}
}{- "jobs": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "title": "string",
- "description": "string",
- "summary": "string",
- "image": "string",
- "external_reference": "string",
- "url_slug": "string",
- "location": "string",
- "city": "string",
- "country": "string",
- "addresses": [
- "string"
], - "salary_package": "string",
- "salary_low": 0,
- "salary_high": 0,
- "external_application_email": "string",
- "external_application_url": "string",
- "featured": true,
- "draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "consultant_name": "string",
- "consultant_email": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "published_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "categories": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "values": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
], - "sectors": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "employment_types": [
- "string"
], - "salary_bands": [
- "string"
], - "consultants": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "regions": [
- "string"
], - "pay_period": [
- "string"
], - "hybrid_working": [
- "string"
]
}
], - "page_token": "string"
}Returns all job categories with their metadata.
[- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
}
]Returns all categories in a simplified format designed for use with the
/jobs/update_or_create_simplified.json endpoint. Keys match the field
names accepted by that endpoint.
{- "sectors": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "employment_types": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "salary_bands": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "consultants": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "regions": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "pay_period": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
], - "hybrid_working": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "parent": "42e2bc1b-6741-4e2e-b138-97b4a342c999"
}
]
}Returns detailed information for a single category including all of its values.
| categoryId required | string <uuid> UUID of the category |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}object (DynamicPageInput) |
{- "dynamic_page": {
- "title": "string",
- "url_slug": "/about",
- "is_draft": true,
- "metadata": { },
- "seo": {
- "title": "string",
- "description": "string",
- "keywords": "string",
- "canonical": "string",
- "robots": "string",
- "open_graph": {
- "image": null
}, - "alternate": {
- "url": "string",
- "hreflang": "string"
}, - "json_schema": "string"
}, - "content": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "component": "JobSearchBannerImagesA",
- "props": { }
}
], - "dynamic_page_module_assignments_attributes": [
- { }
]
}
}| pageId required | string <uuid> UUID of the page to update |
object (DynamicPageInput) |
{- "dynamic_page": {
- "title": "string",
- "url_slug": "/about",
- "is_draft": true,
- "metadata": { },
- "seo": {
- "title": "string",
- "description": "string",
- "keywords": "string",
- "canonical": "string",
- "robots": "string",
- "open_graph": {
- "image": null
}, - "alternate": {
- "url": "string",
- "hreflang": "string"
}, - "json_schema": "string"
}, - "content": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "component": "JobSearchBannerImagesA",
- "props": { }
}
], - "dynamic_page_module_assignments_attributes": [
- { }
]
}
}[- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]Creates a new CMS category with a defined schema.
| dataset_id | string <uuid> |
| name required | string |
| description | string |
required | Array of objects (CmsCategorySchemaField) |
| has_template | boolean |
| url_pattern | string |
| identifier required | string |
| job_categorisation | boolean |
| is_job_categorisation_required | boolean |
| is_nested | boolean |
| default_sort_field | string |
| default_sort_direction | string Enum: "ASC" "DESC" |
| simplified_api_name | string |
| category_type | Array of strings |
| locked_values | boolean |
{- "dataset_id": "8c4c51f1-f6f3-43bc-b65d-7415e8ef22c0",
- "name": "string",
- "description": "string",
- "schema": [
- {
- "name": "string",
- "data_type": "text",
- "default_value": null,
- "description": "string",
- "isRequired": true,
- "isMulti": true,
- "dropdown_values": [
- "string"
], - "object_entries": [
- { }
], - "foreign_category_id": "5ebc966d-f868-4084-9fd1-5ea7af2afa6c"
}
], - "has_template": true,
- "url_pattern": "string",
- "identifier": "string",
- "job_categorisation": true,
- "is_job_categorisation_required": true,
- "is_nested": true,
- "default_sort_field": "string",
- "default_sort_direction": "ASC",
- "simplified_api_name": "string",
- "category_type": [
- "string"
], - "locked_values": true
}{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns a specific CMS category by ID, including its schema and all values.
| categoryId required | string <uuid> UUID of the CMS category |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Replaces the definition of an existing CMS category including its schema.
| categoryId required | string <uuid> UUID of the CMS category |
| dataset_id | string <uuid> |
| name required | string |
| description | string |
required | Array of objects (CmsCategorySchemaField) |
| has_template | boolean |
| url_pattern | string |
| identifier required | string |
| job_categorisation | boolean |
| is_job_categorisation_required | boolean |
| is_nested | boolean |
| default_sort_field | string |
| default_sort_direction | string Enum: "ASC" "DESC" |
| simplified_api_name | string |
| category_type | Array of strings |
| locked_values | boolean |
{- "dataset_id": "8c4c51f1-f6f3-43bc-b65d-7415e8ef22c0",
- "name": "string",
- "description": "string",
- "schema": [
- {
- "name": "string",
- "data_type": "text",
- "default_value": null,
- "description": "string",
- "isRequired": true,
- "isMulti": true,
- "dropdown_values": [
- "string"
], - "object_entries": [
- { }
], - "foreign_category_id": "5ebc966d-f868-4084-9fd1-5ea7af2afa6c"
}
], - "has_template": true,
- "url_pattern": "string",
- "identifier": "string",
- "job_categorisation": true,
- "is_job_categorisation_required": true,
- "is_nested": true,
- "default_sort_field": "string",
- "default_sort_direction": "ASC",
- "simplified_api_name": "string",
- "category_type": [
- "string"
], - "locked_values": true
}{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}| keyword | string Example: keyword=test Keyword to filter categories by name |
[- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "identifier": "string",
- "category_values": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]Creates a new value in the specified CMS category. Keys in schema_attributes
must match the field names defined in the category's schema.
form fields: pass the UUID of the formcategory fields: pass the UUID of a value from the referenced categoryobject fields: pass an array of objects, each with a generated UUID and field valuesfile fields: reference files by field name in the top-level files object, providing a filename and base64-encoded content| categoryId required | string <uuid> UUID of the category |
object | |
object File attachments keyed by the file field name as defined in the category schema | |
| attachments_to_delete | Array of strings IDs of existing attachments to remove |
{- "category_value": {
- "schema_attributes": { },
- "url_slug": "string",
- "is_draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "order": 0
}, - "files": {
- "property1": {
- "filename": "string",
- "base64_file_data": "string"
}, - "property2": {
- "filename": "string",
- "base64_file_data": "string"
}
}, - "attachments_to_delete": [
- "string"
]
}{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Replaces the data for an existing category value. Keys in schema_attributes
must match the field names defined in the category's schema.
Pass attachment IDs in attachments_to_delete to remove existing files.
Add new files via the files object using base64-encoded content.
| categoryId required | string <uuid> UUID of the category |
| categoryValueId required | string <uuid> UUID of the category value to update |
object | |
object File attachments keyed by the file field name as defined in the category schema | |
| attachments_to_delete | Array of strings IDs of existing attachments to remove |
{- "category_value": {
- "schema_attributes": { },
- "url_slug": "string",
- "is_draft": true,
- "is_scheduled": true,
- "scheduled_at": "2019-08-24T14:15:22Z",
- "order": 0
}, - "files": {
- "property1": {
- "filename": "string",
- "base64_file_data": "string"
}, - "property2": {
- "filename": "string",
- "base64_file_data": "string"
}
}, - "attachments_to_delete": [
- "string"
]
}{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "name": {
- "property1": "string",
- "property2": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Placement is located by external_placement_id. If found it will be updated;
otherwise a new placement record is created.
object (PlacementInput) |
{- "placement": {
- "record_type": "candidate",
- "external_placement_id": "PLC-775544",
- "form_name": "string",
- "form_id": "string",
- "flat_fee": "8000.0",
- "candidate_name": "string",
- "candidate_email": "user@example.com",
- "job_title": "string",
- "employment_type": "string",
- "company_name": "string",
- "category": "string",
- "speciality": "string",
- "date_added": "string",
- "date_begin": "string",
- "date_submitted": "string",
- "time_to_place": 0,
- "candidate_source": "string",
- "lead_source": "string",
- "campaign_source": "string",
- "job_id": "string",
- "lead_id": "string",
- "client_id": "string",
- "contact_id": "string",
- "skills": [
- "string"
], - "business_sectors": [
- "string"
], - "corporate_users": [
- "user@example.com"
]
}
}Creates a webhook that fires when subscribed events occur.
Supports job_application and form_submission event types in any combination.
For form_submission triggers, omit form_id to receive all form submissions,
or set it to restrict to a specific form. Use excluded_form_ids to receive all
submissions except from specific forms (set form_id to null in this case).
Custom headers are included in every outgoing webhook POST and can be used for recipient-side authentication.
object (WebhookInput) |
{- "webhook": {
- "name": "Testing Webhook",
- "triggers": [
- {
- "type": "job_application",
- "origin_filter": "myats"
}, - {
- "type": "form_submission",
- "form_id": "c6285151-9175-4314-ad33-002e8f8bc188"
}, - {
- "type": "form_submission"
}, - {
- "type": "form_submission",
- "excluded_form_ids": [
- "44bc4d97-a162-48d4-967c-e67dfaef8ddb"
], - "form_id": null
}
], - "custom_headers": {
- "X-API-Key": "123abc"
}
}
}Resends a previously fired webhook event using its event_id. Any expiring URLs
or signatures in the payload are refreshed. Events can be retriggered for up to
90 days after they were first sent.
| event_id required | string <uuid> |
{- "event_id": "5897f650-ee24-4862-9f22-ddc6a19cedb1"
}Send emails via the Sourceflow platform, optionally from reusable templates.
The template workflow has three steps: create a template from a JSON configuration of
components (POST /email_templates.json), list templates to discover the Liquid parameters
each one needs (GET /email_templates.json), then send an email referencing the template_id
and supplying those parameters (POST /emails/send_email.json). Raw html_body sends are still
supported and require no template.
Creates a reusable email template from a JSON configuration of components and their options.
A template is an ordered list of component "blocks"; each block names a component (key) and
supplies that component's options (props). The available components and their valid prop keys
are defined per-site (published to the site's component library). The header and footer are
rendered automatically and must not be included in the config.
On save, the system scans the fully-assembled template (all components plus the props) for Liquid
{{ variable }} placeholders and records the distinct set in the returned parameters — these
are the values a caller must supply when sending with this template. Site-level variables that
are filled automatically (site.name, site.url, unsubscribe_url) are excluded.
Requires the email_templates/write permission.
required | object |
{- "email_template": {
- "name": "Application received",
- "email_type": "job_application",
- "template_json": [
- {
- "key": "hero-banner",
- "props": {
- "heading": "Thanks for applying",
- "bgColor": "#0055cc"
}
}, - {
- "key": "text-block",
- "props": {
- "body": "Hi {{ candidate.name }}, we received your application for {{ job.title }}."
}
}, - {
- "key": "cta-button",
- "props": {
- "ctaText": "View job",
- "ctaUrl": "{{ job.url }}"
}
}
]
}
}{- "id": "5f1c…",
- "name": "Application received",
- "email_type": "job_application",
- "parameters": [
- "candidate.name",
- "job.title",
- "job.url"
]
}Lists every email template for the current site, including the parameters each one needs.
Use the returned parameters to discover which variable names to pass to parameters on the
send endpoint. An empty array means the template needs no caller-supplied parameters.
Requires the email_templates/read permission.
[- {
- "id": "5f1c…",
- "name": "Application received",
- "email_type": "job_application",
- "parameters": [
- "candidate.name",
- "job.title",
- "job.url"
]
}
]Returns a single template by id, including its full component config (template_json) — use
this to load a saved template into an editor before updating it. Unlike the list endpoint
(GET /email_templates.json), which returns only metadata and parameters, this response
includes the template_json body.
The typical round-trip is: GET /email_templates/{id}.json to load → edit → PATCH /email_templates/{id}.json to save.
Requires the email_templates/read permission.
| id required | string ID of the email template (as returned by create or list). |
{- "id": "5f1c…",
- "name": "Application received",
- "email_type": "job_application",
- "parameters": [
- "candidate.name",
- "job.title"
], - "template_json": [
- {
- "key": "hero-banner",
- "props": {
- "heading": "Thanks for applying"
}
}, - {
- "key": "text-block",
- "props": {
- "body": "Hi {{ candidate.name }}, we received your application for {{ job.title }}."
}
}
]
}Updates an existing template. Partial updates are supported — send only the fields you want to
change. Omitting template_json leaves the stored component blocks untouched; including it
replaces the blocks entirely and re-validates them against the site's component library (same
rules as create). When the blocks change, parameters is recomputed.
PUT is also accepted and behaves identically.
Requires the email_templates/write permission.
| id required | string ID of the email template (as returned by create or list). |
required | object Partial update — supply only the fields you want to change. |
{- "email_template": {
- "name": "Application received (v2)"
}
}{- "id": "5f1c…",
- "name": "Application received (v2)",
- "email_type": "job_application",
- "parameters": [
- "candidate.name"
]
}Identical to PATCH /email_templates/{id}.json. See that operation for request and response
details.
Requires the email_templates/write permission.
| id required | string ID of the email template (as returned by create or list). |
required | object Partial update — supply only the fields you want to change. |
{- "email_template": {
- "name": "string",
- "email_type": "job_application",
- "template_json": [
- {
- "key": "string",
- "props": { }
}
]
}
}{- "id": "string",
- "name": "string",
- "email_type": "string",
- "parameters": [
- "string"
]
}Permanently deletes the template.
Requires the email_templates/write permission.
| id required | string ID of the email template (as returned by create or list). |
{- "error": {
- "code": 404,
- "description": "Not found",
- "details": "Template not found"
}
}Sends an email via the Sourceflow platform.
The body of the email can be provided in exactly one of two ways: a raw html_body, or a
template_id plus a parameters object that fills the template's Liquid variables. Supplying
both html_body and template_id, or neither, returns 400.
Use application/json for plain or HTML emails without attachments.
Use multipart/form-data when including file attachments.
Requires the emails/send permission.
| to required | string Recipient(s). Comma-separated for multiple recipients. |
| subject required | string |
| from | string <email> Sender address the email is sent from. If omitted, the site's default sending address is
used. The domain of this address must be a validated (verified) sending domain for the
site; addresses on unvalidated domains are rejected with |
| body | string Plain-text body. When |
| html_body | string Raw HTML body. Displayed to clients that support HTML email. Mutually exclusive with |
| template_id | string ID of an email template (see |
object Values for the template's Liquid variables; only meaningful with | |
| reply_to | string <email> Sets the |
| attachments | Array of strings <binary> [ items <binary > ] File attachments (max 5 MB per file, 15 MB total). Only supported when the request is sent as |
{- "to": "jane@example.com",
- "from": "careers@example.com",
- "subject": "Thanks for applying",
- "template_id": "5f1c…",
- "parameters": {
- "candidate": {
- "name": "Jane"
},
}
}{- "message": "Email with subject 'Thanks for applying' sent successfully to jane@example.com"
}Provisions a new API partner user, returning client credentials.
object |
{- "api_user": {
- "name": "string"
}
}{- "message": "API User 'Partner Name API User' provisioned.",
- "user": {
- "client_id": "ff08bca4-1e3c-47e2-bf8a-00000000000",
- "client_secret": "xxxxxxxxxxx"
}
}Global-level API for provisioning customers, sites, and API users. Base URL is https://app.sourceflow.co.uk/_sf/api/v1
Creates a new Customer entity and assigns an initial user. Returns credentials for the user that can be used for future site-level API calls.
This is a global-level API. The base URL for customer endpoints is
https://app.sourceflow.co.uk/_sf/api/v1 regardless of which site is being managed.
Requires elevated global API permissions — contact Sourceflow if you have a use case for this.
object | |
object |
{- "customer": {
- "name": "Provision Test"
}, - "user": {
- "name": "Jiminy Cricket",
- "email": "jcricket@pinochio.com",
- "api_only": false
}
}Creates a new site under the specified customer.
This is a global-level API. The base URL for customer endpoints is
https://app.sourceflow.co.uk/_sf/api/v1.
Requires elevated global API permissions.
| customerId required | string <uuid> |
object |
{- "site": {
- "name": "Provision Test Site",
- "seed_categories": true,
- "setup_hosting": true
}
}Provisions an API user under the specified customer. If a user with the given name
already exists and reset_password is not set, only the client_id is returned.
This is a global-level API. The base URL for customer endpoints is
https://app.sourceflow.co.uk/_sf/api/v1.
Requires elevated global API permissions.
| customerId required | string <uuid> |
| user_name | string Name for the API user |
| reset_password | boolean If |
{- "user_name": "Partner Name API User",
- "reset_password": true
}{- "message": "string",
- "user": {
- "client_id": "5b3fa7ba-57d3-4017-a65b-d57dcd2db643",
- "client_secret": "string"
}
}Manage images stored in the Sourceflow Image Manager service (image-manager.sourceflow.co.uk).
Authentication flow (two steps):
POST /_sf/api/v1/auth_tokens.json on your Sourceflow site → receive a short-lived JWTAuthorization: Bearer <token> on all Image Manager requestsScopes — request only what you need when getting the token:
image/upload — required to upload imagesimage/delete — required to delete imagesCDN URLs — uploaded images are served from https://cdn.sourceflow.co.uk/__gallery/{uuid}
Issues a short-lived JWT for use with Image Manager endpoints. The JWT is signed
with a shared secret and carries the requested scope claims.
This endpoint is intended for use within the Sourceflow CMS UI and requires an active CMS session (cookie-based). It is not part of the machine-to-machine OAuth 2.0 flow used by the rest of this API.
Request only the scope(s) you need:
image/upload — required to upload imagesimage/delete — required to delete images| scope required | Array of strings Items Enum: "image/upload" "image/delete" Permissions to grant the token. Request only the scope(s) needed for the operation. |
{- "scope": [
- "image/upload",
- "image/delete"
]
}{- "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLTEyMyIsInNpdGVfaWQiOiJzaXRlLWFiYyIsInNjb3BlIjpbImltYWdlL3VwbG9hZCIsImltYWdlL2RlbGV0ZSJdfQ.signature"
}Returns images belonging to the authenticated site, ordered newest-first.
Supports cursor-based pagination via lastItemId.
Requires any valid Image Service token (no specific scope required).
| size | integer [ 1 .. 100 ] Default: 10 Number of images per page (1–100, default 10) |
| lastItemId | string <uuid> UUID of the last image from the previous page, for cursor pagination |
{- "data": [
- {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "clientId": "site-abc",
- "userId": "user-123",
- "name": "hero-banner.jpg",
- "createdAt": 1700000000000,
- "updatedAt": null,
}
], - "size": 10
}Uploads an image as a base64-encoded string. The service detects the real MIME type from the binary content (not the filename) and rejects non-image files.
On success the file is stored in S3 at __gallery/{uuid} and served via the
CDN at https://cdn.sourceflow.co.uk/__gallery/{uuid}.
Requires a token with the image/upload scope.
| image_name required | string Filename for the image. |
| image required | string <byte> Base64-encoded image file content. The service validates the real MIME type from the binary content — the filename extension is not used for type detection. |
{- "image_name": "profile-photo.jpg",
- "image": "/9j/4AAQSkZJRgABAQEASABIAAD..."
}{- "status": "Image uploaded and metadata stored successfully",
- "image": {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "clientId": "site-abc",
- "userId": "user-123",
- "name": "profile-photo.jpg",
- "createdAt": 1700000000000,
- "updatedAt": null,
}
}Returns metadata for a single image by its UUID. Requires any valid Image Service token (no specific scope required).
| key required | string <uuid> UUID of the image |
{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "clientId": "site-abc",
- "userId": "user-123",
- "name": "hero-banner.jpg",
- "createdAt": 1700000000000,
- "updatedAt": null,
}Permanently deletes an image from both DynamoDB and S3. This cannot be undone.
The token must belong to the same site that owns the image. If the S3 deletion fails after the DynamoDB record is removed, a rollback is automatically attempted to restore the metadata record.
Requires a token with the image/delete scope.
| key required | string <uuid> UUID of the image to delete |
{- "status": "Deleted",
- "id": "550e8400-e29b-41d4-a716-446655440000"
}