Skip to main content
Provisioning is setting up a customer in Twine entirely through the API: creating the Organization, connecting its systems as System Integrations, and linking them with Domain Mappings that decide when data moves. Vendor customers typically do this once per customer they onboard. The steps below are the usual order. Each one needs ids returned by the previous one.
Creating an organization requires create permission on the organization the token belongs to. Firing a sync trigger requires admin permission on the domain mapping or on its source system integration. Neither is part of the default API service account role; ask Twine to grant them to the role you provision with.

1. Create the organization

POST /v1/org creates a new organization as a child of the organization your token belongs to. Every other provisioning endpoint lives under /v1/org/... and acts on the organization of the token making the request, not on an id in the URL. To configure the new organization, you therefore need a token that belongs to it. Ask for one in the same request by adding a role with create_in set to child and create_api_refresh_token set to true:
The response carries the refresh token under roles[].tokens[], with its jwt and jti. This is the only time the refresh token is readable, so store it in your own secret store straight away. Exchange it for an access token as described in Authentication, and use that access token for the remaining steps.
Set suppression_ends_at (and optionally suppression_reason) to keep automatic circuit breakers from tripping on the new organization while it is being onboarded, when error rates and large changes are expected.

2. Create the system integrations

A system integration is one connection to one system. Look up the system_id of each system you need with GET /v1/systems, then create an integration for each with POST /v1/org/system-integrations.

The Twine system integration

Almost every organization needs a system integration for Twine itself. It is the side of a domain mapping that stands for data held in Twine, so it is what lets you read data synced from a source system through the API, and what replicates data you push through the API on to a target system. It takes no credentials:
Creating an organization does not create this integration for you.

External systems

For an external system, send its credentials in auth and its system-specific settings in system_custom. Both are discriminated by slug, and the fields each system accepts are listed in the endpoint reference.
Pass template_id to create the integration from a template, or create_default_mappings to start from the system’s default property mappings. If your customer holds the credentials rather than you, leave auth out and send them a credentials link once the integration exists.

Letting your customer enter credentials

POST /v1/org/system-integrations/{id}/credentials-link returns a url your customer opens to enter the integration’s credentials themselves, without a Twine login. You never see what they enter. Systems that sign in through the vendor send the customer there instead. The link collects credentials only. For a system whose API can live on any host (Flex HRM, Agda PS, S3, SFTP), where the integration connects is yours to set, before you create the link: PATCH /v1/org/system-integrations/{id} with api_endpoint_url in auth (Flex HRM, Agda PS) or the host in system_custom (S3, SFTP). Until then the link request answers 422. Your customer sees that endpoint or host on the form, read-only, so they can tell you if it is not theirs. The link is valid until expires_at (5 days) and can be submitted once. Create a new one if it expires, or whenever the credentials need to be entered again. Creating a link requires admin permission on the system integration, since whoever holds it can set the credentials. Stored secrets are never returned by the API. See Changing credentials and endpoints before updating an integration later.

3. Create the domain mappings

A domain mapping moves one domain of data from a source system integration to a target system integration, for example employees from an HR system into Twine. Create one with POST /v1/org/domain-mappings:
The sync trigger decides when the mapping runs. There are two common setups:
  • Scheduled. Give the trigger a cron_expression and set enabled to true. enabled defaults to false, so a trigger created without it does not run until it is enabled.
  • Manual. Leave cron_expression out. The trigger then only runs when you fire it (see the next step). This suits initial loads, testing, and migrations where you want to control exactly when data moves.
Only the first entry in sync_triggers is used when creating a domain mapping. Add conditions to filter out entities this mapping should not process.

4. Run a sync

A scheduled trigger runs on its own. To run a sync now, whether the trigger is scheduled or manual, fire it:
The response holds the job_id of the sync. Follow its progress with GET /v1/org/jobs/{job_id}. If a sync is already running for the same system integration and domain, the request is answered with 409 Conflict; retry once that sync has finished.

Changing credentials and endpoints

Update an integration with PATCH /v1/org/system-integrations/{id}. Only the fields you send with a value change. A field left out, or sent as null, keeps its stored value, and this holds inside auth and system_custom too. You can therefore rename an integration or change one setting without knowing its credentials. Writing credentials requires admin permission on the system integration. A role without it can update everything else.
PUT /v1/org/system-integrations/{id} is deprecated. It requires auth and system_custom in every request; a null in either keeps the stored value. Use PATCH for new integrations.
Changing an integration’s endpoint clears its stored secrets. When an update changes api_endpoint_url, the stored api_key and api_client_secret are removed unless they are sent in the same request, whether with new values or the current ones. The same applies when the S3 or SFTP host in system_custom changes.This is a security measure against credential theft. Without it, anyone allowed to edit the integration, even without access to its secrets, could point the endpoint at a server they control and simply wait: the next sync would send your customer’s credentials straight to them. Clearing the secrets means a new endpoint only ever receives credentials from someone who already holds them.Because the API never returns stored secrets, you cannot read them back afterwards. Either send the endpoint and its credentials together, or, if your customer holds the credentials, change the endpoint first and then send them a new credentials link.
Only a real change of endpoint clears anything. Sending the current URL again, or the same URL with different surrounding whitespace, a trailing slash, or different letter case in the scheme and host, keeps the secrets. api_client_id is always kept, since it identifies an account rather than proving access to it, and so are webhook secrets, which authenticate requests coming into Twine rather than going out.