Creating users

When upserting targets via the Targets: Bulk Upsert endpoint, you can optionally create a volunteer user account for each target. This is useful for integrations which need to provision user access alongside importing member data.

User creation is best-effort — if user creation fails for a given record, the target data is still imported successfully. See Limitations for details on when user creation can fail silently.

Parameters

The following parameters can be included alongside the standard target fields in each record:

ParameterTypeDefaultDescription
create_userBooleanfalseWhether to create a volunteer user for this target. Accepts true, "y", or "Y" to enable.
create_user_role_slugsStringSpace-separated role slugs to assign to the user (e.g. "volunteer", "co-ordinator volunteer"). The special value "_remove" removes all roles from the user.
create_user_organisation_typeStringThe organisation type to create the user's role against. Must match the external_type of an organisation attached to the target.

An email address is required on the target for user creation to proceed. If the email is blank, user creation is silently skipped.

Example request

curl https://subdomain.yourmovement.org/api/targets/bulk_upsert \
   -XPOST \
   -H 'Authorization: Bearer API_TOKEN' \
   -H 'Content-Type: application/json' \
   -d '{"records": [
     {
       "external_id": "MEM001",
       "first_name": "Jane",
       "last_name": "Smith",
       "email": "[email protected]",
       "phone_number": "+441234567890",
       "create_user": true,
       "create_user_role_slugs": "volunteer",
       "create_user_organisation_type": "branch"
     }
   ]}'

How user creation works

When create_user is set to true (or "y"), the system follows this process:

1. Organisation selection

The system determines which organisation to create the user's role against, using the following priority:

  1. If create_user_organisation_type is provided, it finds an organisation of that type attached to the target. If none is found, user creation is skipped.
  2. Otherwise, if the client has a default create_user_org_kind configured, an organisation of that type is used.
  3. Failing both of the above, the national organisation is used.

2. Matching existing users

Before creating a new user, the system checks for an existing user in this order:

  1. A user already linked to the target (matching target_id)
  2. A user with the same email address (who is not linked to any target)
  3. A user with the same phone number (who is not linked to any target)

If an existing user is found, their details are updated rather than creating a new account.

3. Creating or updating the user

New user: A new user account is created with an auto-generated secure password and the volunteer role on the selected organisation. The user is automatically approved.

Existing user: The user's name, email, phone number, and target link are updated. If the organisation has changed, their existing roles are moved to the new organisation (unless they are currently on the national organisation).

4. Role assignment

If create_user_role_slugs is provided, the specified roles replace any existing roles on the selected organisation:

  • Multiple roles can be specified as a space-separated string, e.g. "co-ordinator volunteer"
  • The special value "_remove" removes all roles from the user
  • If create_user_role_slugs is not provided, existing roles are left unchanged

Limitations

User creation is best-effort. If it fails, the target record is still created — only the user account is not provisioned. The record may appear in the rejected array in the deferred result, but note that in this case the target data has been imported; only the user creation step failed.

  • Email is required. If the target has no email address, user creation is silently skipped with no error.
  • Email uniqueness. If a user with the same email already exists and is linked to a different target, user creation will fail. The system only matches unlinked users (those with no target association) when looking for an existing account to update. A user who is already linked to another target will not be matched, and the attempt to create a new user with the same email will be rejected by the uniqueness constraint.
  • Phone number uniqueness. Similarly, if a user with the same phone number already exists and is linked to a different target, user creation may fail due to the phone number uniqueness constraint.
  • Organisation type must exist. If create_user_organisation_type is specified but no organisation of that type is attached to the target, user creation is silently skipped.
  • Invalid role slugs. If a role slug provided in create_user_role_slugs does not match any configured role, the operation will raise an error for that record.

Reading row-level results

The bulk upsert endpoint processes records asynchronously and returns a deferred_result_id which you can poll to check progress. See the Asynchronous operations guide for full details.

To check the result, poll the deferred results endpoint:

GET /api/deferred_results/{deferred_result_id}

While processing, the response will have "status": "running". Once complete, the response will look like:

{
  "status": "ready",
  "result": {
    "record_count": 3,
    "upserted_count": 2,
    "rejected": [
      {
        "external_id": "MEM003",
        "first_name": "Bob",
        "last_name": "Jones",
        "email": "[email protected]",
        "create_user": true,
        "error": "Validation failed: Email has already been taken"
      }
    ]
  }
}

The rejected array contains the original record data for any records that encountered an error during processing. Each rejected record includes an error key with a description of what went wrong. For errors raised during processing (such as email uniqueness violations from create_user), this will contain the specific error message. For records that fail validation before processing begins (e.g. missing external_id), the error will be "Validation failed".

For example, if a user with the email [email protected] already exists and is linked to a different target, the error will be:

"error": "Validation failed: Email has already been taken"

If the entire job fails unexpectedly, the status will be "failed" with an error key containing a message.

Deferred results are available for 24 hours after creation.