prod - 20261103-155809 - acd260dde964f9fc12a4ec4d79828e2feffa7ef1

Management API

The Seamly Management API enables you to manage Seamly resources directly from your own application.

Use it to automate onboarding and configuration, including:

  • Creating, listing, updating, and deleting organisations.
  • Creating, listing, updating, and deleting projects.
  • Configuring your Voice API endpoint and shared secrets for a project.
  • Creating compliance addresses for an organisation.
  • Listing compliance addresses whose country has telephone numbers available for automatic assignment.
  • Automatically assigning telephone numbers to project voice channels and releasing assignments.

The Management API uses server-to-server authentication. You receive credentials from Seamly Support, exchange them for a short-lived access token, and use that token to authenticate your API requests.

Getting access

Contact Seamly Support to request Management API credentials.

Seamly Support will provide:

Credential Description
client_id Identifies your integration.
client_secret Secret used to authenticate your integration when requesting an access token.

Support also configures the permissions assigned to your integration. These determine which organisations and operations you can access.

Store the credentials in your backend’s secret manager or environment configuration. Keep the client secret and access tokens out of browser code, mobile applications, source control, and logs.

Environments

Base URL
https://api.seamly-app.com

Use the credentials provided by Seamly Support for the environment.

Authentication flow

  1. Request an access token using your client_id and client_secret .
  2. Read the access_token from the response.
  3. Include that token in the Authorization header of each Management API request.
  4. Request a new token before the existing token expires.

1. Request an access token

Send a POST request to:

POST /management/token

Authenticate using HTTP Basic authentication , with your client_id as the username and your client_secret as the password.

Send grant_type=client_credentials in the request body.

Authorization: Basic <base64(client_id:client_secret)>
Content-Type: application/x-www-form-urlencoded

Do not include client_id or client_secret in the request body.

cURL example

Set these environment variables in your backend or local development environment:

export SEAMLY_BASE_URL="https://api.seamly-app.com"
export SEAMLY_CLIENT_ID="<your-client-id>"
export SEAMLY_CLIENT_SECRET="<your-client-secret>"

Request a token:

curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${SEAMLY_BASE_URL}/management/token" \
  --user "${SEAMLY_CLIENT_ID}:${SEAMLY_CLIENT_SECRET}" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials"

Successful response

The endpoint returns HTTP 200 OK :

{
  "access_token": "<access-token>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": "2026-10-06T13:00:00Z"
}
Property Description
access_token Token used to authenticate Management API requests.
token_type Authentication scheme. The value is Bearer .
expires_in Token lifetime in seconds.
expires_at Token expiration timestamp in UTC.

Tokens currently have a lifetime of one hour. Use the expiration information in the response rather than hard-coding this duration.

Reuse the token across requests and obtain a new one shortly before it expires. To renew access, repeat the same token request using your client credentials.

2. Authenticate API requests

Include the access token in the HTTP Authorization header:

Authorization: Bearer <access-token>

For requests with a JSON body, also include:

Content-Type: application/json

Your token contains the permissions assigned to your integration when it was issued. If Support changes your permissions, request a new token to use the updated permissions.

Make your first API request

A useful first request is to list the organisations accessible to your integration:

GET /management/v1/organisations

Set the token returned by the authentication endpoint:

export SEAMLY_ACCESS_TOKEN="<access-token>"

Then make the request:

curl --fail-with-body --silent --show-error \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}"

Example response

{
  "organisations": [
    {
      "id": "985a4914-a5d7-4165-8b30-e4577444b018",
      "name": "Acme"
    }
  ]
}

Use the organisation’s id when making requests for its projects or compliance addresses.

The list contains organisations accessible to your integration and is ordered by name, case-insensitively.

Create a project

Once you have an organisation ID, you can create a project configured to use your Voice API implementation:

POST /management/v1/organisations/{organisation_id}/projects

A project requires:

  • A name.
  • The URL of your Voice API HTTP endpoint.
  • One or two shared secrets, each at least 32 characters long.

These Voice API shared secrets are separate from your Management API client secret. They are used to verify the X-Seamly-Signature on Voice API requests.

Example request

Replace the organisation ID and example settings with your own values:

