public function allocateIds(array $keys, array $options = [])
    {
        // Validate the given keys. First check types, then state of each.
        // The API will throw a 400 if the key is named, but it's an easy
        // check we can handle before going to the API to save a request.
        // @todo replace with json schema
        $this->validateBatch($keys, Key::class, function ($key) {
            if ($key->state() !== Key::STATE_INCOMPLETE) {
                throw new \InvalidArgumentException(sprintf(
                    'Given $key is in an invalid state. Can only allocate IDs for incomplete keys. ' .
                    'Given path was %s',
                    (string) $key
                ));
            }
        });

        $serviceKeys = [];
        foreach ($keys as $key) {
            $serviceKeys[] = $key->keyObject();
        }

        $res = $this->connection->allocateIds([
            'projectId' => $this->projectId,
            'keys' => $serviceKeys
        ] + $options);

        if (isset($res['keys'])) {
            foreach ($res['keys'] as $index => $key) {
                if (!isset($keys[$index])) {
                    continue;
                }

                $end = end($key['path']);
                $id = $end['id'];
                $keys[$index]->setLastElementIdentifier($id);
            }
        }

        return $keys;
    }