export SEAMLY_ORGANISATION_ID="985a4914-a5d7-4165-8b30-e4577444b018"
curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/projects" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Acme Voice",
    "service_api": {
      "api_endpoint": "https://api.acme.com/service",
      "secrets": [
        "replace-with-a-secret-of-at-least-32-characters"
      ]
    }
  }'

Example response

The endpoint returns HTTP 201 Created :

{
  "project": {
    "id": "da54647a-1222-4a5e-a064-36992b0e4706",
    "name": "Acme Voice",
    "api_key": "34e9b8ba-64e5-4fca-8b90-2bdca1f13663",
    "service_api": {
      "api_endpoint": "https://api.acme.com/service",
      "secrets": [
        "replace-with-a-secret-of-at-least-32-characters"
      ]
    },
    "channels": [
      {
        "name": "voice",
        "phone_numbers": []
      }
    ]
  }
}

Seamly creates the project with a generated API key and a voice channel. Creating a project does not automatically assign a telephone number. To assign one, create or select a compliance address belonging to the organisation, then use the telephone number assignment endpoint described below.

Store the returned project ID for subsequent requests. Project responses contain credentials and shared secrets, so avoid logging the complete response.

See the Voice API documentation for implementing your endpoint and verifying signed requests.

Create or select a compliance address

A telephone number assignment requires a compliance address belonging to the same organisation as the project. The address contains the organisation’s voice compliance contact and address details. Its country determines the country from which Seamly selects a telephone number.

Create a compliance address

Send a POST request to:

POST /management/v1/organisations/{organisation_id}/compliance_addresses

For a business, provide the contact and address details, company name, and company registration number:

curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/compliance_addresses" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{
    "contact_type": "business",
    "company_name": "Acme",
    "contact_name": "Alex Example",
    "address_line_1": "Example Street 12",
    "city": "Amsterdam",
    "postal_code": "1012 AB",
    "country_code": "NL",
    "registration_number": "00123456"
  }'

Use an ISO 3166-1 alpha-2 country code, such as NL . For a private person, use contact_type: "private_person" and omit company_name and registration_number . See the OpenAPI specification for all fields and validation rules.

The endpoint returns HTTP 201 Created :

{
  "compliance_address": {
    "id": "9b435e12-3973-4165-b5c4-7a36f80cdf47",
    "organisation_id": "985a4914-a5d7-4165-8b30-e4577444b018",
    "contact_type": "business",
    "company_name": "Acme",
    "contact_name": "Alex Example",
    "address_line_1": "Example Street 12",
    "address_line_2": null,
    "city": "Amsterdam",
    "region": null,
    "postal_code": "1012 AB",
    "country_code": "NL",
    "registration_number": "00123456"
  }
}

Save compliance_address.id for the telephone number assignment request. Creating an address does not guarantee that a telephone number is available in its country.

Select an existing compliance address

To find existing addresses whose country has telephone numbers available for automatic assignment:

curl --fail-with-body --silent --show-error \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/compliance_addresses" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}"

The endpoint returns HTTP 200 OK with a compliance_addresses array, ordered by creation. Each item has the same address fields as the create response above.

This is a filtered availability list, not a complete list of the organisation’s compliance addresses. An empty array does not necessarily mean that no addresses exist:

{
  "compliance_addresses": []
}

An address appearing in this list does not guarantee a successful assignment. The assignment endpoint also checks compatibility with the requested channel, and availability may change between requests.

Assign a telephone number

Once you have a project ID and a compliance address ID, send a POST request to:

POST /management/v1/organisations/{organisation_id}/projects/{project_id}/phone_numbers

Seamly automatically selects an eligible, unassigned telephone number from the compliance address’s country that is compatible with the requested channel. You do not choose a specific telephone number in this request.

Example request

Set the IDs returned by the earlier requests:

export SEAMLY_PROJECT_ID="da54647a-1222-4a5e-a064-36992b0e4706"
export SEAMLY_COMPLIANCE_ADDRESS_ID="9b435e12-3973-4165-b5c4-7a36f80cdf47"

Assign a number to the project’s voice channel:

curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/projects/${SEAMLY_PROJECT_ID}/phone_numbers" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data "{
    \"channel_name\": \"voice\",
    \"compliance_address_id\": \"${SEAMLY_COMPLIANCE_ADDRESS_ID}\"
  }"

The required fields are channel_name and compliance_address_id . The compliance address must belong to the organisation specified in the URL.

Example response

The endpoint returns HTTP 201 Created :

{
  "phone_number": {
    "id": 1,
    "number": "+31201234567",
    "country": "NL",
    "channel_name": "voice",
    "compliance_address_id": "9b435e12-3973-4165-b5c4-7a36f80cdf47"
  }
}

The number field contains the selected telephone number. Save the numeric id if you need to release the assignment later.

If no eligible number is available for the country and channel, the endpoint returns HTTP 409 Conflict with error: "no_available_phone_numbers" . See Error handling below.

View and release assigned telephone numbers

View current assignments

Retrieve the project to see its current telephone number assignments:

curl --fail-with-body --silent --show-error \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/projects/${SEAMLY_PROJECT_ID}" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}"

The endpoint returns HTTP 200 OK . Assignments appear in project.channels[].phone_numbers , with each entry containing id , number , and compliance_address_id .

For legacy or manually created assignments, compliance_address_id may be null .

Release an assignment

Use the numeric telephone number id from the assignment response or project response, not the telephone number itself:

export SEAMLY_PHONE_NUMBER_ID="1"
curl --fail-with-body --silent --show-error \
  --request DELETE \
  --url "${SEAMLY_BASE_URL}/management/v1/organisations/${SEAMLY_ORGANISATION_ID}/projects/${SEAMLY_PROJECT_ID}/phone_numbers/${SEAMLY_PHONE_NUMBER_ID}" \
  --header "Authorization: Bearer ${SEAMLY_ACCESS_TOKEN}"

The endpoint releases the project’s telephone number assignment and returns HTTP 204 No Content , with no response body.

Available operations

All resource endpoints use the /management/v1 prefix.

Resource Operations
Organisations List, create, retrieve, update, and delete.
Projects within an organisation List, create, retrieve, update, and delete.
Compliance addresses within an organisation Create; list addresses whose country has telephone numbers available for automatic assignment.
Telephone numbers assigned to a project Automatically assign and release. Retrieve the project to view current assignments.

The operations available to your integration depend on the permissions configured by Seamly Support. For example, access to an existing organisation does not automatically allow you to create new organisations.

Deleting a project is permanent. Deleting an organisation permanently deletes the organisation, its projects, and related database records.

Error handling

Token endpoint errors

Token errors use the following format:

{
  "error": "invalid_client"
}
HTTP status Error Meaning
400 invalid_request The request is malformed, for example because grant_type is missing or client credentials are included in the body.
400 unsupported_grant_type The requested grant type is unsupported. Use client_credentials .
400 unauthorized_client The credentials are valid, but the integration has no Management API grant. Contact Support.
401 invalid_client HTTP Basic credentials are missing or invalid. Check the credentials and environment.

Management API errors

HTTP status Meaning Suggested action
400 Invalid JSON, where defined by the endpoint. Check the request body’s JSON syntax.
401 Missing, invalid, or expired access token, or no qualifying permissions. Check the Bearer header. Obtain a new token if expired; contact Support if permissions are missing.
403 The operation is not allowed. Check whether your integration has permission for this operation.
404 The resource does not exist or is inaccessible. Check the resource ID, environment, and access permissions.
409 No eligible telephone number is available for the compliance address’s country and requested channel. Check the selected address and channel; contact Seamly Support if you need additional availability.
422 Invalid request data or another validation failure. Inspect the response and correct the request.

When no eligible telephone number is available, the assignment endpoint returns:

{
  "error": "no_available_phone_numbers"
}

Validation errors may include field-level details:

{
  "errors": [
    {
      "title": "Invalid value",
      "detail": "can't be blank",
      "source": {
        "pointer": "/name"
      }
    }
  ]
}

Handle errors according to the endpoint’s specification. Avoid automatically retrying create or delete requests after a timeout: the operation may already have completed.

If a telephone number assignment request times out, retrieve the project and check its current assignments before retrying. The number may already have been assigned, and repeating the request could assign an additional number.

OpenAPI specification

The OpenAPI specification provides the complete reference for endpoint paths, request fields, response schemas, and status codes.

Use this guide to get started and the specification as the authoritative API reference.